summaryrefslogtreecommitdiff
path: root/com32/lib/syslinux/load_linux.c
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2007-05-05 19:23:14 -0700
committerH. Peter Anvin <hpa@zytor.com>2007-05-05 19:23:14 -0700
commit5d534825f533b09cf6df4dcb7230570139a7a17a (patch)
treee12bcbbcecc8bf7e347d693d353bdaabb8c6ed09 /com32/lib/syslinux/load_linux.c
parent8657b2a17cbd8456f6fca36f370cdf4fbfd012ef (diff)
downloadsyslinux-5d534825f533b09cf6df4dcb7230570139a7a17a.tar.gz
Make more space for the heap when doing so is possible
If we have a modern kernel which is loaded high, we can allow a lot more space for the real-mode heap.
Diffstat (limited to 'com32/lib/syslinux/load_linux.c')
-rw-r--r--com32/lib/syslinux/load_linux.c29
1 files changed, 16 insertions, 13 deletions
diff --git a/com32/lib/syslinux/load_linux.c b/com32/lib/syslinux/load_linux.c
index b8d5a732..d2ad2644 100644
--- a/com32/lib/syslinux/load_linux.c
+++ b/com32/lib/syslinux/load_linux.c
@@ -81,9 +81,6 @@ struct linux_header {
#define LOAD_HIGH 0x01
#define CAN_USE_HEAP 0x80
-/* Offset for the command line versus the real mode code */
-#define CMDLINE_OFFSET 0x9000
-
/* Get the combined size of the initramfs */
static addr_t initramfs_size(struct initramfs *initramfs)
{
@@ -147,7 +144,7 @@ int syslinux_boot_linux(void *kernel_buf, size_t kernel_size,
size_t real_mode_size, prot_mode_size;
addr_t real_mode_base, prot_mode_base;
addr_t irf_size;
- size_t cmdline_size;
+ size_t cmdline_size, cmdline_offset;
struct syslinux_rm_regs regs;
struct syslinux_movelist *fraglist = NULL;
struct syslinux_memmap *mmap = NULL;
@@ -159,8 +156,9 @@ int syslinux_boot_linux(void *kernel_buf, size_t kernel_size,
goto bail;
/* Copy the header into private storage */
+ /* Use whdr to modify the actual kernel header */
memcpy(&hdr, kernel_buf, sizeof hdr);
- whdr = (struct linux_header *)kernel_buf; /* Writable header */
+ whdr = (struct linux_header *)kernel_buf;
if (hdr.boot_flag != BOOT_MAGIC)
goto bail;
@@ -189,6 +187,11 @@ int syslinux_boot_linux(void *kernel_buf, size_t kernel_size,
cmdline[cmdline_size-1] = '\0';
}
+ if (hdr.version < 0x0202 || !(hdr.loadflags & 0x01))
+ cmdline_offset = (0x9ff0 - cmdline_size) & ~15;
+ else
+ cmdline_offset = (0xfff0 - cmdline_size) & ~15;
+
real_mode_size = (hdr.setup_sects+1) << 9;
real_mode_base = (hdr.loadflags & LOAD_HIGH) ? 0x10000 : 0x90000;
prot_mode_base = (hdr.loadflags & LOAD_HIGH) ? 0x100000 : 0x10000;
@@ -203,16 +206,16 @@ int syslinux_boot_linux(void *kernel_buf, size_t kernel_size,
if (hdr.version >= 0x0200) {
whdr->type_of_loader = 0x30; /* SYSLINUX unknown module */
if (hdr.version >= 0x0201) {
- whdr->heap_end_ptr = CMDLINE_OFFSET - 0x0200;
+ whdr->heap_end_ptr = cmdline_offset - 0x0200;
whdr->loadflags |= CAN_USE_HEAP;
}
if (hdr.version >= 0x0202) {
- whdr->cmd_line_ptr = real_mode_base + CMDLINE_OFFSET;
+ whdr->cmd_line_ptr = real_mode_base+cmdline_offset;
} else {
whdr->old_cmd_line_magic = OLD_CMDLINE_MAGIC;
- whdr->old_cmd_line_offset = CMDLINE_OFFSET;
+ whdr->old_cmd_line_offset = cmdline_offset;
/* Be paranoid and round up to a multiple of 16 */
- whdr->setup_move_size = (CMDLINE_OFFSET+cmdline_size+15) & ~15;
+ whdr->setup_move_size = (cmdline_offset+cmdline_size+15) & ~15;
}
}
@@ -236,17 +239,17 @@ int syslinux_boot_linux(void *kernel_buf, size_t kernel_size,
if (syslinux_add_movelist(&fraglist, real_mode_base, (addr_t)kernel_buf,
real_mode_size))
goto bail;
- if (syslinux_add_memmap(&amap, real_mode_base, CMDLINE_OFFSET+cmdline_size,
+ if (syslinux_add_memmap(&amap, real_mode_base, cmdline_offset+cmdline_size,
SMT_ALLOC))
goto bail;
/* Zero region between real mode code and cmdline */
if (syslinux_add_memmap(&mmap, real_mode_base+real_mode_size,
- CMDLINE_OFFSET-real_mode_size, SMT_ZERO))
+ cmdline_offset-real_mode_size, SMT_ZERO))
goto bail;
/* Command line */
- if (syslinux_add_movelist(&fraglist, real_mode_base+CMDLINE_OFFSET,
+ if (syslinux_add_movelist(&fraglist, real_mode_base+cmdline_offset,
(addr_t)cmdline, cmdline_size))
goto bail;
@@ -296,7 +299,7 @@ int syslinux_boot_linux(void *kernel_buf, size_t kernel_size,
regs.es = regs.ds = regs.ss = regs.fs = regs.gs = real_mode_base >> 4;
regs.cs = (real_mode_base >> 4)+0x20;
/* regs.ip = 0; */
- regs.esp.w[0] = CMDLINE_OFFSET;
+ regs.esp.w[0] = cmdline_offset;
syslinux_shuffle_boot_rm(fraglist, mmap, 0, &regs);