diff options
author | Matt Fleming <matt.fleming@intel.com> | 2013-07-16 15:15:54 +0100 |
---|---|---|
committer | Matt Fleming <matt.fleming@intel.com> | 2013-07-17 18:29:16 +0100 |
commit | 8f470e7bfe75f6401f6c5432988c620b863ad274 (patch) | |
tree | 39b264e5f60ca44c906fcd0f3065b2fdc3581d05 | |
parent | 6252212849d945450310248b656dfb6f13f5de48 (diff) | |
download | syslinux-8f470e7bfe75f6401f6c5432988c620b863ad274.tar.gz syslinux-8f470e7bfe75f6401f6c5432988c620b863ad274.tar.xz syslinux-8f470e7bfe75f6401f6c5432988c620b863ad274.zip |
movebits: Add syslinux_memmap_find()
Refactor the code for finding a suitable location for kernel
protected-mode and real-mode data. It's complicated enough that it
deserves to be separated into its own function.
Signed-off-by: Matt Fleming <matt.fleming@intel.com>
-rw-r--r-- | com32/include/syslinux/movebits.h | 6 | ||||
-rw-r--r-- | com32/lib/syslinux/load_linux.c | 89 | ||||
-rw-r--r-- | com32/lib/syslinux/zonelist.c | 63 |
3 files changed, 84 insertions, 74 deletions
diff --git a/com32/include/syslinux/movebits.h b/com32/include/syslinux/movebits.h index 5023accb..feeab3aa 100644 --- a/com32/include/syslinux/movebits.h +++ b/com32/include/syslinux/movebits.h @@ -3,6 +3,7 @@ #include <inttypes.h> #include <stdio.h> +#include <stdbool.h> typedef uint32_t addr_t; @@ -81,6 +82,11 @@ struct syslinux_memmap *syslinux_dup_memmap(struct syslinux_memmap *list); int syslinux_memmap_find_type(struct syslinux_memmap *list, enum syslinux_memmap_types type, addr_t * start, addr_t * len, addr_t align); +int syslinux_memmap_find(struct syslinux_memmap *mmap, + addr_t *base, size_t size, + bool relocate, size_t align, + addr_t start_min, addr_t start_max, + addr_t end_min, addr_t end_max); /* Debugging functions */ #ifdef DEBUG diff --git a/com32/lib/syslinux/load_linux.c b/com32/lib/syslinux/load_linux.c index 6a0afd39..3e659c15 100644 --- a/com32/lib/syslinux/load_linux.c +++ b/com32/lib/syslinux/load_linux.c @@ -130,7 +130,7 @@ int bios_boot_linux(void *kernel_buf, size_t kernel_size, char *cmdline) { struct linux_header hdr, *whdr; - size_t real_mode_size, prot_mode_size; + size_t real_mode_size, prot_mode_size, base; addr_t real_mode_base, prot_mode_base; addr_t irf_size; size_t cmdline_size, cmdline_offset; @@ -139,7 +139,6 @@ int bios_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; uint32_t memlimit = 0; uint16_t video_mode = 0; const char *arg; @@ -279,82 +278,24 @@ int bios_boot_linux(void *kernel_buf, size_t kernel_size, /* Place the kernel in memory */ /* First, find a suitable place for the protected-mode code */ + base = prot_mode_base; if (prot_mode_size && - syslinux_memmap_type(amap, prot_mode_base, prot_mode_size) - != SMT_FREE) { - const struct syslinux_memmap *mp; - if (!hdr.relocatable_kernel) { - dprintf("Cannot relocate kernel\n"); - goto bail; - } - - 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; - - if (end - start >= hdr.init_size) { - whdr->code32_start += start - prot_mode_base; - prot_mode_base = start; - ok = true; - break; - } - } - - if (!ok) { - dprintf("Could not find location for protected-mode code\n"); - goto bail; - } + syslinux_memmap_find(amap, &base, hdr.init_size, + hdr.relocatable_kernel, hdr.kernel_alignment, + prot_mode_base, (addr_t)-1, + prot_mode_base, (addr_t)-1)) { + dprintf("Could not find location for protected-mode code\n"); + 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 > 0x90000 || start >= end) - continue; + whdr->code32_start += base - prot_mode_base; - if (end - start >= cmdline_offset + cmdline_size) { - real_mode_base = start; - ok = true; - break; - } - } - - if (!ok) { - dprintf("Could not find location for real-mode code\n"); - goto bail; - } + /* Real mode code */ + if (syslinux_memmap_find(amap, &real_mode_base, + cmdline_offset + cmdline_size, true, 16, + real_mode_base, 0x90000, 0, 640*1024)) { + dprintf("Could not find location for real-mode code\n"); + goto bail; } if (syslinux_add_movelist(&fraglist, real_mode_base, (addr_t) kernel_buf, diff --git a/com32/lib/syslinux/zonelist.c b/com32/lib/syslinux/zonelist.c index d1510d2f..7cd83642 100644 --- a/com32/lib/syslinux/zonelist.c +++ b/com32/lib/syslinux/zonelist.c @@ -281,3 +281,66 @@ struct syslinux_memmap *syslinux_dup_memmap(struct syslinux_memmap *list) return newlist; } + +/* + * Find a memory region, given a set of heuristics and update 'base' if + * successful. + */ +int syslinux_memmap_find(struct syslinux_memmap *mmap, + addr_t *base, size_t size, + bool relocate, size_t align, + addr_t start_min, addr_t start_max, + addr_t end_min, addr_t end_max) +{ + const struct syslinux_memmap *mp; + enum syslinux_memmap_types type; + bool ok; + + if (!size) + return 0; + + type = syslinux_memmap_type(mmap, *base, size); + if (type == SMT_FREE) + return 0; + + if (!relocate) { + dprintf("Cannot relocate\n"); + return -1; + } + + ok = false; + for (mp = mmap; mp && mp->type != SMT_END; mp = mp->next) { + addr_t start, end; + start = mp->start; + end = mp->next->start; + + if (mp->type != SMT_FREE) + continue; + + /* min */ + if (end <= end_min) + continue; /* Only relocate upwards */ + + if (start < start_min) + start = start_min; + + /* max */ + if (end > end_max) + end = end_max; + + start = ALIGN_UP(start, align); + if (start > start_max || start >= end) + continue; + + if (end - start >= size) { + *base = start; + ok = true; + break; + } + } + + if (!ok) + return -1; + + return 0; +} |