summaryrefslogtreecommitdiff
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
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.
-rw-r--r--com32/lib/syslinux/load_linux.c29
-rw-r--r--kernel.inc21
-rw-r--r--runkernel.inc48
3 files changed, 63 insertions, 35 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);
diff --git a/kernel.inc b/kernel.inc
index e4ff0219..d72ce2f3 100644
--- a/kernel.inc
+++ b/kernel.inc
@@ -1,6 +1,6 @@
;; -----------------------------------------------------------------------
;;
-;; Copyright 1994-2002 H. Peter Anvin - All Rights Reserved
+;; Copyright 1994-2007 H. Peter Anvin - All Rights Reserved
;;
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
@@ -56,19 +56,26 @@ su_heapend resw 1 ; 0224
su_pad1 resw 1 ; 0226
su_cmd_line_ptr resd 1 ; 0228
su_ramdisk_max resd 1 ; 022C
- resb (9000h-12)-($-$$) ; Were bootsect.S puts it...
-linux_stack equ $ ; 8FF4
-linux_fdctab equ $
- resb 9000h-($-$$)
-cmd_line_here equ $ ; 9000 Should be out of the way
+ resb (0e000h-12)-($-$$) ; Were bootsect.S puts it...
+linux_stack equ $ ; BFF4
+linux_fdctab resb 12
+cmd_line_here equ $ ; C000 Should be out of the way
endstruc
;
-; Kernel command line signature
+; Old kernel command line signature
;
CMD_MAGIC equ 0A33Fh ; Command line magic
;
+; If we're loading the command line old-style, we need a smaller
+; heap.
+;
+old_cmd_line_here equ 9000h
+old_linux_fdctab equ old_cmd_line_here-12
+old_linux_stack equ old_linux_fdctab
+
+;
; Magic number of su_header field
;
HEADER_ID equ 'HdrS' ; HdrS (in littleendian hex)
diff --git a/runkernel.inc b/runkernel.inc
index aabbd86b..22e8e69c 100644
--- a/runkernel.inc
+++ b/runkernel.inc
@@ -1,6 +1,6 @@
;; -----------------------------------------------------------------------
;;
-;; Copyright 1994-2006 H. Peter Anvin - All Rights Reserved
+;; Copyright 1994-2007 H. Peter Anvin - All Rights Reserved
;;
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
@@ -205,16 +205,18 @@ cmdline_end:
;
; Now check if we have a large kernel, which needs to be loaded high
;
+prepare_header:
mov dword [RamdiskMax], HIGHMEM_MAX ; Default initrd limit
cmp dword [es:su_header],HEADER_ID ; New setup code ID
jne old_kernel ; Old kernel, load low
- cmp word [es:su_version],0200h ; Setup code version 2.0
- jb old_kernel ; Old kernel, load low
- cmp word [es:su_version],0201h ; Version 2.01+?
+ mov ax,[es:su_version]
+ cmp ax,0200h ; Setup code version 2.0
+ jb old_kernel ; Old kernel, load low
+ cmp ax,0201h ; Version 2.01+?
jb new_kernel ; If 2.00, skip this step
mov word [es:su_heapend],linux_stack ; Set up the heap
or byte [es:su_loadflags],80h ; Let the kernel know we care
- cmp word [es:su_version],0203h ; Version 2.03+?
+ cmp ax,0203h ; Version 2.03+?
jb new_kernel ; Not 2.03+
mov eax,[es:su_ramdisk_max]
mov [RamdiskMax],eax ; Set the ramdisk limit
@@ -320,7 +322,7 @@ nk_noinitrd:
mov fs,ax
;
-; Copy command line. Unfortunately, the kernel boot protocol requires
+; Copy command line. Unfortunately, the old kernel boot protocol requires
; the command line to exist in the 9xxxxh range even if the rest of the
; setup doesn't.
;
@@ -332,26 +334,38 @@ nk_noinitrd:
; New cmdline protocol
; Store 32-bit (flat) pointer to command line
mov dword [fs:su_cmd_line_ptr],(real_mode_seg << 4) + cmd_line_here
- jmp short in_proper_place
+ jmp in_proper_place
need_high_cmdline:
;
-; Copy command line up to 90000h
+; Copy command line to 90000h (old style) -- this happens either if
+; we have a zImage kernel or the protocol is less than 2.02.
;
mov ax,9000h ; Note AL <- 0
mov es,ax
mov si,cmd_line_here
- mov di,si
+ mov di,old_cmd_line_here
mov [fs:kern_cmd_magic],word CMD_MAGIC ; Store magic
mov [fs:kern_cmd_offset],di ; Store pointer
+ mov word [HeapEnd],old_linux_stack
+ mov ax,255 ; Max cmdline limit
+ cmp word [fs:su_version],0201h
+ jb .adjusted
+ ; Protocol 2.01+
+ mov word [fs:su_heapend],old_linux_stack
+ jbe .adjusted
+ ; Protocol 2.02+
+ mov dword [fs:su_cmd_line_ptr],0x90000+old_cmd_line_here
+ mov ax,4095 ; 2.02+ allow a higher limit
+.adjusted:
mov cx,[CmdLineLen]
- cmp cx,255
+ cmp cx,ax
jna .len_ok
- mov cx,255 ; Protocol < 0x202 has 255 as hard limit
+ mov cx,ax ; Truncate the command line
.len_ok:
fs rep movsb
- stosb ; Final null, note AL == 0 already
+ stosb ; Final null, note AL=0 already
push fs
pop es
@@ -419,8 +433,8 @@ root_not_floppy:
;
%if IS_SYSLINUX || IS_MDSLINUX
lgs si,[cs:fdctab]
- mov di,linux_fdctab
- mov cx,6 ; 12 bytes
+ mov di,[cs:HeapEnd]
+ mov cx,6
gs rep movsw
mov [cs:fdctab],word linux_fdctab ; Save new floppy tab pos
mov [cs:fdctab+2],es
@@ -445,13 +459,15 @@ kill_motor:
; Set up segment registers and the Linux real-mode stack
; Note: es == the real mode segment
;
+
cli
mov bx,es
mov ds,bx
mov fs,bx
mov gs,bx
mov ss,bx
- mov sp,linux_stack
+ mov sp,[cs:HeapEnd]
+
;
; We're done... now RUN THAT KERNEL!!!!
; Setup segment == real mode segment + 020h; we need to jump to offset
@@ -622,6 +638,8 @@ no_high_mem: ; Error routine
ret
section .data
+ alignb 2
+HeapEnd dw linux_stack ; Default end of heap
boot_image db 'BOOT_IMAGE='
boot_image_len equ $-boot_image