aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--NEWS3
-rw-r--r--ldlinux.asm53
-rw-r--r--pxelinux.asm53
3 files changed, 107 insertions, 2 deletions
diff --git a/NEWS b/NEWS
index 3ee54aa6..a14a2bf0 100644
--- a/NEWS
+++ b/NEWS
@@ -8,6 +8,9 @@ Changes in 1.51:
* Yet another attempt at A20 coding. Now support BIOS call
15:2401 as well, and handle machines which always have A20
on separately.
+ * Support memory detection using INT 15h, AX=0E820h. BIOS
+ manufacturers have apparently gotten sloppy about keeping
+ INT 15h, AX=0E801h working properly.
Changes in 1.50:
* Yet another A20-code update. It seems some "legacy-free"
diff --git a/ldlinux.asm b/ldlinux.asm
index 19310741..575a8fb6 100644
--- a/ldlinux.asm
+++ b/ldlinux.asm
@@ -319,6 +319,7 @@ NumBuf resb 16 ; Buffer to load number
NumBufEnd equ NumBuf+15 ; Pointer to last byte in NumBuf
alignb 4
PartInfo resb 16 ; Partition table entry
+E820Buf resd 5 ; INT 15:E820 data buffer
InitRDat resd 1 ; Load address (linear) for initrd
HiLoadAddr resd 1 ; Address pointer for high load loop
HighMemSize resd 1 ; End of memory pointer (bytes)
@@ -1816,9 +1817,56 @@ kernel_sane: push ax
cmp word [es:bs_bootsign],0AA55h
jne near kernel_corrupt ; Boot sec signature missing
;
-; Get the BIOS' idea of what the size of high memory is
+; Get the BIOS' idea of what the size of high memory is.
;
push si ; Save our cluster pointer!
+;
+; First, try INT 15:E820 (get BIOS memory map)
+;
+get_e820:
+ push es
+ push ds
+ pop es
+ xor ebx,ebx
+.int_loop: mov eax,0000e820h
+ mov edx,'SMAP'
+ mov ecx,20
+ mov di,E820Buf
+ int 15h
+ jc no_e820
+ cmp eax,'SMAP'
+ jne no_e820
+ and ebx,ebx ; Did we not find anything?
+ jz no_e820
+;
+; Look for a memory block starting at <= 1 MB and continuing upward
+;
+ cmp dword [E820Buf+4], byte 0
+ ja .int_loop ; Start >= 4 GB
+ mov edx,[E820Buf]
+ cmp edx, (1 << 20)
+ ja .int_loop
+ mov eax, 0FFFFFFFFh
+ cmp dword [E820Buf+12], byte 0
+ ja .huge ; Size >= 4 GB
+ mov eax, [E820Buf+8]
+.huge: mov ecx, (1 << 20)
+ sub ecx, edx
+ sub eax, ecx ; Adjust size to start at 1 MB
+ jb .int_loop ; Completely below 1 MB
+
+ ; 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!!!!
+
+ ; We're good!
+ pop es
+ jmp short got_highmem
+
+;
+; INT 15:E820 failed. Try INT 15:E801.
+;
+no_e820: pop es
mov ax,0e801h ; Query high memory (semi-recent)
int 15h
@@ -1832,6 +1880,9 @@ kernel_sane: push ax
add eax,(16 << 20) ; Add first 16M
jmp short got_highmem
+;
+; INT 15:E801 failed. Try INT 15:88.
+;
no_e801:
mov ah,88h ; Query high memory (oldest)
int 15h
diff --git a/pxelinux.asm b/pxelinux.asm
index 56e5b08a..812bf434 100644
--- a/pxelinux.asm
+++ b/pxelinux.asm
@@ -324,6 +324,7 @@ InitRDCName resb FILENAME_MAX ; Unmangled initrd name
MNameBuf resb FILENAME_MAX
InitRD resb FILENAME_MAX
PartInfo resb 16 ; Partition table entry
+E820Buf resd 5 ; INT 15:E820 data buffer
InitRDat resd 1 ; Load address (linear) for initrd
HiLoadAddr resd 1 ; Address pointer for high load loop
HighMemSize resd 1 ; End of memory pointer (bytes)
@@ -1436,9 +1437,56 @@ kernel_sane: push ax
cmp word [es:bs_bootsign],0AA55h
jne near kernel_corrupt ; Boot sec signature missing
;
-; Get the BIOS' idea of what the size of high memory is
+; Get the BIOS' idea of what the size of high memory is.
;
push si ; Save our cluster pointer!
+;
+; First, try INT 15:E820 (get BIOS memory map)
+;
+get_e820:
+ push es
+ push ds
+ pop es
+ xor ebx,ebx
+.int_loop: mov eax,0000e820h
+ mov edx,'SMAP'
+ mov ecx,20
+ mov di,E820Buf
+ int 15h
+ jc no_e820
+ cmp eax,'SMAP'
+ jne no_e820
+ and ebx,ebx ; Did we not find anything?
+ jz no_e820
+;
+; Look for a memory block starting at <= 1 MB and continuing upward
+;
+ cmp dword [E820Buf+4], byte 0
+ ja .int_loop ; Start >= 4 GB
+ mov edx,[E820Buf]
+ cmp edx, (1 << 20)
+ ja .int_loop
+ mov eax, 0FFFFFFFFh
+ cmp dword [E820Buf+12], byte 0
+ ja .huge ; Size >= 4 GB
+ mov eax, [E820Buf+8]
+.huge: mov ecx, (1 << 20)
+ sub ecx, edx
+ sub eax, ecx ; Adjust size to start at 1 MB
+ jb .int_loop ; Completely below 1 MB
+
+ ; 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!!!!
+
+ ; We're good!
+ pop es
+ jmp short got_highmem
+
+;
+; INT 15:E820 failed. Try INT 15:E801.
+;
+no_e820: pop es
mov ax,0e801h ; Query high memory (semi-recent)
int 15h
@@ -1452,6 +1500,9 @@ kernel_sane: push ax
add eax,(16 << 20) ; Add first 16M
jmp short got_highmem
+;
+; INT 15:E801 failed. Try INT 15:88.
+;
no_e801:
mov ah,88h ; Query high memory (oldest)
int 15h