blob: 1cd46dd97a3e59bcb1b7c4d5c769f683cdc3c5d1 [file] [log] [blame]
;; -----------------------------------------------------------------------
;;
;; 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)