Better E820 memory parser
authorhpa <hpa>
Fri, 23 Apr 2004 04:14:15 +0000 (04:14 +0000)
committerhpa <hpa>
Fri, 23 Apr 2004 04:14:15 +0000 (04:14 +0000)
NEWS
highmem.inc
isolinux.asm
ldlinux.asm
pxelinux.asm

diff --git a/NEWS b/NEWS
index 9a80c88..3f1682b 100644 (file)
--- 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
index e3a830b..b10cc8b 100644 (file)
@@ -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.
index 028c35a..33d2231 100644 (file)
@@ -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
index 138ad6a..675b3e1 100644 (file)
@@ -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
index edc081d..ffbeed1 100644 (file)
@@ -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