Put virtual kernels (CLI labels) in high memory syslinux-3.62-pre7
authorH. Peter Anvin <hpa@zytor.com>
Sat, 16 Feb 2008 06:51:46 +0000 (22:51 -0800)
committerH. Peter Anvin <hpa@zytor.com>
Sat, 16 Feb 2008 06:54:28 +0000 (22:54 -0800)
Support putting virtual kernels in high memory instead of using a
dedicated segment for it.  This both reduces the low memory footprint
by 64K, and allows for functionally unlimited labels (tested with over
a hundred thousand.)

NEWS
com32.inc
configinit.inc
extlinux.asm
isolinux.asm
ldlinux.asm
parseconfig.inc
pxelinux.asm
rllpack.inc
runkernel.inc
ui.inc

diff --git a/NEWS b/NEWS
index 6810082..8626a1d 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -12,6 +12,9 @@ Changes in 3.62:
          Linux kernel limit.
        * vesamenu: support systems without linear framebuffer support
          (sigh, what is this, 1993?) and 15-bit RGB modes.
+       * Move the label storage (for the command-line interface) to
+         high memory, removing the size limit and freeing up 64K of
+         low memory.
 
 Changes in 3.61:
        * EXTLINUX: fix crash when accessing an empty file.
index 220c9d7..ac51359 100644 (file)
--- a/com32.inc
+++ b/com32.inc
@@ -57,7 +57,6 @@ is_com32_image:
                sub cx,si
                fs rep movsb
 
-               call highmemsize        ; We need the high memory size...
                call comboot_setup_api  ; Set up the COMBOOT-style API
 
                mov edi,pm_entry        ; Load address
@@ -115,9 +114,10 @@ com32_enter_pm:
 ;
 com32_call_start:
                ;
-               ; Point the stack to the end of high memory
+               ; Point the stack to the end of (permitted) high memory
                ;
-               mov esp,[word HighMemSize]
+               mov esp,[word HighMemRsvd]
+               xor sp,sp               ; Align to a 64K boundary
 
                ;
                ; Set up the protmode IDT and the interrupt jump buffers
index c6591b6..a5eaf1b 100644 (file)
                section .text
 
 reset_config:
-               xor eax,eax
+               call highmemsize
 
                ; Initialize the .config section
+               xor eax,eax
                mov si,section..config.start
                mov di,section..config.vstart
                mov cx,section..config.end.start
@@ -50,6 +51,9 @@ mkkeymap:     stosb
                inc al
                loop mkkeymap
 
+               mov eax,[HighMemSize]
+               mov [VKernelEnd],eax
+
                ret
 
                section .data
index 232a58f..8b2eff5 100644 (file)
@@ -56,7 +56,7 @@ SYMLINK_SECTORS       equ 2                   ; Max number of sectors in a symlink
 ; The following structure is used for "virtual kernels"; i.e. LILO-style
 ; option labels.  The options we permit here are `kernel' and `append
 ; Since there is no room in the bottom 64K for all of these, we
-; stick them at vk_seg:0000 and copy them down before we need them.
+; stick them in high memory and copy them down before we need them.
 ;
                struc vkernel
 vk_vname:      resb FILENAME_MAX       ; Virtual name **MUST BE FIRST!**
@@ -76,9 +76,8 @@ vk_end:               equ $                   ; Should be <= vk_size
 ;
 ; 0000h - main code/data segment (and BIOS segment)
 ;
-real_mode_seg  equ 4000h
-cache_seg      equ 3000h               ; 64K area for metadata cache
-vk_seg          equ 2000h              ; Virtual kernels
+real_mode_seg  equ 3000h
+cache_seg      equ 2000h               ; 64K area for metadata cache
 xfer_buf_seg   equ 1000h               ; Bounce buffer for I/O to high mem
 comboot_seg    equ real_mode_seg       ; COMBOOT image loading zone
 
index 81caf76..be8fd0f 100644 (file)
@@ -50,7 +50,7 @@ SECTOR_SIZE   equ (1 << SECTOR_SHIFT)
 ; The following structure is used for "virtual kernels"; i.e. LILO-style
 ; option labels.  The options we permit here are `kernel' and `append
 ; Since there is no room in the bottom 64K for all of these, we
