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