From 8340f5e03ec7d5abd68f55a76e7e8c9bf8a29ecc Mon Sep 17 00:00:00 2001 From: hpa Date: Fri, 23 Apr 2004 04:14:15 +0000 Subject: [PATCH] Better E820 memory parser --- NEWS | 2 ++ highmem.inc | 41 +++++++++++++++++++++++++++++++++++------ isolinux.asm | 2 ++ ldlinux.asm | 2 ++ pxelinux.asm | 2 ++ 5 files changed, 43 insertions(+), 6 deletions(-) diff --git a/NEWS b/NEWS index 9a80c88..3f1682b 100644 --- a/NEWS +++ b/NEWS @@ -14,6 +14,8 @@ Changes in 2.09: SYSLINUX from COMBOOT!!!! * COMBOOT: Fix "get key without echo" API function. * SYSLINUX: Fix bug that affected the API open function. + * ALL: Improve the E820 memory parser, to work around some + buggy BIOSes. Changes in 2.08: * Add new configuration command "ontimeout" to allow timeout diff --git a/highmem.inc b/highmem.inc index e3a830b..b10cc8b 100644 --- a/highmem.inc +++ b/highmem.inc @@ -1,7 +1,7 @@ ;; $Id$ ;; ----------------------------------------------------------------------- ;; -;; Copyright 1994-2002 H. Peter Anvin - All Rights Reserved +;; Copyright 1994-2004 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 @@ -31,17 +31,24 @@ highmemsize: ; get_e820: xor ebx,ebx ; Start with first record + mov dword [E820Max],-(1 << 20) ; Max amount of high memory + mov dword [E820Mem],ebx ; Detected amount of high memory mov es,bx ; Need ES = DS = 0 for now jmp short .do_e820 ; Skip "at end" check first time! .int_loop: and ebx,ebx ; If we're back at beginning... - jz no_e820 ; ... bail; nothing found + jz .e820_done ; ... we're done .do_e820: mov eax,0000E820h mov edx,534D4150h ; "SMAP" backwards xor ecx,ecx mov cl,20 ; ECX <- 20 mov di,E820Buf int 15h - jc no_e820 + jnc .no_carry + ; If carry, ebx == 0 means error, ebx != 0 means we're done + and ebx,ebx + jnz .e820_done + jmp no_e820 +.no_carry: cmp eax,534D4150h jne no_e820 ; @@ -51,7 +58,19 @@ get_e820: ja .int_loop ; Start >= 4 GB? mov edx, (1 << 20) sub edx, [E820Buf] - jb .int_loop ; Start >= 1 MB? + jnb .ram_range ; Start >= 1 MB? + ; If we get here, it starts > 1 MB but < 4 GB; if this is a + ; *non*-memory range, remember this as unusable; some BIOSes + ; get the length of primary RAM wrong! + cmp dword [E820Buf+16], byte 1 + je .int_loop ; If it's memory, don't worry about it + neg edx ; This means what for memory limit? + cmp edx,[E820Max] ; Better or worse + jnb .int_loop + mov [E820Max],edx + jmp .int_loop + +.ram_range: stc sbb eax,eax ; eax <- 0xFFFFFFFF cmp dword [E820Buf+12], byte 0 @@ -62,10 +81,20 @@ get_e820: ; Now EAX contains the size of memory 1 MB...up cmp dword [E820Buf+16], byte 1 - jne near err_nohighmem ; High memory isn't usable memory!!!! + jne .int_loop ; High memory isn't usable memory!!!! ; We're good! - jmp short got_highmem_add1mb ; Still need to add low 1 MB + mov [E820Mem],eax + jmp .int_loop ; Still need to add low 1 MB + +.e820_done: + mov eax,[E820Mem] + and eax,eax + jz no_e820 ; Nothing found by E820? + cmp eax,[E820Max] ; Make sure we're not limited + jna got_highmem_add1mb + mov eax,[E820Max] + jmp got_highmem_add1mb ; ; INT 15:E820 failed. Try INT 15:E801. diff --git a/isolinux.asm b/isolinux.asm index 028c35a..33d2231 100644 --- a/isolinux.asm +++ b/isolinux.asm @@ -152,6 +152,8 @@ MNameBuf resb FILENAME_MAX InitRD resb FILENAME_MAX PartInfo resb 16 ; Partition table entry E820Buf resd 5 ; INT 15:E820 data buffer +E820Mem resd 1 ; Memory detected by E820 +E820Max resd 1 ; Is E820 memory capped? HiLoadAddr resd 1 ; Address pointer for high load loop HighMemSize resd 1 ; End of memory pointer (bytes) RamdiskMax resd 1 ; Highest address for a ramdisk diff --git a/ldlinux.asm b/ldlinux.asm index 138ad6a..675b3e1 100644 --- a/ldlinux.asm +++ b/ldlinux.asm @@ -148,6 +148,8 @@ EndofDirSec resw 1 ; = trackbuf+bsBytesPerSec-31 alignb 4 E820Buf resd 5 ; INT 15:E820 data buffer +E820Mem resd 1 ; Memory detected by E820 +E820Max resd 1 ; Is E820 memory capped? HiLoadAddr resd 1 ; Address pointer for high load loop HighMemSize resd 1 ; End of memory pointer (bytes) RamdiskMax resd 1 ; Highest address for a ramdisk diff --git a/pxelinux.asm b/pxelinux.asm index edc081d..ffbeed1 100644 --- a/pxelinux.asm +++ b/pxelinux.asm @@ -238,6 +238,8 @@ MAC resb 16 ; Actual MAC address MACStr resb 3*17 ; MAC address as a string PartInfo resb 16 ; Partition table entry E820Buf resd 5 ; INT 15:E820 data buffer +E820Mem resd 1 ; Memory detected by E820 +E820Max resd 1 ; Is E820 memory capped? HiLoadAddr resd 1 ; Address pointer for high load loop HighMemSize resd 1 ; End of memory pointer (bytes) RamdiskMax resd 1 ; Highest address for a ramdisk -- 2.7.4