-; stick them at vk_seg:0000 and copy them down before we need them.
+; stick them in high memory and copy them down before we need them.
 ;
                struc vkernel
 vk_vname:      resb FILENAME_MAX       ; Virtual name **MUST BE FIRST!**
@@ -67,8 +67,7 @@ vk_end:               equ $                   ; Should be <= vk_size
 ; Segment assignments in the bottom 640K
 ; 0000h - main code/data segment (and BIOS segment)
 ;
-real_mode_seg  equ 3000h
-vk_seg          equ 2000h              ; Virtual kernels
+real_mode_seg  equ 2000h
 xfer_buf_seg   equ 1000h               ; Bounce buffer for I/O to high mem
 comboot_seg    equ real_mode_seg       ; COMBOOT image loading zone
 
index 0c5c94f..0f06315 100644 (file)
@@ -58,7 +58,7 @@ SECTOR_SIZE   equ (1 << SECTOR_SHIFT)
 ; The following structure is used for "virtual kernels"; i.e. LILO-style
 ; option labels.  The options we permit here are `kernel' and `append
 ; Since there is no room in the bottom 64K for all of these, we
-; stick them at vk_seg:0000 and copy them down before we need them.
+; stick them in high memory and copy them down before we need them.
 ;
                struc vkernel
 vk_vname:      resb FILENAME_MAX       ; Virtual name **MUST BE FIRST!**
@@ -78,9 +78,8 @@ vk_end:               equ $                   ; Should be <= vk_size
 ;
 ; 0000h - main code/data segment (and BIOS segment)
 ;
-real_mode_seg  equ 4000h
-cache_seg      equ 3000h               ; 64K area for metadata cache
-vk_seg          equ 2000h              ; Virtual kernels
+real_mode_seg  equ 3000h
+cache_seg      equ 2000h               ; 64K area for metadata cache
 xfer_buf_seg   equ 1000h               ; Bounce buffer for I/O to high mem
 comboot_seg    equ real_mode_seg       ; COMBOOT image loading zone
 
index 739a884..90c1f3c 100644 (file)
@@ -399,23 +399,12 @@ commit_vk:
                xor ax,ax
                rep stosb
 
-               ; Pack temporarily into trackbuf
+               ; Pack into high memory
                mov si,VKernelBuf
-               mov di,trackbuf
+               mov edi,[VKernelEnd]
                mov cx,vk_size
                call rllpack
-               ; Now DX = number of bytes
-               mov di,[VKernelBytes]
-               mov cx,dx
-               add dx,di
-               jc .overflow                    ; If > 1 segment
-               mov [VKernelBytes],dx
-               mov si,trackbuf
-               push es
-               push word vk_seg
-               pop es
-               rep movsb
-               pop es
+               mov [VKernelEnd],edi
                ret
 .overflow:
                mov si,vk_overflow_msg
@@ -426,6 +415,14 @@ commit_vk:
 vk_overflow_msg        db 'Out of memory parsing config file', CR, LF, 0
 SerialNotice   db 1                    ; Only print this once
 
+               section .bss
+               alignb 4
+VKernelEnd     resd 1                  ; Lowest high memory address used
+
+               ; This symbol should be used by loaders to indicate
+               ; the highest address *they* are allowed to use.
+HighMemRsvd    equ VKernelEnd
+                                       ; by vkernels
                section .config
                align 4, db 0
 KbdTimeout      dd 0                    ; Keyboard timeout (if any)
@@ -440,7 +437,6 @@ AllowImplicit   dw 1                    ; Allow implicit kernels
 AllowOptions   dw 1                    ; User-specified options allowed
 IncludeLevel   dw 1                    ; Nesting level
 SerialPort     dw 0                    ; Serial port base (or 0 for no serial port)
-VKernelBytes   dw 0                    ; Number of bytes used by vkernels
 VKernel                db 0                    ; Have we seen any "label" statements?
 
 %if IS_PXELINUX
