diff options
Diffstat (limited to 'com32/lib/syslinux/load_linux.c')
-rw-r--r-- | com32/lib/syslinux/load_linux.c | 78 |
1 files changed, 78 insertions, 0 deletions
diff --git a/com32/lib/syslinux/load_linux.c b/com32/lib/syslinux/load_linux.c index cca2efd0..4f583cd7 100644 --- a/com32/lib/syslinux/load_linux.c +++ b/com32/lib/syslinux/load_linux.c @@ -31,9 +31,11 @@ * Load a Linux kernel (Image/zImage/bzImage). */ +#include <stdbool.h> #include <stdlib.h> #include <inttypes.h> #include <string.h> +#include <syslinux/align.h> #include <syslinux/linux.h> #include <syslinux/bootrm.h> #include <syslinux/movebits.h> @@ -159,6 +161,7 @@ int syslinux_boot_linux(void *kernel_buf, size_t kernel_size, struct syslinux_movelist *fraglist = NULL; struct syslinux_memmap *mmap = NULL; struct syslinux_memmap *amap = NULL; + bool ok; cmdline_size = strlen(cmdline)+1; @@ -189,6 +192,9 @@ int syslinux_boot_linux(void *kernel_buf, size_t kernel_size, if (!memlimit || memlimit-1 > hdr.initrd_addr_max) memlimit = hdr.initrd_addr_max+1; /* Zero for no limit */ + if (hdr.version < 0x0205) + hdr.relocatable_kernel = 0; + if (hdr.version < 0x0206) hdr.cmdline_max_len = 256; @@ -250,7 +256,79 @@ int syslinux_boot_linux(void *kernel_buf, size_t kernel_size, /* Place the kernel in memory */ + /* First, find a suitable place for the protected-mode code */ + if (syslinux_memmap_type(amap, prot_mode_base, prot_mode_size) + != SMT_FREE) { + const struct syslinux_memmap *mp; + if (!hdr.relocatable_kernel) + goto bail; /* Can't relocate - no hope */ + + ok = false; + for (mp = amap; mp; mp = mp->next) { + addr_t start, end; + start = mp->start; + end = mp->next->start; + + if (mp->type != SMT_FREE) + continue; + + if (end <= prot_mode_base) + continue; /* Only relocate upwards */ + + if (start <= prot_mode_base) + start = prot_mode_base; + + start = ALIGN_UP(start, hdr.kernel_alignment); + if (start >= end) + continue; + + /* The 3* here is a total fudge factor... it's supposed to + account for the fact that the kernel needs to be decompressed, + and then followed by the BSS and BRK regions. This doesn't, + however, account for the fact that the kernel is decompressed + into a whole other place, either. */ + if (end - start >= 3*prot_mode_size) { + prot_mode_base = start; + ok = true; + break; + } + } + + if (!ok) + goto bail; + } + /* Real mode code */ + if (syslinux_memmap_type(amap, real_mode_base, + cmdline_offset+cmdline_size) != SMT_FREE) { + const struct syslinux_memmap *mp; + + ok = false; + for (mp = amap; mp; mp = mp->next) { + addr_t start, end; + start = mp->start; + end = mp->next->start; + + if (mp->type != SMT_FREE) + continue; + + if (start < real_mode_base) + start = real_mode_base; /* Lowest address we'll use */ + if (end > 640*1024) + end = 640*1024; + + start = ALIGN_UP(start, 16); + if (start >= end) + continue; + + if (end - start >= cmdline_offset+cmdline_size) { + real_mode_base = start; + ok = true; + break; + } + } + } + if (syslinux_add_movelist(&fraglist, real_mode_base, (addr_t)kernel_buf, real_mode_size)) goto bail; |