summaryrefslogtreecommitdiff
path: root/common/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/main.c')
-rw-r--r--common/main.c94
1 files changed, 86 insertions, 8 deletions
diff --git a/common/main.c b/common/main.c
index 0786027..a8fdf58 100644
--- a/common/main.c
+++ b/common/main.c
@@ -43,15 +43,23 @@
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
+ * image when qemu loaded us there.
*/
-#define TB_LOAD_ADDR 0x40200000
+extern char __image_copy_end[];
+#define TB_LOAD_ADDR ((uintptr_t)__image_copy_end + (16ULL << 20))
/* the file semihosting serves as the payload */
#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)
{
@@ -81,6 +89,26 @@ void tashaboot_main(uintptr_t fw_arg)
#endif
{
+ /* report the RAM we actually live in, before any mmu */
+ extern int tb_dtb_patch_memory(uintptr_t dtb,
+ uint64_t base,
+ uint64_t size);
+ int r;
+
+ r = 0; (void)r;
+
+ {
+ uint32_t *cells = (uint32_t *)(fw_arg + 0x16c);
+ int i;
+
+ dprintf(ALWAYS, "cells after:");
+ for (i = 0; i < 4; i++)
+ dprintf(ALWAYS, " %08x", cells[i]);
+ dprintf(ALWAYS, "\n");
+ }
+ }
+
+ {
/* spin table gates into the dtb, one per cpu node */
extern unsigned long *tb_spin_gates_ptr;
extern int tb_dtb_patch_spin_table(uintptr_t dtb,
@@ -114,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");