index 7237fff..8bb87c2 100644 (file)
@@ -101,7 +101,7 @@ TFTP_EOPTNEG        equ htons(8)            ; Option negotiation failure
 ; The following structure is used for "virtual kernels"; i.e. LILO-style
 ; option labels.  The options we permit here are `kernel' and `append
 ; Since there is no room in the bottom 64K for all of these, we
-; stick them at vk_seg:0000 and copy them down before we need them.
+; stick them in high memory and copy them down before we need them.
 ;
                struc vkernel
 vk_vname:      resb FILENAME_MAX       ; Virtual name **MUST BE FIRST!**
@@ -119,9 +119,8 @@ vk_end:             equ $                   ; Should be <= vk_size
 ; Segment assignments in the bottom 640K
 ; 0000h - main code/data segment (and BIOS segment)
 ;
-real_mode_seg  equ 4000h
-pktbuf_seg     equ 3000h               ; Packet buffers segments
-vk_seg          equ 2000h              ; Virtual kernels
+real_mode_seg  equ 3000h
+pktbuf_seg     equ 2000h               ; Packet buffers segments
 xfer_buf_seg   equ 1000h               ; Bounce buffer for I/O to high mem
 comboot_seg    equ real_mode_seg       ; COMBOOT image loading zone
 
index 0714956..e5d1d5e 100644 (file)
@@ -1,5 +1,4 @@
-; -*- fundamental -*-
-; -----------------------------------------------------------------------
+; -*- fundamental -*- ---------------------------------------------------
 ;
 ;   Copyright 2004-2008 H. Peter Anvin - All Rights Reserved
 ;
 ; 129-255      = (x-126) times subsequent byte
 ; 0            = end of data
 ;
+; These structures are stored *in reverse order* in high memory.
+; High memory pointers point to one byte beyond the end.
+;
 
                section .text
 
 ;
 ; rllpack:
-;      Pack CX bytes from DS:SI into ES:DI
-;      Returns updated SI, DI and CX = number of bytes output
+;      Pack CX bytes from SI into EDI.
+;      Returns updated SI and EDI.
 ;
 rllpack:
-               push ax
-               push bx
+               push word .pmentry
+               call simple_pm_call
+               ret
+
+.pmentry:
                push cx
-               push bp
-               push di
+               push ebx
+               push edx
 .startseq:
                xor ax,ax               ; Zero byte
-               xor bx,bx               ; Run length zero
-               mov bp,di               ; Pointer to header byte
-               stosb                   ; Store header byte (might be zero)
+               xor ebx,ebx             ; Run length zero
+               dec edi
+               mov edx,edi             ; Pointer to header byte
+               mov [edi],al
                jcxz .done_null
 .stdbyte:
                lodsb
-               stosb
+               dec edi
+               mov [edi],al
                dec cx
                cmp ah,al
                je .same
@@ -53,7 +60,7 @@ rllpack:
                xor bx,bx
 .plainbyte:
                inc bx
-               inc byte [es:bp]
+               inc byte [edx]
                jcxz .done
                jns .stdbyte
                jmp .startseq
@@ -61,18 +68,20 @@ rllpack:
                cmp bl,2
                jb .plainbyte
                ; 3 bytes or more in a row, time to convert sequence
-               sub byte [es:bp],bl
+               sub [edx],bl
                jnz .normal
-               dec di                  ; We killed a whole stretch, remove start byte
+               inc edi                 ; We killed a whole stretch,
+                                       ; drop start byte
 .normal:
                inc bx
-               sub di,bx
-               mov bp,di
+               add edi,ebx
                mov al,bl
                add al,126
-               stosb
-               mov al,ah
-               stosb
+               dec edi
+               mov edx,edi
+               mov [edi],al
+               dec edi
+               mov [edi],ah
 .getrun:
                jcxz .done
                cmp bl,255-126
@@ -81,52 +90,57 @@ rllpack:
                cmp al,ah
                jne .nomatch
                inc bx
-               inc byte [es:bp]
+               inc byte [edx]
                dec cx
                jmp .getrun
 .nomatch:
                dec si
                jmp .startseq
 .done:
