Skip to contentSkip to conversation

ARM/efi minor fixes + stub pre-boot compat checks

PATCH Superseded Ard Biesheuvel 4 participants 13 messages Feb 4, 2016 – Feb 11, 2016

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

v2 cover ARM/efi minor fixes + stub pre-boot compat checks

I merged two EFI/ARM related series, whose v1's I sent out last week:

Changes since v1:
- added various tags from various people
- new patch #3 to undefine __init

@Matt: are you happy with all of this going through the arm64 tree? I don't think it clashes with anything else we've got queued up for v4.6 in tip/efi/core

Series 1: arm efi minor fixes
http://thread.gmane.org/gmane.linux.ports.arm.kernel/473027
This fixes two minor issues with the handling of .init data in the stub (#1, #2)

Patch #3 is a new patch that un-#defines __init in efistub.h, to catch its inadvertent use in the UEFI stub

Patch #4 replaces some instances of early_memremap() with early_memremap_ro() where the region in question is only accessed in r/o mode.

Series 2: UEFI stub pre-boot compat checks
http://thread.gmane.org/gmane.linux.ports.arm.kernel/473189

As discussed earlier today [1], and last year [2], it makes sense for the UEFI stub to perform some basic checks on the hardware for missing features that would prevent the kernel from booting to a state where it can even complain about this.

So implements this for ARM, to check on LPAE builds whether the CPU supports it (patch #5), and for arm64, to check whether the build time granule is implemented by the CPU (patch #6). Patch #7 wires it up into the shared init code.

[1] http://thread.gmane.org/gmane.linux.ports.arm.kernel/472880
[2] http://thread.gmane.org/gmane.linux.ports.arm.kernel/447370

Ard Biesheuvel (7):
arm64: efistub: drop __init annotation from handle_kernel_image()
arm64: vmlinux.lds.S: handle .init.rodata.xxx and .init.bss sections
efi: efistub: prevent __init annotations from being used
efi: arm-init: use read-only early mappings
ARM: efistub: check for LPAE support before booting a LPAE kernel
arm64: efistub: check for h/w support before booting a >4 KB granule
kernel
ARM/arm64: efistub: perform hardware compatibility check

 arch/arm64/kernel/vmlinux.lds.S           |  1 +
 drivers/firmware/efi/arm-init.c           | 14 ++++----
 drivers/firmware/efi/libstub/arm-stub.c   |  4 +++
 drivers/firmware/efi/libstub/arm32-stub.c | 17 ++++++++++
 drivers/firmware/efi/libstub/arm64-stub.c | 34 ++++++++++++++++----
 drivers/firmware/efi/libstub/efistub.h    | 12 +++++++
 6 files changed, 68 insertions(+), 14 deletions(-)
Signature · 1 line
2.5.0
#1 lore raw

PATCH v2 1/7 arm64: efistub: drop __init annotation from handle_kernel_image()

After moving arm64-stub.c to libstub/, all of its sections are emitted as .init.xxx sections automatically, and the __init annotation of handle_kernel_image() causes it to end up in .init.init.text, which is not recognized as an __init section by the linker scripts. So drop the annotation.

---
 drivers/firmware/efi/libstub/arm64-stub.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)
drivers/firmware/efi/libstub/arm64-stub.c +7 -7
index 78dfbd34b6bf..9e0342745e4f 100644
@@ -13,13 +13,13 @@
 #include <asm/efi.h>
 #include <asm/sections.h>
 
-efi_status_t __init handle_kernel_image(efi_system_table_t *sys_table_arg,
-					unsigned long *image_addr,
-					unsigned long *image_size,
-					unsigned long *reserve_addr,
-					unsigned long *reserve_size,
-					unsigned long dram_base,
-					efi_loaded_image_t *image)
+efi_status_t handle_kernel_image(efi_system_table_t *sys_table_arg,
+				 unsigned long *image_addr,
+				 unsigned long *image_size,
+				 unsigned long *reserve_addr,
+				 unsigned long *reserve_size,
+				 unsigned long dram_base,
+				 efi_loaded_image_t *image)
 {
 	efi_status_t status;
 	unsigned long kernel_size, kernel_memsize = 0;
Signature · 1 line
2.5.0
#2 lore raw

PATCH v2 2/7 arm64: vmlinux.lds.S: handle .init.rodata.xxx and .init.bss sections

In reply to Ard Biesheuvel

The EFI stub is typically built into the decompressor (x86, ARM) so none of its symbols are annotated as __init. However, on arm64, the stub is linked into the kernel proper, and the code is __init annotated at the section level by prepending all names of SHF_ALLOC sections with '.init'.

This results in section names like .init.rodata.str1.8 (for string literals) and .init.bss (which is tiny), both of which can be moved into the .init.data output section.

---
 arch/arm64/kernel/vmlinux.lds.S | 1 +
 1 file changed, 1 insertion(+)
arch/arm64/kernel/vmlinux.lds.S +1 -0
index e3928f578891..cbf4db440e9c 100644
@@ -134,6 +134,7 @@ SECTIONS
 		CON_INITCALL
 		SECURITY_INITCALL
 		INIT_RAM_FS
+		*(.init.rodata.* .init.bss)	/* from the EFI stub */
 	}
 	.exit.data : {
 		ARM_EXIT_KEEP(EXIT_DATA)
Signature · 1 line
2.5.0
#3 lore raw

PATCH v2 3/7 efi: efistub: prevent __init annotations from being used

In reply to Ard Biesheuvel

__init annotations should not be used in the EFI stub, since the code is either included in the decompressor (x86, ARM) where they have no effect, or the whole stub is __init annotated at the section level (arm64), by renaming the sections, in which case the __init annotations will be redundant, and will result in section names like .init.init.text, and our linker script does not expect that. So un-#define __init so that its inadvertent use will force a build error.

---
 drivers/firmware/efi/libstub/efistub.h | 10 ++++++++++
 1 file changed, 10 insertions(+)
drivers/firmware/efi/libstub/efistub.h +10 -0
index 6b6548fda089..275f395c886d 100644
@@ -5,6 +5,16 @@
 /* error code which can't be mistaken for valid address */
 #define EFI_ERROR	(~0UL)
 
+/*
+ * __init annotations should not be used in the EFI stub, since the code is
+ * either included in the decompressor (x86, ARM) where they have no effect,
+ * or the whole stub is __init annotated at the section level (arm64), by
+ * renaming the sections, in which case the __init annotation will be
+ * redundant, and will result in section names like .init.init.text, and our
+ * linker script does not expect that.
+ */
+#undef __init
+
 void efi_char16_printk(efi_system_table_t *, efi_char16_t *);
 
 efi_status_t efi_open_volume(efi_system_table_t *sys_table_arg, void *__image,
Signature · 1 line
2.5.0
#4 lore raw

PATCH v2 4/7 efi: arm-init: use read-only early mappings

In reply to Ard Biesheuvel

The early mappings of the EFI system table contents and the UEFI memory map are read-only from the OS point of view. So map them read-only to protect them from inadvertent modification.

---
 drivers/firmware/efi/arm-init.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)
drivers/firmware/efi/arm-init.c +7 -7
index 9e15d571b53c..aa1f743152a2 100644
@@ -61,8 +61,8 @@ static int __init uefi_init(void)
 	char vendor[100] = "unknown";
 	int i, retval;
 
-	efi.systab = early_memremap(efi_system_table,
-				    sizeof(efi_system_table_t));
+	efi.systab = early_memremap_ro(efi_system_table,
+				       sizeof(efi_system_table_t));
 	if (efi.systab == NULL) {
 		pr_warn("Unable to map EFI system table.\n");
 		return -ENOMEM;
@@ -86,8 +86,8 @@ static int __init uefi_init(void)
 			efi.systab->hdr.revision & 0xffff);
 
 	/* Show what we know for posterity */
-	c16 = early_memremap(efi_to_phys(efi.systab->fw_vendor),
-			     sizeof(vendor) * sizeof(efi_char16_t));
+	c16 = early_memremap_ro(efi_to_phys(efi.systab->fw_vendor),
+				sizeof(vendor) * sizeof(efi_char16_t));
 	if (c16) {
 		for (i = 0; i < (int) sizeof(vendor) - 1 && *c16; ++i)
 			vendor[i] = c16[i];
@@ -100,8 +100,8 @@ static int __init uefi_init(void)
 		efi.systab->hdr.revision & 0xffff, vendor);
 
 	table_size = sizeof(efi_config_table_64_t) * efi.systab->nr_tables;
-	config_tables = early_memremap(efi_to_phys(efi.systab->tables),
-				       table_size);
+	config_tables = early_memremap_ro(efi_to_phys(efi.systab->tables),
+					  table_size);
 	if (config_tables == NULL) {
 		pr_warn("Unable to map EFI config table array.\n");
 		retval = -ENOMEM;
@@ -185,7 +185,7 @@ void __init efi_init(void)
 	efi_system_table = params.system_table;
 
 	memmap.phys_map = params.mmap;
-	memmap.map = early_memremap(params.mmap, params.mmap_size);
+	memmap.map = early_memremap_ro(params.mmap, params.mmap_size);
 	if (memmap.map == NULL) {
 		/*
 		* If we are booting via UEFI, the UEFI memory map is the only
Signature · 1 line
2.5.0
#5 lore raw

PATCH v2 5/7 ARM: efistub: check for LPAE support before booting a LPAE kernel

In reply to Ard Biesheuvel

A kernel built with support for LPAE cannot boot to a state where it can inform the user about it if it fails due to missing LPAE support in the hardware.

If we happen to be booting via UEFI, we can fail gracefully so check for LPAE support in the hardware on CONFIG_ARM_LPAE builds before entering the kernel proper.

---
 drivers/firmware/efi/libstub/arm32-stub.c | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)
drivers/firmware/efi/libstub/arm32-stub.c +17 -0
index 495ebd657e38..6f42be4d0084 100644
@@ -9,6 +9,23 @@
 #include <linux/efi.h>
 #include <asm/efi.h>
 
+efi_status_t check_platform_features(efi_system_table_t *sys_table_arg)
+{
+	int block;
+
+	/* non-LPAE kernels can run anywhere */
+	if (!IS_ENABLED(CONFIG_ARM_LPAE))
+		return EFI_SUCCESS;
+
+	/* LPAE kernels need compatible hardware */
+	block = cpuid_feature_extract(CPUID_EXT_MMFR0, 0);
+	if (block < 5) {
+		pr_efi_err(sys_table_arg, "This LPAE kernel is not supported by your CPU\n");
+		return EFI_UNSUPPORTED;
+	}
+	return EFI_SUCCESS;
+}
+
 efi_status_t handle_kernel_image(efi_system_table_t *sys_table,
 				 unsigned long *image_addr,
 				 unsigned long *image_size,
Signature · 1 line
2.5.0
#6 lore raw

PATCH v2 6/7 arm64: efistub: check for h/w support before booting a >4 KB granule kernel

In reply to Ard Biesheuvel

A kernel built with support for a page size that is not supported by the hardware it runs on cannot boot to a state where it can inform the user about it.

If we happen to be booting via UEFI, we can fail gracefully so check if the currently configured page size is supported by the hardware before entering the kernel proper. Note that UEFI mandates support for 4 KB pages, so in that case, no check is needed.

---
 drivers/firmware/efi/libstub/arm64-stub.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)
drivers/firmware/efi/libstub/arm64-stub.c +20 -0
index 9e0342745e4f..aef04ad60e0d 100644
@@ -12,6 +12,26 @@
 #include <linux/efi.h>
 #include <asm/efi.h>
 #include <asm/sections.h>
+#include <asm/sysreg.h>
+
+efi_status_t check_platform_features(efi_system_table_t *sys_table_arg)
+{
+	u64 tg;
+
+	/* UEFI mandates support for 4 KB granule, no need to check */
+	if (IS_ENABLED(CONFIG_ARM64_4K_PAGES))
+		return EFI_SUCCESS;
+
+	tg = (read_cpuid(ID_AA64MMFR0_EL1) >> ID_AA64MMFR0_TGRAN_SHIFT) & 0xf;
+	if (tg != ID_AA64MMFR0_TGRAN_SUPPORTED) {
+		if (IS_ENABLED(CONFIG_ARM64_64K_PAGES))
+			pr_efi_err(sys_table_arg, "This 64 KB granule kernel is not supported by your CPU\n");
+		else
+			pr_efi_err(sys_table_arg, "This 16 KB granule kernel is not supported by your CPU\n");
+		return EFI_UNSUPPORTED;
+	}
+	return EFI_SUCCESS;
+}
 
 efi_status_t handle_kernel_image(efi_system_table_t *sys_table_arg,
 				 unsigned long *image_addr,
Signature · 1 line
2.5.0
#7 lore raw

PATCH v2 7/7 ARM/arm64: efistub: perform hardware compatibility check

In reply to Ard Biesheuvel

Before proceeding with relocating the kernel and parsing the command line, insert a call to check_platform_features() to allow an arch specific check to be performed whether the current kernel can execute on the current hardware.

---
 drivers/firmware/efi/libstub/arm-stub.c | 4 ++++
 drivers/firmware/efi/libstub/efistub.h  | 2 ++
 2 files changed, 6 insertions(+)
drivers/firmware/efi/libstub/arm-stub.c +4 -0
index 3397902e4040..6086a874fa3c 100644
@@ -190,6 +190,10 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table,
 
 	pr_efi(sys_table, "Booting Linux Kernel...\n");
 
+	status = check_platform_features(sys_table);
+	if (status != EFI_SUCCESS)
+		goto fail;
+
 	/*
 	 * Get a handle to the loaded image protocol.  This is used to get
 	 * information about the running image, such as size and the command
drivers/firmware/efi/libstub/efistub.h +2 -0
index 275f395c886d..a25ac4c7955f 100644
@@ -53,4 +53,6 @@ void efi_get_virtmap(efi_memory_desc_t *memory_map, unsigned long map_size,
 		     unsigned long desc_size, efi_memory_desc_t *runtime_map,
 		     int *count);
 
+efi_status_t check_platform_features(efi_system_table_t *sys_table_arg);
+
 #endif
Signature · 1 line
2.5.0
reviewer
#8 lore raw

v2 cover ARM/efi minor fixes + stub pre-boot compat checks

In reply to Ard Biesheuvel
Quoted 9 lines · Ard Biesheuvel

Ard Biesheuvel (7):
arm64: efistub: drop __init annotation from handle_kernel_image()
arm64: vmlinux.lds.S: handle .init.rodata.xxx and .init.bss sections
efi: efistub: prevent __init annotations from being used
efi: arm-init: use read-only early mappings
ARM: efistub: check for LPAE support before booting a LPAE kernel
arm64: efistub: check for h/w support before booting a >4 KB granule
kernel
ARM/arm64: efistub: perform hardware compatibility check

This all looks good to be, so FWIW, for the series:

Mark.

#9 lore raw

v2 cover ARM/efi minor fixes + stub pre-boot compat checks

In reply to Ard Biesheuvel
Quoted 8 lines · Ard Biesheuvel

I merged two EFI/ARM related series, whose v1's I sent out last week:

Changes since v1:
- added various tags from various people
- new patch #3 to undefine __init

@Matt: are you happy with all of this going through the arm64 tree? I don't think it clashes with anything else we've got queued up for v4.6 in tip/efi/core

How come this is going through the arm64 tree? Are there other patch series that this depends on or that depend on it?

If it makes the most sense to take it through that tree, then I'm fine with it but I'd like to hear a rationale.

#10 lore raw

v2 cover ARM/efi minor fixes + stub pre-boot compat checks

Quoted 7 lines · Matt Fleming
Quoted 6 lines · Ard Biesheuvel

I merged two EFI/ARM related series, whose v1's I sent out last week:

Changes since v1:
- added various tags from various people
- new patch #3 to undefine __init

Quoted 8 lines
Quoted 2 lines

@Matt: are you happy with all of this going through the arm64 tree? I don't think it clashes with anything else we've got queued up for v4.6 in tip/efi/core

How come this is going through the arm64 tree? Are there other patch series that this depends on or that depend on it?

If it makes the most sense to take it through that tree, then I'm fine with it but I'd like to hear a rationale.

I simply thought it would be most convenient, since it touches ARM-specific files only. But if you feel it should go via the EFI tree instead, that is also fine by me.

Thanks,
Ard.

#11 lore raw

v2 cover ARM/efi minor fixes + stub pre-boot compat checks

Quoted 14 lines · Ard Biesheuvel
Quoted 13 lines · Matt Fleming
Quoted 8 lines · Ard Biesheuvel

I merged two EFI/ARM related series, whose v1's I sent out last week:

Changes since v1:
- added various tags from various people
- new patch #3 to undefine __init

@Matt: are you happy with all of this going through the arm64 tree? I don't think it clashes with anything else we've got queued up for v4.6 in tip/efi/core

How come this is going through the arm64 tree? Are there other patch series that this depends on or that depend on it?

Quoted 6 lines
Quoted 2 lines

If it makes the most sense to take it through that tree, then I'm fine with it but I'd like to hear a rationale.

I simply thought it would be most convenient, since it touches ARM-specific files only. But if you feel it should go via the EFI tree instead, that is also fine by me.

Since the diff stat is heavily weighted towards drivers/firmware/efi I think it should go via the EFI tree. So I'll pick this up (the changes look fine) unless Will or Catalin complain otherwise.

I'm also keen to allay any concerns that the EFI tree is somehow x86-specific.

#12 lore raw

v2 cover ARM/efi minor fixes + stub pre-boot compat checks

Quoted 18 lines · Matt Fleming
Quoted 17 lines · Ard Biesheuvel
Quoted 15 lines · Matt Fleming
Quoted 8 lines · Ard Biesheuvel

I merged two EFI/ARM related series, whose v1's I sent out last week:

Changes since v1:
- added various tags from various people
- new patch #3 to undefine __init

@Matt: are you happy with all of this going through the arm64 tree? I don't think it clashes with anything else we've got queued up for v4.6 in tip/efi/core

How come this is going through the arm64 tree? Are there other patch series that this depends on or that depend on it?

If it makes the most sense to take it through that tree, then I'm fine with it but I'd like to hear a rationale.

Quoted 7 lines
Quoted 3 lines

I simply thought it would be most convenient, since it touches ARM-specific files only. But if you feel it should go via the EFI tree instead, that is also fine by me.

Since the diff stat is heavily weighted towards drivers/firmware/efi I think it should go via the EFI tree. So I'll pick this up (the changes look fine) unless Will or Catalin complain otherwise.

No complaints here (the arm64 bits are all acked).

Will