Skip to content

Commit

Permalink
elfloader: pass DTB from bootloader to seL4 on ARM
Browse files Browse the repository at this point in the history
On ARM, we expect the physical address of the dtb to be passed in r2 on
aarch32 or x0 on aarch64. RISC-V supplies a DTB in a1, but we currently
don't pass it to the kernel.

The elfloader then moves the dtb to immediately after where the
kernel is loaded in memory, and passes that address on to the kernel.

If there is no bootloader provided DTB, the elfloader will pass 0
to the kernel as the start address of the DTB.
  • Loading branch information
fourkbomb committed May 1, 2019
1 parent d95f31a commit c573511
Show file tree
Hide file tree
Showing 9 changed files with 154 additions and 16 deletions.
4 changes: 2 additions & 2 deletions elfloader-tool/include/arch-arm/elfloader.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
typedef void (*init_arm_kernel_t)(paddr_t ui_p_reg_start,
paddr_t ui_p_reg_end,
uintptr_t pv_offset,
vaddr_t v_entry);

vaddr_t v_entry,
paddr_t dtb, uint32_t dtb_size);


/* Enable the mmu. */
Expand Down
3 changes: 2 additions & 1 deletion elfloader-tool/include/elfloader_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ struct image_info {

extern struct image_info kernel_info;
extern struct image_info user_info;
extern void *dtb;

/* Symbols defined in linker scripts. */
extern char _start[];
Expand All @@ -65,7 +66,7 @@ extern char _archive_start_end[];

/* Load images. */
void load_images(struct image_info *kernel_info, struct image_info *user_info,
int max_user_images, int *num_images);
int max_user_images, int *num_images, void **dtb, uint32_t *dtb_size);

/* Platform functions */
void platform_init(void);
Expand Down
15 changes: 15 additions & 0 deletions elfloader-tool/include/fdt.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* Copyright 2018, Data61
* Commonwealth Scientific and Industrial Research Organisation (CSIRO)
* ABN 41 687 119 230.
*
* This software may be distributed and modified according to the terms of
* the GNU General Public License version 2. Note that NO WARRANTY is provided.
* See "LICENSE_GPLv2.txt" for details.
*
* @TAG(DATA61_GPL)
*/

#pragma once

uint32_t fdt_size(void *fdt);
9 changes: 5 additions & 4 deletions elfloader-tool/src/arch-arm/32/crt0.S
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,15 @@ BEGIN_FUNC(_start)
/* Disable Async aborts that might be pending from bootloader */
cpsid ifa

/* r0 contains the FDT address from the bootloader */
#if CONFIG_MAX_NUM_NODES > 1
/* Enable SMP */
mrc ACTLR(r0)
orr r0, r0, #(1 << 6) /* enable SMP bit */
mrc ACTLR(r1)
orr r1, r1, #(1 << 6) /* enable SMP bit */
#ifdef CONFIG_ARM_CORTEX_A9
orr r0, r0, #1 /* enable FW bit */
orr r1, r1, #1 /* enable FW bit */
#endif
mcr ACTLR(r0)
mcr ACTLR(r1)
#endif /* CONFIG_MAX_NUM_NODES > 1 */

ldr sp, =core_stack_alloc + 0xff0
Expand Down
5 changes: 4 additions & 1 deletion elfloader-tool/src/arch-arm/smp_boot.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ static volatile int non_boot_lock = 0;

void arm_disable_dcaches(void);

extern void *dtb;
extern uint32_t dtb_size;