-               xor al,al
-               stosb
+               dec edi
+               mov [edi],cl            ; CX = 0 here
 .done_null:
-               pop dx
-               sub dx,di
-               neg dx
-               pop bp
+               pop edx
+               pop ebx
                pop cx
-               pop bx
-               pop ax
                ret
 ;
 ; rllunpack:
-;      Unpack bytes from DS:SI into ES:DI
-;      On return SI, DI are updated and CX contains number of bytes output
+;      Unpack bytes from ESI into DI
+;      On return ESI, DI are updated and CX contains number of bytes output.
 ;
 rllunpack:
-               push ax
+               push word .pmentry
+               call simple_pm_call
+               ret
+
+.pmentry:
                push di
                xor cx,cx
 .header:
-               lodsb
+               dec esi
+               mov al,[esi]
                and al,al
                jz .done
                cmp al,129
                jae .isrun
                ; Not a run
                mov cl,al
-               rep movsb
+.copy:
+               dec esi
+               mov al,[esi]
+               stosb
+               loop .copy
                jmp .header
 .isrun:
                sub al,126
                mov cl,al
-               lodsb
+               dec esi
+               mov al,[esi]
                rep stosb
                jmp .header
 .done:
                pop cx
                sub cx,di
                neg cx
-               pop ax
                ret
index 39d8e90..98d826f 100644 (file)
@@ -97,10 +97,14 @@ kernel_sane:        push ax
 ; Save the cluster pointer for later...
 ;
                push si
+
 ;
-; Get the BIOS' idea of what the size of high memory is.
+; Initialize our end of memory pointer
 ;
-               call highmemsize
+               mov eax,[HighMemRsvd]
+               xor ax,ax                       ; Align to a 64K boundary
+               mov [MyHighMemSize],eax
+
 ;
 ; Construct the command line (append options have already been copied)
 ;
@@ -195,7 +199,7 @@ is_mem_cmd:
 %if HIGHMEM_SLOP != 0
                sub ebx,HIGHMEM_SLOP
 %endif
-               mov [cs:HighMemSize],ebx
+               mov [cs:MyHighMemSize],ebx
                jmp short skip_this_opt
 cmdline_end:
                 push cs                         ; Restore standard DS
@@ -256,7 +260,7 @@ read_kernel:
                 mov si,dotdot_msg              ; Print dots
                 call cwritestr
 
-                mov eax,[HighMemSize]
+                mov eax,[MyHighMemSize]
                sub eax,100000h                 ; Load address
                cmp eax,[KernelSize]
                jb no_high_mem          ; Not enough high memory
@@ -592,7 +596,7 @@ loadinitrd:
                mov es,ax
 
                push ecx                        ; Bytes to load
-               mov edx,[HighMemSize]           ; End of memory
+               mov edx,[MyHighMemSize]         ; End of memory
                dec edx
                mov eax,[RamdiskMax]            ; Highest address allowed by kernel
                cmp edx,eax
@@ -670,6 +674,7 @@ boot_image_len  equ $-boot_image
 
                section .bss
                alignb 4
+MyHighMemSize  resd 1                  ; Possibly adjusted highmem size
 RamdiskMax     resd 1                  ; Highest address for ramdisk
 KernelSize     resd 1                  ; Size of kernel in bytes
 KernelSects    resd 1                  ; Size of kernel in sectors
diff --git a/ui.inc b/ui.inc
index 7e5ac11..69ba7dc 100644 (file)
--- a/ui.inc
+++ b/ui.inc
@@ -297,19 +297,14 @@ clin_opt_ok:
 ; Now check if it is a "virtual kernel"
 ;
 vk_check:
-               xor si,si                       ; Beginning of vk_seg
+               mov esi,[HighMemSize]           ; Start from top of memory
 .scan:
-               cmp si,[VKernelBytes]
-               jae .not_vk
-
-               push ds
-               push word vk_seg
-               pop ds
+               cmp esi,[VKernelEnd]
+               jbe .not_vk
 
                mov di,VKernelBuf
                call rllunpack
-               pop ds
-               ; SI updated on return
+               ; ESI updated on return
 
                sub di,cx                       ; Return to beginning of buf
                push si