diff --git a/elfloader-tool/include/elfloader_common.h b/elfloader-tool/include/elfloader_common.h index 7a54c316..84ae4eb7 100644 --- a/elfloader-tool/include/elfloader_common.h +++ b/elfloader-tool/include/elfloader_common.h @@ -34,6 +34,15 @@ typedef uintptr_t vaddr_t; #define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0])) #define NULL ((void *)0) + +/* + * Information about a DTB we are loading. + */ +typedef struct { + paddr_t phys_base; + size_t size; +} dtb_info_t; + /* * Information about an image we are loading. */ @@ -93,9 +102,7 @@ int load_images( struct image_info *user_info, unsigned int max_user_images, unsigned int *num_images, - void const *bootloader_dtb, - void const **chosen_dtb, - size_t *chosen_dtb_size); + dtb_info_t *dtb_info); /* Platform functions */ void platform_init(void); diff --git a/elfloader-tool/src/arch-arm/smp_boot.c b/elfloader-tool/src/arch-arm/smp_boot.c index d429d113..3903174f 100644 --- a/elfloader-tool/src/arch-arm/smp_boot.c +++ b/elfloader-tool/src/arch-arm/smp_boot.c @@ -23,8 +23,7 @@ static volatile int non_boot_lock = 0; void arm_disable_dcaches(void); -extern void const *dtb; -extern uint32_t dtb_size; +extern dtb_info_t dtb_info; /* Entry point for all CPUs other than the initial. */ void non_boot_main(void) @@ -58,10 +57,15 @@ void non_boot_main(void) arm_enable_mmu(); } + /* Usually DTBs are much less than 4 GiB, so this cast should be fine. */ + uint32_t dtb_size_u32 = (uint32_t)dtb_info.size; + /* Jump to the kernel. */ ((init_arm_kernel_t)kernel_info.virt_entry)(user_info.phys_region_start, user_info.phys_region_end, user_info.phys_virt_offset, - user_info.virt_entry, (paddr_t)dtb, dtb_size); + user_info.virt_entry, + (word_t)dtb_info.phys_base, + (word_t)dtb_size_u32); printf("AP Kernel returned back to the elf-loader.\n"); abort(); diff --git a/elfloader-tool/src/arch-arm/sys_boot.c b/elfloader-tool/src/arch-arm/sys_boot.c index bf98aaf2..e83b2a61 100644 --- a/elfloader-tool/src/arch-arm/sys_boot.c +++ b/elfloader-tool/src/arch-arm/sys_boot.c @@ -32,8 +32,7 @@ char core_stack_alloc[CONFIG_MAX_NUM_NODES][BIT(PAGE_BITS)]; struct image_info kernel_info; struct image_info user_info; -void const *dtb; -size_t dtb_size; +dtb_info_t dtb_info; extern void finish_relocation(int offset, void *_dynamic, unsigned int total_offset); void continue_boot(int was_relocated); @@ -101,8 +100,6 @@ void relocate_below_kernel(void) */ void main(UNUSED void *arg) { - void *bootloader_dtb = NULL; - /* initialize platform to a state where we can print to a UART */ if (initialise_devices()) { printf("ERROR: Did not successfully return from initialise_devices()\n"); @@ -116,13 +113,22 @@ void main(UNUSED void *arg) print_cpuid(); printf(" paddr=[%p..%p]\n", _text, _end - 1); + /* Assume by default, that no DTB is provided from a previous + * bootloader stage. Since 0 is a valid physical address, the size + * field is used to indicate if the address is valid. The value -1 + * is to be used if the actual size is not known. + */ + dtb_info.phys_base = 0; + dtb_info.size = 0; + #if defined(CONFIG_IMAGE_UIMAGE) /* U-Boot passes a DTB. Ancient bootloaders may pass atags. When booting via * bootelf argc is NULL. */ if (arg && (DTB_MAGIC == *(uint32_t *)arg)) { - bootloader_dtb = arg; + dtb_info.phys_base = (paddr_t)arg; + dtb_info.size = (size_t)(-1); } #elif defined(CONFIG_IMAGE_EFI) @@ -132,20 +138,24 @@ void main(UNUSED void *arg) abort(); } - bootloader_dtb = efi_get_fdt(); + /* For EFI, the DTB address is not supposed to be 0. */ + void *efi_dtb = efi_get_fdt(); + if (efi_dtb) { + dtb_info.phys_base = (paddr_t)efi_dtb; + dtb_info.size = (size_t)(-1); + } #endif - if (bootloader_dtb) { - printf(" dtb=%p\n", bootloader_dtb); + if (0 != dtb_info.size) { + printf(" dtb=%p\n", dtb_info.phys_base); } else { printf("No DTB passed in from boot loader.\n"); } /* Unpack ELF images into memory. */ unsigned int num_apps = 0; - int ret = load_images(&kernel_info, &user_info, 1, &num_apps, - bootloader_dtb, &dtb, &dtb_size); + int ret = load_images(&kernel_info, &user_info, 1, &num_apps, &dtb_info); if (0 != ret) { printf("ERROR: image loading failed\n"); abort(); @@ -221,12 +231,15 @@ void continue_boot(int was_relocated) printf("Jumping to kernel-image entry point...\n\n"); } + /* Usually DTBs are much less than 4 GiB, so this cast should be fine. */ + uint32_t dtb_size_u32 = (uint32_t)dtb_info.size; + ((init_arm_kernel_t)kernel_info.virt_entry)(user_info.phys_region_start, user_info.phys_region_end, user_info.phys_virt_offset, user_info.virt_entry, - (word_t)dtb, - dtb_size); + (word_t)dtb_info.phys_base, + (word_t)dtb_size_u32); /* We should never get here. */ printf("ERROR: Kernel returned back to the ELF Loader\n"); diff --git a/elfloader-tool/src/arch-riscv/boot.c b/elfloader-tool/src/arch-riscv/boot.c index f485594a..e776f309 100644 --- a/elfloader-tool/src/arch-riscv/boot.c +++ b/elfloader-tool/src/arch-riscv/boot.c @@ -60,8 +60,7 @@ unsigned long l2pt_elf[PTES_PER_PT] __attribute__((aligned(4096))); char elfloader_stack_alloc[BIT(CONFIG_KERNEL_STACK_BITS)]; /* first HART will initialise these */ -void const *dtb = NULL; -size_t dtb_size = 0; +dtb_info_t dtb_info; /* * overwrite the default implementation for abort() @@ -194,10 +193,12 @@ static int run_elfloader(UNUSED int hart_id, void *bootloader_dtb) { int ret; + dtb_info.phys_base = (paddr_t)bootloader_dtb; + dtb_info.size = (size_t)(-1); + /* Unpack ELF images into memory. */ unsigned int num_apps = 0; - ret = load_images(&kernel_info, &user_info, 1, &num_apps, - bootloader_dtb, &dtb, &dtb_size); + ret = load_images(&kernel_info, &user_info, 1, &num_apps, &dtb_info); if (0 != ret) { printf("ERROR: image loading failed, code %d\n", ret); return -1; @@ -238,13 +239,16 @@ static int run_elfloader(UNUSED int hart_id, void *bootloader_dtb) printf("Enabling MMU and paging\n"); enable_virtual_memory(); + /* Usually DTBs are much less than 4 GiB, so this cast should be fine. */ + uint32_t dtb_size_u32 = (uint32_t)dtb_info.size; + printf("Jumping to kernel-image entry point...\n\n"); ((init_riscv_kernel_t)kernel_info.virt_entry)(user_info.phys_region_start, user_info.phys_region_end, user_info.phys_virt_offset, user_info.virt_entry, - (word_t)dtb, - dtb_size + (word_t)dtb_info.phys_base, + (word_t)dtb_size_u32 #if CONFIG_MAX_NUM_NODES > 1 , hart_id, @@ -271,6 +275,8 @@ void secondary_entry(int hart_id, int core_id) enable_virtual_memory(); + /* Usually DTBs are much less than 4 GiB, so this cast should be fine. */ + uint32_t dtb_size_u32 = (uint32_t)dtb_info.size; /* If adding or modifying these parameters you will need to update the registers in head.S */ @@ -278,8 +284,8 @@ void secondary_entry(int hart_id, int core_id) user_info.phys_region_end, user_info.phys_virt_offset, user_info.virt_entry, - (word_t)dtb, - dtb_size, + (word_t)dtb_info.phys_base, + (word_t)dtb_size_u32, hart_id, core_id ); diff --git a/elfloader-tool/src/common.c b/elfloader-tool/src/common.c index 9846422f..0ae8edd9 100644 --- a/elfloader-tool/src/common.c +++ b/elfloader-tool/src/common.c @@ -384,9 +384,7 @@ int load_images( struct image_info *user_info, unsigned int max_user_images, unsigned int *num_images, - void const *bootloader_dtb, - void const **chosen_dtb, - size_t *chosen_dtb_size) + dtb_info_t *dtb_info) { int ret; uint64_t kernel_phys_start, kernel_phys_end; @@ -434,31 +432,32 @@ int load_images( #ifdef CONFIG_ELFLOADER_INCLUDE_DTB - if (chosen_dtb) { - printf("Looking for DTB in CPIO archive..."); - /* - * Note the lack of newline in the above printf(). Normally one would - * have an fflush(stdout) here to ensure that the message shows up on a - * line-buffered stream (which is the POSIX default on terminal - * devices). But we are freestanding (on the "bare metal"), and using - * our own unbuffered printf() implementation. - */ - dtb = cpio_get_file(cpio, cpio_len, "kernel.dtb", NULL); - if (dtb == NULL) { - printf("not found.\n"); - } else { - has_dtb_cpio = 1; - printf("found at %p.\n", dtb); - } + printf("Looking for DTB in CPIO archive..."); + /* + * Note the lack of newline in the above printf(). Normally one would + * have an fflush(stdout) here to ensure that the message shows up on a + * line-buffered stream (which is the POSIX default on terminal + * devices). But we are freestanding (on the "bare metal"), and using + * our own unbuffered printf() implementation. + */ + dtb = cpio_get_file(cpio, cpio_len, "kernel.dtb", NULL); + if (dtb == NULL) { + printf("not found.\n"); + } else { + has_dtb_cpio = 1; + printf("found at %p.\n", dtb); } #endif /* CONFIG_ELFLOADER_INCLUDE_DTB */ - if (chosen_dtb && !dtb && bootloader_dtb) { - /* Use the bootloader's DTB if we are not using the DTB in the CPIO - * archive. - */ - dtb = bootloader_dtb; + /* If we don't have a DTB here, use the one a bootloader might have + * provided. Since 0 is a valid physical address, the size field is used to + * determin if the address is valid. A size of -1 indicates, that the actual + * size is not known - which is usually the case, because a bootloader often + * just passes an address. + */ + if (!dtb && (dtb_info->size > 0)) { + dtb = (void const *)dtb_info->phys_base; } /* @@ -489,9 +488,11 @@ int load_images( printf("Loaded DTB from %p.\n", dtb); printf(" paddr=[%p..%p]\n", dtb_phys_start, dtb_phys_end - 1); - *chosen_dtb = (void *)dtb_phys_start; - *chosen_dtb_size = dtb_size; + dtb_info->phys_base = dtb_phys_start; + dtb_info->size = dtb_size; } else { + dtb_info->phys_base = 0; + dtb_info->size = 0; next_phys_addr = ROUND_UP(kernel_phys_end, PAGE_BITS); }