diff options
author | H. Peter Anvin <hpa@zytor.com> | 2007-05-05 19:23:14 -0700 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2007-05-05 19:23:14 -0700 |
commit | 5d534825f533b09cf6df4dcb7230570139a7a17a (patch) | |
tree | e12bcbbcecc8bf7e347d693d353bdaabb8c6ed09 | |
parent | 8657b2a17cbd8456f6fca36f370cdf4fbfd012ef (diff) | |
download | syslinux-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.c | 29 | ||||
-rw-r--r-- | kernel.inc | 21 | ||||
-rw-r--r-- | runkernel.inc | 48 |
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, ®s); @@ -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 |