From mboxrd@z Thu Jan 1 00:00:00 1970 From: Alexander Graf Date: Tue, 2 Feb 2016 01:59:58 +0100 Subject: [U-Boot] [PATCH 09/14] efi_loader: Implement memory allocation and map In-Reply-To: References: <1452834380-164453-1-git-send-email-agraf@suse.de> <1452834380-164453-10-git-send-email-agraf@suse.de> Message-ID: <56AFFF8E.4010501@suse.de> List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de On 01/31/2016 04:23 PM, Simon Glass wrote: > Hi Alexander, > > On 14 January 2016 at 22:06, Alexander Graf wrote: >> Due to popular request, this is a separate patch implementing all of the memory >> allocation and memory mapping bits. >> >> We assume we always have a linear RAM map. At TOM U-Boot resides. Inside of >> U-Boot there is the runtime region that we need to explicitly expose via the >> EFI memory map. Below U-Boot, we reserve 128MB of RAM for LOADER_DATA. >> >> Signed-off-by: Alexander Graf >> --- >> lib/efi_loader/efi_boottime.c | 99 ++++++++++++++++++++++++++++++++++++++- >> lib/efi_loader/efi_image_loader.c | 28 ++++++++++- >> 2 files changed, 123 insertions(+), 4 deletions(-) >> >> diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c >> index 45217ef..ff3f969 100644 >> --- a/lib/efi_loader/efi_boottime.c >> +++ b/lib/efi_loader/efi_boottime.c >> @@ -98,6 +98,8 @@ static void efi_restore_tpl(unsigned long old_tpl) >> static void *efi_alloc(uint64_t len, int memory_type) >> { >> switch (memory_type) { >> + case EFI_LOADER_DATA: >> + return efi_loader_alloc(len); >> default: >> return malloc(len); >> } >> @@ -143,16 +145,109 @@ static efi_status_t efi_free_pages(uint64_t memory, unsigned long pages) >> return EFI_EXIT(EFI_SUCCESS); >> } >> >> -/* Will be implemented in a later patch */ >> +/* >> + * Returns the EFI memory map. In our case, this looks pretty simple: >> + * >> + * ____________________________ TOM >> + * | | >> + * | Second half of U-Boot | > What does 'second half' mean? It means that there's one big chunk of "U-Boot" with the RTS sitting in the middle, dividing it into 2 halves :). I hope my new memory allocation code makes this more obvious. > >> + * |____________________________| &__efi_runtime_stop >> + * | | >> + * | EFI Runtime Services | >> + * |____________________________| &__efi_runtime_start >> + * | | >> + * | First half of U-Boot | >> + * |____________________________| start of EFI loader allocation space >> + * | | >> + * | Free RAM | >> + * |____________________________| CONFIG_SYS_SDRAM_BASE >> + * >> + * All pointers are extended to live on a 4k boundary. After exiting the boot >> + * services, only the EFI Runtime Services chunk of memory stays alive. >> + */ >> static efi_status_t efi_get_memory_map(unsigned long *memory_map_size, >> struct efi_mem_desc *memory_map, >> unsigned long *map_key, >> unsigned long *descriptor_size, >> uint32_t *descriptor_version) >> { >> + struct efi_mem_desc efi_memory_map[] = { >> + { >> + /* RAM before U-Boot */ >> + .type = EFI_CONVENTIONAL_MEMORY, >> + .attribute = 1 << EFI_MEMORY_WB_SHIFT, >> + }, >> + { >> + /* First half of U-Boot */ >> + .type = EFI_LOADER_DATA, >> + .attribute = 1 << EFI_MEMORY_WB_SHIFT, >> + }, >> + { >> + /* EFI Runtime Services */ >> + .type = EFI_RUNTIME_SERVICES_CODE, >> + .attribute = (1 << EFI_MEMORY_WB_SHIFT) | >> + (1ULL << EFI_MEMORY_RUNTIME_SHIFT), >> + }, >> + { >> + /* Second half of U-Boot */ >> + .type = EFI_LOADER_DATA, >> + .attribute = 1 << EFI_MEMORY_WB_SHIFT, >> + }, >> + }; >> + ulong runtime_start, runtime_end, runtime_len_pages, runtime_len; >> + >> EFI_ENTRY("%p, %p, %p, %p, %p", memory_map_size, memory_map, map_key, >> descriptor_size, descriptor_version); >> - return EFI_EXIT(EFI_UNSUPPORTED); >> + >> + runtime_start = (ulong)&__efi_runtime_start & ~0xfffULL; >> + runtime_end = ((ulong)&__efi_runtime_stop + 0xfff) & ~0xfffULL; >> + runtime_len_pages = (runtime_end - runtime_start) >> 12; >> + runtime_len = runtime_len_pages << 12; >> + >> + /* Fill in where normal RAM is (up to U-Boot's top of stack) */ >> + efi_memory_map[0].num_pages = gd->start_addr_sp >> 12; >> +#ifdef CONFIG_SYS_SDRAM_BASE > If not defined, what happens? The new code uses gd->bd->bi_dram. > >> + efi_memory_map[0].physical_start = CONFIG_SYS_SDRAM_BASE; >> + efi_memory_map[0].virtual_start = CONFIG_SYS_SDRAM_BASE; >> + efi_memory_map[0].num_pages -= CONFIG_SYS_SDRAM_BASE >> 12; >> +#endif >> + >> + /* Give us some space for the stack */ >> + efi_memory_map[0].num_pages -= (16 * 1024 * 1024) >> 12; >> + >> + /* Reserve the EFI loader pool */ >> + efi_memory_map[0].num_pages -= EFI_LOADER_POOL_SIZE >> 12; >> + >> + /* Cut out the runtime services */ >> + efi_memory_map[2].physical_start = runtime_start; >> + efi_memory_map[2].virtual_start = efi_memory_map[2].physical_start; >> + efi_memory_map[2].num_pages = runtime_len_pages; >> + >> + /* Allocate the rest to U-Boot */ >> + efi_memory_map[1].physical_start = efi_memory_map[0].physical_start + >> + (efi_memory_map[0].num_pages << 12); >> + efi_memory_map[1].virtual_start = efi_memory_map[1].physical_start; >> + efi_memory_map[1].num_pages = (runtime_start - >> + efi_memory_map[1].physical_start) >> 12; >> + >> + efi_memory_map[3].physical_start = runtime_start + runtime_len; >> + efi_memory_map[3].virtual_start = efi_memory_map[3].physical_start; >> + efi_memory_map[3].num_pages = (gd->ram_top - >> + efi_memory_map[3].physical_start) >> 12; >> + >> + *memory_map_size = sizeof(efi_memory_map); >> + >> + if (descriptor_size) >> + *descriptor_size = sizeof(struct efi_mem_desc); >> + >> + if (*memory_map_size < sizeof(efi_memory_map)) { >> + return EFI_EXIT(EFI_BUFFER_TOO_SMALL); >> + } >> + >> + if (memory_map) >> + memcpy(memory_map, efi_memory_map, sizeof(efi_memory_map)); >> + >> + return EFI_EXIT(EFI_SUCCESS); >> } >> >> static efi_status_t efi_allocate_pool(int pool_type, unsigned long size, void **buffer) >> diff --git a/lib/efi_loader/efi_image_loader.c b/lib/efi_loader/efi_image_loader.c >> index a7788bf..67c4b06 100644 >> --- a/lib/efi_loader/efi_image_loader.c >> +++ b/lib/efi_loader/efi_image_loader.c >> @@ -29,10 +29,34 @@ efi_status_t efi_return_handle(void *handle, efi_guid_t *protocol, >> return EFI_SUCCESS; >> } >> >> -/* Will be implemented in a later patch */ >> +/* >> + * EFI payloads potentially want to load pretty big images into memory, >> + * so our small malloc region isn't enough for them. However, they usually >> + * don't need a smart allocator either. >> + * >> + * So instead give them a really dumb one. We just reserve EFI_LOADER_POOL_SIZE >> + * bytes from 16MB below the stack start to give the stack some space. >> + * Then every allocation gets a 4k aligned chunk from it. We never free. >> + */ >> void *efi_loader_alloc(uint64_t len) >> { >> - return NULL; >> + static unsigned long loader_pool; >> + void *r; >> + >> + if (!loader_pool) { >> + loader_pool = ((gd->start_addr_sp >> 12) << 12) - >> + (16 * MB) - EFI_LOADER_POOL_SIZE; > I think it would be better to reserve this in board_f() with a > reserve...() function. Perhaps store the address in global_data. The new code doesn't reserve anything anymore :) Alex > >> + } >> + >> + len = ROUND_UP(len, 4096); >> + /* Out of memory */ >> + if ((loader_pool + len) >= (gd->relocaddr - TOTAL_MALLOC_LEN)) > debug() here? > >> + return NULL; >> + >> + r = (void *)loader_pool; >> + loader_pool += len; >> + >> + return r; >> } >> >> /* >> -- >> 2.1.4 > Regards, > Simon