From c9cddae667ebea9bdeba68db49c0e3230e85f9d4 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Fri, 15 Feb 2008 22:51:46 -0800 Subject: Put virtual kernels (CLI labels) in high memory 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 | 3 ++ com32.inc | 6 ++-- configinit.inc | 6 +++- extlinux.asm | 7 ++--- isolinux.asm | 5 ++-- ldlinux.asm | 7 ++--- parseconfig.inc | 26 ++++++++--------- pxelinux.asm | 7 ++--- rllpack.inc | 86 +++++++++++++++++++++++++++++++++------------------------ runkernel.inc | 15 ++++++---- ui.inc | 13 +++------ 11 files changed, 97 insertions(+), 84 deletions(-) diff --git a/NEWS b/NEWS index 6810082f..8626a1d5 100644 --- 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. diff --git a/com32.inc b/com32.inc index 220c9d7b..ac513593 100644 --- 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 diff --git a/configinit.inc b/configinit.inc index c6591b60..a5eaf1b3 100644 --- a/configinit.inc +++ b/configinit.inc @@ -19,9 +19,10 @@ 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 diff --git a/extlinux.asm b/extlinux.asm index 232a58f3..8b2eff5b 100644 --- a/extlinux.asm +++ b/extlinux.asm @@ -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 diff --git a/isolinux.asm b/isolinux.asm index 81caf766..be8fd0f7 100644 --- a/isolinux.asm +++ b/isolinux.asm @@ -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 diff --git a/ldlinux.asm b/ldlinux.asm index 0c5c94f8..0f063154 100644 --- a/ldlinux.asm +++ b/ldlinux.asm @@ -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 diff --git a/parseconfig.inc b/parseconfig.inc index 739a884b..90c1f3c9 100644 --- a/parseconfig.inc +++ b/parseconfig.inc @@ -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 diff --git a/pxelinux.asm b/pxelinux.asm index 7237fff4..8bb87c26 100644 --- a/pxelinux.asm +++ b/pxelinux.asm @@ -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 diff --git a/rllpack.inc b/rllpack.inc index 0714956a..e5d1d5e5 100644 --- a/rllpack.inc +++ b/rllpack.inc @@ -1,5 +1,4 @@ -; -*- fundamental -*- -; ----------------------------------------------------------------------- +; -*- fundamental -*- --------------------------------------------------- ; ; Copyright 2004-2008 H. Peter Anvin - All Rights Reserved ; @@ -21,30 +20,38 @@ ; 1-128 = x verbatim bytes follow ; 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 diff --git a/runkernel.inc b/runkernel.inc index 39d8e908..98d826f0 100644 --- a/runkernel.inc +++ b/runkernel.inc @@ -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 7e5ac112..69ba7dc6 100644 --- 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 -- cgit v1.2.1