aboutsummaryrefslogtreecommitdiffstats
path: root/core/highmem.inc
diff options
context:
space:
mode:
Diffstat (limited to 'core/highmem.inc')
-rw-r--r--core/highmem.inc148
1 files changed, 148 insertions, 0 deletions
diff --git a/core/highmem.inc b/core/highmem.inc
new file mode 100644
index 00000000..1cd46dd9
--- /dev/null
+++ b/core/highmem.inc
@@ -0,0 +1,148 @@
+;; -----------------------------------------------------------------------
+;;
+;; Copyright 1994-2008 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
+;; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+;; Boston MA 02111-1307, USA; either version 2 of the License, or
+;; (at your option) any later version; incorporated herein by reference.
+;;
+;; -----------------------------------------------------------------------
+
+;;
+;; highmem.inc
+;;
+;; Probe for the size of high memory. This can be overridden by a
+;; mem= command on the command line while booting a new kernel.
+;;
+
+ section .text
+
+;
+; This is set up as a subroutine; it will set up the global variable
+; HighMemSize. All registers are preserved.
+;
+highmemsize:
+ push es
+ pushad
+
+ push cs
+ pop es
+
+;
+; First, try INT 15:E820 (get BIOS memory map)
+;
+; Note: we may have to scan this multiple times, because some (daft) BIOSes
+; report main memory as multiple contiguous ranges...
+;
+get_e820:
+ mov dword [E820Max],-(1 << 20) ; Max amount of high memory
+ mov dword [E820Mem],(1 << 20) ; End of detected high memory
+.start_over:
+ xor ebx,ebx ; Start with first record
+ jmp short .do_e820 ; Skip "at end" check first time!
+.int_loop: and ebx,ebx ; If we're back at beginning...
+ 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
+ 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
+;
+; 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 eax, [E820Buf]
+ cmp dword [E820Buf+16],1
+ je .is_ram ; Is it memory?
+ ;
+ ; Non-memory range. Remember this as a limit; some BIOSes get the length
+ ; of primary RAM incorrect!
+ ;
+ cmp eax, (1 << 20)
+ jb .int_loop ; Starts in lowmem region
+ cmp eax,[E820Max]
+ jae .int_loop ; Already above limit
+ mov [E820Max],eax ; Set limit
+ jmp .int_loop
+
+.is_ram:
+ cmp eax,[E820Mem]
+ ja .int_loop ; Not contiguous with our starting point
+ add eax,[E820Buf+8]
+ jc .overflow
+ cmp dword [E820Buf+12],0
+ je .nooverflow
+.overflow:
+ or eax,-1
+.nooverflow:
+ cmp eax,[E820Mem]
+ jbe .int_loop ; All is below our baseline
+ mov [E820Mem],eax
+ jmp .start_over ; Start over in case we find an adjacent range
+
+.e820_done:
+ mov eax,[E820Mem]
+ cmp eax,[E820Max]
+ jna .not_limited
+ mov eax,[E820Max]
+.not_limited:
+ cmp eax,(1 << 20)
+ ja got_highmem ; Did we actually find memory?
+ ; otherwise fall through
+
+;
+; INT 15:E820 failed. Try INT 15:E801.
+;
+no_e820:
+ mov ax,0e801h ; Query high memory (semi-recent)
+ int 15h
+ jc no_e801
+ cmp ax,3c00h
+ ja no_e801 ; > 3C00h something's wrong with this call
+ jb e801_hole ; If memory hole we can only use low part
+
+ mov ax,bx
+ shl eax,16 ; 64K chunks
+ 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
+ cmp ax,14*1024 ; Don't trust memory >15M
+ jna e801_hole
+ mov ax,14*1024
+e801_hole:
+ and eax,0ffffh
+ shl eax,10 ; Convert from kilobytes
+ add eax,(1 << 20) ; First megabyte
+got_highmem:
+%if HIGHMEM_SLOP != 0
+ sub eax,HIGHMEM_SLOP
+%endif
+ mov [HighMemSize],eax
+ popad
+ pop es
+ ret ; Done!
+
+ section .bss
+ alignb 4
+E820Buf resd 5 ; INT 15:E820 data buffer
+E820Mem resd 1 ; Memory detected by E820
+E820Max resd 1 ; Is E820 memory capped?
+HighMemSize resd 1 ; End of memory pointer (bytes)