|
;; $Id: highmem.inc,v 1.1 2007-09-01 22:44:04 niro Exp $ |
|
1 |
;; ----------------------------------------------------------------------- |
;; ----------------------------------------------------------------------- |
2 |
;; |
;; |
3 |
;; Copyright 1994-2004 H. Peter Anvin - All Rights Reserved |
;; Copyright 1994-2008 H. Peter Anvin - All Rights Reserved |
4 |
;; |
;; |
5 |
;; This program is free software; you can redistribute it and/or modify |
;; This program is free software; you can redistribute it and/or modify |
6 |
;; it under the terms of the GNU General Public License as published by |
;; it under the terms of the GNU General Public License as published by |
12 |
|
|
13 |
;; |
;; |
14 |
;; highmem.inc |
;; highmem.inc |
15 |
;; |
;; |
16 |
;; Probe for the size of high memory. This can be overridden by a |
;; Probe for the size of high memory. This can be overridden by a |
17 |
;; mem= command on the command line while booting a new kernel. |
;; mem= command on the command line while booting a new kernel. |
18 |
;; |
;; |
21 |
|
|
22 |
; |
; |
23 |
; This is set up as a subroutine; it will set up the global variable |
; This is set up as a subroutine; it will set up the global variable |
24 |
; HighMemSize. All registers are preserved. Assumes DS == CS. |
; HighMemSize. All registers are preserved. |
25 |
; |
; |
26 |
highmemsize: |
highmemsize: |
27 |
push es |
push es |
28 |
|
pushfd |
29 |
pushad |
pushad |
30 |
|
|
31 |
|
push cs |
32 |
|
pop es |
33 |
|
|
34 |
; |
; |
35 |
; First, try INT 15:E820 (get BIOS memory map) |
; First, try INT 15:E820 (get BIOS memory map) |
36 |
; |
; |
37 |
|
; Note: we may have to scan this multiple times, because some (daft) BIOSes |
38 |
|
; report main memory as multiple contiguous ranges... |
39 |
|
; |
40 |
get_e820: |
get_e820: |
|
xor ebx,ebx ; Start with first record |
|
41 |
mov dword [E820Max],-(1 << 20) ; Max amount of high memory |
mov dword [E820Max],-(1 << 20) ; Max amount of high memory |
42 |
mov dword [E820Mem],ebx ; Detected amount of high memory |
mov dword [E820Mem],(1 << 20) ; End of detected high memory |
43 |
mov es,bx ; Need ES = DS = 0 for now |
.start_over: |
44 |
|
mov di,E820Buf |
45 |
|
xor ax,ax |
46 |
|
mov cx,10 |
47 |
|
rep stosw ; Clear buffer |
48 |
|
xor ebx,ebx ; Start with first record |
49 |
jmp short .do_e820 ; Skip "at end" check first time! |
jmp short .do_e820 ; Skip "at end" check first time! |
50 |
.int_loop: and ebx,ebx ; If we're back at beginning... |
.int_loop: and ebx,ebx ; If we're back at beginning... |
51 |
jz .e820_done ; ... we're done |
jz .e820_done ; ... we're done |
52 |
.do_e820: mov eax,0000E820h |
.do_e820: mov eax,0000E820h |
53 |
mov edx,534D4150h ; "SMAP" backwards |
mov edx,534D4150h ; "SMAP" backwards |
54 |
xor ecx,ecx |
xor ecx,ecx |
55 |
mov cl,20 ; ECX <- 20 |
mov cl,20 ; ECX <- 20 (size of buffer) |
56 |
mov di,E820Buf |
mov di,E820Buf |
57 |
int 15h |
int 15h |
58 |
jnc .no_carry |
jnc .no_carry |
63 |
.no_carry: |
.no_carry: |
64 |
cmp eax,534D4150h |
cmp eax,534D4150h |
65 |
jne no_e820 |
jne no_e820 |
66 |
|
cmp cx,20 |
67 |
|
jb no_e820 |
68 |
|
|
69 |
; |
; |
70 |
; Look for a memory block starting at <= 1 MB and continuing upward |
; Look for a memory block starting at <= 1 MB and continuing upward |
71 |
; |
; |
72 |
cmp dword [E820Buf+4], byte 0 |
cmp dword [E820Buf+4], byte 0 |
73 |
ja .int_loop ; Start >= 4 GB? |
ja .int_loop ; Start >= 4 GB? |
74 |
mov edx, (1 << 20) |
mov eax, [E820Buf] |
75 |
sub edx, [E820Buf] |
cmp dword [E820Buf+16],1 |
76 |
jnb .ram_range ; Start >= 1 MB? |
je .is_ram ; Is it memory? |
77 |
; If we get here, it starts > 1 MB but < 4 GB; if this is a |
; |
78 |
; *non*-memory range, remember this as unusable; some BIOSes |
; Non-memory range. Remember this as a limit; some BIOSes get the length |
79 |
; get the length of primary RAM wrong! |
; of primary RAM incorrect! |
80 |
cmp dword [E820Buf+16], byte 1 |
; |
81 |
je .int_loop ; If it's memory, don't worry about it |
.not_ram: |
82 |
neg edx ; This means what for memory limit? |
cmp eax, (1 << 20) |
83 |
cmp edx,[E820Max] ; Better or worse |
jb .int_loop ; Starts in lowmem region |
84 |
jnb .int_loop |
cmp eax,[E820Max] |
85 |
mov [E820Max],edx |
jae .int_loop ; Already above limit |
86 |
|
mov [E820Max],eax ; Set limit |
87 |
jmp .int_loop |
jmp .int_loop |
|
|
|
|
.ram_range: |
|
|
stc |
|
|
sbb eax,eax ; eax <- 0xFFFFFFFF |
|
|
cmp dword [E820Buf+12], byte 0 |
|
|
ja .huge ; Size >= 4 GB |
|
|
mov eax, [E820Buf+8] |
|
|
.huge: sub eax, edx ; Adjust size to start at 1 MB |
|
|
jbe .int_loop ; Completely below 1 MB? |
|
|
|
|
|
; Now EAX contains the size of memory 1 MB...up |
|
|
cmp dword [E820Buf+16], byte 1 |
|
|
jne .int_loop ; High memory isn't usable memory!!!! |
|
88 |
|
|
89 |
; We're good! |
.is_ram: |
90 |
|
cmp eax,[E820Mem] |
91 |
|
ja .int_loop ; Not contiguous with our starting point |
92 |
|
add eax,[E820Buf+8] |
93 |
|
jc .overflow |
94 |
|
cmp dword [E820Buf+12],0 |
95 |
|
je .nooverflow |
96 |
|
.overflow: |
97 |
|
or eax,-1 |
98 |
|
.nooverflow: |
99 |
|
cmp eax,[E820Mem] |
100 |
|
jbe .int_loop ; All is below our baseline |
101 |
mov [E820Mem],eax |
mov [E820Mem],eax |
102 |
jmp .int_loop ; Still need to add low 1 MB |
jmp .start_over ; Start over in case we find an adjacent range |
103 |
|
|
104 |
.e820_done: |
.e820_done: |
105 |
mov eax,[E820Mem] |
mov eax,[E820Mem] |
106 |
and eax,eax |
cmp eax,[E820Max] |
107 |
jz no_e820 ; Nothing found by E820? |
jna .not_limited |
|
cmp eax,[E820Max] ; Make sure we're not limited |
|
|
jna got_highmem_add1mb |
|
108 |
mov eax,[E820Max] |
mov eax,[E820Max] |
109 |
jmp got_highmem_add1mb |
.not_limited: |
110 |
|
cmp eax,(1 << 20) |
111 |
|
ja got_highmem ; Did we actually find memory? |
112 |
|
; otherwise fall through |
113 |
|
|
114 |
; |
; |
115 |
; INT 15:E820 failed. Try INT 15:E801. |
; INT 15:E820 failed. Try INT 15:E801. |
125 |
mov ax,bx |
mov ax,bx |
126 |
shl eax,16 ; 64K chunks |
shl eax,16 ; 64K chunks |
127 |
add eax,(16 << 20) ; Add first 16M |
add eax,(16 << 20) ; Add first 16M |
128 |
jmp short got_highmem |
jmp short got_highmem |
129 |
|
|
130 |
; |
; |
131 |
; INT 15:E801 failed. Try INT 15:88. |
; INT 15:E801 failed. Try INT 15:88. |
139 |
e801_hole: |
e801_hole: |
140 |
and eax,0ffffh |
and eax,0ffffh |
141 |
shl eax,10 ; Convert from kilobytes |
shl eax,10 ; Convert from kilobytes |
|
got_highmem_add1mb: |
|
142 |
add eax,(1 << 20) ; First megabyte |
add eax,(1 << 20) ; First megabyte |
143 |
got_highmem: |
got_highmem: |
144 |
%if HIGHMEM_SLOP != 0 |
%if HIGHMEM_SLOP != 0 |
146 |
%endif |
%endif |
147 |
mov [HighMemSize],eax |
mov [HighMemSize],eax |
148 |
popad |
popad |
149 |
|
popfd |
150 |
pop es |
pop es |
151 |
ret ; Done! |
ret ; Done! |
152 |
|
|