root / pc-bios / optionrom / multiboot.S @ 8676188b
History | View | Annotate | Download (4.3 kB)
1 |
/* |
---|---|
2 |
* Multiboot Option ROM |
3 |
* |
4 |
* This program is free software; you can redistribute it and/or modify |
5 |
* it under the terms of the GNU General Public License as published by |
6 |
* the Free Software Foundation; either version 2 of the License, or |
7 |
* (at your option) any later version. |
8 |
* |
9 |
* This program is distributed in the hope that it will be useful, |
10 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 |
* GNU General Public License for more details. |
13 |
* |
14 |
* You should have received a copy of the GNU General Public License |
15 |
* along with this program; if not, write to the Free Software |
16 |
* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
17 |
* |
18 |
* Copyright Novell Inc, 2009 |
19 |
* Authors: Alexander Graf <agraf@suse.de> |
20 |
*/ |
21 |
|
22 |
#define NO_QEMU_PROTOS |
23 |
#include "../../hw/fw_cfg.h" |
24 |
|
25 |
#define BIOS_CFG_IOPORT_CFG 0x510 |
26 |
#define BIOS_CFG_IOPORT_DATA 0x511 |
27 |
|
28 |
#define MULTIBOOT_MAGIC 0x2badb002 |
29 |
|
30 |
/* Read a variable from the fw_cfg device. |
31 |
Clobbers: %edx |
32 |
Out: %eax */ |
33 |
.macro read_fw VAR |
34 |
mov $\VAR, %ax |
35 |
mov $BIOS_CFG_IOPORT_CFG, %dx |
36 |
outw %ax, (%dx) |
37 |
mov $BIOS_CFG_IOPORT_DATA, %dx |
38 |
inb (%dx), %al |
39 |
shl $8, %eax |
40 |
inb (%dx), %al |
41 |
shl $8, %eax |
42 |
inb (%dx), %al |
43 |
shl $8, %eax |
44 |
inb (%dx), %al |
45 |
bswap %eax |
46 |
.endm |
47 |
|
48 |
.code16 |
49 |
.text |
50 |
.global _start |
51 |
_start: |
52 |
.short 0xaa55 |
53 |
.byte 1 /* (_end - _start) / 512 */ |
54 |
push %eax |
55 |
push %ds |
56 |
|
57 |
/* setup ds so we can access the IVT */ |
58 |
xor %ax, %ax |
59 |
mov %ax, %ds |
60 |
|
61 |
/* save old int 19 */ |
62 |
mov (0x19*4), %eax |
63 |
mov %eax, %cs:old_int19 |
64 |
|
65 |
/* install our int 19 handler */ |
66 |
movw $int19_handler, (0x19*4) |
67 |
mov %cs, (0x19*4+2) |
68 |
|
69 |
pop %ds |
70 |
pop %eax |
71 |
lret |
72 |
|
73 |
int19_handler: |
74 |
/* DS = CS */ |
75 |
movw %cs, %ax |
76 |
movw %ax, %ds |
77 |
|
78 |
/* fall through */ |
79 |
|
80 |
run_multiboot: |
81 |
|
82 |
cli |
83 |
cld |
84 |
|
85 |
mov %cs, %eax |
86 |
shl $0x4, %eax |
87 |
|
88 |
/* fix the gdt descriptor to be PC relative */ |
89 |
mov (gdt_desc+2), %ebx |
90 |
add %eax, %ebx |
91 |
mov %ebx, (gdt_desc+2) |
92 |
|
93 |
/* fix the prot mode indirect jump to be PC relative */ |
94 |
mov (prot_jump), %ebx |
95 |
add %eax, %ebx |
96 |
mov %ebx, (prot_jump) |
97 |
|
98 |
/* FS = bootinfo_struct */ |
99 |
read_fw FW_CFG_INITRD_ADDR |
100 |
shr $4, %eax |
101 |
mov %ax, %fs |
102 |
|
103 |
/* ES = mmap_addr */ |
104 |
read_fw FW_CFG_INITRD_SIZE |
105 |
shr $4, %eax |
106 |
mov %ax, %es |
107 |
|
108 |
/* Initialize multiboot mmap structs using int 0x15(e820) */ |
109 |
xor %ebx, %ebx |
110 |
/* mmap start after first size */ |
111 |
movl $4, %edi |
112 |
|
113 |
mmap_loop: |
114 |
/* entry size (mmap struct) & max buffer size (int15) */ |
115 |
movl $20, %ecx |
116 |
/* store entry size */ |
117 |
movl %ecx, %es:-4(%edi) |
118 |
/* e820 */ |
119 |
movl $0x0000e820, %eax |
120 |
/* 'SMAP' magic */ |
121 |
movl $0x534d4150, %edx |
122 |
int $0x15 |
123 |
|
124 |
mmap_check_entry: |
125 |
/* last entry? then we're done */ |
126 |
jb mmap_done |
127 |
and %bx, %bx |
128 |
jz mmap_done |
129 |
/* valid entry, so let's loop on */ |
130 |
|
131 |
mmap_store_entry: |
132 |
/* %ax = entry_number * 24 */ |
133 |
mov $24, %ax |
134 |
mul %bx |
135 |
mov %ax, %di |
136 |
movw %di, %fs:0x2c |
137 |
/* %di = 4 + (entry_number * 24) */ |
138 |
add $4, %di |
139 |
jmp mmap_loop |
140 |
|
141 |
mmap_done: |
142 |
real_to_prot: |
143 |
/* Load the GDT before going into protected mode */ |
144 |
lgdt: |
145 |
data32 lgdt %cs:gdt_desc |
146 |
|
147 |
/* get us to protected mode now */ |
148 |
movl $1, %eax |
149 |
movl %eax, %cr0 |
150 |
|
151 |
/* the LJMP sets CS for us and gets us to 32-bit */ |
152 |
ljmp: |
153 |
data32 ljmp *%cs:prot_jump |
154 |
|
155 |
prot_mode: |
156 |
.code32 |
157 |
|
158 |
/* initialize all other segments */ |
159 |
movl $0x10, %eax |
160 |
movl %eax, %ss |
161 |
movl %eax, %ds |
162 |
movl %eax, %es |
163 |
movl %eax, %fs |
164 |
movl %eax, %gs |
165 |
|
166 |
/* Jump off to the kernel */ |
167 |
read_fw FW_CFG_KERNEL_ADDR |
168 |
mov %eax, %ecx |
169 |
|
170 |
/* EBX contains a pointer to the bootinfo struct */ |
171 |
read_fw FW_CFG_INITRD_ADDR |
172 |
movl %eax, %ebx |
173 |
|
174 |
/* EAX has to contain the magic */ |
175 |
movl $MULTIBOOT_MAGIC, %eax |
176 |
ljmp2: |
177 |
jmp *%ecx |
178 |
|
179 |
/* Variables */ |
180 |
.align 4, 0 |
181 |
old_int19: .long 0 |
182 |
|
183 |
prot_jump: .long prot_mode |
184 |
.short 8 |
185 |
|
186 |
.align 4, 0 |
187 |
gdt: |
188 |
/* 0x00 */ |
189 |
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 |
190 |
|
191 |
/* 0x08: code segment (base=0, limit=0xfffff, type=32bit code exec/read, DPL=0, 4k) */ |
192 |
.byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x9a, 0xcf, 0x00 |
193 |
|
194 |
/* 0x10: data segment (base=0, limit=0xfffff, type=32bit data read/write, DPL=0, 4k) */ |
195 |
.byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0xcf, 0x00 |
196 |
|
197 |
/* 0x18: code segment (base=0, limit=0x0ffff, type=16bit code exec/read/conf, DPL=0, 1b) */ |
198 |
.byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00 |
199 |
|
200 |
/* 0x20: data segment (base=0, limit=0x0ffff, type=16bit data read/write, DPL=0, 1b) */ |
201 |
.byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00 |
202 |
|
203 |
gdt_desc: |
204 |
.short (5 * 8) - 1 |
205 |
.long gdt |
206 |
|
207 |
.align 512, 0 |
208 |
_end: |
209 |
|