Skip to contentSkip to conversation

arm64/efi: use stable virtual mappings for UEFI runtime services

RFC PATCH New Ard Biesheuvel 5 participants 10 messages Oct 8, 2014 – Oct 15, 2014

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

RFC PATCH 1/1 arm64/efi: use stable virtual mappings for UEFI runtime services

In order to allow kexec under UEFI, we need to make sure that the virtual mapping of the UEFI Runtime Services is chosen in such a way that we can reuse it again after kexec. The reason for this is that we can only install a virtual mapping once, which means we need to choose wisely, i.e., the virtual mapping should be compatible with any kind of kernel we choose to kexec next.

This patch chooses a mapping where all the UEFI memory regions are rounded up to be a multiple of 64 KB in size (to be compatible with 64 KB granule kernels) and mapped adjacently into the lower, userland half of the kernel virtual memory space starting at 0x4000_0000 (1 GB).

---

Note that this patch is RFC quality; it may need to be split up, and the declaration of __create_mapping() needs to be moved to a header file. However, it should be sufficient to illustrate how we can use a virtual mapping that is installed using SetVirtualAddressMap(), is stable across kexec and is compatible with both 4 KB and 64 KB pagesize kernels.

I haven't tested this code under kexec myself, but I have confirmed that the runtime services work as expected (rtc-efi and efivars). The comments that Mark Salter and Will Deacon gave on the id mapping patch here

http://marc.info/?l=linux-arm-kernel&m=140681612407532&w=2

should apply equally to this patch: taking exceptions while the EFI pgd is installed into TTBR0 appears to work correctly, but more testing is needed.

 arch/arm64/include/asm/efi.h |  17 +++--
 arch/arm64/kernel/efi.c      | 163 +++++++++++++++++++++++++++++--------------
 arch/arm64/mm/mmu.c          |   2 +-
 3 files changed, 124 insertions(+), 58 deletions(-)
arch/arm64/include/asm/efi.h +13 -4
index a34fd3b12e2b..38921c8592b5 100644
@@ -12,23 +12,32 @@ extern void efi_idmap_init(void);
 #define efi_idmap_init()
 #endif
 
+void efi_load_rt_mapping(void);
+void efi_unload_rt_mapping(void);
+
 #define efi_call_virt(f, ...)						\
 ({									\
-	efi_##f##_t *__f = efi.systab->runtime->f;			\
+	efi_##f##_t *__f;						\
 	efi_status_t __s;						\
 									\
-	kernel_neon_begin();						\
+	kernel_neon_begin();	/* disables preemption */		\
+	efi_load_rt_mapping();						\
+	__f = efi.systab->runtime->f;					\
 	__s = __f(__VA_ARGS__);						\
+	efi_unload_rt_mapping();					\
 	kernel_neon_end();						\
 	__s;								\
 })
 
 #define __efi_call_virt(f, ...)						\
 ({									\
-	efi_##f##_t *__f = efi.systab->runtime->f;			\
+	efi_##f##_t *__f;						\
 									\
-	kernel_neon_begin();						\
+	kernel_neon_begin();	/* disables preemption */		\
+	efi_load_rt_mapping();						\
+	__f = efi.systab->runtime->f;					\
 	__f(__VA_ARGS__);						\
+	efi_unload_rt_mapping();					\
 	kernel_neon_end();						\
 })
 
arch/arm64/kernel/efi.c +110 -53

239 lines not on this page · raw message

