You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
279 lines
11 KiB
279 lines
11 KiB
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 |
|
From: Peter Jones <pjones@redhat.com> |
|
Date: Thu, 11 Jul 2019 14:38:57 +0200 |
|
Subject: [PATCH] arm/arm64 loader: Better memory allocation and error |
|
messages. |
|
|
|
On mustang, our memory map looks like: |
|
|
|
Type Physical start - end #Pages Size Attributes |
|
reserved 0000004000000000-00000040001fffff 00000200 2MiB UC WC WT WB |
|
conv-mem 0000004000200000-0000004393ffffff 00393e00 14654MiB UC WC WT WB |
|
ldr-code 0000004394000000-00000043f7ffffff 00064000 1600MiB UC WC WT WB |
|
BS-data 00000043f8000000-00000043f801ffff 00000020 128KiB UC WC WT WB |
|
conv-mem 00000043f8020000-00000043fa15bfff 0000213c 34032KiB UC WC WT WB |
|
ldr-code 00000043fa15c000-00000043fa2a1fff 00000146 1304KiB UC WC WT WB |
|
ldr-data 00000043fa2a2000-00000043fa3e8fff 00000147 1308KiB UC WC WT WB |
|
conv-mem 00000043fa3e9000-00000043fa3e9fff 00000001 4KiB UC WC WT WB |
|
ldr-data 00000043fa3ea000-00000043fa3eafff 00000001 4KiB UC WC WT WB |
|
ldr-code 00000043fa3eb000-00000043fa4affff 000000c5 788KiB UC WC WT WB |
|
BS-code 00000043fa4b0000-00000043fa59ffff 000000f0 960KiB UC WC WT WB |
|
RT-code 00000043fa5a0000-00000043fa5affff 00000010 64KiB RT UC WC WT WB |
|
RT-data 00000043fa5b0000-00000043fa5bffff 00000010 64KiB RT UC WC WT WB |
|
RT-code 00000043fa5c0000-00000043fa5cffff 00000010 64KiB RT UC WC WT WB |
|
ldr-data 00000043fa5d0000-00000043fa5d0fff 00000001 4KiB UC WC WT WB |
|
BS-code 00000043fa5d1000-00000043fa5ddfff 0000000d 52KiB UC WC WT WB |
|
reserved 00000043fa5de000-00000043fa60ffff 00000032 200KiB UC WC WT WB |
|
ACPI-rec 00000043fa610000-00000043fa6affff 000000a0 640KiB UC WC WT WB |
|
ACPI-nvs 00000043fa6b0000-00000043fa6bffff 00000010 64KiB UC WC WT WB |
|
ACPI-rec 00000043fa6c0000-00000043fa70ffff 00000050 320KiB UC WC WT WB |
|
RT-code 00000043fa710000-00000043fa72ffff 00000020 128KiB RT UC WC WT WB |
|
RT-data 00000043fa730000-00000043fa78ffff 00000060 384KiB RT UC WC WT WB |
|
RT-code 00000043fa790000-00000043fa79ffff 00000010 64KiB RT UC WC WT WB |
|
RT-data 00000043fa7a0000-00000043fa99ffff 00000200 2MiB RT UC WC WT WB |
|
RT-code 00000043fa9a0000-00000043fa9affff 00000010 64KiB RT UC WC WT WB |
|
RT-data 00000043fa9b0000-00000043fa9cffff 00000020 128KiB RT UC WC WT WB |
|
BS-code 00000043fa9d0000-00000043fa9d9fff 0000000a 40KiB UC WC WT WB |
|
reserved 00000043fa9da000-00000043fa9dbfff 00000002 8KiB UC WC WT WB |
|
conv-mem 00000043fa9dc000-00000043fc29dfff 000018c2 25352KiB UC WC WT WB |
|
BS-data 00000043fc29e000-00000043fc78afff 000004ed 5044KiB UC WC WT WB |
|
conv-mem 00000043fc78b000-00000043fca01fff 00000277 2524KiB UC WC WT WB |
|
BS-data 00000043fca02000-00000043fcea3fff 000004a2 4744KiB UC WC WT WB |
|
conv-mem 00000043fcea4000-00000043fcea4fff 00000001 4KiB UC WC WT WB |
|
BS-data 00000043fcea5000-00000043fd192fff 000002ee 3000KiB UC WC WT WB |
|
conv-mem 00000043fd193000-00000043fd2b0fff 0000011e 1144KiB UC WC WT WB |
|
BS-data 00000043fd2b1000-00000043ff80ffff 0000255f 38268KiB UC WC WT WB |
|
BS-code 00000043ff810000-00000043ff99ffff 00000190 1600KiB UC WC WT WB |
|
RT-code 00000043ff9a0000-00000043ff9affff 00000010 64KiB RT UC WC WT WB |
|
conv-mem 00000043ff9b0000-00000043ff9bffff 00000010 64KiB UC WC WT WB |
|
RT-data 00000043ff9c0000-00000043ff9effff 00000030 192KiB RT UC WC WT WB |
|
conv-mem 00000043ff9f0000-00000043ffa05fff 00000016 88KiB UC WC WT WB |
|
BS-data 00000043ffa06000-00000043ffffffff 000005fa 6120KiB UC WC WT WB |
|
MMIO 0000000010510000-0000000010510fff 00000001 4KiB RT |
|
MMIO 0000000010548000-0000000010549fff 00000002 8KiB RT |
|
MMIO 0000000017000000-0000000017001fff 00000002 8KiB RT |
|
MMIO 000000001c025000-000000001c025fff 00000001 4KiB RT |
|
|
|
This patch adds a requirement when we're trying to find the base of ram, that |
|
the memory we choose is actually /allocatable/ conventional memory, not merely |
|
write-combining. On this machine that means we wind up with an allocation |
|
around 0x4392XXXXXX, which is a reasonable address. |
|
|
|
This also changes grub_efi_allocate_pages_real() so that if 0 is allocated, it |
|
tries to allocate again starting with the same max address it did the first |
|
time, rather than interposing GRUB_EFI_MAX_USABLE_ADDRESS there, so that any |
|
per-platform constraints on its given address are maintained. |
|
|
|
Signed-off-by: Peter Jones <pjones@redhat.com> |
|
--- |
|
grub-core/kern/efi/mm.c | 33 +++++++++++++++----- |
|
grub-core/loader/arm64/linux.c | 68 +++++++++++++++++++++++++++++++----------- |
|
2 files changed, 76 insertions(+), 25 deletions(-) |
|
|
|
diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c |
|
index f6aef0ef649..85ad4b4494c 100644 |
|
--- a/grub-core/kern/efi/mm.c |
|
+++ b/grub-core/kern/efi/mm.c |
|
@@ -154,6 +154,7 @@ grub_efi_allocate_pages_real (grub_efi_physical_address_t address, |
|
{ |
|
grub_efi_status_t status; |
|
grub_efi_boot_services_t *b; |
|
+ grub_efi_physical_address_t ret = address; |
|
|
|
/* Limit the memory access to less than 4GB for 32-bit platforms. */ |
|
if (address > GRUB_EFI_MAX_USABLE_ADDRESS) |
|
@@ -170,19 +171,22 @@ grub_efi_allocate_pages_real (grub_efi_physical_address_t address, |
|
} |
|
|
|
b = grub_efi_system_table->boot_services; |
|
- status = efi_call_4 (b->allocate_pages, alloctype, memtype, pages, &address); |
|
+ status = efi_call_4 (b->allocate_pages, alloctype, memtype, pages, &ret); |
|
if (status != GRUB_EFI_SUCCESS) |
|
{ |
|
+ grub_dprintf ("efi", |
|
+ "allocate_pages(%d, %d, 0x%0lx, 0x%016lx) = 0x%016lx\n", |
|
+ alloctype, memtype, pages, address, status); |
|
grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); |
|
return NULL; |
|
} |
|
|
|
- if (address == 0) |
|
+ if (ret == 0) |
|
{ |
|
/* Uggh, the address 0 was allocated... This is too annoying, |
|
so reallocate another one. */ |
|
- address = GRUB_EFI_MAX_USABLE_ADDRESS; |
|
- status = efi_call_4 (b->allocate_pages, alloctype, memtype, pages, &address); |
|
+ ret = address; |
|
+ status = efi_call_4 (b->allocate_pages, alloctype, memtype, pages, &ret); |
|
grub_efi_free_pages (0, pages); |
|
if (status != GRUB_EFI_SUCCESS) |
|
{ |
|
@@ -191,9 +195,9 @@ grub_efi_allocate_pages_real (grub_efi_physical_address_t address, |
|
} |
|
} |
|
|
|
- grub_efi_store_alloc (address, pages); |
|
+ grub_efi_store_alloc (ret, pages); |
|
|
|
- return (void *) ((grub_addr_t) address); |
|
+ return (void *) ((grub_addr_t) ret); |
|
} |
|
|
|
void * |
|
@@ -713,8 +717,21 @@ grub_efi_get_ram_base(grub_addr_t *base_addr) |
|
for (desc = memory_map, *base_addr = GRUB_EFI_MAX_USABLE_ADDRESS; |
|
(grub_addr_t) desc < ((grub_addr_t) memory_map + memory_map_size); |
|
desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size)) |
|
- if (desc->attribute & GRUB_EFI_MEMORY_WB) |
|
- *base_addr = grub_min (*base_addr, desc->physical_start); |
|
+ { |
|
+ if (desc->type == GRUB_EFI_CONVENTIONAL_MEMORY && |
|
+ (desc->attribute & GRUB_EFI_MEMORY_WB)) |
|
+ { |
|
+ *base_addr = grub_min (*base_addr, desc->physical_start); |
|
+ grub_dprintf ("efi", "setting base_addr=0x%016lx\n", *base_addr); |
|
+ } |
|
+ else |
|
+ { |
|
+ grub_dprintf ("efi", "ignoring address 0x%016lx\n", desc->physical_start); |
|
+ } |
|
+ } |
|
+ |
|
+ if (*base_addr == GRUB_EFI_MAX_USABLE_ADDRESS) |
|
+ grub_dprintf ("efi", "base_addr 0x%016lx is probably wrong.\n", *base_addr); |
|
|
|
grub_free(memory_map); |
|
|
|
diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c |
|
index 04994d5c67d..70a0075ec5e 100644 |
|
--- a/grub-core/loader/arm64/linux.c |
|
+++ b/grub-core/loader/arm64/linux.c |
|
@@ -71,20 +71,25 @@ finalize_params_linux (void) |
|
{ |
|
grub_efi_loaded_image_t *loaded_image = NULL; |
|
int node, retval, len; |
|
- |
|
+ grub_err_t err = GRUB_ERR_NONE; |
|
void *fdt; |
|
|
|
fdt = grub_fdt_load (GRUB_EFI_LINUX_FDT_EXTRA_SPACE); |
|
- |
|
if (!fdt) |
|
- goto failure; |
|
+ { |
|
+ err = grub_error(GRUB_ERR_BAD_OS, "failed to load FDT"); |
|
+ goto failure; |
|
+ } |
|
|
|
node = grub_fdt_find_subnode (fdt, 0, "chosen"); |
|
if (node < 0) |
|
node = grub_fdt_add_subnode (fdt, 0, "chosen"); |
|
|
|
if (node < 1) |
|
- goto failure; |
|
+ { |
|
+ err = grub_error(grub_errno, "failed to load chosen fdt node."); |
|
+ goto failure; |
|
+ } |
|
|
|
/* Set initrd info */ |
|
if (initrd_start && initrd_end > initrd_start) |
|
@@ -95,15 +100,26 @@ finalize_params_linux (void) |
|
retval = grub_fdt_set_prop64 (fdt, node, "linux,initrd-start", |
|
initrd_start); |
|
if (retval) |
|
- goto failure; |
|
+ { |
|
+ err = grub_error(retval, "Failed to set linux,initrd-start property"); |
|
+ goto failure; |
|
+ } |
|
+ |
|
retval = grub_fdt_set_prop64 (fdt, node, "linux,initrd-end", |
|
initrd_end); |
|
if (retval) |
|
- goto failure; |
|
+ { |
|
+ err = grub_error(retval, "Failed to set linux,initrd-end property"); |
|
+ goto failure; |
|
+ } |
|
} |
|
|
|
- if (grub_fdt_install() != GRUB_ERR_NONE) |
|
- goto failure; |
|
+ retval = grub_fdt_install(); |
|
+ if (retval != GRUB_ERR_NONE) |
|
+ { |
|
+ err = grub_error(retval, "Failed to install fdt"); |
|
+ goto failure; |
|
+ } |
|
|
|
grub_dprintf ("linux", "Installed/updated FDT configuration table @ %p\n", |
|
fdt); |
|
@@ -111,14 +127,20 @@ finalize_params_linux (void) |
|
/* Convert command line to UCS-2 */ |
|
loaded_image = grub_efi_get_loaded_image (grub_efi_image_handle); |
|
if (!loaded_image) |
|
- goto failure; |
|
+ { |
|
+ err = grub_error(grub_errno, "Failed to install fdt"); |
|
+ goto failure; |
|
+ } |
|
|
|
loaded_image->load_options_size = len = |
|
(grub_strlen (linux_args) + 1) * sizeof (grub_efi_char16_t); |
|
loaded_image->load_options = |
|
grub_efi_allocate_any_pages (GRUB_EFI_BYTES_TO_PAGES (loaded_image->load_options_size)); |
|
if (!loaded_image->load_options) |
|
- return grub_error(GRUB_ERR_BAD_OS, "failed to create kernel parameters"); |
|
+ { |
|
+ err = grub_error(GRUB_ERR_BAD_OS, "failed to create kernel parameters"); |
|
+ goto failure; |
|
+ } |
|
|
|
loaded_image->load_options_size = |
|
2 * grub_utf8_to_utf16 (loaded_image->load_options, len, |
|
@@ -128,7 +150,7 @@ finalize_params_linux (void) |
|
|
|
failure: |
|
grub_fdt_unload(); |
|
- return grub_error(GRUB_ERR_BAD_OS, "failed to install/update FDT"); |
|
+ return err; |
|
} |
|
|
|
static void |
|
@@ -212,16 +234,28 @@ grub_linux_unload (void) |
|
static void * |
|
allocate_initrd_mem (int initrd_pages) |
|
{ |
|
- grub_addr_t max_addr; |
|
+ grub_addr_t max_addr = 0; |
|
+ grub_err_t err; |
|
+ void *ret; |
|
|
|
- if (grub_efi_get_ram_base (&max_addr) != GRUB_ERR_NONE) |
|
- return NULL; |
|
+ err = grub_efi_get_ram_base (&max_addr); |
|
+ if (err != GRUB_ERR_NONE) |
|
+ { |
|
+ grub_error (err, "grub_efi_get_ram_base() failed"); |
|
+ return NULL; |
|
+ } |
|
+ |
|
+ grub_dprintf ("linux", "max_addr: 0x%016lx, INITRD_MAX_ADDRESS_OFFSET: 0x%016llx\n", |
|
+ max_addr, INITRD_MAX_ADDRESS_OFFSET); |
|
|
|
max_addr += INITRD_MAX_ADDRESS_OFFSET - 1; |
|
+ grub_dprintf ("linux", "calling grub_efi_allocate_pages_real (0x%016lx, 0x%08x, EFI_ALLOCATE_MAX_ADDRESS, EFI_LOADER_DATA)", max_addr, initrd_pages); |
|
|
|
- return grub_efi_allocate_pages_real (max_addr, initrd_pages, |
|
- GRUB_EFI_ALLOCATE_MAX_ADDRESS, |
|
- GRUB_EFI_LOADER_DATA); |
|
+ ret = grub_efi_allocate_pages_real (max_addr, initrd_pages, |
|
+ GRUB_EFI_ALLOCATE_MAX_ADDRESS, |
|
+ GRUB_EFI_LOADER_DATA); |
|
+ grub_dprintf ("linux", "got 0x%016llx\n", (unsigned long long)ret); |
|
+ return ret; |
|
} |
|
|
|
static grub_err_t
|
|
|