linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] efi/arm: fix allocation failure when reserving the kernel base
@ 2019-08-02  5:38 Chester Lin
  2019-08-04  7:57 ` Ard Biesheuvel
  2019-08-20 11:56 ` Russell King - ARM Linux admin
  0 siblings, 2 replies; 24+ messages in thread
From: Chester Lin @ 2019-08-02  5:38 UTC (permalink / raw)
  To: linux, ard.biesheuvel, akpm, rppt, ren_guo, Juergen Gross, geert, mingo
  Cc: Joey Lee, linux-efi, guillaume.gardet, linux-kernel, Chester Lin,
	Gary Lin, linux-arm-kernel

In some cases the arm32 efistub could fail to allocate memory for
uncompressed kernel. For example, we got the following error message when
verifying EFI stub on Raspberry Pi-2 [kernel-5.2.1 + grub-2.04] :

  EFI stub: Booting Linux Kernel...
  EFI stub: ERROR: Unable to allocate memory for uncompressed kernel.
  EFI stub: ERROR: Failed to relocate kernel

After checking the EFI memory map we found that the first page [0 - 0xfff]
had been reserved by Raspberry Pi-2's firmware, and the efistub tried to
set the dram base at 0, which was actually in a reserved region.

  grub> lsefimmap
  Type      Physical start  - end             #Pages        Size Attributes
  reserved  0000000000000000-0000000000000fff 00000001      4KiB WB
  conv-mem  0000000000001000-0000000007ef5fff 00007ef5 130004KiB WB
  RT-data   0000000007ef6000-0000000007f09fff 00000014     80KiB RT WB
  conv-mem  0000000007f0a000-000000002d871fff 00025968 615840KiB WB
  .....

To avoid a reserved address, we have to ignore the memory regions which are
marked as EFI_RESERVED_TYPE, and only conventional memory regions can be
chosen. If the region before the kernel base is unaligned, it will be
marked as EFI_RESERVED_TYPE and let kernel ignore it so that memblock_limit
will not be sticked with a very low address such as 0x1000.

Signed-off-by: Chester Lin <clin@suse.com>
---
 arch/arm/mm/mmu.c                         |  3 ++
 drivers/firmware/efi/libstub/arm32-stub.c | 43 ++++++++++++++++++-----
 2 files changed, 37 insertions(+), 9 deletions(-)

diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index f3ce34113f89..909b11ba48d8 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -1184,6 +1184,9 @@ void __init adjust_lowmem_bounds(void)
 		phys_addr_t block_start = reg->base;
 		phys_addr_t block_end = reg->base + reg->size;
 
+		if (memblock_is_nomap(reg))
+			continue;
+
 		if (reg->base < vmalloc_limit) {
 			if (block_end > lowmem_limit)
 				/*
diff --git a/drivers/firmware/efi/libstub/arm32-stub.c b/drivers/firmware/efi/libstub/arm32-stub.c
index e8f7aefb6813..10d33d36df00 100644
--- a/drivers/firmware/efi/libstub/arm32-stub.c
+++ b/drivers/firmware/efi/libstub/arm32-stub.c
@@ -128,7 +128,7 @@ static efi_status_t reserve_kernel_base(efi_system_table_t *sys_table_arg,
 
 	for (l = 0; l < map_size; l += desc_size) {
 		efi_memory_desc_t *desc;
-		u64 start, end;
+		u64 start, end, spare, kernel_base;
 
 		desc = (void *)memory_map + l;
 		start = desc->phys_addr;
@@ -144,27 +144,52 @@ static efi_status_t reserve_kernel_base(efi_system_table_t *sys_table_arg,
 		case EFI_BOOT_SERVICES_DATA:
 			/* Ignore types that are released to the OS anyway */
 			continue;
-
+		case EFI_RESERVED_TYPE:
+			/* Ignore reserved regions */
+			continue;
 		case EFI_CONVENTIONAL_MEMORY:
 			/*
 			 * Reserve the intersection between this entry and the
 			 * region.
 			 */
 			start = max(start, (u64)dram_base);
-			end = min(end, (u64)dram_base + MAX_UNCOMP_KERNEL_SIZE);
+			kernel_base = round_up(start, PMD_SIZE);
+			spare = kernel_base - start;
+			end = min(end, kernel_base + MAX_UNCOMP_KERNEL_SIZE);
+
+			status = efi_call_early(allocate_pages,
+					EFI_ALLOCATE_ADDRESS,
+					EFI_LOADER_DATA,
+					MAX_UNCOMP_KERNEL_SIZE / EFI_PAGE_SIZE,
+					&kernel_base);
+			if (status != EFI_SUCCESS) {
+				pr_efi_err(sys_table_arg,
+					"reserve_kernel_base: alloc failed.\n");
+				goto out;
+			}
+			*reserve_addr = kernel_base;
 
+			if (!spare)
+				break;
+			/*
+			 * If there's a gap between start and kernel_base,
+			 * it needs be reserved so that the memblock_limit
+			 * will not fall on a very low address when running
+			 * adjust_lowmem_bounds(), wchich could eventually
+			 * cause CMA reservation issue.
+			 */
 			status = efi_call_early(allocate_pages,
 						EFI_ALLOCATE_ADDRESS,
-						EFI_LOADER_DATA,
-						(end - start) / EFI_PAGE_SIZE,
+						EFI_RESERVED_TYPE,
+						spare / EFI_PAGE_SIZE,
 						&start);
 			if (status != EFI_SUCCESS) {
 				pr_efi_err(sys_table_arg,
-					"reserve_kernel_base(): alloc failed.\n");
+					"reserve spare-region failed\n");
 				goto out;
 			}
