diff options
Diffstat (limited to 'common/main.c')
| -rw-r--r-- | common/main.c | 69 |
1 files changed, 60 insertions, 9 deletions
diff --git a/common/main.c b/common/main.c index cd234bb..a8fdf58 100644 --- a/common/main.c +++ b/common/main.c @@ -43,10 +43,6 @@ extern int tb_console_init(void); /* - * fixed load address, the osdev way. past the bootloader at the - * bottom of RAM, the image header decides its final resting place. - */ -/* * the payload goes 16MB clear of wherever this bootloader is * actually running, ADR knows the runtime base and qemu is free * to place us anywhere. hardcoding 0x40200000 smashed our own @@ -59,6 +55,11 @@ extern char __image_copy_end[]; #define TB_BOOTFILE "Image" extern void __NO_RETURN tb_boot_linux(uintptr_t ep, uintptr_t fw_arg); +extern uintptr_t tb_dtb_relocate(uintptr_t dtb, void *scratch, + size_t scratch_size, size_t grow); +extern int tb_dtb_add_chosen_prop(uintptr_t dtb, const char *name, + const void *val, size_t len); +static size_t initrd_size; void tashaboot_main(uintptr_t fw_arg) { @@ -141,22 +142,72 @@ void tashaboot_main(uintptr_t fw_arg) } /* + * firmware owns the devicetree it hands the kernel. ours + * relocates into scratch with grow room, then the chosen + * properties are added there and the kernel gets the new + * address, the same flow libfdt firmware uses. + */ + { + /* + * the scratch lives at a fixed free address, clear of + * our image, the payload, and the kernel relocation + * zone. a bss array would sit inside 0x40080000+ and + * the kernel overwrites it while copying itself. + */ + uint8_t *dtb_scratch = (uint8_t *)0x45000000ULL; + uintptr_t newdtb; + + newdtb = tb_dtb_relocate(fw_arg, dtb_scratch, + 0x10000, 0x200); + if (!newdtb) { + dprintf(ALWAYS, "dtb: relocate failed\n"); + platform_halt(); + } + + fw_arg = newdtb; + } + + /* * the initrd rides after the kernel, the dtb /chosen carries * linux,initrd-start and -end, both already patched in place * with this layout. */ { - extern int tb_load_raw(const char *fname, - uintptr_t load_addr); - int r = tb_load_raw(TB_INITRD_FILE, TB_INITRD_ADDR); + int r = tb_load_raw(TB_INITRD_FILE, TB_INITRD_ADDR, + &initrd_size); if (r == 0) - dprintf(ALWAYS, "initrd at %lx\n", - (unsigned long)TB_INITRD_ADDR); + dprintf(ALWAYS, "initrd at %lx, %lx bytes\n", + (unsigned long)TB_INITRD_ADDR, + (unsigned long)initrd_size); else dprintf(ALWAYS, "no initrd (%d)\n", r); } + /* + * the chosen properties, written now that the initrd size + * is known. the cells are big endian, the fdt is a big + * endian format end to end. + */ + { + uint8_t start_cells[8], end_cells[8]; + uint64_t start = TB_INITRD_ADDR; + uint64_t end = TB_INITRD_ADDR + initrd_size; + int a, b; + + for (int i = 0; i < 8; i++) { + start_cells[i] = (uint8_t)(start >> (56 - 8 * i)); + end_cells[i] = (uint8_t)(end >> (56 - 8 * i)); + } + a = tb_dtb_add_chosen_prop(fw_arg, "linux,initrd-start", + start_cells, 8); + b = tb_dtb_add_chosen_prop(fw_arg, "linux,initrd-end", + end_cells, 8); + dprintf(ALWAYS, "dtb: initrd props %d %d\n", a, b); + } + + + dprintf(ALWAYS, "loaded %llu bytes at %lx, entry %lx\n", (unsigned long long)img.size, img.load, img.ep); dprintf(ALWAYS, "jumping\n"); |
