]> git.proxmox.com Git - qemu.git/blame - pc-bios/optionrom/multiboot.S
Convert multiboot to fw_cfg backed data storage
[qemu.git] / pc-bios / optionrom / multiboot.S
CommitLineData
f16408df
AG
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
8167ee88 15 * along with this program; if not, see <http://www.gnu.org/licenses/>.
f16408df
AG
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
77873196
AG
29#define GS_PROT_JUMP 0
30#define GS_GDT_DESC 6
31
32/* Break the translation block flow so -d cpu shows us values */
33#define DEBUG_HERE \
34 jmp 1f; \
35 1:
36
f16408df
AG
37/* Read a variable from the fw_cfg device.
38 Clobbers: %edx
39 Out: %eax */
40.macro read_fw VAR
41 mov $\VAR, %ax
42 mov $BIOS_CFG_IOPORT_CFG, %dx
43 outw %ax, (%dx)
44 mov $BIOS_CFG_IOPORT_DATA, %dx
45 inb (%dx), %al
46 shl $8, %eax
47 inb (%dx), %al
48 shl $8, %eax
49 inb (%dx), %al
50 shl $8, %eax
51 inb (%dx), %al
52 bswap %eax
53.endm
54
77873196
AG
55/*
56 * Read a blob from the fw_cfg device.
57 * Requires _ADDR, _SIZE and _DATA values for the parameter.
58 *
59 * Clobbers: %eax, %edx, %es, %ecx, %edi
60 */
61#define read_fw_blob(var) \
62 read_fw var ## _ADDR; \
63 mov %eax, %edi; \
64 read_fw var ## _SIZE; \
65 mov %eax, %ecx; \
66 mov $var ## _DATA, %ax; \
67 mov $BIOS_CFG_IOPORT_CFG, %edx; \
68 outw %ax, (%dx); \
69 mov $BIOS_CFG_IOPORT_DATA, %dx; \
70 cld; \
71 DEBUG_HERE \
72 rep insb (%dx), %es:(%edi);
73
f16408df
AG
74.code16
75.text
76 .global _start
77_start:
78 .short 0xaa55
77873196 79 .byte (_end - _start) / 512
f16408df
AG
80 push %eax
81 push %ds
82
83 /* setup ds so we can access the IVT */
84 xor %ax, %ax
85 mov %ax, %ds
86
f16408df
AG
87 /* install our int 19 handler */
88 movw $int19_handler, (0x19*4)
89 mov %cs, (0x19*4+2)
90
91 pop %ds
92 pop %eax
93 lret
94
95int19_handler:
96 /* DS = CS */
97 movw %cs, %ax
98 movw %ax, %ds
99
100 /* fall through */
101
102run_multiboot:
103
104 cli
105 cld
106
107 mov %cs, %eax
108 shl $0x4, %eax
109
77873196 110 /* set up a long jump descriptor that is PC relative */
f16408df 111
77873196
AG
112 /* move stack memory to %gs */
113 mov %ss, %ecx
114 shl $0x4, %ecx
115 mov %esp, %ebx
116 add %ebx, %ecx
117 sub $0x20, %ecx
118 sub $0x30, %esp
119 shr $0x4, %ecx
120 mov %cx, %gs
121
122 /* now push the indirect jump decriptor there */
f16408df
AG
123 mov (prot_jump), %ebx
124 add %eax, %ebx
77873196
AG
125 movl %ebx, %gs:GS_PROT_JUMP
126 mov $8, %bx
127 movw %bx, %gs:GS_PROT_JUMP + 4
128
129 /* fix the gdt descriptor to be PC relative */
130 movw (gdt_desc), %bx
131 movw %bx, %gs:GS_GDT_DESC
132 movl (gdt_desc+2), %ebx
133 add %eax, %ebx
134 movl %ebx, %gs:GS_GDT_DESC + 2
135
136 /* Read the bootinfo struct into RAM */
137 read_fw_blob(FW_CFG_INITRD)
f16408df
AG
138
139 /* FS = bootinfo_struct */
140 read_fw FW_CFG_INITRD_ADDR
141 shr $4, %eax
142 mov %ax, %fs
143
144 /* ES = mmap_addr */
77873196 145 mov %eax, %fs:0x48
f16408df
AG
146 shr $4, %eax
147 mov %ax, %es
148
149 /* Initialize multiboot mmap structs using int 0x15(e820) */
150 xor %ebx, %ebx
151 /* mmap start after first size */
152 movl $4, %edi
153
154mmap_loop:
155 /* entry size (mmap struct) & max buffer size (int15) */
156 movl $20, %ecx
157 /* store entry size */
ff56954b 158 /* old as(1) doesn't like this insn so emit the bytes instead:
f16408df 159 movl %ecx, %es:-4(%edi)
ff56954b
JL
160 */
161 .dc.b 0x26,0x67,0x66,0x89,0x4f,0xfc
f16408df
AG
162 /* e820 */
163 movl $0x0000e820, %eax
164 /* 'SMAP' magic */
165 movl $0x534d4150, %edx
166 int $0x15
167
168mmap_check_entry:
169 /* last entry? then we're done */
170 jb mmap_done
171 and %bx, %bx
172 jz mmap_done
173 /* valid entry, so let's loop on */
174
175mmap_store_entry:
176 /* %ax = entry_number * 24 */
177 mov $24, %ax
178 mul %bx
179 mov %ax, %di
180 movw %di, %fs:0x2c
181 /* %di = 4 + (entry_number * 24) */
182 add $4, %di
183 jmp mmap_loop
184
185mmap_done:
186real_to_prot:
187 /* Load the GDT before going into protected mode */
188lgdt:
77873196 189 data32 lgdt %gs:GS_GDT_DESC
f16408df
AG
190
191 /* get us to protected mode now */
192 movl $1, %eax
193 movl %eax, %cr0
194
195 /* the LJMP sets CS for us and gets us to 32-bit */
196ljmp:
77873196 197 data32 ljmp *%gs:GS_PROT_JUMP
f16408df
AG
198
199prot_mode:
200.code32
201
202 /* initialize all other segments */
203 movl $0x10, %eax
204 movl %eax, %ss
205 movl %eax, %ds
206 movl %eax, %es
207 movl %eax, %fs
208 movl %eax, %gs
209
77873196
AG
210 /* Read the kernel and modules into RAM */
211 read_fw_blob(FW_CFG_KERNEL)
212
f16408df 213 /* Jump off to the kernel */
77873196 214 read_fw FW_CFG_KERNEL_ENTRY
f16408df
AG
215 mov %eax, %ecx
216
217 /* EBX contains a pointer to the bootinfo struct */
218 read_fw FW_CFG_INITRD_ADDR
219 movl %eax, %ebx
220
221 /* EAX has to contain the magic */
222 movl $MULTIBOOT_MAGIC, %eax
223ljmp2:
224 jmp *%ecx
225
226/* Variables */
227.align 4, 0
f16408df
AG
228prot_jump: .long prot_mode
229 .short 8
230
231.align 4, 0
232gdt:
233 /* 0x00 */
234.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
235
236 /* 0x08: code segment (base=0, limit=0xfffff, type=32bit code exec/read, DPL=0, 4k) */
237.byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x9a, 0xcf, 0x00
238
239 /* 0x10: data segment (base=0, limit=0xfffff, type=32bit data read/write, DPL=0, 4k) */
240.byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0xcf, 0x00
241
242 /* 0x18: code segment (base=0, limit=0x0ffff, type=16bit code exec/read/conf, DPL=0, 1b) */
243.byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00
244
245 /* 0x20: data segment (base=0, limit=0x0ffff, type=16bit data read/write, DPL=0, 1b) */
246.byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00
247
248gdt_desc:
249.short (5 * 8) - 1
250.long gdt
251
252.align 512, 0
253_end:
254