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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
|
/*
* e820_bios.S: read e820 by int 15h call.
*
* The C language function exported by this file is:
* int get_e820_by_bios(void *e820_buf);
* @e820_buf: e820 mem map buffer, allocated by caller
* return: number of e820 entries
*
* Copyright (C) 2013 Intel Corporation.
* Author: Bin Gao <bin.gao@intel.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include "bootstub.h"
/* Real mode low memory layout */
#define IDT_START 0x0
#define RELOCATED_START 0xa000
#define STACK_START 0xb000
#define DATA_START 0xb200
#define SAVED_GDTR_ADDR 0xb100
#define SAVED_IDTR_ADDR 0xb110
#define COUNT_ADDR 0xb120
#define TOTAL_COUNT_ADDR 0xb130
#define MIN_BUF_LEN 20
#define BUF_LEN 2048
#define MAX_NR_ENTRIES 128
#define SMAP 0x534d4150
#define E820 0xe820
.text
.section ".text.head","ax",@progbits
.code32
.globl get_e820_by_bios
get_e820_by_bios:
jmp start_32bit
.balign 16
idtr:
.word 0xffff
.long IDT_START
.balign 16
gdt:
.quad 0
.quad GDT_ENTRY(0x009b, 0, 0xffff)
.quad GDT_ENTRY(0x0093, 0, 0xffff)
gdtr:
.word 3*8-1
.long gdt
saved_esp:
.long 0
start_32bit:
pushal
pushfl
/* Save ESP, GDTR and IDTR registers */
movl $saved_esp, %eax
movl %esp, (%eax)
xorl %eax, %eax
sidtl SAVED_IDTR_ADDR(%eax)
sgdtl SAVED_GDTR_ADDR(%eax)
/* Relocate real mode codes to 64k segment */
movl $relocated_end + 4, %ecx
subl $relocated_start, %ecx
shrl $2, %ecx
movl $relocated_start, %esi
movl $RELOCATED_START, %edi
rep movsl
/* Set up real mode IDT */
lidtl %cs:idtr
/* Set up real mode GDT */
lgdtl %cs:gdtr
movl $16, %ecx
movl %ecx, %ds
movl %ecx, %es
movl %ecx, %fs
movl %ecx, %gs
movl %ecx, %ss
/* Switch to 16bit segment */
ljmpl $8, $RELOCATED_START
.code16
relocated_start:
reloc_base = .
/* Switch to real mode */
andb $0x10, %al
movl %eax, %cr0
ljmpw $0, $realmode_entry - relocated_start + RELOCATED_START
realmode_entry = .
/* In real mode now, set up segment selectors */
movl $0, %eax
movl %eax, %ds
movl %eax, %es
movl %eax, %ss
movl %eax, %gs
movl %eax, %fs
movl $STACK_START, %esp
/* Do int 15h call */
movl $COUNT_ADDR, %eax
movl $0, (%eax)
movl $TOTAL_COUNT_ADDR, %eax
movl $0, (%eax)
xorl %ebx, %ebx
movw $DATA_START, %di
again:
movw $E820, %ax
movw $BUF_LEN, %cx
movl $SMAP, %edx
int $0x15
jc error /* EFLGAS.CF is set */
cmpl $SMAP, %eax
jne error /* eax is not 'SMAP' */
cmpw $MIN_BUF_LEN, %cx
jl error /* returned buffer len < 20 */
cmpw $BUF_LEN, %cx
jg error /* returned buffer len > provided buffer len */
movl $TOTAL_COUNT_ADDR, %eax
addw %cx, (%eax)
movl $COUNT_ADDR, %eax
incl (%eax)
movl (%eax), %eax
cmpl $MAX_NR_ENTRIES, %eax /* max supported entries: 128 */
jge done
testl %ebx, %ebx /* ebx == 0: done, ebx != 0: continue */
je done
addw %cx, %di
jmp again
done:
jmp 2f
error:
movl $COUNT_ADDR, %eax
movl $~0, (%eax)
2:
/* Switch back to protected mode */
xorl %ebx, %ebx
lidtl SAVED_IDTR_ADDR(%ebx)
lgdtl SAVED_GDTR_ADDR(%ebx)
movl %cr0, %ebx
orb $1, %bl
movl %ebx, %cr0
.byte 0x66, 0xea /* opcode(JMP FAR) with operand size override */
.long resumed_protected_mode /* offset */
.word __BOOT_CS /* segment selector */
relocated_end = .
.code32
resumed_protected_mode:
cli /* in case real mode codes turn on interrrupt! */
/* Restore segment registers */
movl $__BOOT_DS, %ebx
movl %ebx, %ds
movl %ebx, %es
movl %ebx, %gs
movl %ebx, %fs
movl %ebx, %ss
/* Restore stack pointer */
movl $saved_esp, %eax
movl (%eax), %esp
/* Copy e820 data from our buffer to caller's buffer */
xorl %eax, %eax
movl TOTAL_COUNT_ADDR(%eax), %ecx
movl $DATA_START, %esi
movl 40(%esp), %edi
rep movsb
popfl
popal
/* Return number of e820 entries */
movl $COUNT_ADDR, %eax
movl (%eax), %eax
ret
|