arch/arm64/mm/mmu.c +1 -1
index 6894ef3e6234..8ecf2264334e 100644
@@ -249,7 +249,7 @@ static void __init alloc_init_pud(pgd_t *pgd, unsigned long addr,
  * Create the page directory entries and any necessary page tables for the
  * mapping specified by 'md'.
  */
-static void __init __create_mapping(pgd_t *pgd, phys_addr_t phys,
+void __init __create_mapping(pgd_t *pgd, phys_addr_t phys,
 				    unsigned long virt, phys_addr_t size,
 				    int map_io)
 {
Signature · 1 line
1.8.3.2
#1 lore raw

RFC PATCH 1/1 arm64/efi: use stable virtual mappings for UEFI runtime services

Hi Ard,

Quoted 3 lines · Ard Biesheuvel

I haven't tested this code under kexec myself, but I have confirmed that the runtime services work as expected (rtc-efi and efivars). The comments that Mark Salter and Will Deacon gave on the id mapping patch here

I applied this patch to my kexec master branch [1] and tested a basic kexec re-boot using the FVP_Base_AEMv8A-AEMv8A_0.8_5602 model and the 14.09 LEG EFI build.

It crashes when the 2nd stage kernel is starting up on the first dereference of the c16 variable in uefi_init():

  c16 = early_memremap(efi.systab->fw_vendor, sizeof(vendor));
  if (c16) {
    for (i = 0; i < (int) sizeof(vendor) - 1 && *c16; ++i) {
                                                ^^^^ crashes here

early_memremap() returns 0xFFFFFFBFFBCBF618, and the dereference starts the crash. I did not look into it further.

[1] https://git.linaro.org/people/geoff.levand/linux-kexec.git

-Geoff

#2 lore raw

RFC PATCH 1/1 arm64/efi: use stable virtual mappings for UEFI runtime services

Hi, Geoff

Quoted 14 lines · Geoff Levand

Hi Ard,

Quoted 3 lines · Ard Biesheuvel

I haven't tested this code under kexec myself, but I have confirmed that the runtime services work as expected (rtc-efi and efivars). The comments that Mark Salter and Will Deacon gave on the id mapping patch here

I applied this patch to my kexec master branch [1] and tested a basic kexec re-boot using the FVP_Base_AEMv8A-AEMv8A_0.8_5602 model and the 14.09 LEG EFI build.

It crashes when the 2nd stage kernel is starting up on the first dereference of the c16 variable in uefi_init():

Quoted 7 lines
  c16 = early_memremap(efi.systab->fw_vendor, sizeof(vendor));
  if (c16) {
    for (i = 0; i < (int) sizeof(vendor) - 1 && *c16; ++i) {
                                                ^^^^ crashes here

early_memremap() returns 0xFFFFFFBFFBCBF618, and the dereference starts the crash. I did not look into it further.

This is an expected behaviour as I mentioned before, we need save fw_vendor and the other two physical addresses and pass them to 2nd kernel.

UEFI firmware will convert them to virtual address after entering virtual mode.

Thanks
Dave

#3 lore raw

RFC PATCH 1/1 arm64/efi: use stable virtual mappings for UEFI runtime services

Quoted 22 lines · Dave Young

Hi, Geoff

Quoted 19 lines · Geoff Levand

Hi Ard,

Quoted 3 lines · Ard Biesheuvel

I haven't tested this code under kexec myself, but I have confirmed that the runtime services work as expected (rtc-efi and efivars). The comments that Mark Salter and Will Deacon gave on the id mapping patch here

I applied this patch to my kexec master branch [1] and tested a basic kexec re-boot using the FVP_Base_AEMv8A-AEMv8A_0.8_5602 model and the 14.09 LEG EFI build.

It crashes when the 2nd stage kernel is starting up on the first dereference of the c16 variable in uefi_init():

  c16 = early_memremap(efi.systab->fw_vendor, sizeof(vendor));
  if (c16) {
    for (i = 0; i < (int) sizeof(vendor) - 1 && *c16; ++i) {
                                                ^^^^ crashes here
Quoted 8 lines
Quoted 2 lines

early_memremap() returns 0xFFFFFFBFFBCBF618, and the dereference starts the crash. I did not look into it further.

This is an expected behaviour as I mentioned before, we need save fw_vendor and the other two physical addresses and pass them to 2nd kernel.

UEFI firmware will convert them to virtual address after entering virtual mode.

Yes, you did point that out before, and I haven't addressed it in my patch.

But allow me to emphasize *again* that these issues will simply cease to exist if we decide to not use SetVirtualAddressMap() at all, and call the UEFI Runtime Services through their physical mappings.

Patch here
http://marc.info/?l=linux-arm-kernel&m=140681612407532&w=2

Signature · 1 line
Ard.
#4 lore raw

RFC PATCH 1/1 arm64/efi: use stable virtual mappings for UEFI runtime services

Quoted 32 lines · Ard Biesheuvel
Quoted 22 lines · Dave Young

Hi, Geoff

Quoted 19 lines · Geoff Levand

Hi Ard,

Quoted 3 lines · Ard Biesheuvel

I haven't tested this code under kexec myself, but I have confirmed that the runtime services work as expected (rtc-efi and efivars). The comments that Mark Salter and Will Deacon gave on the id mapping patch here

I applied this patch to my kexec master branch [1] and tested a basic kexec re-boot using the FVP_Base_AEMv8A-AEMv8A_0.8_5602 model and the 14.09 LEG EFI build.

It crashes when the 2nd stage kernel is starting up on the first dereference of the c16 variable in uefi_init():

  c16 = early_memremap(efi.systab->fw_vendor, sizeof(vendor));
  if (c16) {
    for (i = 0; i < (int) sizeof(vendor) - 1 && *c16; ++i) {
                                                ^^^^ crashes here
Quoted 8 lines
Quoted 2 lines

early_memremap() returns 0xFFFFFFBFFBCBF618, and the dereference starts the crash. I did not look into it further.

This is an expected behaviour as I mentioned before, we need save fw_vendor and the other two physical addresses and pass them to 2nd kernel.

UEFI firmware will convert them to virtual address after entering virtual mode.

Quoted 8 lines

Yes, you did point that out before, and I haven't addressed it in my patch.

But allow me to emphasize *again* that these issues will simply cease to exist if we decide to not use SetVirtualAddressMap() at all, and call the UEFI Runtime Services through their physical mappings.

Patch here
http://marc.info/?l=linux-arm-kernel&m=140681612407532&w=2

IIRC, noot calling SetVirtualAddressMap() was suggested in x86 too but was finally rejected. Reason being that developers wanted to stay close to windows and it was calling SetVirtualAddressMap(). Concern was that if we take an entirely different path then it might not be well tested.

I don't know if same concerns apply in arm64 world or not.

Thanks
Vivek

#5 lore raw

RFC PATCH 1/1 arm64/efi: use stable virtual mappings for UEFI runtime services

Quoted 39 lines · Vivek Goyal
Quoted 38 lines · Ard Biesheuvel
Quoted 22 lines · Dave Young

Hi, Geoff

Quoted 19 lines · Geoff Levand

Hi Ard,

Quoted 3 lines · Ard Biesheuvel

I haven't tested this code under kexec myself, but I have confirmed that the runtime services work as expected (rtc-efi and efivars). The comments that Mark Salter and Will Deacon gave on the id mapping patch here

I applied this patch to my kexec master branch [1] and tested a basic kexec re-boot using the FVP_Base_AEMv8A-AEMv8A_0.8_5602 model and the 14.09 LEG EFI build.

It crashes when the 2nd stage kernel is starting up on the first dereference of the c16 variable in uefi_init():

  c16 = early_memremap(efi.systab->fw_vendor, sizeof(vendor));
  if (c16) {
    for (i = 0; i < (int) sizeof(vendor) - 1 && *c16; ++i) {
                                                ^^^^ crashes here
Quoted 8 lines
Quoted 2 lines

early_memremap() returns 0xFFFFFFBFFBCBF618, and the dereference starts the crash. I did not look into it further.

This is an expected behaviour as I mentioned before, we need save fw_vendor and the other two physical addresses and pass them to 2nd kernel.

UEFI firmware will convert them to virtual address after entering virtual mode.

Yes, you did point that out before, and I haven't addressed it in my patch.

But allow me to emphasize *again* that these issues will simply cease to exist if we decide to not use SetVirtualAddressMap() at all, and call the UEFI Runtime Services through their physical mappings.

Quoted 8 lines
Quoted 2 lines

Patch here
http://marc.info/?l=linux-arm-kernel&m=140681612407532&w=2

IIRC, noot calling SetVirtualAddressMap() was suggested in x86 too but was finally rejected. Reason being that developers wanted to stay close to windows and it was calling SetVirtualAddressMap(). Concern was that if we take an entirely different path then it might not be well tested.

The primary argument for using SetVirtualAddressMap() is that it will be untested and hence broken otherwise. That would prevent us from ever reverse the decision not to use it, as it would cause a regression for systems in the field.

Quoted 2 lines

I don't know if same concerns apply in arm64 world or not.

Unlike in the x86 world, Linux is expected to be the dominant use case for UEFI on arm64 for the foreseeable future, so vendors will care about whether the implementation of UEFI they ship works correctly with Linux. The only way to force those vendors to implement SetVirtualAddressMap() correctly is to call it unconditionally in the kernel.

#6 lore raw

RFC PATCH 1/1 arm64/efi: use stable virtual mappings for UEFI runtime services

In reply to Ard Biesheuvel

Hi Ard,

Quoted 8 lines · Ard Biesheuvel
Quoted 7 lines · Dave Young
Quoted 2 lines · Geoff Levand

early_memremap() returns 0xFFFFFFBFFBCBF618, and the dereference starts the crash. I did not look into it further.

This is an expected behaviour as I mentioned before, we need save fw_vendor and the other two physical addresses and pass them to 2nd kernel.

Quoted 8 lines
Quoted 2 lines

UEFI firmware will convert them to virtual address after entering virtual mode.

Yes, you did point that out before, and I haven't addressed it in my patch.

But allow me to emphasize *again* that these issues will simply cease to exist if we decide to not use SetVirtualAddressMap() at all, and call the UEFI Runtime Services through their physical mappings.

Once you figure out what you will do, and you think you have a complete working solution, let me know and I will test them. I don't plan to do any more UEFI testing until then.

-Geoff

#7 lore raw

RFC PATCH 1/1 arm64/efi: use stable virtual mappings for UEFI runtime services

Quoted 16 lines · Geoff Levand

Hi Ard,

Quoted 13 lines · Ard Biesheuvel
Quoted 9 lines · Dave Young
Quoted 2 lines · Geoff Levand

early_memremap() returns 0xFFFFFFBFFBCBF618, and the dereference starts the crash. I did not look into it further.

This is an expected behaviour as I mentioned before, we need save fw_vendor and the other two physical addresses and pass them to 2nd kernel.

UEFI firmware will convert them to virtual address after entering virtual mode.

Yes, you did point that out before, and I haven't addressed it in my patch.

Quoted 8 lines
Quoted 3 lines

But allow me to emphasize *again* that these issues will simply cease to exist if we decide to not use SetVirtualAddressMap() at all, and call the UEFI Runtime Services through their physical mappings.

Once you figure out what you will do, and you think you have a complete working solution, let me know and I will test them. I don't plan to do any more UEFI testing until then.

I agree it makes sense that we align on and implement a complete approach before spending any more of your time on this.

Thanks for testing,
Ard.

reviewer
#8 lore raw

RFC PATCH 1/1 arm64/efi: use stable virtual mappings for UEFI runtime services

In reply to Dave Young
Quoted 22 lines · Dave Young

Hi, Geoff

Quoted 19 lines · Geoff Levand

Hi Ard,

Quoted 3 lines · Ard Biesheuvel

I haven't tested this code under kexec myself, but I have confirmed that the runtime services work as expected (rtc-efi and efivars). The comments that Mark Salter and Will Deacon gave on the id mapping patch here

I applied this patch to my kexec master branch [1] and tested a basic kexec re-boot using the FVP_Base_AEMv8A-AEMv8A_0.8_5602 model and the 14.09 LEG EFI build.

It crashes when the 2nd stage kernel is starting up on the first dereference of the c16 variable in uefi_init():

  c16 = early_memremap(efi.systab->fw_vendor, sizeof(vendor));
  if (c16) {
    for (i = 0; i < (int) sizeof(vendor) - 1 && *c16; ++i) {
                                                ^^^^ crashes here
Quoted 7 lines
Quoted 2 lines

early_memremap() returns 0xFFFFFFBFFBCBF618, and the dereference starts the crash. I did not look into it further.

This is an expected behaviour as I mentioned before, we need save fw_vendor and the other two physical addresses and pass them to 2nd kernel.

UEFI firmware will convert them to virtual address after entering virtual mode.

So long as we know they are virtual addresses (implied by whatever way we detect we're in virtual mode), and we know the virt->phys mappings (which are in the EFI memmap passed via the DTB), we should be able to figure out those physical addresses without having to pass them explicitly, regardless of what mapping is used.

Mark.

#9 lore raw

RFC PATCH 1/1 arm64/efi: use stable virtual mappings for UEFI runtime services

Quoted 29 lines · Mark Rutland
Quoted 28 lines · Dave Young

Hi, Geoff

Quoted 14 lines · Geoff Levand

Hi Ard,

Quoted 3 lines · Ard Biesheuvel

I haven't tested this code under kexec myself, but I have confirmed that the runtime services work as expected (rtc-efi and efivars). The comments that Mark Salter and Will Deacon gave on the id mapping patch here

I applied this patch to my kexec master branch [1] and tested a basic kexec re-boot using the FVP_Base_AEMv8A-AEMv8A_0.8_5602 model and the 14.09 LEG EFI build.

It crashes when the 2nd stage kernel is starting up on the first dereference of the c16 variable in uefi_init():

Quoted 7 lines
  c16 = early_memremap(efi.systab->fw_vendor, sizeof(vendor));
  if (c16) {
    for (i = 0; i < (int) sizeof(vendor) - 1 && *c16; ++i) {
                                                ^^^^ crashes here

early_memremap() returns 0xFFFFFFBFFBCBF618, and the dereference starts the crash. I did not look into it further.

This is an expected behaviour as I mentioned before, we need save fw_vendor and the other two physical addresses and pass them to 2nd kernel.

Quoted 7 lines
Quoted 1 line

UEFI firmware will convert them to virtual address after entering virtual mode.

So long as we know they are virtual addresses (implied by whatever way we detect we're in virtual mode), and we know the virt->phys mappings (which are in the EFI memmap passed via the DTB), we should be able to figure out those physical addresses without having to pass them explicitly, regardless of what mapping is used.

It's possible to get the physical address from the converted virt address in this case.