aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatt Fleming <matt.fleming@intel.com>2013-07-16 15:15:54 +0100
committerMatt Fleming <matt.fleming@intel.com>2013-07-17 18:29:16 +0100
commit8f470e7bfe75f6401f6c5432988c620b863ad274 (patch)
tree39b264e5f60ca44c906fcd0f3065b2fdc3581d05
parent6252212849d945450310248b656dfb6f13f5de48 (diff)
downloadsyslinux-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.h6
-rw-r--r--com32/lib/syslinux/load_linux.c89
-rw-r--r--com32/lib/syslinux/zonelist.c63
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;
+}