summaryrefslogtreecommitdiff
path: root/e820_bios.S
blob: 833cd3102b32ecc5581971e2031eb41c6a71cb60 (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
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