/* Entry point for all CPUs other than the initial. */
void non_boot_main(void)
{
Expand Down Expand Up @@ -53,7 +56,7 @@ void non_boot_main(void)
/* 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);
user_info.virt_entry, (paddr_t)dtb, dtb_size);

printf("AP Kernel returned back to the elf-loader.\n");
abort();
Expand Down
41 changes: 38 additions & 3 deletions elfloader-tool/src/arch-arm/sys_boot.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@
#include <binaries/efi/efi.h>
#include <elfloader.h>

/* 0xd00dfeed in big endian */
#define DTB_MAGIC (0xedfe0dd0)

ALIGN(BIT(PAGE_BITS)) VISIBLE
char core_stack_alloc[CONFIG_MAX_NUM_NODES][BIT(PAGE_BITS)];

Expand All @@ -33,15 +36,37 @@ struct image_info user_info;
*
* Unpack images, setup the MMU, jump to the kernel.
*/
void main(void)
void main(UNUSED void *arg)
{
int num_apps;
uint32_t dtb_size;
void *dtb;

#ifdef CONFIG_IMAGE_UIMAGE
if (arg) {
uint32_t magic = *(uint32_t *)arg;
/*
* This might happen on ancient bootloaders which
* still think Linux wants atags instead of a
* device tree.
*/
if (magic != DTB_MAGIC) {
printf("Bootloader did not supply a valid device tree!\n");
arg = NULL;
}
}
dtb = arg;
#else
dtb = NULL;
#endif

#ifdef CONFIG_IMAGE_EFI
if (efi_exit_boot_services() != EFI_SUCCESS) {
printf("Unable to exit UEFI boot services!\n");
abort();
}

/* TODO: get DTB from EFI like Linux does. */
#endif

/* Print welcome message. */
Expand All @@ -51,8 +76,18 @@ void main(void)

printf(" paddr=[%p..%p]\n", _start, _end - 1);

/*
* U-Boot will either pass us a DTB, or (if we're being booted via bootelf)
* pass '0' in argc.
*/
if (dtb) {
printf(" dtb=%p\n", dtb);
} else {
printf("No DTB found!\n");
}

/* Unpack ELF images into memory. */
load_images(&kernel_info, &user_info, 1, &num_apps);
load_images(&kernel_info, &user_info, 1, &num_apps, &dtb, &dtb_size);
if (num_apps != 1) {
printf("No user images loaded!\n");
abort();
Expand Down Expand Up @@ -98,7 +133,7 @@ void main(void)

((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);
user_info.virt_entry, (paddr_t)dtb, dtb_size);

/* We should never get here. */
printf("Kernel returned back to the elf-loader.\n");
Expand Down
6 changes: 4 additions & 2 deletions elfloader-tool/src/arch-riscv/boot.c
Original file line number Diff line number Diff line change
Expand Up @@ -121,13 +121,14 @@ uint64_t vm_mode = 0x9llu << 60;
#endif

int num_apps = 0;
void main(void)
void main(UNUSED int hardid, void *dtb)
{
uint32_t dtb_size;
printf("ELF-loader started on\n");

printf(" paddr=[%p..%p]\n", _start, _end - 1);
/* Unpack ELF images into memory. */
load_images(&kernel_info, &user_info, 1, &num_apps);
load_images(&kernel_info, &user_info, 1, &num_apps, &dtb, &dtb_size);
if (num_apps != 1) {
printf("No user images loaded!\n");
abort();
Expand All @@ -146,6 +147,7 @@ void main(void)
:
);

/* TODO: pass DTB to kernel. */
((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);
Expand Down
37 changes: 34 additions & 3 deletions elfloader-tool/src/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <cpio/cpio.h>

#include <elfloader.h>
#include <fdt.h>

#ifdef CONFIG_HASH_SHA
#include "crypt_sha256.h"
Expand Down Expand Up @@ -262,10 +263,11 @@ static paddr_t load_elf(const char *name, void *elf, paddr_t dest_paddr,
* We attempt to check for some of these, but some may go unnoticed.
*/
void load_images(struct image_info *kernel_info, struct image_info *user_info,
int max_user_images, int *num_images)
int max_user_images, int *num_images, void **dtb, uint32_t *dtb_size)
{
int i;
uint64_t kernel_phys_start, kernel_phys_end;
uintptr_t dtb_phys_start, dtb_phys_end;
paddr_t next_phys_addr;
const char *elf_filename;
unsigned long unused;
Expand All @@ -283,8 +285,37 @@ void load_images(struct image_info *kernel_info, struct image_info *user_info,
}

elf_getMemoryBounds(kernel_elf, 1, &kernel_phys_start, &kernel_phys_end);
next_phys_addr = load_elf("kernel", kernel_elf,
(paddr_t)kernel_phys_start, kernel_info, 0, unused, "kernel.bin");

/*
* Move the DTB out of the way, if it's present.
*/
if (dtb && *dtb) {
/* keep it page aligned */
next_phys_addr = dtb_phys_start = ROUND_UP(kernel_phys_end, PAGE_BITS);

*dtb_size = fdt_size(*dtb);
if (!*dtb_size) {
printf("Invalid device tree blob supplied!\n");
abort();
}

/* Make sure this is a sane thing to do */
ensure_phys_range_valid(next_phys_addr, next_phys_addr + *dtb_size);

memmove((void *)next_phys_addr, *dtb, *dtb_size);
next_phys_addr += *dtb_size;
next_phys_addr = ROUND_UP(next_phys_addr, PAGE_BITS);
dtb_phys_end = next_phys_addr;

printf("Loaded dtb from %p\n", *dtb);
printf(" paddr=[%lx..%lx]\n", dtb_phys_start, dtb_phys_end - 1);
*dtb = (void *)dtb_phys_start;
} else {
next_phys_addr = ROUND_UP(kernel_phys_end, PAGE_BITS);
}

load_elf("kernel", kernel_elf,
(paddr_t)kernel_phys_start, kernel_info, 0, unused, "kernel.bin");

/*
* Load userspace images.
Expand Down
50 changes: 50 additions & 0 deletions elfloader-tool/src/fdt.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright 2019, Data61
* Commonwealth Scientific and Industrial Research Organisation (CSIRO)
* ABN 41 687 119 230.
*
* This software may be distributed and modified according to the terms of
* the GNU General Public License version 2. Note that NO WARRANTY is provided.
* See "LICENSE_GPLv2.txt" for details.
*
* @TAG(DATA61_GPL)
*/
#include <types.h>

#define FDT_MAGIC (0xd00dfeed)
/* Newest FDT version that we understand */
#define FDT_MAX_VER 17

struct fdt_header {
uint32_t magic;
uint32_t totalsize;
uint32_t off_dt_struct;
uint32_t off_dt_strings;
uint32_t off_mem_rsvmap;
uint32_t version;
uint32_t last_comp_version;
uint32_t boot_cpuid_phys;
uint32_t size_dt_strings;
uint32_t size_dt_struct;
};

uint32_t be32_to_le(uint32_t be)
{
return ((be & 0xff) << 24) |
((be & 0xff00) << 8) |
((be & 0xff0000) >> 8) |
((be & 0xff000000) >> 24);
}

uint32_t fdt_size(void *fdt)
{
struct fdt_header *hdr = (struct fdt_header *)fdt;

if (be32_to_le(hdr->magic) != FDT_MAGIC ||
be32_to_le(hdr->last_comp_version) > FDT_MAX_VER) {
return 0;
}

return be32_to_le(hdr->totalsize);
}

0 comments on commit c573511

Please sign in to comment.