arm64 EFI patches for 3.19
Subsystems (3)
cover arm64 EFI patches for 3.19
This is a bit of a mixed bag of patches that we would like to see merged for 3.19. Most of them have been posted and discussed on linux-efi and/or LAKML before, and one of them has even been merged and reverted twice.
Patches #1 - #4 are fixes for compliance with the UEFI and PE/COFF specs. No issues are known that require these patches, so there is no reason to pull them into a stable release.
Patches #5 and #6 address minor issues in the arm64 EFI init code.
Patches #7 - #10 implement DMI/SMBIOS for arm64, both the existing 32-bit version and the upcoming 3.0 version that allows the SMBIOS structure table to reside at a physical offset that cannot be encoded in 32-bits. It also install a 'Hardware: xxx' string that is printed along with oopses and kernel call stack dumps on systems that implement DMI/SMBIOS.
Please refer to the patches themselves for version history. Acks and/or comments appreciated.
Ard Biesheuvel (9):
arm64/efi: efistub: jump to 'stext' directly, not through the header arm64/efi: set PE/COFF section alignment to 4 KB arm64/efi: set PE/COFF file alignment to 512 bytes arm64/efi: reserve regions of type ACPI_MEMORY_NVS arm64/efi: drop redundant set_bit(EFI_CONFIG_TABLES) arm64/efi: use UEFI memory map unconditionally if available
efi: dmi: add support for SMBIOS 3.0 UEFI configuration table
dmi: add support for SMBIOS 3.0 64-bit entry point
arm64: dmi: set DMI string as dump stack arch description
Yi Li (1):
arm64: dmi: Add SMBIOS/DMI support
arch/arm64/Kconfig | 11 +++++++ arch/arm64/include/asm/dmi.h | 31 ++++++++++++++++++ arch/arm64/kernel/efi-entry.S | 3 +- arch/arm64/kernel/efi.c | 29 +++++++++++------ arch/arm64/kernel/head.S | 24 +++++++++----- arch/arm64/kernel/vmlinux.lds.S | 17 ++++++++++ drivers/firmware/dmi_scan.c | 70 +++++++++++++++++++++++++++++++++++++++-- drivers/firmware/efi/efi.c | 4 +++ include/linux/efi.h | 6 +++- 9 files changed, 175 insertions(+), 20 deletions(-) create mode 100644 arch/arm64/include/asm/dmi.h
Signature · 1 line
1.8.3.2
PATCH 1/10 arm64/efi: efistub: jump to 'stext' directly, not through the header
After the EFI stub has done its business, it jumps into the kernel by branching to offset #0 of the loaded Image, which is where it expects to find the header containing a 'branch to stext' instruction.
However, the UEFI spec 2.1.1 states the following regarding PE/COFF image loading:
"A UEFI image is loaded into memory through the LoadImage() Boot Service. This service loads an image with a PE32+ format into memory. This PE32+ loader is required to load all sections of the PE32+ image into memory."
In other words, it is /not/ required to load parts of the image that are not covered by a PE/COFF section, so it may not have loaded the header at the expected offset, as it is not covered by any PE/COFF section.
So instead, jump to 'stext' directly, which is at the base of the PE/COFF .text section, by supplying a symbol 'stext_offset' to efi-entry.o which contains the relative offset of stext into the Image. Also replace other open coded calculations of the same value with a reference to 'stext_offset'
---
v3:
- rebased onto 3.17+
- added spec reference to commit message
v2:
- drop :lo12: relocation against stext_offset in favor of using a literal '=stext_offset' which is safer
--- arch/arm64/kernel/efi-entry.S | 3 ++- arch/arm64/kernel/head.S | 10 ++++++---- 2 files changed, 8 insertions(+), 5 deletions(-)
arch/arm64/kernel/efi-entry.S +2 -1
@@ -61,7 +61,8 @@ ENTRY(efi_stub_entry) */ mov x20, x0 // DTB address ldr x0, [sp, #16] // relocated _text address - mov x21, x0 + ldr x21, =stext_offset + add x21, x0, x21 /* * Flush dcache covering current runtime addresses
arch/arm64/kernel/head.S +6 -4
@@ -132,6 +132,8 @@ efi_head: #endif #ifdef CONFIG_EFI + .globl stext_offset + .set stext_offset, stext - efi_head .align 3 pe_header: .ascii "PE"
@@ -155,7 +157,7 @@ optional_header: .long 0 // SizeOfInitializedData .long 0 // SizeOfUninitializedData .long efi_stub_entry - efi_head // AddressOfEntryPoint - .long stext - efi_head // BaseOfCode + .long stext_offset // BaseOfCode extra_header_fields: .quad 0 // ImageBase
@@ -172,7 +174,7 @@ extra_header_fields: .long _end - efi_head // SizeOfImage // Everything before the kernel image is considered part of the header - .long stext - efi_head // SizeOfHeaders + .long stext_offset // SizeOfHeaders .long 0 // CheckSum .short 0xa // Subsystem (EFI application) .short 0 // DllCharacteristics
@@ -217,9 +219,9 @@ section_table: .byte 0 .byte 0 // end of 0 padding of section name .long _end - stext // VirtualSize - .long stext - efi_head // VirtualAddress + .long stext_offset // VirtualAddress .long _edata - stext // SizeOfRawData - .long stext - efi_head // PointerToRawData + .long stext_offset // PointerToRawData .long 0 // PointerToRelocations (0 for executables) .long 0 // PointerToLineNumbers (0 for executables)
Signature · 1 line
1.8.3.2
Mark Rutland
reviewerPATCH 1/10 arm64/efi: efistub: jump to 'stext' directly, not through the header
Hi Ard,
Quoted 15 lines · Ard Biesheuvel
After the EFI stub has done its business, it jumps into the kernel by branching to offset #0 of the loaded Image, which is where it expects to find the header containing a 'branch to stext' instruction.
However, the UEFI spec 2.1.1 states the following regarding PE/COFF image loading:
"A UEFI image is loaded into memory through theLoadImage()Boot Service. This service loads an image with a PE32+ format into memory. This PE32+ loader is required to load all sections of the PE32+ image into memory."In other words, it is /not/ required to load parts of the image that are not covered by a PE/COFF section, so it may not have loaded the header at the expected offset, as it is not covered by any PE/COFF section.
Quoted 7 lines
So instead, jump to 'stext' directly, which is at the base of the PE/COFF .text section, by supplying a symbol '
stext_offset' to efi-entry.o which contains the relative offset of stext into the Image. Also replace other open coded calculations of the same value with a reference to 'stext_offset'Signed-off-by Ard Biesheuvel <[email protected]>
Given the constraints you describe above, and prior discussions, this looks sane to me:
Mark.
Quoted 74 lines
---
v3:
- rebased onto 3.17+
- added spec reference to commit messagev2:
- drop :lo12: relocation againststext_offsetin favor of using a literal '=stext_offset' which is safer--- arch/arm64/kernel/efi-entry.S | 3 ++- arch/arm64/kernel/head.S | 10 ++++++---- 2 files changed, 8 insertions(+), 5 deletions(-)arch/arm64/kernel/efi-entry.S +2
-1@@ -61,7 +61,8 @@ ENTRY(efi_stub_entry) */ mov x20, x0 // DTB address ldr x0, [sp, #16] // relocated _text address - mov x21, x0 + ldr x21, =stext_offset + add x21, x0, x21 /* * Flush dcache covering current runtime addressesarch/arm64/kernel/head.S +6
-4@@ -132,6 +132,8 @@ efi_head: #endif #ifdef CONFIG_EFI + .globl stext_offset + .set stext_offset, stext - efi_head .align 3 pe_header: .ascii "PE"@@ -155,7 +157,7 @@ optional_header: .long 0 // SizeOfInitializedData .long 0 // SizeOfUninitializedData .long efi_stub_entry - efi_head // AddressOfEntryPoint - .long stext - efi_head // BaseOfCode + .long stext_offset // BaseOfCode extra_header_fields: .quad 0 // ImageBase@@ -172,7 +174,7 @@ extra_header_fields: .long _end - efi_head // SizeOfImage // Everything before the kernel image is considered part of the header - .long stext - efi_head // SizeOfHeaders + .long stext_offset // SizeOfHeaders .long 0 // CheckSum .short 0xa // Subsystem (EFI application) .short 0 // DllCharacteristics@@ -217,9 +219,9 @@ section_table: .byte 0 .byte 0 // end of 0 padding of section name .long _end - stext // VirtualSize - .long stext - efi_head // VirtualAddress + .long stext_offset // VirtualAddress .long _edata - stext // SizeOfRawData - .long stext - efi_head // PointerToRawData + .long stext_offset // PointerToRawData .long 0 // PointerToRelocations (0 for executables) .long 0 // PointerToLineNumbers (0 for executables)Signature · 1 line
1.8.3.2
PATCH 2/10 arm64/efi: set PE/COFF section alignment to 4 KB
In reply to Ard BiesheuvelPosition independent AArch64 code needs to be linked and loaded at the same relative offset from a 4 KB boundary, or adrp/add and adrp/ldr pairs will not work correctly. (This is how PC relative symbol references with a 4 GB reach are emitted)
We need to declare this in the PE/COFF header, otherwise the PE/COFF loader may load the Image and invoke the stub at an offset which violates this rule.
---
v2: added comment explaining '.align 12' in head.S
--- arch/arm64/kernel/head.S | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)
arch/arm64/kernel/head.S +10 -2
@@ -161,7 +161,7 @@ optional_header: extra_header_fields: .quad 0 // ImageBase - .long 0x20 // SectionAlignment + .long 0x1000 // SectionAlignment .long 0x8 // FileAlignment .short 0 // MajorOperatingSystemVersion .short 0 // MinorOperatingSystemVersion
@@ -228,7 +228,15 @@ section_table: .short 0 // NumberOfRelocations (0 for executables) .short 0 // NumberOfLineNumbers (0 for executables) .long 0xe0500020 // Characteristics (section flags) - .align 5 + + /* + * EFI will load stext onwards at the 4k section alignment + * described in the PE/COFF header. To ensure that instruction + * sequences using an adrp and a :lo12: immediate will function + * correctly at this alignment, we must ensure that stext is + * placed at a 4k boundary in the Image to begin with. + */ + .align 12 #endif ENTRY(stext)
Signature · 1 line
1.8.3.2
Mark Rutland
reviewerPATCH 2/10 arm64/efi: set PE/COFF section alignment to 4 KB
Quoted 11 lines · Ard Biesheuvel
Position independent AArch64 code needs to be linked and loaded at the same relative offset from a 4 KB boundary, or adrp/add and adrp/ldr pairs will not work correctly. (This is how PC relative symbol references with a 4 GB reach are emitted)
We need to declare this in the PE/COFF header, otherwise the PE/COFF loader may load the Image and invoke the stub at an offset which violates this rule.
Reviewed-by Roy Franz <[email protected]>Signed-off-by Ard Biesheuvel <[email protected]>
Mark.
Quoted 40 lines
---
v2: added comment explaining '.align 12' inhead.S--- arch/arm64/kernel/head.S | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)arch/arm64/kernel/head.S +10
-2@@ -161,7 +161,7 @@ optional_header: extra_header_fields: .quad 0 // ImageBase - .long 0x20 // SectionAlignment + .long 0x1000 // SectionAlignment .long 0x8 // FileAlignment .short 0 // MajorOperatingSystemVersion .short 0 // MinorOperatingSystemVersion@@ -228,7 +228,15 @@ section_table: .short 0 // NumberOfRelocations (0 for executables) .short 0 // NumberOfLineNumbers (0 for executables) .long 0xe0500020 // Characteristics (section flags) - .align 5 + + /* + * EFI will load stext onwards at the 4k section alignment + * described in the PE/COFF header. To ensure that instruction + * sequences using an adrp and a :lo12: immediate will function + * correctly at this alignment, we must ensure that stext is + * placed at a 4k boundary in the Image to begin with. + */ + .align 12 #endif ENTRY(stext)Signature · 1 line
1.8.3.2
PATCH 3/10 arm64/efi: set PE/COFF file alignment to 512 bytes
In reply to Ard BiesheuvelChange our PE/COFF header to use the minimum file alignment of 512 bytes (0x200), as mandated by the PE/COFF spec v8.3
Also update the linker script so that the Image file itself is also a round multiple of FileAlignment.
--- arch/arm64/kernel/head.S | 2 +- arch/arm64/kernel/vmlinux.lds.S | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-)
arch/arm64/kernel/head.S +1 -1
@@ -162,7 +162,7 @@ optional_header: extra_header_fields: .quad 0 // ImageBase .long 0x1000 // SectionAlignment - .long 0x8 // FileAlignment + .long PECOFF_FILE_ALIGNMENT // FileAlignment .short 0 // MajorOperatingSystemVersion .short 0 // MinorOperatingSystemVersion .short 0 // MajorImageVersion
arch/arm64/kernel/vmlinux.lds.S +17 -0
@@ -32,6 +32,22 @@ jiffies = jiffies_64; *(.hyp.text) \ VMLINUX_SYMBOL(__hyp_text_end) = .; +/* + * The size of the PE/COFF section that covers the kernel image, which + * runs from stext to _edata, must be a round multiple of the PE/COFF + * FileAlignment, which we set to its minimum value of 0x200. 'stext' + * itself is 4 KB aligned, so padding out _edata to a 0x200 aligned + * boundary should be sufficient. + */ +PECOFF_FILE_ALIGNMENT = 0x200; + +#ifdef CONFIG_EFI +#define PECOFF_EDATA_PADDING \ + .pecoff_edata_padding : { BYTE(0); . = ALIGN(PECOFF_FILE_ALIGNMENT); } +#else +#define PECOFF_EDATA_PADDING +#endif + SECTIONS { /*
@@ -103,6 +119,7 @@ SECTIONS _data = .; _sdata = .; RW_DATA_SECTION(64, PAGE_SIZE, THREAD_SIZE) + PECOFF_EDATA_PADDING _edata = .; BSS_SECTION(0, 0, 0)
Signature · 1 line
1.8.3.2
PATCH 4/10 arm64/efi: reserve regions of type ACPI_MEMORY_NVS
In reply to Ard BiesheuvelMemory regions of type ACPI_MEMORY_NVS should be preserved by the OS, so make sure we reserve them at boot.
--- arch/arm64/kernel/efi.c | 1 + 1 file changed, 1 insertion(+)
arch/arm64/kernel/efi.c +1 -0
@@ -132,6 +132,7 @@ static __init int is_reserve_region(efi_memory_desc_t *md)return 1 ;if (md->type ==EFI_ACPI_RECLAIM_MEMORY || + md->type ==EFI_ACPI_MEMORY_NVS || md->type ==EFI_RESERVED_TYPE )return 1 ;
Signature · 1 line
1.8.3.2
Mark Rutland
reviewerPATCH 4/10 arm64/efi: reserve regions of type ACPI_MEMORY_NVS
Quoted 13 lines · Ard Biesheuvel
Memory regions of type
ACPI_MEMORY_NVSshould be preserved by the OS, so make sure we reserve them at boot.Signed-off-by Ard Biesheuvel <[email protected]>--- arch/arm64/kernel/efi.c | 1 + 1 file changed, 1 insertion(+)arch/arm64/kernel/efi.c +0
-0
arch/arm64/kernel/efi.c static __init int is_reserve_region(efi_memory_desc_t *md) · line 137
Quoted 6 lines
arch/arm64/kernel/efi.c +1
-0@@ -132,6 +132,7 @@ static __init int is_reserve_region(efi_memory_desc_t *md)return 1 ;if (md->type ==EFI_ACPI_RECLAIM_MEMORY || + md->type ==EFI_ACPI_MEMORY_NVS || md->type ==EFI_RESERVED_TYPE )return 1 ;
Shouldn't we also filter out EFI_UNUSABLE_MEMORY? Or does that happen elsewhere?
Perhaps instead we should invert this logic and assume memory should be reserved if not EfiLoaderCode, EfiLoaderData, EfiBootServicesCode, EfiBootServicesData, or EfiConventionalMemory. That looks to be what x86 does.
Mark.
PATCH 4/10 arm64/efi: reserve regions of type ACPI_MEMORY_NVS
Quoted 16 lines · Mark Rutland
Quoted 15 lines · Ard Biesheuvel
Memory regions of type
ACPI_MEMORY_NVSshould be preserved by the OS, so make sure we reserve them at boot.Signed-off-by Ard Biesheuvel <[email protected]>--- arch/arm64/kernel/efi.c | 1 + 1 file changed, 1 insertion(+)arch/arm64/kernel/efi.c +0
-0@@ -132,6 +132,7 @@ static __init int is_reserve_region(efi_memory_desc_t *md)return 1 ;
Quoted 8 lines
arch/arm64/kernel/efi.c static __init int is_reserve_region(efi_memory_desc_t *md) · line 137
Quoted 4 lines
arch/arm64/kernel/efi.c +1
-0if (md->type ==EFI_ACPI_RECLAIM_MEMORY || + md->type ==EFI_ACPI_MEMORY_NVS || md->type ==EFI_RESERVED_TYPE )return 1 ;Shouldn't we also filter out
EFI_UNUSABLE_MEMORY? Or does that happen elsewhere?
Yes, good point.
Quoted 5 lines
Perhaps instead we should invert this logic and assume memory should be reserved if not EfiLoaderCode, EfiLoaderData, EfiBootServicesCode, EfiBootServicesData, or EfiConventionalMemory. That looks to be what x86 does.
That would make it more robust against new types in future spec changes, I suppose, although that would seem unlikely.
I am happy to change the patch to take that approach instead, if others agree that it is preferable?
Signature · 1 line
Ard.
PATCH 4/10 arm64/efi: reserve regions of type ACPI_MEMORY_NVS
Quoted 34 lines · Ard Biesheuvel
Quoted 16 lines · Mark Rutland
Quoted 15 lines · Ard Biesheuvel
Memory regions of type
ACPI_MEMORY_NVSshould be preserved by the OS, so make sure we reserve them at boot.Signed-off-by Ard Biesheuvel <[email protected]>--- arch/arm64/kernel/efi.c | 1 + 1 file changed, 1 insertion(+)arch/arm64/kernel/efi.c +0
-0@@ -132,6 +132,7 @@ static __init int is_reserve_region(efi_memory_desc_t *md)return 1 ;Quoted 8 lines
arch/arm64/kernel/efi.c static __init int is_reserve_region(efi_memory_desc_t *md) · line 137
Quoted 4 lines
arch/arm64/kernel/efi.c +1
-0if (md->type ==EFI_ACPI_RECLAIM_MEMORY || + md->type ==EFI_ACPI_MEMORY_NVS || md->type ==EFI_RESERVED_TYPE )return 1 ;Shouldn't we also filter out
EFI_UNUSABLE_MEMORY? Or does that happen elsewhere?Yes, good point.
Quoted 5 lines
Perhaps instead we should invert this logic and assume memory should be reserved if not EfiLoaderCode, EfiLoaderData, EfiBootServicesCode, EfiBootServicesData, or EfiConventionalMemory. That looks to be what x86 does.
Quoted 6 lines
That would make it more robust against new types in future spec changes, I suppose, although that would seem unlikely.
I am happy to change the patch to take that approach instead, if others agree that it is preferable?
As it turns out, there is another problem with this code:is_reserve_region() currently identifies a region of type EFI_RUNTIME_SERVICES_DATA as not reserved if it does not have the EFI_MEMORY_RUNTIME attribute set. However, it is perfectly legal for the firmware not to request a virtual mapping for such a region if it contains things like configuration tables that are not used by any of the Runtime Services themselves.
I will replace this patch with one that inverts the logic, as MarkR suggests, but also drops the test against EFI_MEMORY_RUNTIME.
Signature · 1 line
Ard.
PATCH 5/10 arm64/efi: drop redundant set_bit(EFI_CONFIG_TABLES)
In reply to Ard BiesheuvelThe EFI_CONFIG_TABLES bit already gets set by efi_config_init(), so there is no reason to set it again after this function returns successfully.
--- arch/arm64/kernel/efi.c | 2 -- 1 file changed, 2 deletions(-)
arch/arm64/kernel/efi.c +0 -2
@@ -112,8 +112,6 @@ static int __init uefi_init(void) efi.systab->hdr.revision & 0xffff, vendor); retval =efi_config_init (NULL ); -if (retval ==0 ) -set_bit (EFI_CONFIG_TABLES , &efi.flags); out:early_memunmap (efi.systab,sizeof (efi_system_table_t));
Signature · 1 line
1.8.3.2
PATCH 5/10 arm64/efi: drop redundant set_bit(EFI_CONFIG_TABLES)
Quoted 8 lines · Ard Biesheuvel
The
EFI_CONFIG_TABLESbit already gets set byefi_config_init(), so there is no reason to set it again after this function returns successfully.Signed-off-by Ard Biesheuvel <[email protected]>--- arch/arm64/kernel/efi.c | 2 -- 1 file changed, 2 deletions(-)
Since you mentioned it,
Will
Quoted 17 lines
arch/arm64/kernel/efi.c +0
-2@@ -112,8 +112,6 @@ static int __init uefi_init(void) efi.systab->hdr.revision & 0xffff, vendor); retval =efi_config_init (NULL ); -if (retval ==0 ) -set_bit (EFI_CONFIG_TABLES , &efi.flags); out:early_memunmap (efi.systab,sizeof (efi_system_table_t));Signature · 1 line
1.8.3.2
PATCH 6/10 arm64/efi: use UEFI memory map unconditionally if available
In reply to Ard BiesheuvelOn systems that boot via UEFI, all memory nodes are deleted from the device tree, and instead, the size and location of system RAM is derived from the UEFI memory map. This is handled by reserve_regions, which not only reserves parts of memory that UEFI declares as reserved, but also installs the memblocks that cover the remaining usable memory.
Currently, reserve_regions() is only called if uefi_init() succeeds. However, it does not actually depend on anything that uefi_init() does, and not calling reserve_regions() results in a broken boot, so it is better to just call it unconditionally.
--- arch/arm64/kernel/efi.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-)
arch/arm64/kernel/efi.c +4 -7
@@ -313,8 +313,7 @@ void __init efi_init(void) memmap.desc_size = params.desc_size; memmap.desc_version = params.desc_ver; -if (uefi_init () <0 ) -return ; +WARN_ON (uefi_init () <0 );reserve_regions (); }
@@ -374,15 +373,13 @@ static int __init arm64_enter_virtual_mode(void)int count =0 ;unsigned long flags; -if (!efi_enabled (EFI_BOOT )) { -pr_info ("EFI services will not be available.\n" ); -return -1 ; - } +if (!efi_enabled (EFI_MEMMAP )) +return 0 ; mapsize = memmap.map_end - memmap.map;early_memunmap (memmap.map, mapsize); -if (efi_runtime_disabled ()) { +if (!efi_enabled (EFI_BOOT ) ||efi_runtime_disabled ()) {pr_info ("EFI runtime services will be disabled.\n" );return -1 ; }
Signature · 1 line
1.8.3.2
PATCH 6/10 arm64/efi: use UEFI memory map unconditionally if available
Quoted 21 lines · Ard Biesheuvel
On systems that boot via UEFI, all memory nodes are deleted from the device tree, and instead, the size and location of system RAM is derived from the UEFI memory map. This is handled by
reserve_regions, which not only reserves parts of memory that UEFI declares as reserved, but also installs the memblocks that cover the remaining usable memory.Currently,
reserve_regions()is only called ifuefi_init()succeeds. However, it does not actually depend on anything thatuefi_init()does, and not callingreserve_regions()results in a broken boot, so it is better to just call it unconditionally.Signed-off-by Ard Biesheuvel <[email protected]>--- arch/arm64/kernel/efi.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-)arch/arm64/kernel/efi.c +0
-0
arch/arm64/kernel/efi.c void __init efi_init(void) · line 319
Quoted 9 lines
arch/arm64/kernel/efi.c +1
-2@@ -313,8 +313,7 @@ void __init efi_init(void) memmap.desc_size = params.desc_size; memmap.desc_version = params.desc_ver; -if (uefi_init () <0 ) -return ; +WARN_ON (uefi_init () <0 );reserve_regions (); }
It also looks like EFI_BOOT flag will be set even if uefi_init fails. If uefi_init fails, we only need reserve_regions() for the purpose of adding memblocks. Otherwise, we end up wasting a lot of memory. So, something like this would also be needed:
arch/arm64/kernel/efi.c +7 -6
@@ -81,9 +81,6 @@ static int __init uefi_init(void)return -ENOMEM ; } -set_bit (EFI_BOOT , &efi.flags); -set_bit (EFI_64BIT , &efi.flags); -/* * Verify the EFI Table */
@@ -109,6 +106,9 @@ static int __init uefi_init(void) efi.systab->hdr.revision >>16 , efi.systab->hdr.revision & 0xffff, vendor); +set_bit (EFI_BOOT , &efi.flags); +set_bit (EFI_64BIT , &efi.flags); + retval =efi_config_init (NULL );if (retval ==0 )set_bit (EFI_CONFIG_TABLES , &efi.flags);
@@ -177,9 +177,10 @@ static __init void reserve_regions(void)if (is_normal_ram (md))early_init_dt_add_memory_arch (paddr, size); -if (is_reserve_region (md) || - md->type ==EFI_BOOT_SERVICES_CODE || - md->type ==EFI_BOOT_SERVICES_DATA ) { +if (efi_enabled (EFI_BOOT ) && + (is_reserve_region (md) || + md->type ==EFI_BOOT_SERVICES_CODE || + md->type ==EFI_BOOT_SERVICES_DATA )) {memblock_reserve (paddr, size);if (uefi_debug)pr_cont ("*" );
Quoted 19 lines
arch/arm64/kernel/efi.c +3
-5@@ -374,15 +373,13 @@ static int __init arm64_enter_virtual_mode(void)int count =0 ;unsigned long flags; -if (!efi_enabled (EFI_BOOT )) { -pr_info ("EFI services will not be available.\n" ); -return -1 ; - } +if (!efi_enabled (EFI_MEMMAP )) +return 0 ; mapsize = memmap.map_end - memmap.map;early_memunmap (memmap.map, mapsize); -if (efi_runtime_disabled ()) { +if (!efi_enabled (EFI_BOOT ) ||efi_runtime_disabled ()) {pr_info ("EFI runtime services will be disabled.\n" );return -1 ; }
PATCH 6/10 arm64/efi: use UEFI memory map unconditionally if available
Quoted 29 lines · Mark Salter
Quoted 28 lines · Ard Biesheuvel
On systems that boot via UEFI, all memory nodes are deleted from the device tree, and instead, the size and location of system RAM is derived from the UEFI memory map. This is handled by
reserve_regions, which not only reserves parts of memory that UEFI declares as reserved, but also installs the memblocks that cover the remaining usable memory.Currently,
reserve_regions()is only called ifuefi_init()succeeds. However, it does not actually depend on anything thatuefi_init()does, and not callingreserve_regions()results in a broken boot, so it is better to just call it unconditionally.Signed-off-by Ard Biesheuvel <[email protected]>--- arch/arm64/kernel/efi.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-)arch/arm64/kernel/efi.c +1
-2@@ -313,8 +313,7 @@ void __init efi_init(void) memmap.desc_size = params.desc_size; memmap.desc_version = params.desc_ver; -if (uefi_init () <0 ) -return ; +WARN_ON (uefi_init () <0 );
Quoted 6 lines
arch/arm64/kernel/efi.c void __init efi_init(void) · line 319
Quoted 2 lines
arch/arm64/kernel/efi.c +0
-0reserve_regions (); }It also looks like
EFI_BOOTflag will be set even ifuefi_initfails. Ifuefi_initfails, we only needreserve_regions()for the purpose of adding memblocks. Otherwise, we end up wasting a lot of memory.
Indeed. But perhaps it would be cleaner to add the memblocks in a separate function that gets called before uefi_init(), let reserve_regions() do just what it name implies, and retain the above hunk so that the reserve_regions() call is only performed if UEFI initialized correctly.
Signature · 1 line
Ard.
Quoted 62 lines
So, something like this would also be needed:
arch/arm64/kernel/efi.c +7
-6@@ -81,9 +81,6 @@ static int __init uefi_init(void)return -ENOMEM ; } -set_bit (EFI_BOOT , &efi.flags); -set_bit (EFI_64BIT , &efi.flags); -/* * Verify the EFI Table */ @@ -109,6 +106,9 @@ static int __init uefi_init(void) efi.systab->hdr.revision >>16 , efi.systab->hdr.revision & 0xffff, vendor); +set_bit (EFI_BOOT , &efi.flags); +set_bit (EFI_64BIT , &efi.flags); + retval =efi_config_init (NULL );if (retval ==0 )set_bit (EFI_CONFIG_TABLES , &efi.flags);@@ -177,9 +177,10 @@ static __init void reserve_regions(void)if (is_normal_ram (md))early_init_dt_add_memory_arch (paddr, size); -if (is_reserve_region (md) || - md->type ==EFI_BOOT_SERVICES_CODE || - md->type ==EFI_BOOT_SERVICES_DATA ) { +if (efi_enabled (EFI_BOOT ) && + (is_reserve_region (md) || + md->type ==EFI_BOOT_SERVICES_CODE || + md->type ==EFI_BOOT_SERVICES_DATA )) {memblock_reserve (paddr, size);if (uefi_debug)pr_cont ("*" );Quoted 20 lines
arch/arm64/kernel/efi.c +3
-5@@ -374,15 +373,13 @@ static int __init arm64_enter_virtual_mode(void)int count =0 ;unsigned long flags; -if (!efi_enabled (EFI_BOOT )) { -pr_info ("EFI services will not be available.\n" ); -return -1 ; - } +if (!efi_enabled (EFI_MEMMAP )) +return 0 ; mapsize = memmap.map_end - memmap.map;early_memunmap (memmap.map, mapsize); -if (efi_runtime_disabled ()) { +if (!efi_enabled (EFI_BOOT ) ||efi_runtime_disabled ()) {pr_info ("EFI runtime services will be disabled.\n" );return -1 ; }
PATCH 6/10 arm64/efi: use UEFI memory map unconditionally if available
Quoted 37 lines · Ard Biesheuvel
Quoted 29 lines · Mark Salter
Quoted 28 lines · Ard Biesheuvel
On systems that boot via UEFI, all memory nodes are deleted from the device tree, and instead, the size and location of system RAM is derived from the UEFI memory map. This is handled by
reserve_regions, which not only reserves parts of memory that UEFI declares as reserved, but also installs the memblocks that cover the remaining usable memory.Currently,
reserve_regions()is only called ifuefi_init()succeeds. However, it does not actually depend on anything thatuefi_init()does, and not callingreserve_regions()results in a broken boot, so it is better to just call it unconditionally.Signed-off-by Ard Biesheuvel <[email protected]>--- arch/arm64/kernel/efi.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-)arch/arm64/kernel/efi.c +1
-2@@ -313,8 +313,7 @@ void __init efi_init(void) memmap.desc_size = params.desc_size; memmap.desc_version = params.desc_ver; -if (uefi_init () <0 ) -return ; +WARN_ON (uefi_init () <0 );Quoted 6 lines
arch/arm64/kernel/efi.c void __init efi_init(void) · line 319
Quoted 2 lines
arch/arm64/kernel/efi.c +0
-0reserve_regions (); }It also looks like
EFI_BOOTflag will be set even ifuefi_initfails. Ifuefi_initfails, we only needreserve_regions()for the purpose of adding memblocks. Otherwise, we end up wasting a lot of memory.
Quoted 6 lines
Indeed. But perhaps it would be cleaner to add the memblocks in a separate function that gets called before
uefi_init(), letreserve_regions()do just what it name implies, and retain the above hunk so that thereserve_regions()call is only performed if UEFI initialized correctly.
That works for me.
Mark Rutland
reviewerPATCH 6/10 arm64/efi: use UEFI memory map unconditionally if available
In reply to Mark SalterQuoted 29 lines · Mark Salter
Quoted 28 lines · Ard Biesheuvel
On systems that boot via UEFI, all memory nodes are deleted from the device tree, and instead, the size and location of system RAM is derived from the UEFI memory map. This is handled by
reserve_regions, which not only reserves parts of memory that UEFI declares as reserved, but also installs the memblocks that cover the remaining usable memory.Currently,
reserve_regions()is only called ifuefi_init()succeeds. However, it does not actually depend on anything thatuefi_init()does, and not callingreserve_regions()results in a broken boot, so it is better to just call it unconditionally.Signed-off-by Ard Biesheuvel <[email protected]>--- arch/arm64/kernel/efi.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-)arch/arm64/kernel/efi.c +1
-2@@ -313,8 +313,7 @@ void __init efi_init(void) memmap.desc_size = params.desc_size; memmap.desc_version = params.desc_ver; -if (uefi_init () <0 ) -return ; +WARN_ON (uefi_init () <0 );
Quoted 6 lines
arch/arm64/kernel/efi.c void __init efi_init(void) · line 319
Quoted 2 lines
arch/arm64/kernel/efi.c +0
-0reserve_regions (); }It also looks like
EFI_BOOTflag will be set even ifuefi_initfails. Ifuefi_initfails, we only needreserve_regions()for the purpose of adding memblocks. Otherwise, we end up wasting a lot of memory.
What memory are we wasting in that case? Surely the only items that we could choose to throw away if we failed uefi_init are EFI_ACPI_RECLAIM_MEMORY and EFI_MEMORY_RUNTIME?
We might want to keep those around so we can kexec into a kernel where we can make use of them. Surely they shouldn't take up a significant proportion of the available memory?
Thanks,
Mark.
PATCH 6/10 arm64/efi: use UEFI memory map unconditionally if available
Quoted 37 lines · Mark Rutland
Quoted 29 lines · Mark Salter
Quoted 28 lines · Ard Biesheuvel
On systems that boot via UEFI, all memory nodes are deleted from the device tree, and instead, the size and location of system RAM is derived from the UEFI memory map. This is handled by
reserve_regions, which not only reserves parts of memory that UEFI declares as reserved, but also installs the memblocks that cover the remaining usable memory.Currently,
reserve_regions()is only called ifuefi_init()succeeds. However, it does not actually depend on anything thatuefi_init()does, and not callingreserve_regions()results in a broken boot, so it is better to just call it unconditionally.Signed-off-by Ard Biesheuvel <[email protected]>--- arch/arm64/kernel/efi.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-)arch/arm64/kernel/efi.c +1
-2@@ -313,8 +313,7 @@ void __init efi_init(void) memmap.desc_size = params.desc_size; memmap.desc_version = params.desc_ver; -if (uefi_init () <0 ) -return ; +WARN_ON (uefi_init () <0 );Quoted 6 lines
arch/arm64/kernel/efi.c void __init efi_init(void) · line 319
Quoted 2 lines
arch/arm64/kernel/efi.c +0
-0reserve_regions (); }It also looks like
EFI_BOOTflag will be set even ifuefi_initfails. Ifuefi_initfails, we only needreserve_regions()for the purpose of adding memblocks. Otherwise, we end up wasting a lot of memory.
Quoted 7 lines
What memory are we wasting in that case? Surely the only items that we could choose to throw away if we failed
uefi_initareEFI_ACPI_RECLAIM_MEMORYandEFI_MEMORY_RUNTIME?We might want to keep those around so we can kexec into a kernel where we can make use of them. Surely they shouldn't take up a significant proportion of the available memory?
In addition, reserve_regions() also reserves BOOT_SERVICES (which gets freed up later after set_virtual_address_map(). That won't happen if uefi_init() fails. In any case, if uefi_init() fails, we won't be able to find the ACPI tables kexec kernel won't be able to either. The BOOT_SERVICES stuff is the big chunk. There was some discussion of not reserving that but no one has gotten around to writing the patch to clean out the code that does it.
PATCH 6/10 arm64/efi: use UEFI memory map unconditionally if available
Quoted 46 lines · Mark Salter
Quoted 37 lines · Mark Rutland
Quoted 29 lines · Mark Salter
Quoted 28 lines · Ard Biesheuvel
On systems that boot via UEFI, all memory nodes are deleted from the device tree, and instead, the size and location of system RAM is derived from the UEFI memory map. This is handled by
reserve_regions, which not only reserves parts of memory that UEFI declares as reserved, but also installs the memblocks that cover the remaining usable memory.Currently,
reserve_regions()is only called ifuefi_init()succeeds. However, it does not actually depend on anything thatuefi_init()does, and not callingreserve_regions()results in a broken boot, so it is better to just call it unconditionally.Signed-off-by Ard Biesheuvel <[email protected]>--- arch/arm64/kernel/efi.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-)arch/arm64/kernel/efi.c +1
-2@@ -313,8 +313,7 @@ void __init efi_init(void) memmap.desc_size = params.desc_size; memmap.desc_version = params.desc_ver; -if (uefi_init () <0 ) -return ; +WARN_ON (uefi_init () <0 );Quoted 6 lines
arch/arm64/kernel/efi.c void __init efi_init(void) · line 319
Quoted 2 lines
arch/arm64/kernel/efi.c +0
-0reserve_regions (); }It also looks like
EFI_BOOTflag will be set even ifuefi_initfails. Ifuefi_initfails, we only needreserve_regions()for the purpose of adding memblocks. Otherwise, we end up wasting a lot of memory.Quoted 7 lines
What memory are we wasting in that case? Surely the only items that we could choose to throw away if we failed
uefi_initareEFI_ACPI_RECLAIM_MEMORYandEFI_MEMORY_RUNTIME?We might want to keep those around so we can kexec into a kernel where we can make use of them. Surely they shouldn't take up a significant proportion of the available memory?
Quoted 8 lines
In addition,
reserve_regions()also reservesBOOT_SERVICES(which gets freed up later afterset_virtual_address_map(). That won't happen ifuefi_init()fails. In any case, ifuefi_init()fails, we won't be able to find the ACPI tables kexec kernel won't be able to either. TheBOOT_SERVICESstuff is the big chunk. There was some discussion of not reserving that but no one has gotten around to writing the patch to clean out the code that does it.
I am working on some patches to move the call to SetVirtualAddressMap() to the stub, allowing us to handle the first boot and subsequent kexec boots uniformly. This also means there will be no need to reserve the BOOT_SERVICES regions anymore.
Perhaps we should drop this patch from this series, and I can revisit it as part of the kexec series. That can wait for 3.20, I suppose, as I don't see kexec being merged for 3.19
Signature · 1 line
Ard.
Mark Rutland
reviewerPATCH 6/10 arm64/efi: use UEFI memory map unconditionally if available
In reply to Mark Salter[...]
Quoted 8 lines
Quoted 8 lines
Quoted 3 lines
It also looks like
EFI_BOOTflag will be set even ifuefi_initfails. Ifuefi_initfails, we only needreserve_regions()for the purpose of adding memblocks. Otherwise, we end up wasting a lot of memory.What memory are we wasting in that case? Surely the only items that we could choose to throw away if we failed
uefi_initareEFI_ACPI_RECLAIM_MEMORYandEFI_MEMORY_RUNTIME?
Quoted 8 lines
Quoted 3 lines
We might want to keep those around so we can kexec into a kernel where we can make use of them. Surely they shouldn't take up a significant proportion of the available memory?
In addition,
reserve_regions()also reservesBOOT_SERVICES(which gets freed up later afterset_virtual_address_map(). That won't happen ifuefi_init()fails. In any case, ifuefi_init()fails, we won't be able to find the ACPI tables kexec kernel won't be able to either.
If you need the ACPI tables, the first kernel won't boot. However, if we fail to map the runtime services data and code, that doesn't mean the next kernel can't. We might have failed to map the runtime services due to an early_ioremap bug or similar, and that could be fixed in the kernel we're about to kexec to.
If we're going to nuke runtime regions, we should nuke them in the memory map descriptors as a courtesy to the next kernel. Otherwise we could be more courteous and simply leave them be (which is my preference).
Quoted 3 lines
The
BOOT_SERVICESstuff is the big chunk. There was some discussion of not reserving that but no one has gotten around to writing the patch to clean out the code that does it.
I've just spent some time doing so; patch below. It boots happily on my Juno (with 4KiB pages at least), but I haven't given it much of a stress test.
I wasn't sure if unusable memory could show up with EFI_MEMORY_WB attributes. If so, this patch still won't prevent that from being mapped as cacheable, but that should be easy to fix.
Thanks,
Mark.
---->8----
Quoted 1 line
From
581d5bac5b4a6f93e23737012b71c58d809af6bbMon Sep 17 00:00:00 2001
From: Mark Rutland <[email protected]>
Date: Thu, 23 Oct 2014 19:41:55 +0100
Subject: [PATCH] arm64: efi: Simplify memory descriptor handling
Currently discovering the memory map from UEFI is a multi-stage affair, where the boot services code and data are kept around for much longer than necessary. Additionally, potential overlap between memory and IO mappings at kernel page granularity is not handled.
This patch attempts to solve both of these issues, with the addition and filtering of memory regions being handled in a single function.
First, all normal memory (i.e. anything which can be mapped writeback cacheable) is added to memblock. Second, IO and reserved regions are filtered out of memblock at kernel page granularity, to prevent potential conflicting mappings.
As some reserved regions must be present in the idmap these are reserved. Everything else that's not normal memory is removed, preventing the possibility of a cacheable mapping covering something it shouldn't.
--- arch/arm64/kernel/efi.c | 181 +++++++++++------------------------------------- 1 file changed, 42 insertions(+), 139 deletions(-)
arch/arm64/kernel/efi.c +42 -139
@@ -154,161 +154,66 @@ static __init int is_reserve_region(efi_memory_desc_t *md)return 0 ; } -static __init void reserve_regions (void ) +static __init void efi_add_memory (void ) {efi_memory_desc_t *md; -u64 paddr, npages, size; +u64 paddr, size;if (uefi_debug) -pr_info ("Processing EFI memory map:\n" ); +pr_info ("EFI: adding normal memory:\n" );for_each_efi_memory_desc (&memmap, md) { +if (!is_normal_ram (md)) +continue ; + paddr = md->phys_addr; - npages = md->num_pages; + size = md->num_pages <<EFI_PAGE_SHIFT ;if (uefi_debug) -pr_info (" 0x%012llx-0x%012llx [%s]" , - paddr, paddr + (npages <<EFI_PAGE_SHIFT ) -1 , +pr_info (" 0x%012llx-0x%012llx [%s]\n" , + paddr, size -1 , memory_type_name[md->type]); -memrange_efi_to_native (&paddr, &npages); - size = npages <<PAGE_SHIFT ; +early_init_dt_add_memory_arch (paddr, size); + } + +/* +* Regions describe in an EFI_MEMORY_DESCRIPTOR are only guaranteed to +* be 4KiB aligned but the kernel page size could be larger, and +* regions with different attributes could fall into the same kernel +* page. Thus we must remove any memory in the same kernel page as an +* IO region. +* +* Reserved regions of memory need to be in the idmap, so just reserve +* them. +*/ +if (uefi_debug) +pr_info ("EFI: correcting for overlapping regions:\n" ); + +for_each_efi_memory_desc (&memmap, md) { +if (!is_reserve_region (md) &&is_normal_ram (md)) +continue ; + + paddr = md->phys_addr; + size = md->num_pages <<EFI_PAGE_SHIFT ; + + size =PAGE_ALIGN (size + (paddr & ~PAGE_MASK )); + paddr &=PAGE_MASK ; -if (is_normal_ram (md)) -early_init_dt_add_memory_arch (paddr, size); +if (uefi_debug) +pr_info (" 0x%012llx-0x%012llx [%s]\n" , + paddr, size -1 , + memory_type_name[md->type]); -if (is_reserve_region (md) || - md->type ==EFI_BOOT_SERVICES_CODE || - md->type ==EFI_BOOT_SERVICES_DATA ) { +if (is_reserve_region (md))memblock_reserve (paddr, size); -if (uefi_debug) -pr_cont ("*" ); - } - -if (uefi_debug) -pr_cont ("\n" ); +else +memblock_remove (paddr, size); }set_bit (EFI_MEMMAP , &efi.flags); } - -static u64 __init free_one_region (u64 start,u64 end) -{ -u64 size = end - start; - -if (uefi_debug) -pr_info (" EFI freeing: 0x%012llx-0x%012llx\n" , start, end -1 ); - -free_bootmem_late (start, size); -return size; -} - -static u64 __init free_region (u64 start,u64 end) -{ -u64 map_start, map_end, total =0 ; - -if (end <= start) -return total; - - map_start = (u64 )memmap.phys_map; - map_end =PAGE_ALIGN (map_start + (memmap.map_end - memmap.map)); - map_start &=PAGE_MASK ; - -if (start < map_end && end > map_start) { -/* region overlaps UEFI memmap */ -if (start < map_start) - total +=free_one_region (start, map_start); - -if (map_end < end) - total +=free_one_region (map_end, end); - }else - total +=free_one_region (start, end); - -return total; -} - -static void __init free_boot_services (void ) -{ -u64 total_freed =0 ; -u64 keep_end, free_start, free_end; -efi_memory_desc_t *md; - -/* -* If kernel uses larger pages than UEFI, we have to be careful -* not to inadvertantly free memory we want to keep if there is -* overlap@the kernel page size alignment. We do not want to -* free is_reserve_region() memory nor the UEFI memmap itself. -* -* The memory map is sorted, so we keep track of the end of -* any previous region we want to keep, remember any region -* we want to free and defer freeing it until we encounter -* the next region we want to keep. This way, before freeing -* it, we can clip it as needed to avoid freeing memory we -* want to keep for UEFI. -*/ - - keep_end =0 ; - free_start =0 ; - -for_each_efi_memory_desc (&memmap, md) { -u64 paddr, npages, size; - -if (is_reserve_region (md)) { -/* -* We don't want to free any memory from this region. -*/ -if (free_start) { -/* adjust free_end then free region */ -if (free_end > md->phys_addr) - free_end -=PAGE_SIZE ; - total_freed +=free_region (free_start, free_end); - free_start =0 ; - } - keep_end = md->phys_addr + (md->num_pages <<EFI_PAGE_SHIFT ); -continue ; - } - -if (md->type !=EFI_BOOT_SERVICES_CODE && - md->type !=EFI_BOOT_SERVICES_DATA ) { -/* no need to free this region */ -continue ; - } - -/* -* We want to free memory from this region. -*/ - paddr = md->phys_addr; - npages = md->num_pages; -memrange_efi_to_native (&paddr, &npages); - size = npages <<PAGE_SHIFT ; - -if (free_start) { -if (paddr <= free_end) - free_end = paddr + size; -else { - total_freed +=free_region (free_start, free_end); - free_start = paddr; - free_end = paddr + size; - } - }else { - free_start = paddr; - free_end = paddr + size; - } -if (free_start < keep_end) { - free_start +=PAGE_SIZE ; -if (free_start >= free_end) - free_start =0 ; - } - } -if (free_start) - total_freed +=free_region (free_start, free_end); - -if (total_freed) -pr_info ("Freed 0x%llx bytes of EFI boot services memory" , - total_freed); -} -void __init efi_init (void ) {struct efi_fdt_params params;
@@ -330,7 +235,7 @@ void __init efi_init(void)if (uefi_init () <0 )return ; -reserve_regions (); +efi_add_memory (); }void __init efi_idmap_init (void )
@@ -452,8 +357,6 @@ static int __init arm64_enter_virtual_mode(void)kfree (virtmap); -free_boot_services (); -if (status !=EFI_SUCCESS ) {pr_err ("Failed to set EFI virtual address map! [%lx]\n" , status);
Signature · 1 line
1.9.1
PATCH 6/10 arm64/efi: use UEFI memory map unconditionally if available
Quoted 56 lines · Mark Rutland
[...]
Quoted 8 lines
Quoted 8 lines
Quoted 3 lines
It also looks like
EFI_BOOTflag will be set even ifuefi_initfails. Ifuefi_initfails, we only needreserve_regions()for the purpose of adding memblocks. Otherwise, we end up wasting a lot of memory.What memory are we wasting in that case? Surely the only items that we could choose to throw away if we failed
uefi_initareEFI_ACPI_RECLAIM_MEMORYandEFI_MEMORY_RUNTIME?Quoted 8 lines
Quoted 3 lines
We might want to keep those around so we can kexec into a kernel where we can make use of them. Surely they shouldn't take up a significant proportion of the available memory?
In addition,
reserve_regions()also reservesBOOT_SERVICES(which gets freed up later afterset_virtual_address_map(). That won't happen ifuefi_init()fails. In any case, ifuefi_init()fails, we won't be able to find the ACPI tables kexec kernel won't be able to either.If you need the ACPI tables, the first kernel won't boot. However, if we fail to map the runtime services data and code, that doesn't mean the next kernel can't. We might have failed to map the runtime services due to an
early_ioremapbug or similar, and that could be fixed in the kernel we're about to kexec to.If we're going to nuke runtime regions, we should nuke them in the memory map descriptors as a courtesy to the next kernel. Otherwise we could be more courteous and simply leave them be (which is my preference).
Quoted 3 lines
The
BOOT_SERVICESstuff is the big chunk. There was some discussion of not reserving that but no one has gotten around to writing the patch to clean out the code that does it.I've just spent some time doing so; patch below. It boots happily on my Juno (with 4KiB pages at least), but I haven't given it much of a stress test.
I wasn't sure if unusable memory could show up with
EFI_MEMORY_WBattributes. If so, this patch still won't prevent that from being mapped as cacheable, but that should be easy to fix.Thanks,
Mark.---->8----
From581d5bac5b4a6f93e23737012b71c58d809af6bbMon Sep 17 00:00:00 2001
From: Mark Rutland <[email protected]>
Date: Thu, 23 Oct 2014 19:41:55 +0100
Subject: [PATCH] arm64: efi: Simplify memory descriptor handlingCurrently discovering the memory map from UEFI is a multi-stage affair, where the boot services code and data are kept around for much longer than necessary. Additionally, potential overlap between memory and IO mappings at kernel page granularity is not handled.
Quoted 8 lines
This patch attempts to solve both of these issues, with the addition and filtering of memory regions being handled in a single function.
First, all normal memory (i.e. anything which can be mapped writeback cacheable) is added to memblock. Second, IO and reserved regions are filtered out of memblock at kernel page granularity, to prevent potential conflicting mappings.
Fortunately, this is being addressed in an upcoming UEFI spec
revision: it will not be allowed for memory regions that could potentially conflict in terms of cache attributes to share the same 64 KB page frame.
As I mentioned, my kexec patches will move SetVirtualAddressMap() to the stub, which means we will also be able to drop the id map bits entirely. As I said, let's revisit this in that context, and drop it for now.
Signature · 1 line
Ard.
Quoted 242 lines
As some reserved regions must be present in the idmap these are reserved. Everything else that's not normal memory is removed, preventing the possibility of a cacheable mapping covering something it shouldn't.
Signed-off-by Mark Rutland <[email protected]>Cc Ard Biesheuvel <[email protected]Cc Catalin Marinas <[email protected]>Cc Leif Lindholm <[email protected]Cc Mark Salter <[email protected]>--- arch/arm64/kernel/efi.c | 181 +++++++++++------------------------------------- 1 file changed, 42 insertions(+), 139 deletions(-)arch/arm64/kernel/efi.c +42
-140@@ -154,161 +154,66 @@ static __init int is_reserve_region(efi_memory_desc_t *md)return 0 ; } -static __init void reserve_regions (void ) +static __init void efi_add_memory (void ) {efi_memory_desc_t *md; -u64 paddr, npages, size; +u64 paddr, size;if (uefi_debug) -pr_info ("Processing EFI memory map:\n" ); +pr_info ("EFI: adding normal memory:\n" );for_each_efi_memory_desc (&memmap, md) { +if (!is_normal_ram (md)) +continue ; + paddr = md->phys_addr; - npages = md->num_pages; + size = md->num_pages <<EFI_PAGE_SHIFT ;if (uefi_debug) -pr_info (" 0x%012llx-0x%012llx [%s]" , - paddr, paddr + (npages <<EFI_PAGE_SHIFT ) -1 , +pr_info (" 0x%012llx-0x%012llx [%s]\n" , + paddr, size -1 , memory_type_name[md->type]); -memrange_efi_to_native (&paddr, &npages); - size = npages <<PAGE_SHIFT ; +early_init_dt_add_memory_arch (paddr, size); + } + +/* +* Regions describe in an EFI_MEMORY_DESCRIPTOR are only guaranteed to +* be 4KiB aligned but the kernel page size could be larger, and +* regions with different attributes could fall into the same kernel +* page. Thus we must remove any memory in the same kernel page as an +* IO region. +* +* Reserved regions of memory need to be in the idmap, so just reserve +* them. +*/ +if (uefi_debug) +pr_info ("EFI: correcting for overlapping regions:\n" ); + +for_each_efi_memory_desc (&memmap, md) { +if (!is_reserve_region (md) &&is_normal_ram (md)) +continue ; + + paddr = md->phys_addr; + size = md->num_pages <<EFI_PAGE_SHIFT ; + + size =PAGE_ALIGN (size + (paddr & ~PAGE_MASK )); + paddr &=PAGE_MASK ; -if (is_normal_ram (md)) -early_init_dt_add_memory_arch (paddr, size); +if (uefi_debug) +pr_info (" 0x%012llx-0x%012llx [%s]\n" , + paddr, size -1 , + memory_type_name[md->type]); -if (is_reserve_region (md) || - md->type ==EFI_BOOT_SERVICES_CODE || - md->type ==EFI_BOOT_SERVICES_DATA ) { +if (is_reserve_region (md))memblock_reserve (paddr, size); -if (uefi_debug) -pr_cont ("*" ); - } - -if (uefi_debug) -pr_cont ("\n" ); +else +memblock_remove (paddr, size); }set_bit (EFI_MEMMAP , &efi.flags); } - -static u64 __init free_one_region (u64 start,u64 end) -{ -u64 size = end - start; - -if (uefi_debug) -pr_info (" EFI freeing: 0x%012llx-0x%012llx\n" , start, end -1 ); - -free_bootmem_late (start, size); -return size; -} - -static u64 __init free_region (u64 start,u64 end) -{ -u64 map_start, map_end, total =0 ; - -if (end <= start) -return total; - - map_start = (u64 )memmap.phys_map; - map_end =PAGE_ALIGN (map_start + (memmap.map_end - memmap.map)); - map_start &=PAGE_MASK ; - -if (start < map_end && end > map_start) { -/* region overlaps UEFI memmap */ -if (start < map_start) - total +=free_one_region (start, map_start); - -if (map_end < end) - total +=free_one_region (map_end, end); - }else - total +=free_one_region (start, end); - -return total; -} - -static void __init free_boot_services (void ) -{ -u64 total_freed =0 ; -u64 keep_end, free_start, free_end; -efi_memory_desc_t *md; - -/* -* If kernel uses larger pages than UEFI, we have to be careful -* not to inadvertantly free memory we want to keep if there is -* overlap at the kernel page size alignment. We do not want to -* free is_reserve_region() memory nor the UEFI memmap itself. -* -* The memory map is sorted, so we keep track of the end of -* any previous region we want to keep, remember any region -* we want to free and defer freeing it until we encounter -* the next region we want to keep. This way, before freeing -* it, we can clip it as needed to avoid freeing memory we -* want to keep for UEFI. -*/ - - keep_end =0 ; - free_start =0 ; - -for_each_efi_memory_desc (&memmap, md) { -u64 paddr, npages, size; - -if (is_reserve_region (md)) { -/* -* We don't want to free any memory from this region. -*/ -if (free_start) { -/* adjust free_end then free region */ -if (free_end > md->phys_addr) - free_end -=PAGE_SIZE ; - total_freed +=free_region (free_start, free_end); - free_start =0 ; - } - keep_end = md->phys_addr + (md->num_pages <<EFI_PAGE_SHIFT ); -continue ; - } - -if (md->type !=EFI_BOOT_SERVICES_CODE && - md->type !=EFI_BOOT_SERVICES_DATA ) { -/* no need to free this region */ -continue ; - } - -/* -* We want to free memory from this region. -*/ - paddr = md->phys_addr; - npages = md->num_pages; -memrange_efi_to_native (&paddr, &npages); - size = npages <<PAGE_SHIFT ; - -if (free_start) { -if (paddr <= free_end) - free_end = paddr + size; -else { - total_freed +=free_region (free_start, free_end); - free_start = paddr; - free_end = paddr + size; - } - }else { - free_start = paddr; - free_end = paddr + size; - } -if (free_start < keep_end) { - free_start +=PAGE_SIZE ; -if (free_start >= free_end) - free_start =0 ; - } - } -if (free_start) - total_freed +=free_region (free_start, free_end); - -if (total_freed) -pr_info ("Freed 0x%llx bytes of EFI boot services memory" , - total_freed); -} -void __init efi_init (void ) {struct efi_fdt_params params;@@ -330,7 +235,7 @@ void __init efi_init(void)if (uefi_init () <0 )return ; -reserve_regions (); +efi_add_memory (); }void __init efi_idmap_init (void )@@ -452,8 +357,6 @@ static int __init arm64_enter_virtual_mode(void)kfree (virtmap); -free_boot_services (); -if (status !=EFI_SUCCESS ) {pr_err ("Failed to set EFI virtual address map! [%lx]\n" , status); --1.9.1
PATCH 7/10 efi: dmi: add support for SMBIOS 3.0 UEFI configuration table
In reply to Ard BiesheuvelThis adds support to the UEFI side for detecting the presence of a SMBIOS 3.0 64-bit entry point. This allows the actual SMBIOS structure table to reside at a physical offset over 4 GB, which cannot be supported by the legacy SMBIOS 32-bit entry point.
Since the firmware can legally provide both entry points, store the SMBIOS 3.0 entry point in a separate variable, and let the DMI decoding layer decide which one will be used.
--- drivers/firmware/efi/efi.c | 4 ++++ include/linux/efi.h | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-)
drivers/firmware/efi/efi.c +4 -0
@@ -30,6 +30,7 @@ struct efi __read_mostly efi = { .acpi = EFI_INVALID_TABLE_ADDR, .acpi20 = EFI_INVALID_TABLE_ADDR, .smbios = EFI_INVALID_TABLE_ADDR, + .smbios3 = EFI_INVALID_TABLE_ADDR, .sal_systab = EFI_INVALID_TABLE_ADDR, .boot_info = EFI_INVALID_TABLE_ADDR, .hcdp = EFI_INVALID_TABLE_ADDR,
@@ -86,6 +87,8 @@ static ssize_t systab_show(struct kobject *kobj, str +=sprintf (str,"ACPI=0x%lx\n" , efi.acpi);if (efi.smbios !=EFI_INVALID_TABLE_ADDR ) str +=sprintf (str,"SMBIOS=0x%lx\n" , efi.smbios); +if (efi.smbios3 !=EFI_INVALID_TABLE_ADDR ) + str +=sprintf (str,"SMBIOS3=0x%lx\n" , efi.smbios3);if (efi.hcdp !=EFI_INVALID_TABLE_ADDR ) str +=sprintf (str,"HCDP=0x%lx\n" , efi.hcdp);if (efi.boot_info !=EFI_INVALID_TABLE_ADDR )
@@ -260,6 +263,7 @@ static __initdata efi_config_table_type_t common_tables[] = { {MPS_TABLE_GUID, "MPS", &efi.mps}, {SAL_SYSTEM_TABLE_GUID, "SALsystab", &efi.sal_systab}, {SMBIOS_TABLE_GUID, "SMBIOS", &efi.smbios}, + {SMBIOS3_TABLE_GUID, "SMBIOS 3.0", &efi.smbios3}, {UGA_IO_PROTOCOL_GUID, "UGA", &efi.uga}, {NULL_GUID, NULL, NULL}, };
include/linux/efi.h +5 -1
@@ -547,6 +547,9 @@ void efi_native_runtime_setup(void);#define SMBIOS_TABLE_GUID \ EFI_GUID( 0xeb9d2d31, 0x2d88, 0x11d3, 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d ) +#define SMBIOS3_TABLE_GUID \ + EFI_GUID( 0xf2fd1544, 0x9794, 0x4a2c, 0x99, 0x2e, 0xe5, 0xbb, 0xcf, 0x20, 0xe3, 0x94 ) +#define SAL_SYSTEM_TABLE_GUID \ EFI_GUID( 0xeb9d2d32, 0x2d88, 0x11d3, 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d )
@@ -810,7 +813,8 @@ extern struct efi {unsigned long mps;/* MPS table */ unsigned long acpi;/* ACPI table (IA64 ext 0.71) */ unsigned long acpi20;/* ACPI table (ACPI 2.0) */ -unsigned long smbios;/* SM BIOS table */ +unsigned long smbios;/* SM BIOS table (32 bit entry point) */ +unsigned long smbios3;/* SM BIOS table (64 bit entry point) */ unsigned long sal_systab;/* SAL system table */ unsigned long boot_info;/* boot info table */ unsigned long hcdp;/* HCDP table */
Signature · 1 line
1.8.3.2
PATCH 7/10 efi: dmi: add support for SMBIOS 3.0 UEFI configuration table
Quoted 9 lines · Ard Biesheuvel
This adds support to the UEFI side for detecting the presence of a SMBIOS 3.0 64-bit entry point. This allows the actual SMBIOS structure table to reside at a physical offset over 4 GB, which cannot be supported by the legacy SMBIOS 32-bit entry point.
Since the firmware can legally provide both entry points, store the SMBIOS 3.0 entry point in a separate variable, and let the DMI decoding layer decide which one will be used.
Quoted 7 lines
Acked-by Leif Lindholm <[email protected]>Signed-off-by Ard Biesheuvel <[email protected]>--- drivers/firmware/efi/efi.c | 4 ++++ include/linux/efi.h | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-)
Looks like you might also need to change driver/xen/efi.c to set EFI_INVALID_TABLE_ADDR for the new table address?
Signature · 1 line
Matt Fleming, Intel Open Source Technology Center
PATCH 7/10 efi: dmi: add support for SMBIOS 3.0 UEFI configuration table
Quoted 18 lines · Matt Fleming
Quoted 9 lines · Ard Biesheuvel
This adds support to the UEFI side for detecting the presence of a SMBIOS 3.0 64-bit entry point. This allows the actual SMBIOS structure table to reside at a physical offset over 4 GB, which cannot be supported by the legacy SMBIOS 32-bit entry point.
Since the firmware can legally provide both entry points, store the SMBIOS 3.0 entry point in a separate variable, and let the DMI decoding layer decide which one will be used.
Quoted 7 lines
Acked-by Leif Lindholm <[email protected]>Signed-off-by Ard Biesheuvel <[email protected]>--- drivers/firmware/efi/efi.c | 4 ++++ include/linux/efi.h | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-)
Quoted 3 lines
Looks like you might also need to change
driver/xen/efi.cto setEFI_INVALID_TABLE_ADDRfor the new table address?
You're quite right. Will add it in v2
Signature · 1 line
Ard.
PATCH 8/10 dmi: add support for SMBIOS 3.0 64-bit entry point
In reply to Ard BiesheuvelThe DMTF SMBIOS reference spec v3.0.0 defines a new 64-bit entry point, which enables support for SMBIOS structure tables residing at a physical offset over 4 GB. This is especially important for upcoming arm64 platforms whose system RAM resides entirely above the 4 GB boundary.
For the UEFI case, this code attempts to detect the new SMBIOS 3.0 header magic at the offset passed in the SMBIOS3_TABLE_GUID UEFI configuration table. If this configuration table is not provided, or if we fail to parse the header, we fall back to using the legacy SMBIOS_TABLE_GUID configuration table. This is in line with the spec, that allows both configuration tables to be provided, but mandates that they must point to the same structure table, unless the version pointed to by the 64-bit entry point is a superset of the 32-bit one.
For the non-UEFI case, the detection logic is modified to look for the SMBIOS 3.0 header magic before it looks for the legacy header magic.
Note that this patch is based on version 3.0.0d [draft] of the specification, which is expected not to deviate from the final version in ways that would affect the correctness of this implementation.
--- drivers/firmware/dmi_scan.c | 70 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 68 insertions(+), 2 deletions(-)
drivers/firmware/dmi_scan.c +68 -2
@@ -93,6 +93,12 @@ static void dmi_table(u8 *buf, int len, int num,const struct dmi_header *dm = (const struct dmi_header *)data;/* +* 7.45 End-of-Table (Type 127) [SMBIOS reference spec v3.0.0] +*/ +if (dm->type ==127 ) +break ; + +/* * We want to know the total length (formatted area and * strings) before decoding to make sure we won't run off the * table in dmi_decode or dmi_string
@@ -107,7 +113,7 @@ static void dmi_table(u8 *buf, int len, int num, } } -static u32 dmi_base; +static phys_addr_t dmi_base;static u16 dmi_len;static u16 dmi_num;
@@ -514,12 +520,72 @@ static int __init dmi_present(const u8 *buf)return 1 ; } +/* +* Check for the SMBIOS 3.0 64-bit entry point signature. Unlike the legacy +* 32-bit entry point, there is no embedded DMI header (_DMI_) in here. +*/ +static int __init dmi_smbios3_present (const u8 *buf) +{ +if (memcmp (buf,"_SM3_" ,5 ) ==0 && + buf[6 ] <32 &&dmi_checksum (buf, buf[6 ])) { + dmi_ver =get_unaligned_be16 (buf +7 ); + dmi_len =get_unaligned_le32 (buf +12 ); + dmi_base =get_unaligned_le64 (buf +16 ); + +/* +* The 64-bit SMBIOS 3.0 entry point no longer has a field +* containing the number of structures present in the table. +* Instead, it defines the table size as a maximum size, and +* relies on the end-of-table structure type (#127) to be used +* to signal the end of the table. +* So let's define dmi_num as an upper bound as well: each +* structure has a 4 byte header, so dmi_len / 4 is an upper +* bound for the number of structures in the table. +*/ + dmi_num = dmi_len /4 ; + +if (dmi_walk_early (dmi_decode) ==0 ) { +pr_info ("SMBIOS %d.%d present.\n" , + dmi_ver >>8 , dmi_ver &0xFF ); +dmi_format_ids (dmi_ids_string,sizeof (dmi_ids_string)); +printk (KERN_DEBUG "DMI: %s\n" , dmi_ids_string); +return 0 ; + } + } +return 1 ; +} +void __init dmi_scan_machine (void ) {char __iomem *p, *q;char buf[32 ];if (efi_enabled (EFI_CONFIG_TABLES )) { +/* +* According to the DMTF SMBIOS reference spec v3.0.0, it is +* allowed to define both the 64-bit entry point (smbios3) and +* the 32-bit entry point (smbios), in which case they should +* either both point to the same SMBIOS structure table, or the +* table pointed to by the 64-bit entry point should contain a +* superset of the table contents pointed to by the 32-bit entry +* point (section 5.2) +* This implies that the 64-bit entry point should have +* precedence if it is defined and supported by the OS. If we +* have the 64-bit entry point, but fail to decode it, fall +* back to the legacy one (if available) +*/ +if (efi.smbios3 !=EFI_INVALID_TABLE_ADDR ) { + p =dmi_early_remap (efi.smbios3,32 ); +if (p ==NULL ) + goto error; +memcpy_fromio (buf, p,32 ); +dmi_early_unmap (p,32 ); + +if (!dmi_smbios3_present (buf)) { + dmi_available =1 ; + goto out; + } + }if (efi.smbios ==EFI_INVALID_TABLE_ADDR ) goto error;
@@ -552,7 +618,7 @@ void __init dmi_scan_machine(void)memset (buf,0 ,16 );for (q = p; q < p +0x10000 ; q +=16 ) {memcpy_fromio (buf +16 , q,16 ); -if (!dmi_present (buf)) { +if (!dmi_smbios3_present (buf) || !dmi_present (buf)) { dmi_available =1 ;dmi_early_unmap (p,0x10000 ); goto out;
Signature · 1 line
1.8.3.2
PATCH 9/10 arm64: dmi: Add SMBIOS/DMI support
In reply to Ard BiesheuvelFrom: Yi Li <[email protected]>
SMBIOS is important for server hardware vendors. It implements a spec for providing descriptive information about the platform. Things like serial numbers, physical layout of the ports, build configuration data, and the like.
---
A short history of this patch:
v4: Moved call to dmi_scan_machine() to separate core_initcall(), so that it is
called unconditionally, i.e., even if UEFI fails to initialize. Otherwise, any drivers that attempt to consult DMI info for quirks handling start spewing errors, as Catalin unfortunately found out after merging (and subsequently reverting) this patch into arm64 for-next/core for the second time.
v3: Moved call to dmi_scan_machine() into arm64_enter_virtual_mode(). This is
to ensure that it is called early enough, because dmi_scan_machine() needs to be called before dmi_id_init(), which itself is invoked using an arch_initcall(). DMI depends on UEFI on arm64, so it is legal to only invoke dmi_scan_machine() when building with UEFI support. However, calling it from arm64_enter_virtual_mode() was a mistake, as it could result in dmi_scan_machine() not being called at all, resulting in the issues found by Catalin.
v2: Use efi_lookup_mapped_addr() to obtain the virtual address of the SMBIOS
structure table instead of calling ioremap_cache(). This seemed a good idea at the time, as the UEFI memory map covers those regions, so the virtual mapping should be known as well. However, this is only true if the firmware has requested a virtual remapping for the region by setting the EFI_MEMORY_RUNTIME bit, which Tianocore/EDK2 appears to do, but violates the UEFI spec. ("In general, UEFI Configuration Tables loaded at boot time (e.g., SMBIOS table) can be contained in memory of type EfiRuntimeServicesData (recommended and the system firmware must not request a virtual mapping), [...]", section 2.3.6, UEFI spec v2.4B). This version was merged into the arm64 for-next/core branch and reverted again later per our request.
--- arch/arm64/Kconfig | 11 +++++++++++ arch/arm64/include/asm/dmi.h | 31 +++++++++++++++++++++++++++++++ arch/arm64/kernel/efi.c | 13 +++++++++++++ 3 files changed, 55 insertions(+) create mode 100644 arch/arm64/include/asm/dmi.h
arch/arm64/Kconfig +11 -0
@@ -400,6 +400,17 @@ config EFI allow the kernel to be booted as an EFI application. This is only useful on systems that have UEFI firmware. +config DMI + bool "Enable support for SMBIOS (DMI) tables" + depends on EFI + default y + help + This enables SMBIOS/DMI feature for systems. + + This option is only useful on systems that have UEFI firmware. + However, even with this option, the resultant kernel should + continue to boot on existing non-UEFI platforms. + endmenu menu "Userspace binary formats"
arch/arm64/include/asm/dmi.h new file +31 -0
@@ -0,0 +1,31 @@ +/* +* arch/arm64/include/asm/dmi.h +* +* Copyright (C) 2013 Linaro Limited. +* Written by: Yi Li (yi.li at linaro.org) +* +* based on arch/ia64/include/asm/dmi.h +* +* This file is subject to the terms and conditions of the GNU General Public +* License. See the file "COPYING" in the main directory of this archive +* for more details. +*/ + +#ifndef __ASM_DMI_H +#define __ASM_DMI_H + +#include <linux/io.h> +#include <linux/slab.h> + +/* +* According to section 2.3.6 of the UEFI spec, the firmware should not +* request a virtual mapping for configuration tables such as SMBIOS. +* This means we have to map them before use. +*/ +#define dmi_early_remap (x, l) ioremap_cache(x, l) +#define dmi_early_unmap (x, l) iounmap(x) +#define dmi_remap (x, l) ioremap_cache(x, l) +#define dmi_unmap (x) iounmap(x) +#define dmi_alloc (l) kzalloc(l, GFP_KERNEL) + +#endif
arch/arm64/kernel/efi.c +13 -0
@@ -11,6 +11,7 @@* */ +#include <linux/dmi.h> #include <linux/efi.h> #include <linux/export.h> #include <linux/memblock.h>
@@ -467,3 +468,15 @@ err_unmap:return -1 ; }early_initcall (arm64_enter_virtual_mode); + +static int __init arm64_dmi_init (void ) +{ +/* +* On arm64, DMI depends on UEFI, and dmi_scan_machine() needs to +* be called early because dmi_id_init(), which is an arch_initcall +* itself, depends on dmi_scan_machine() having been called already. +*/ +dmi_scan_machine (); +return 0 ; +} +core_initcall (arm64_dmi_init);
Signature · 1 line
1.8.3.2
PATCH 10/10 arm64: dmi: set DMI string as dump stack arch description
In reply to Ard BiesheuvelThis sets the DMI string, containing system type, serial number, firmware version etc. as dump stack arch description, so that oopses and other kernel stack dumps automatically have this information included, if available.
--- arch/arm64/kernel/efi.c | 2 ++ 1 file changed, 2 insertions(+)
arch/arm64/kernel/efi.c +2 -0
@@ -477,6 +477,8 @@ static int __init arm64_dmi_init(void)* itself, depends on dmi_scan_machine() having been called already. */ dmi_scan_machine (); +if (dmi_available) +dmi_set_dump_stack_arch_desc ();return 0 ; }core_initcall (arm64_dmi_init);
Signature · 1 line
1.8.3.2
PATCH 10/10 arm64: dmi: set DMI string as dump stack arch description
Quoted 15 lines · Ard Biesheuvel
This sets the DMI string, containing system type, serial number, firmware version etc. as dump stack arch description, so that oopses and other kernel stack dumps automatically have this information included, if available.
Signed-off-by Ard Biesheuvel <[email protected]>--- arch/arm64/kernel/efi.c | 2 ++ 1 file changed, 2 insertions(+)arch/arm64/kernel/efi.c +0
-0
arch/arm64/kernel/efi.c static int __init arm64_dmi_init(void) · line 481
Quoted 5 lines
arch/arm64/kernel/efi.c +2
-0@@ -477,6 +477,8 @@ static int __init arm64_dmi_init(void)* itself, depends on dmi_scan_machine() having been called already. */ dmi_scan_machine (); +if (dmi_available) +dmi_set_dump_stack_arch_desc ();
This looks fine, but I don't understand why you would ever *not* want to call this when DMI is available. In other words, why can't this be part of dmi_scan_machine?
Will
PATCH 10/10 arm64: dmi: set DMI string as dump stack arch description
Quoted 11 lines · Will Deacon
Quoted 10 lines · Ard Biesheuvel
This sets the DMI string, containing system type, serial number, firmware version etc. as dump stack arch description, so that oopses and other kernel stack dumps automatically have this information included, if available.
Signed-off-by Ard Biesheuvel <[email protected]>--- arch/arm64/kernel/efi.c | 2 ++ 1 file changed, 2 insertions(+)
Quoted 15 lines
arch/arm64/kernel/efi.c static int __init arm64_dmi_init(void) · line 481
Quoted 10 lines
arch/arm64/kernel/efi.c +2
-0@@ -477,6 +477,8 @@ static int __init arm64_dmi_init(void)* itself, depends on dmi_scan_machine() having been called already. */ dmi_scan_machine (); +if (dmi_available) +dmi_set_dump_stack_arch_desc ();This looks fine, but I don't understand why you would ever *not* want to call this when DMI is available. In other words, why can't this be part of
dmi_scan_machine?
/**
* dmi_set_dump_stack_arch_desc - set arch description for dump_stack() *
* Invoke dump_stack_set_arch_desc() with DMI system information so that
* DMI identifiers are printed out on task dumps. Arch boot code should
* call this function after dmi_scan_machine() if it wants to print out DMI
* identifiers on task dumps.
*/
Apparently, the author of the function had reason to assume that not all architectures that implement DMI would choose to use the DMI string as arch description even if it is available.
Currently, ia64 and x86 call this function unconditionally, which means the arch description is cleared if it was set before, and moving the call to dmi_scan_machine() should retain the same behavior. For the arm64 case, I think calling it conditionally is better: if we ever want to populate the arch description from DT, the unconditional call would clear its contents even on non-DMI systems.
Signature · 1 line
Ard.
cover arm64 EFI patches for 3.19
In reply to Ard BiesheuvelHi Ard,
Quoted 10 lines · Ard Biesheuvel
This is a bit of a mixed bag of patches that we would like to see merged for 3.19. Most of them have been posted and discussed on linux-efi and/or LAKML before, and one of them has even been merged and reverted twice.
Patches #1 - #4 are fixes for compliance with the UEFI and PE/COFF specs. No issues are known that require these patches, so there is no reason to pull them into a stable release.
Patches #5 and #6 address minor issues in the arm64 EFI init code.
Quoted 8 lines
Patches #7 - #10 implement DMI/SMBIOS for arm64, both the existing 32-bit version and the upcoming 3.0 version that allows the SMBIOS structure table to reside at a physical offset that cannot be encoded in 32-bits. It also install a 'Hardware: xxx' string that is printed along with oopses and kernel call stack dumps on systems that implement DMI/SMBIOS.
Please refer to the patches themselves for version history. Acks and/or comments appreciated.
It would be helpful for me if you could split this into two series -- one for the arm64 tree and the other for the efi tree. That would also make the dependencies clearer, so I know whether any of the arch bits need to go via Matt.
Cheers,
Will
cover arm64 EFI patches for 3.19
Quoted 19 lines · Will Deacon
Hi Ard,
Quoted 16 lines · Ard Biesheuvel
This is a bit of a mixed bag of patches that we would like to see merged for 3.19. Most of them have been posted and discussed on linux-efi and/or LAKML before, and one of them has even been merged and reverted twice.
Patches #1 - #4 are fixes for compliance with the UEFI and PE/COFF specs. No issues are known that require these patches, so there is no reason to pull them into a stable release.
Patches #5 and #6 address minor issues in the arm64 EFI init code.
Patches #7 - #10 implement DMI/SMBIOS for arm64, both the existing 32-bit version and the upcoming 3.0 version that allows the SMBIOS structure table to reside at a physical offset that cannot be encoded in 32-bits. It also install a 'Hardware: xxx' string that is printed along with oopses and kernel call stack dumps on systems that implement DMI/SMBIOS.
Quoted 8 lines
Quoted 2 lines
Please refer to the patches themselves for version history. Acks and/or comments appreciated.
It would be helpful for me if you could split this into two series -- one for the arm64 tree and the other for the efi tree. That would also make the dependencies clearer, so I know whether any of the arch bits need to go via Matt.
Yeah, I was struggling a bit with that. I think the agreement was that everything EFI related goes through Matt's tree, but I don't think that necessarily makes sense for patches that only touch arch/arm64, unless there are interdependencies with the generic code.
Quoted 1 line
From this series, only patches #7 and #8 need to go through Matt's
tree, and even if #9 and #10 are also related to SMBIOS, they are in fact orthogonal to #7 and #8, so those can still go through the arm64 tree without any merge order issues later on.
@Matt: any thoughts?
In addition, #4 and #6 are still being discussed, and I haven't received any acks on #5 and #10.
Signature · 1 line
Ard.
cover arm64 EFI patches for 3.19
Quoted 6 lines · Ard Biesheuvel
Yeah, I was struggling a bit with that. I think the agreement was that everything EFI related goes through Matt's tree, but I don't think that necessarily makes sense for patches that only touch
arch/arm64, unless there are interdependencies with the generic code.
Quoted 6 lines
From this series, only patches #7 and #8 need to go through Matt's tree, and even if #9 and #10 are also related to SMBIOS, they are in fact orthogonal to #7 and #8, so those can still go through the arm64 tree without any merge order issues later on.
@Matt: any thoughts?
In this case, if it makes things easier for you folks in terms of dependencies to take this *all* through the arm64 tree, that seems sensible to me.
cover arm64 EFI patches for 3.19
Quoted 12 lines · Matt Fleming
Quoted 11 lines · Ard Biesheuvel
Yeah, I was struggling a bit with that. I think the agreement was that everything EFI related goes through Matt's tree, but I don't think that necessarily makes sense for patches that only touch
arch/arm64, unless there are interdependencies with the generic code.From this series, only patches #7 and #8 need to go through Matt's tree, and even if #9 and #10 are also related to SMBIOS, they are in fact orthogonal to #7 and #8, so those can still go through the arm64 tree without any merge order issues later on.
Quoted 5 lines
Quoted 1 line
@Matt: any thoughts?
In this case, if it makes things easier for you folks in terms of dependencies to take this *all* through the arm64 tree, that seems sensible to me.
Thanks, Matt. I won't merge anything that touches files outside of arch/arm64 without your ack, but then I'll be happy to take this lot via the arm64 tree.
Will