summaryrefslogtreecommitdiffstats
path: root/highmem.inc
blob: fdeaf69197fed867923d01b460c263d33dd7f17e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
;; $Id$
;; -----------------------------------------------------------------------
;;   
;;   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
;;   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.  Assumes DS == CS.
;
highmemsize:
		push es
		pushad

;
; First, try INT 15:E820 (get BIOS memory map)
;
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 .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 edx, (1 << 20)
		sub edx, [E820Buf]
		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
		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!!!!

		; We're good!
		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.
;
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
got_highmem_add1mb:
		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)