diff options
Diffstat (limited to 'com32/lib/syslinux/load_linux.c')
-rw-r--r-- | com32/lib/syslinux/load_linux.c | 41 |
1 files changed, 40 insertions, 1 deletions
diff --git a/com32/lib/syslinux/load_linux.c b/com32/lib/syslinux/load_linux.c index 45cd6965..b68aef7b 100644 --- a/com32/lib/syslinux/load_linux.c +++ b/com32/lib/syslinux/load_linux.c @@ -180,7 +180,8 @@ static int map_initramfs(struct syslinux_movelist **fraglist, } int syslinux_boot_linux(void *kernel_buf, size_t kernel_size, - struct initramfs *initramfs, char *cmdline) + struct initramfs *initramfs, struct fdt *fdt, + char *cmdline) { struct linux_header hdr, *whdr; size_t real_mode_size, prot_mode_size; @@ -449,6 +450,44 @@ int syslinux_boot_linux(void *kernel_buf, size_t kernel_size, } } + if (fdt && fdt->len > 0) { + const addr_t align_mask = DEVICETREE_MAX_ALIGN - 1; + struct syslinux_memmap *ml; + struct setup_data *setup; + addr_t best_addr = 0; + size_t size; + + size = sizeof(*setup) + fdt->len; + + setup = malloc(size); + if (!setup) + goto bail; + + setup->next = 0; + setup->type = SETUP_DTB; + setup->len = fdt->len; + memcpy(setup->data, fdt->data, fdt->len); + + for (ml = amap; ml->type != SMT_END; ml = ml->next) { + addr_t adj_start = (ml->start + align_mask) & ~align_mask; + addr_t adj_end = ml->next->start & ~align_mask; + + if (ml->type == SMT_FREE && adj_end - adj_start >= size) + best_addr = (adj_end - size) & ~align_mask; + } + + if (!best_addr) + goto bail; + + whdr->setup_data = best_addr; + + if (syslinux_add_memmap(&amap, best_addr, size, SMT_ALLOC)) + goto bail; + + if (syslinux_add_movelist(&fraglist, best_addr, (addr_t) setup, size)) + goto bail; + } + /* Set up the registers on entry */ memset(®s, 0, sizeof regs); regs.es = regs.ds = regs.ss = regs.fs = regs.gs = real_mode_base >> 4; |