]>
Commit | Line | Data |
---|---|---|
57a46d05 AG |
1 | /* |
2 | * Linux Boot 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 <[email protected]> | |
19 | * | |
20 | * Based on code in hw/pc.c. | |
21 | */ | |
22 | ||
23 | #include "optionrom.h" | |
24 | ||
75b9f690 GN |
25 | #define BOOT_ROM_PRODUCT "Linux loader" |
26 | ||
57a46d05 AG |
27 | BOOT_ROM_START |
28 | ||
29 | run_linuxboot: | |
30 | ||
31 | cli | |
32 | cld | |
33 | ||
34 | jmp copy_kernel | |
35 | boot_kernel: | |
36 | ||
37 | read_fw FW_CFG_SETUP_ADDR | |
38 | ||
39 | mov %eax, %ebx | |
40 | shr $4, %ebx | |
41 | ||
42 | /* All segments contain real_addr */ | |
43 | mov %bx, %ds | |
44 | mov %bx, %es | |
45 | mov %bx, %fs | |
46 | mov %bx, %gs | |
47 | mov %bx, %ss | |
48 | ||
49 | /* CX = CS we want to jump to */ | |
50 | add $0x20, %bx | |
51 | mov %bx, %cx | |
52 | ||
53 | /* SP = cmdline_addr-real_addr-16 */ | |
54 | read_fw FW_CFG_CMDLINE_ADDR | |
55 | mov %eax, %ebx | |
56 | read_fw FW_CFG_SETUP_ADDR | |
57 | sub %eax, %ebx | |
58 | sub $16, %ebx | |
59 | mov %ebx, %esp | |
60 | ||
61 | /* Build indirect lret descriptor */ | |
62 | pushw %cx /* CS */ | |
63 | xor %ax, %ax | |
64 | pushw %ax /* IP = 0 */ | |
65 | ||
66 | /* Clear registers */ | |
67 | xor %eax, %eax | |
68 | xor %ebx, %ebx | |
69 | xor %ecx, %ecx | |
70 | xor %edx, %edx | |
71 | xor %edi, %edi | |
72 | xor %ebp, %ebp | |
73 | ||
74 | /* Jump to Linux */ | |
75 | lret | |
76 | ||
77 | ||
78 | copy_kernel: | |
269e2358 PB |
79 | /* Read info block in low memory (0x10000 or 0x90000) */ |
80 | read_fw FW_CFG_SETUP_ADDR | |
81 | shr $4, %eax | |
82 | mov %eax, %es | |
83 | xor %edi, %edi | |
84 | read_fw_blob_addr32_edi(FW_CFG_SETUP) | |
85 | ||
86 | cmpw $0x203, %es:0x206 // if protocol >= 0x203 | |
87 | jae 1f // have initrd_max | |
88 | movl $0x37ffffff, %es:0x22c // else assume 0x37ffffff | |
89 | 1: | |
90 | ||
91 | /* Check if using kernel-specified initrd address */ | |
92 | read_fw FW_CFG_INITRD_ADDR | |
93 | mov %eax, %edi // (load_kernel wants it in %edi) | |
94 | read_fw FW_CFG_INITRD_SIZE // find end of initrd | |
95 | add %edi, %eax | |
96 | xor %es:0x22c, %eax // if it matches es:0x22c | |
97 | and $-4096, %eax // (apart from padding for page) | |
98 | jz load_kernel // then initrd is not at top | |
99 | // of memory | |
100 | ||
101 | /* pc.c placed the initrd at end of memory. Compute a better | |
102 | * initrd address based on e801 data. | |
103 | */ | |
cdebec5e PB |
104 | mov $0xe801, %ax |
105 | xor %cx, %cx | |
106 | xor %dx, %dx | |
107 | int $0x15 | |
108 | ||
109 | /* Output could be in AX/BX or CX/DX */ | |
110 | or %cx, %cx | |
111 | jnz 1f | |
112 | or %dx, %dx | |
113 | jnz 1f | |
114 | mov %ax, %cx | |
115 | mov %bx, %dx | |
116 | 1: | |
117 | ||
118 | or %dx, %dx | |
119 | jnz 2f | |
120 | addw $1024, %cx /* add 1 MB */ | |
121 | movzwl %cx, %edi | |
122 | shll $10, %edi /* convert to bytes */ | |
123 | jmp 3f | |
124 | ||
125 | 2: | |
126 | addw $16777216 >> 16, %dx /* add 16 MB */ | |
127 | movzwl %dx, %edi | |
128 | shll $16, %edi /* convert to bytes */ | |
129 | ||
130 | 3: | |
131 | read_fw FW_CFG_INITRD_SIZE | |
132 | subl %eax, %edi | |
133 | andl $-4096, %edi /* EDI = start of initrd */ | |
269e2358 | 134 | movl %edi, %es:0x218 /* put it in the header */ |
57a46d05 | 135 | |
269e2358 | 136 | load_kernel: |
57a46d05 AG |
137 | /* We need to load the kernel into memory we can't access in 16 bit |
138 | mode, so let's get into 32 bit mode, write the kernel and jump | |
139 | back again. */ | |
140 | ||
36ecd7c0 | 141 | /* Reserve space on the stack for our GDT descriptor. */ |
cdebec5e PB |
142 | mov %esp, %ebp |
143 | sub $16, %esp | |
57a46d05 AG |
144 | |
145 | /* Now create the GDT descriptor */ | |
36ecd7c0 | 146 | movw $((3 * 8) - 1), -16(%bp) |
57a46d05 | 147 | mov %cs, %eax |
d0652aa8 | 148 | movzwl %ax, %eax |
57a46d05 | 149 | shl $4, %eax |
d0652aa8 AK |
150 | addl $gdt, %eax |
151 | movl %eax, -14(%bp) | |
57a46d05 AG |
152 | |
153 | /* And load the GDT */ | |
36ecd7c0 PB |
154 | data32 lgdt -16(%bp) |
155 | mov %ebp, %esp | |
57a46d05 AG |
156 | |
157 | /* Get us to protected mode now */ | |
158 | mov $1, %eax | |
159 | mov %eax, %cr0 | |
160 | ||
dc61b0dc | 161 | /* So we can set ES to a 32-bit segment */ |
57a46d05 | 162 | mov $0x10, %eax |
dc61b0dc | 163 | mov %eax, %es |
57a46d05 | 164 | |
dc61b0dc | 165 | /* We're now running in 16-bit CS, but 32-bit ES! */ |
57a46d05 AG |
166 | |
167 | /* Load kernel and initrd */ | |
cdebec5e | 168 | read_fw_blob_addr32_edi(FW_CFG_INITRD) |
590bf491 | 169 | read_fw_blob_addr32(FW_CFG_KERNEL) |
590bf491 | 170 | read_fw_blob_addr32(FW_CFG_CMDLINE) |
cdebec5e | 171 | |
57a46d05 AG |
172 | /* And now jump into Linux! */ |
173 | mov $0, %eax | |
174 | mov %eax, %cr0 | |
175 | ||
dc61b0dc | 176 | /* ES = CS */ |
57a46d05 | 177 | mov %cs, %ax |
dc61b0dc | 178 | mov %ax, %es |
57a46d05 AG |
179 | |
180 | jmp boot_kernel | |
181 | ||
182 | /* Variables */ | |
183 | ||
184 | .align 4, 0 | |
185 | gdt: | |
186 | /* 0x00 */ | |
187 | .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 | |
188 | ||
189 | /* 0x08: code segment (base=0, limit=0xfffff, type=32bit code exec/read, DPL=0, 4k) */ | |
190 | .byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x9a, 0xcf, 0x00 | |
191 | ||
192 | /* 0x10: data segment (base=0, limit=0xfffff, type=32bit data read/write, DPL=0, 4k) */ | |
193 | .byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0xcf, 0x00 | |
194 | ||
195 | BOOT_ROM_END |