-			break;
 
+			break;
 		case EFI_LOADER_CODE:
 		case EFI_LOADER_DATA:
 			/*
@@ -220,7 +245,7 @@ efi_status_t handle_kernel_image(efi_system_table_t *sys_table,
 	*image_size = image->image_size;
 	status = efi_relocate_kernel(sys_table, image_addr, *image_size,
 				     *image_size,
-				     dram_base + MAX_UNCOMP_KERNEL_SIZE, 0);
+				     *reserve_addr + MAX_UNCOMP_KERNEL_SIZE, 0);
 	if (status != EFI_SUCCESS) {
 		pr_efi_err(sys_table, "Failed to relocate kernel.\n");
 		efi_free(sys_table, *reserve_size, *reserve_addr);
@@ -233,7 +258,7 @@ efi_status_t handle_kernel_image(efi_system_table_t *sys_table,
 	 * in memory. The kernel determines the base of DRAM from the
 	 * address at which the zImage is loaded.
 	 */
-	if (*image_addr + *image_size > dram_base + ZIMAGE_OFFSET_LIMIT) {
+	if (*image_addr + *image_size > *reserve_addr + ZIMAGE_OFFSET_LIMIT) {
 		pr_efi_err(sys_table, "Failed to relocate kernel, no low memory available.\n");
 		efi_free(sys_table, *reserve_size, *reserve_addr);
 		*reserve_size = 0;
-- 
2.22.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2019-08-21  9:43 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-08-02  5:38 [PATCH] efi/arm: fix allocation failure when reserving the kernel base Chester Lin
2019-08-04  7:57 ` Ard Biesheuvel
2019-08-14  7:58   ` Guillaume Gardet
2019-08-15  7:59   ` Ard Biesheuvel
2019-08-15 11:16     ` Chester Lin
2019-08-15 11:32       ` Ard Biesheuvel
2019-08-15 13:37         ` Mike Rapoport
2019-08-19  7:56           ` Chester Lin
2019-08-19 14:56             ` Ard Biesheuvel
2019-08-20  7:33               ` Chester Lin
2019-08-20  7:49               ` Mike Rapoport
2019-08-20 10:29                 ` Chester Lin
2019-08-20 11:00                 ` Ard Biesheuvel
2019-08-20 11:54   ` Russell King - ARM Linux admin
2019-08-20 12:27     ` Ard Biesheuvel
2019-08-20 11:56 ` Russell King - ARM Linux admin
2019-08-20 12:28   ` Ard Biesheuvel
2019-08-21  6:10     ` Chester Lin
2019-08-21  6:35       ` Ard Biesheuvel
2019-08-21  7:11         ` Mike Rapoport
2019-08-21  7:22           ` Chester Lin
2019-08-21  7:29           ` Ard Biesheuvel
2019-08-21  8:29             ` Mike Rapoport
2019-08-21  9:42               ` Ard Biesheuvel

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).