Initialize
[sdk/emulator/qemu.git] / pc-bios / optionrom / multiboot.S
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 #include "optionrom.h"
22
23 #define MULTIBOOT_MAGIC         0x2badb002
24
25 #define GS_PROT_JUMP            0
26 #define GS_GDT_DESC             6
27
28
29 BOOT_ROM_START
30
31 run_multiboot:
32
33         cli
34         cld
35
36         mov             %cs, %eax
37         shl             $0x4, %eax
38
39         /* set up a long jump descriptor that is PC relative */
40
41         /* move stack memory to %gs */
42         mov             %ss, %ecx
43         shl             $0x4, %ecx
44         mov             %esp, %ebx
45         add             %ebx, %ecx
46         sub             $0x20, %ecx
47         sub             $0x30, %esp
48         shr             $0x4, %ecx
49         mov             %cx, %gs
50
51         /* now push the indirect jump decriptor there */
52         mov             (prot_jump), %ebx
53         add             %eax, %ebx
54         movl            %ebx, %gs:GS_PROT_JUMP
55         mov             $8, %bx
56         movw            %bx, %gs:GS_PROT_JUMP + 4
57
58         /* fix the gdt descriptor to be PC relative */
59         movw            (gdt_desc), %bx
60         movw            %bx, %gs:GS_GDT_DESC
61         movl            (gdt_desc+2), %ebx
62         add             %eax, %ebx
63         movl            %ebx, %gs:GS_GDT_DESC + 2
64
65         xor             %eax, %eax
66         mov             %eax, %es
67
68         /* Read the bootinfo struct into RAM */
69         read_fw_blob(FW_CFG_INITRD)
70
71         /* FS = bootinfo_struct */
72         read_fw         FW_CFG_INITRD_ADDR
73         shr             $4, %eax
74         mov             %ax, %fs
75
76         /* ES = mmap_addr */
77         mov             %fs:48, %eax
78         shr             $4, %eax
79         mov             %ax, %es
80
81         /* Initialize multiboot mmap structs using int 0x15(e820) */
82         xor             %ebx, %ebx
83         /* mmap start after first size */
84         movl            $4, %edi
85
86 mmap_loop:
87         /* entry size (mmap struct) & max buffer size (int15) */
88         movl            $20, %ecx
89         /* store entry size */
90         /* old as(1) doesn't like this insn so emit the bytes instead:
91         movl            %ecx, %es:-4(%edi)
92         */
93         .dc.b           0x26,0x67,0x66,0x89,0x4f,0xfc
94         /* e820 */
95         movl            $0x0000e820, %eax
96         /* 'SMAP' magic */
97         movl            $0x534d4150, %edx
98         int             $0x15
99
100 mmap_check_entry:
101         /* last entry? then we're done */
102         jb              mmap_done
103         and             %bx, %bx
104         jz              mmap_done
105         /* valid entry, so let's loop on */
106
107 mmap_store_entry:
108         /* %ax = entry_number * 24 */
109         mov             $24, %ax
110         mul             %bx
111         mov             %ax, %di
112         movw            %di, %fs:0x2c
113         /* %di = 4 + (entry_number * 24) */
114         add             $4, %di
115         jmp             mmap_loop
116
117 mmap_done:
118 real_to_prot:
119         /* Load the GDT before going into protected mode */
120 lgdt:
121         data32 lgdt     %gs:GS_GDT_DESC
122
123         /* get us to protected mode now */
124         movl            $1, %eax
125         movl            %eax, %cr0
126
127         /* the LJMP sets CS for us and gets us to 32-bit */
128 ljmp:
129         data32 ljmp     *%gs:GS_PROT_JUMP
130
131 prot_mode:
132 .code32
133
134         /* initialize all other segments */
135         movl            $0x10, %eax
136         movl            %eax, %ss
137         movl            %eax, %ds
138         movl            %eax, %es
139         movl            %eax, %fs
140         movl            %eax, %gs
141
142         /* Read the kernel and modules into RAM */
143         read_fw_blob(FW_CFG_KERNEL)
144
145         /* Jump off to the kernel */
146         read_fw         FW_CFG_KERNEL_ENTRY
147         mov             %eax, %ecx
148
149         /* EBX contains a pointer to the bootinfo struct */
150         read_fw         FW_CFG_INITRD_ADDR
151         movl            %eax, %ebx
152
153         /* EAX has to contain the magic */
154         movl            $MULTIBOOT_MAGIC, %eax
155 ljmp2:
156         jmp             *%ecx
157
158 /* Variables */
159 .align 4, 0
160 prot_jump:      .long prot_mode
161                 .short 8
162
163 .align 4, 0
164 gdt:
165         /* 0x00 */
166 .byte   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
167
168         /* 0x08: code segment (base=0, limit=0xfffff, type=32bit code exec/read, DPL=0, 4k) */
169 .byte   0xff, 0xff, 0x00, 0x00, 0x00, 0x9a, 0xcf, 0x00
170
171         /* 0x10: data segment (base=0, limit=0xfffff, type=32bit data read/write, DPL=0, 4k) */
172 .byte   0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0xcf, 0x00
173
174         /* 0x18: code segment (base=0, limit=0x0ffff, type=16bit code exec/read/conf, DPL=0, 1b) */
175 .byte   0xff, 0xff, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00
176
177         /* 0x20: data segment (base=0, limit=0x0ffff, type=16bit data read/write, DPL=0, 1b) */
178 .byte   0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00
179
180 gdt_desc:
181 .short  (5 * 8) - 1
182 .long   gdt
183
184 BOOT_ROM_END