1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23asm(
24".text\n"
25".global _start\n"
26"_start:\n"
27" .short 0xaa55\n"
28" .byte 3\n"
29" .byte 0xcb\n"
30" .org 0x18\n"
31" .short 0\n"
32" .short _pnph\n"
33"_pnph:\n"
34" .ascii \"$PnP\"\n"
35" .byte 0x01\n"
36" .byte (_pnph_len / 16)\n"
37" .short 0x0000\n"
38" .byte 0x00\n"
39" .byte 0x00\n"
40" .long 0x00000000\n"
41" .short _manufacturer\n"
42" .short _product\n"
43" .long 0x00000000\n"
44" .short 0x0000\n"
45" .short 0x0000\n"
46" .short _bev\n"
47" .short 0x0000\n"
48" .short 0x0000\n"
49" .equ _pnph_len, . - _pnph\n"
50"_manufacturer:\n"
51" .asciz \"QEMU\"\n"
52"_product:\n"
53" .asciz \"Linux loader DMA\"\n"
54" .align 4, 0\n"
55"_bev:\n"
56" cli\n"
57" cld\n"
58" jmp load_kernel\n"
59);
60
61
62
63
64
65#include <stdint.h>
66#include "optrom.h"
67#include "optrom_fw_cfg.h"
68
69static inline void set_es(void *addr)
70{
71 uint32_t seg = (uint32_t)addr >> 4;
72 asm("movl %0, %%es" : : "r"(seg));
73}
74
75static inline uint16_t readw_es(uint16_t offset)
76{
77 uint16_t val;
78 asm(ADDR32 "movw %%es:(%1), %0" : "=r"(val) : "r"((uint32_t)offset));
79 barrier();
80 return val;
81}
82
83static inline uint32_t readl_es(uint16_t offset)
84{
85 uint32_t val;
86 asm(ADDR32 "movl %%es:(%1), %0" : "=r"(val) : "r"((uint32_t)offset));
87 barrier();
88 return val;
89}
90
91static inline void writel_es(uint16_t offset, uint32_t val)
92{
93 barrier();
94 asm(ADDR32 "movl %0, %%es:(%1)" : : "r"(val), "r"((uint32_t)offset));
95}
96
97
98static uint32_t get_e801_addr(void)
99{
100 uint16_t ax, bx, cx, dx;
101 uint32_t ret;
102
103 asm("int $0x15\n"
104 : "=a"(ax), "=b"(bx), "=c"(cx), "=d"(dx)
105 : "a"(0xe801), "b"(0), "c"(0), "d"(0));
106
107
108
109
110 if (cx == 0 && dx == 0) {
111 cx = ax;
112 dx = bx;
113 }
114
115 if (dx) {
116
117
118
119 ret = ((uint32_t)dx + 256 ) << 16;
120 } else {
121
122
123
124
125
126
127
128 ret = ((uint32_t)cx + 1024 ) << 10;
129 }
130
131 return ret;
132}
133
134
135extern void load_kernel(void) asm("load_kernel");
136
137void load_kernel(void)
138{
139 void *setup_addr;
140 void *initrd_addr;
141 void *kernel_addr;
142 void *cmdline_addr;
143 uint32_t setup_size;
144 uint32_t initrd_size;
145 uint32_t kernel_size;
146 uint32_t cmdline_size;
147 uint32_t initrd_end_page, max_allowed_page;
148 uint32_t segment_addr, stack_addr;
149
150 bios_cfg_read_entry_dma(&setup_addr, FW_CFG_SETUP_ADDR, 4);
151 bios_cfg_read_entry_dma(&setup_size, FW_CFG_SETUP_SIZE, 4);
152 bios_cfg_read_entry_dma(setup_addr, FW_CFG_SETUP_DATA, setup_size);
153
154 set_es(setup_addr);
155
156
157 if (readw_es(0x206) < 0x203) {
158
159 writel_es(0x22c, 0x37ffffff);
160 }
161
162 bios_cfg_read_entry_dma(&initrd_addr, FW_CFG_INITRD_ADDR, 4);
163 bios_cfg_read_entry_dma(&initrd_size, FW_CFG_INITRD_SIZE, 4);
164
165 initrd_end_page = ((uint32_t)(initrd_addr + initrd_size) & -4096);
166 max_allowed_page = (readl_es(0x22c) & -4096);
167
168 if (initrd_end_page != 0 && max_allowed_page != 0 &&
169 initrd_end_page != max_allowed_page) {
170
171
172
173 initrd_addr = (void *)((get_e801_addr() - initrd_size) & -4096);
174 writel_es(0x218, (uint32_t)initrd_addr);
175
176 }
177
178 bios_cfg_read_entry_dma(initrd_addr, FW_CFG_INITRD_DATA, initrd_size);
179
180 bios_cfg_read_entry_dma(&kernel_addr, FW_CFG_KERNEL_ADDR, 4);
181 bios_cfg_read_entry_dma(&kernel_size, FW_CFG_KERNEL_SIZE, 4);
182 bios_cfg_read_entry_dma(kernel_addr, FW_CFG_KERNEL_DATA, kernel_size);
183
184 bios_cfg_read_entry_dma(&cmdline_addr, FW_CFG_CMDLINE_ADDR, 4);
185 bios_cfg_read_entry_dma(&cmdline_size, FW_CFG_CMDLINE_SIZE, 4);
186 bios_cfg_read_entry_dma(cmdline_addr, FW_CFG_CMDLINE_DATA, cmdline_size);
187
188
189 segment_addr = ((uint32_t)setup_addr >> 4);
190 stack_addr = (uint32_t)(cmdline_addr - setup_addr - 16);
191
192
193
194
195 asm("movw %%ax, %%ds\n"
196 "movw %%ax, %%es\n"
197 "movw %%ax, %%fs\n"
198 "movw %%ax, %%gs\n"
199 "movw %%ax, %%ss\n"
200 "movl %%ebx, %%esp\n"
201 "addw $0x20, %%ax\n"
202 "pushw %%ax\n"
203 "pushw $0\n"
204
205 "xor %%ebx, %%ebx\n"
206 "xor %%ecx, %%ecx\n"
207 "xor %%edx, %%edx\n"
208 "xor %%edi, %%edi\n"
209 "xor %%ebp, %%ebp\n"
210 "lretw\n"
211 : : "a"(segment_addr), "b"(stack_addr));
212}
213