blob: 833cd3102b32ecc5581971e2031eb41c6a71cb60 [file] [log] [blame]
Bin Gao923fa8d2013-03-30 00:27:10 -07001/*
2 * e820_bios.S: read e820 by int 15h call.
3 *
4 * The C language function exported by this file is:
5 * int get_e820_by_bios(void *e820_buf);
6 * @e820_buf: e820 mem map buffer, allocated by caller
7 * return: number of e820 entries
8 *
9 * Copyright (C) 2013 Intel Corporation.
10 * Author: Bin Gao <bin.gao@intel.com>
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms and conditions of the GNU General Public License,
14 * version 2, as published by the Free Software Foundation.
15 *
16 * This program is distributed in the hope it will be useful, but WITHOUT
17 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
19 * more details.
20 *
21 * You should have received a copy of the GNU General Public License along with
22 * this program; if not, write to the Free Software Foundation, Inc.,
23 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
24 *
25 */
26
27#include "bootstub.h"
28
29/* Real mode low memory layout */
30#define IDT_START 0x0
31#define RELOCATED_START 0xa000
32#define STACK_START 0xb000
33#define DATA_START 0xb200
34
35#define SAVED_GDTR_ADDR 0xb100
36#define SAVED_IDTR_ADDR 0xb110
37#define COUNT_ADDR 0xb120
38#define TOTAL_COUNT_ADDR 0xb130
39#define MIN_BUF_LEN 20
40#define BUF_LEN 2048
41#define MAX_NR_ENTRIES 128
42
43#define SMAP 0x534d4150
44#define E820 0xe820
45
46.text
47.section ".text.head","ax",@progbits
48
49 .code32
50 .globl get_e820_by_bios
51get_e820_by_bios:
52 jmp start_32bit
53
54 .balign 16
55idtr:
56 .word 0xffff
57 .long IDT_START
58
59 .balign 16
60gdt:
61 .quad 0
62 .quad GDT_ENTRY(0x009b, 0, 0xffff)
63 .quad GDT_ENTRY(0x0093, 0, 0xffff)
64gdtr:
65 .word 3*8-1
66 .long gdt
67
68saved_esp:
69 .long 0
70
71start_32bit:
72 pushal
73 pushfl
74
75 /* Save ESP, GDTR and IDTR registers */
76 movl $saved_esp, %eax
77 movl %esp, (%eax)
78 xorl %eax, %eax
79 sidtl SAVED_IDTR_ADDR(%eax)
80 sgdtl SAVED_GDTR_ADDR(%eax)
81
82 /* Relocate real mode codes to 64k segment */
83 movl $relocated_end + 4, %ecx
84 subl $relocated_start, %ecx
85 shrl $2, %ecx
86 movl $relocated_start, %esi
87 movl $RELOCATED_START, %edi
88 rep movsl
89
90 /* Set up real mode IDT */
91 lidtl %cs:idtr
92
93 /* Set up real mode GDT */
94 lgdtl %cs:gdtr
95 movl $16, %ecx
96 movl %ecx, %ds
97 movl %ecx, %es
98 movl %ecx, %fs
99 movl %ecx, %gs
100 movl %ecx, %ss
101
102 /* Switch to 16bit segment */
103 ljmpl $8, $RELOCATED_START
104
105 .code16
106relocated_start:
107reloc_base = .
108
109 /* Switch to real mode */
110 andb $0x10, %al
111 movl %eax, %cr0
112 ljmpw $0, $realmode_entry - relocated_start + RELOCATED_START
113
114realmode_entry = .
115 /* In real mode now, set up segment selectors */
116 movl $0, %eax
117 movl %eax, %ds
118 movl %eax, %es
119 movl %eax, %ss
120 movl %eax, %gs
121 movl %eax, %fs
122
123 movl $STACK_START, %esp
124
125 /* Do int 15h call */
126 movl $COUNT_ADDR, %eax
127 movl $0, (%eax)
128 movl $TOTAL_COUNT_ADDR, %eax
129 movl $0, (%eax)
130 xorl %ebx, %ebx
131 movw $DATA_START, %di
132again:
133 movw $E820, %ax
134 movw $BUF_LEN, %cx
135 movl $SMAP, %edx
136 int $0x15
137 jc error /* EFLGAS.CF is set */
138 cmpl $SMAP, %eax
139 jne error /* eax is not 'SMAP' */
140 cmpw $MIN_BUF_LEN, %cx
141 jl error /* returned buffer len < 20 */
142 cmpw $BUF_LEN, %cx
143 jg error /* returned buffer len > provided buffer len */
144 movl $TOTAL_COUNT_ADDR, %eax
145 addw %cx, (%eax)
146 movl $COUNT_ADDR, %eax
147 incl (%eax)
148 movl (%eax), %eax
149 cmpl $MAX_NR_ENTRIES, %eax /* max supported entries: 128 */
150 jge done
151 testl %ebx, %ebx /* ebx == 0: done, ebx != 0: continue */
152 je done
153 addw %cx, %di
154 jmp again
155done:
156 jmp 2f
157error:
158 movl $COUNT_ADDR, %eax
159 movl $~0, (%eax)
1602:
161
162 /* Switch back to protected mode */
163 xorl %ebx, %ebx
164 lidtl SAVED_IDTR_ADDR(%ebx)
165 lgdtl SAVED_GDTR_ADDR(%ebx)
166 movl %cr0, %ebx
167 orb $1, %bl
168 movl %ebx, %cr0
169 .byte 0x66, 0xea /* opcode(JMP FAR) with operand size override */
170 .long resumed_protected_mode /* offset */
171 .word __BOOT_CS /* segment selector */
172relocated_end = .
173
174 .code32
175resumed_protected_mode:
176 cli /* in case real mode codes turn on interrrupt! */
177 /* Restore segment registers */
178 movl $__BOOT_DS, %ebx
179 movl %ebx, %ds
180 movl %ebx, %es
181 movl %ebx, %gs
182 movl %ebx, %fs
183 movl %ebx, %ss
184
185 /* Restore stack pointer */
186 movl $saved_esp, %eax
187 movl (%eax), %esp
188
189 /* Copy e820 data from our buffer to caller's buffer */
190 xorl %eax, %eax
191 movl TOTAL_COUNT_ADDR(%eax), %ecx
192 movl $DATA_START, %esi
193 movl 40(%esp), %edi
194 rep movsb
195
196 popfl
197 popal
198
199 /* Return number of e820 entries */
200 movl $COUNT_ADDR, %eax
201 movl (%eax), %eax
202 ret