root / pc-bios / optionrom / multiboot.S @ 076d2471
History | View | Annotate | Download (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 |
#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 |