1 | /* |
---|
2 | * QEMU PC System Emulator |
---|
3 | * |
---|
4 | * Copyright (c) 2003-2004 Fabrice Bellard |
---|
5 | * |
---|
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
---|
7 | * of this software and associated documentation files (the "Software"), to deal |
---|
8 | * in the Software without restriction, including without limitation the rights |
---|
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
---|
10 | * copies of the Software, and to permit persons to whom the Software is |
---|
11 | * furnished to do so, subject to the following conditions: |
---|
12 | * |
---|
13 | * The above copyright notice and this permission notice shall be included in |
---|
14 | * all copies or substantial portions of the Software. |
---|
15 | * |
---|
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
---|
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
---|
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
---|
19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
---|
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
---|
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
---|
22 | * THE SOFTWARE. |
---|
23 | */ |
---|
24 | #include "vl.h" |
---|
25 | |
---|
26 | /* output Bochs bios info messages */ |
---|
27 | //#define DEBUG_BIOS |
---|
28 | |
---|
29 | #define BIOS_FILENAME "bios.bin" |
---|
30 | #define VGABIOS_FILENAME "vgabios.bin" |
---|
31 | #define VGABIOS_CIRRUS_FILENAME "vgabios-cirrus.bin" |
---|
32 | #define LINUX_BOOT_FILENAME "linux_boot.bin" |
---|
33 | |
---|
34 | #define KERNEL_LOAD_ADDR 0x00100000 |
---|
35 | #define INITRD_LOAD_ADDR 0x00600000 |
---|
36 | #define KERNEL_PARAMS_ADDR 0x00090000 |
---|
37 | #define KERNEL_CMDLINE_ADDR 0x00099000 |
---|
38 | |
---|
39 | static fdctrl_t *floppy_controller; |
---|
40 | static RTCState *rtc_state; |
---|
41 | #ifndef CONFIG_DM |
---|
42 | static PITState *pit; |
---|
43 | #endif /* !CONFIG_DM */ |
---|
44 | #ifndef CONFIG_DM |
---|
45 | static IOAPICState *ioapic; |
---|
46 | #endif /* !CONFIG_DM */ |
---|
47 | |
---|
48 | static void ioport80_write(void *opaque, uint32_t addr, uint32_t data) |
---|
49 | { |
---|
50 | } |
---|
51 | |
---|
52 | /* MSDOS compatibility mode FPU exception support */ |
---|
53 | /* XXX: add IGNNE support */ |
---|
54 | void cpu_set_ferr(CPUX86State *s) |
---|
55 | { |
---|
56 | pic_set_irq(13, 1); |
---|
57 | } |
---|
58 | |
---|
59 | static void ioportF0_write(void *opaque, uint32_t addr, uint32_t data) |
---|
60 | { |
---|
61 | pic_set_irq(13, 0); |
---|
62 | } |
---|
63 | |
---|
64 | /* TSC handling */ |
---|
65 | uint64_t cpu_get_tsc(CPUX86State *env) |
---|
66 | { |
---|
67 | /* Note: when using kqemu, it is more logical to return the host TSC |
---|
68 | because kqemu does not trap the RDTSC instruction for |
---|
69 | performance reasons */ |
---|
70 | #if USE_KQEMU |
---|
71 | if (env->kqemu_enabled) { |
---|
72 | return cpu_get_real_ticks(); |
---|
73 | } else |
---|
74 | #endif |
---|
75 | { |
---|
76 | return cpu_get_ticks(); |
---|
77 | } |
---|
78 | } |
---|
79 | |
---|
80 | #ifndef CONFIG_DM |
---|
81 | /* IRQ handling */ |
---|
82 | int cpu_get_pic_interrupt(CPUState *env) |
---|
83 | { |
---|
84 | int intno; |
---|
85 | |
---|
86 | intno = apic_get_interrupt(env); |
---|
87 | if (intno >= 0) { |
---|
88 | /* set irq request if a PIC irq is still pending */ |
---|
89 | /* XXX: improve that */ |
---|
90 | pic_update_irq(isa_pic); |
---|
91 | return intno; |
---|
92 | } |
---|
93 | /* read the irq from the PIC */ |
---|
94 | intno = pic_read_irq(isa_pic); |
---|
95 | return intno; |
---|
96 | } |
---|
97 | #endif /* CONFIG_DM */ |
---|
98 | |
---|
99 | static void pic_irq_request(void *opaque, int level) |
---|
100 | { |
---|
101 | CPUState *env = opaque; |
---|
102 | if (level) |
---|
103 | cpu_interrupt(env, CPU_INTERRUPT_HARD); |
---|
104 | else |
---|
105 | cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); |
---|
106 | } |
---|
107 | |
---|
108 | /* PC cmos mappings */ |
---|
109 | |
---|
110 | #define REG_EQUIPMENT_BYTE 0x14 |
---|
111 | #define REG_IBM_CENTURY_BYTE 0x32 |
---|
112 | #define REG_IBM_PS2_CENTURY_BYTE 0x37 |
---|
113 | |
---|
114 | |
---|
115 | static inline int to_bcd(RTCState *s, int a) |
---|
116 | { |
---|
117 | return ((a / 10) << 4) | (a % 10); |
---|
118 | } |
---|
119 | |
---|
120 | static int cmos_get_fd_drive_type(int fd0) |
---|
121 | { |
---|
122 | int val; |
---|
123 | |
---|
124 | switch (fd0) { |
---|
125 | case 0: |
---|
126 | /* 1.44 Mb 3"5 drive */ |
---|
127 | val = 4; |
---|
128 | break; |
---|
129 | case 1: |
---|
130 | /* 2.88 Mb 3"5 drive */ |
---|
131 | val = 5; |
---|
132 | break; |
---|
133 | case 2: |
---|
134 | /* 1.2 Mb 5"5 drive */ |
---|
135 | val = 2; |
---|
136 | break; |
---|
137 | default: |
---|
138 | val = 0; |
---|
139 | break; |
---|
140 | } |
---|
141 | return val; |
---|
142 | } |
---|
143 | |
---|
144 | static void cmos_init_hd(int type_ofs, int info_ofs, BlockDriverState *hd) |
---|
145 | { |
---|
146 | RTCState *s = rtc_state; |
---|
147 | int cylinders, heads, sectors; |
---|
148 | bdrv_get_geometry_hint(hd, &cylinders, &heads, §ors); |
---|
149 | rtc_set_memory(s, type_ofs, 47); |
---|
150 | rtc_set_memory(s, info_ofs, cylinders); |
---|
151 | rtc_set_memory(s, info_ofs + 1, cylinders >> 8); |
---|
152 | rtc_set_memory(s, info_ofs + 2, heads); |
---|
153 | rtc_set_memory(s, info_ofs + 3, 0xff); |
---|
154 | rtc_set_memory(s, info_ofs + 4, 0xff); |
---|
155 | rtc_set_memory(s, info_ofs + 5, 0xc0 | ((heads > 8) << 3)); |
---|
156 | rtc_set_memory(s, info_ofs + 6, cylinders); |
---|
157 | rtc_set_memory(s, info_ofs + 7, cylinders >> 8); |
---|
158 | rtc_set_memory(s, info_ofs + 8, sectors); |
---|
159 | } |
---|
160 | |
---|
161 | static int get_bios_disk(char *boot_device, int index) { |
---|
162 | |
---|
163 | if (index < strlen(boot_device)) { |
---|
164 | switch (boot_device[index]) { |
---|
165 | case 'a': |
---|
166 | return 0x01; /* floppy */ |
---|
167 | case 'c': |
---|
168 | return 0x02; /* hard drive */ |
---|
169 | case 'd': |
---|
170 | return 0x03; /* cdrom */ |
---|
171 | case 'n': |
---|
172 | return 0x04; /* network */ |
---|
173 | } |
---|
174 | } |
---|
175 | return 0x00; /* no device */ |
---|
176 | } |
---|
177 | |
---|
178 | /* hd_table must contain 4 block drivers */ |
---|
179 | static void cmos_init(uint64_t ram_size, char *boot_device, BlockDriverState **hd_table, time_t timeoffset) |
---|
180 | { |
---|
181 | RTCState *s = rtc_state; |
---|
182 | int val; |
---|
183 | int fd0, fd1, nb; |
---|
184 | time_t ti; |
---|
185 | struct tm *tm; |
---|
186 | int i; |
---|
187 | |
---|
188 | /* set the CMOS date */ |
---|
189 | time(&ti); |
---|
190 | ti += timeoffset; |
---|
191 | if (rtc_utc) |
---|
192 | tm = gmtime(&ti); |
---|
193 | else |
---|
194 | tm = localtime(&ti); |
---|
195 | rtc_set_date(s, tm); |
---|
196 | |
---|
197 | val = to_bcd(s, (tm->tm_year / 100) + 19); |
---|
198 | rtc_set_memory(s, REG_IBM_CENTURY_BYTE, val); |
---|
199 | rtc_set_memory(s, REG_IBM_PS2_CENTURY_BYTE, val); |
---|
200 | |
---|
201 | /* various important CMOS locations needed by PC/Bochs bios */ |
---|
202 | |
---|
203 | /* memory size */ |
---|
204 | val = 640; /* base memory in K */ |
---|
205 | rtc_set_memory(s, 0x15, val); |
---|
206 | rtc_set_memory(s, 0x16, val >> 8); |
---|
207 | |
---|
208 | val = (ram_size / 1024) - 1024; |
---|
209 | if (val > 65535) |
---|
210 | val = 65535; |
---|
211 | rtc_set_memory(s, 0x17, val); |
---|
212 | rtc_set_memory(s, 0x18, val >> 8); |
---|
213 | rtc_set_memory(s, 0x30, val); |
---|
214 | rtc_set_memory(s, 0x31, val >> 8); |
---|
215 | |
---|
216 | if (ram_size > (16 * 1024 * 1024)) |
---|
217 | val = (ram_size / 65536) - ((16 * 1024 * 1024) / 65536); |
---|
218 | else |
---|
219 | val = 0; |
---|
220 | if (val > 65535) |
---|
221 | val = 65535; |
---|
222 | rtc_set_memory(s, 0x34, val); |
---|
223 | rtc_set_memory(s, 0x35, val >> 8); |
---|
224 | |
---|
225 | if (boot_device == NULL) { |
---|
226 | /* default to hd, then cd, then floppy. */ |
---|
227 | boot_device = "cda"; |
---|
228 | } |
---|
229 | rtc_set_memory(s, 0x3d, get_bios_disk(boot_device, 0) | |
---|
230 | (get_bios_disk(boot_device, 1) << 4)); |
---|
231 | rtc_set_memory(s, 0x38, (get_bios_disk(boot_device, 2) << 4) | |
---|
232 | (!fd_bootchk ? 0x01 : 0x00)); |
---|
233 | |
---|
234 | /* floppy type */ |
---|
235 | |
---|
236 | fd0 = fdctrl_get_drive_type(floppy_controller, 0); |
---|
237 | fd1 = fdctrl_get_drive_type(floppy_controller, 1); |
---|
238 | |
---|
239 | val = (cmos_get_fd_drive_type(fd0) << 4) | cmos_get_fd_drive_type(fd1); |
---|
240 | rtc_set_memory(s, 0x10, val); |
---|
241 | |
---|
242 | val = 0; |
---|
243 | nb = 0; |
---|
244 | if (fd0 < 3) |
---|
245 | nb++; |
---|
246 | if (fd1 < 3) |
---|
247 | nb++; |
---|
248 | switch (nb) { |
---|
249 | case 0: |
---|
250 | break; |
---|
251 | case 1: |
---|
252 | val |= 0x01; /* 1 drive, ready for boot */ |
---|
253 | break; |
---|
254 | case 2: |
---|
255 | val |= 0x41; /* 2 drives, ready for boot */ |
---|
256 | break; |
---|
257 | } |
---|
258 | val |= 0x02; /* FPU is there */ |
---|
259 | val |= 0x04; /* PS/2 mouse installed */ |
---|
260 | rtc_set_memory(s, REG_EQUIPMENT_BYTE, val); |
---|
261 | |
---|
262 | /* hard drives */ |
---|
263 | |
---|
264 | rtc_set_memory(s, 0x12, (hd_table[0] ? 0xf0 : 0) | (hd_table[1] ? 0x0f : 0)); |
---|
265 | if (hd_table[0]) |
---|
266 | cmos_init_hd(0x19, 0x1b, hd_table[0]); |
---|
267 | if (hd_table[1]) |
---|
268 | cmos_init_hd(0x1a, 0x24, hd_table[1]); |
---|
269 | |
---|
270 | val = 0; |
---|
271 | for (i = 0; i < 4; i++) { |
---|
272 | if (hd_table[i]) { |
---|
273 | int cylinders, heads, sectors, translation; |
---|
274 | /* NOTE: bdrv_get_geometry_hint() returns the physical |
---|
275 | geometry. It is always such that: 1 <= sects <= 63, 1 |
---|
276 | <= heads <= 16, 1 <= cylinders <= 16383. The BIOS |
---|
277 | geometry can be different if a translation is done. */ |
---|
278 | translation = bdrv_get_translation_hint(hd_table[i]); |
---|
279 | if (translation == BIOS_ATA_TRANSLATION_AUTO) { |
---|
280 | bdrv_get_geometry_hint(hd_table[i], &cylinders, &heads, §ors); |
---|
281 | if (cylinders <= 1024 && heads <= 16 && sectors <= 63) { |
---|
282 | /* No translation. */ |
---|
283 | translation = 0; |
---|
284 | } else { |
---|
285 | /* LBA translation. */ |
---|
286 | translation = 1; |
---|
287 | } |
---|
288 | } else { |
---|
289 | translation--; |
---|
290 | } |
---|
291 | val |= translation << (i * 2); |
---|
292 | } |
---|
293 | } |
---|
294 | rtc_set_memory(s, 0x39, val); |
---|
295 | } |
---|
296 | |
---|
297 | void ioport_set_a20(int enable) |
---|
298 | { |
---|
299 | /* XXX: send to all CPUs ? */ |
---|
300 | cpu_x86_set_a20(first_cpu, enable); |
---|
301 | } |
---|
302 | |
---|
303 | int ioport_get_a20(void) |
---|
304 | { |
---|
305 | return ((first_cpu->a20_mask >> 20) & 1); |
---|
306 | } |
---|
307 | |
---|
308 | static void ioport92_write(void *opaque, uint32_t addr, uint32_t val) |
---|
309 | { |
---|
310 | ioport_set_a20((val >> 1) & 1); |
---|
311 | /* XXX: bit 0 is fast reset */ |
---|
312 | } |
---|
313 | |
---|
314 | static uint32_t ioport92_read(void *opaque, uint32_t addr) |
---|
315 | { |
---|
316 | return ioport_get_a20() << 1; |
---|
317 | } |
---|
318 | |
---|
319 | /***********************************************************/ |
---|
320 | /* Bochs BIOS debug ports */ |
---|
321 | |
---|
322 | void bochs_bios_write(void *opaque, uint32_t addr, uint32_t val) |
---|
323 | { |
---|
324 | static const char shutdown_str[8] = "Shutdown"; |
---|
325 | static int shutdown_index = 0; |
---|
326 | |
---|
327 | switch(addr) { |
---|
328 | /* Bochs BIOS messages */ |
---|
329 | case 0x400: |
---|
330 | case 0x401: |
---|
331 | fprintf(stderr, "BIOS panic at rombios.c, line %d\n", val); |
---|
332 | exit(1); |
---|
333 | case 0x402: |
---|
334 | case 0x403: |
---|
335 | #ifdef DEBUG_BIOS |
---|
336 | fprintf(stderr, "%c", val); |
---|
337 | #endif |
---|
338 | break; |
---|
339 | case 0x8900: |
---|
340 | /* same as Bochs power off */ |
---|
341 | if (val == shutdown_str[shutdown_index]) { |
---|
342 | shutdown_index++; |
---|
343 | if (shutdown_index == 8) { |
---|
344 | shutdown_index = 0; |
---|
345 | qemu_system_shutdown_request(); |
---|
346 | } |
---|
347 | } else { |
---|
348 | shutdown_index = 0; |
---|
349 | } |
---|
350 | break; |
---|
351 | |
---|
352 | /* LGPL'ed VGA BIOS messages */ |
---|
353 | case 0x501: |
---|
354 | case 0x502: |
---|
355 | fprintf(stderr, "VGA BIOS panic, line %d\n", val); |
---|
356 | exit(1); |
---|
357 | case 0x500: |
---|
358 | case 0x503: |
---|
359 | #ifdef DEBUG_BIOS |
---|
360 | fprintf(stderr, "%c", val); |
---|
361 | #endif |
---|
362 | break; |
---|
363 | } |
---|
364 | } |
---|
365 | |
---|
366 | void bochs_bios_init(void) |
---|
367 | { |
---|
368 | register_ioport_write(0x400, 1, 2, bochs_bios_write, NULL); |
---|
369 | register_ioport_write(0x401, 1, 2, bochs_bios_write, NULL); |
---|
370 | register_ioport_write(0x402, 1, 1, bochs_bios_write, NULL); |
---|
371 | register_ioport_write(0x403, 1, 1, bochs_bios_write, NULL); |
---|
372 | register_ioport_write(0x8900, 1, 1, bochs_bios_write, NULL); |
---|
373 | |
---|
374 | register_ioport_write(0x501, 1, 2, bochs_bios_write, NULL); |
---|
375 | register_ioport_write(0x502, 1, 2, bochs_bios_write, NULL); |
---|
376 | register_ioport_write(0x500, 1, 1, bochs_bios_write, NULL); |
---|
377 | register_ioport_write(0x503, 1, 1, bochs_bios_write, NULL); |
---|
378 | } |
---|
379 | |
---|
380 | |
---|
381 | int load_kernel(const char *filename, uint8_t *addr, |
---|
382 | uint8_t *real_addr) |
---|
383 | { |
---|
384 | int fd, size; |
---|
385 | int setup_sects; |
---|
386 | |
---|
387 | fd = open(filename, O_RDONLY | O_BINARY); |
---|
388 | if (fd < 0) |
---|
389 | return -1; |
---|
390 | |
---|
391 | /* load 16 bit code */ |
---|
392 | if (read(fd, real_addr, 512) != 512) |
---|
393 | goto fail; |
---|
394 | setup_sects = real_addr[0x1F1]; |
---|
395 | if (!setup_sects) |
---|
396 | setup_sects = 4; |
---|
397 | if (read(fd, real_addr + 512, setup_sects * 512) != |
---|
398 | setup_sects * 512) |
---|
399 | goto fail; |
---|
400 | |
---|
401 | /* load 32 bit code */ |
---|
402 | size = read(fd, addr, 16 * 1024 * 1024); |
---|
403 | if (size < 0) |
---|
404 | goto fail; |
---|
405 | close(fd); |
---|
406 | return size; |
---|
407 | fail: |
---|
408 | close(fd); |
---|
409 | return -1; |
---|
410 | } |
---|
411 | |
---|
412 | static void main_cpu_reset(void *opaque) |
---|
413 | { |
---|
414 | CPUState *env = opaque; |
---|
415 | cpu_reset(env); |
---|
416 | } |
---|
417 | |
---|
418 | /*************************************************/ |
---|
419 | |
---|
420 | #ifndef CONFIG_DM |
---|
421 | static void putb(uint8_t **pp, int val) |
---|
422 | { |
---|
423 | uint8_t *q; |
---|
424 | q = *pp; |
---|
425 | *q++ = val; |
---|
426 | *pp = q; |
---|
427 | } |
---|
428 | |
---|
429 | static void putstr(uint8_t **pp, const char *str) |
---|
430 | { |
---|
431 | uint8_t *q; |
---|
432 | q = *pp; |
---|
433 | while (*str) |
---|
434 | *q++ = *str++; |
---|
435 | *pp = q; |
---|
436 | } |
---|
437 | |
---|
438 | static void putle16(uint8_t **pp, int val) |
---|
439 | { |
---|
440 | uint8_t *q; |
---|
441 | q = *pp; |
---|
442 | *q++ = val; |
---|
443 | *q++ = val >> 8; |
---|
444 | *pp = q; |
---|
445 | } |
---|
446 | |
---|
447 | static void putle32(uint8_t **pp, int val) |
---|
448 | { |
---|
449 | uint8_t *q; |
---|
450 | q = *pp; |
---|
451 | *q++ = val; |
---|
452 | *q++ = val >> 8; |
---|
453 | *q++ = val >> 16; |
---|
454 | *q++ = val >> 24; |
---|
455 | *pp = q; |
---|
456 | } |
---|
457 | |
---|
458 | static int mpf_checksum(const uint8_t *data, int len) |
---|
459 | { |
---|
460 | int sum, i; |
---|
461 | sum = 0; |
---|
462 | for(i = 0; i < len; i++) |
---|
463 | sum += data[i]; |
---|
464 | return sum & 0xff; |
---|
465 | } |
---|
466 | |
---|
467 | /* Build the Multi Processor table in the BIOS. Same values as Bochs. */ |
---|
468 | static void bios_add_mptable(uint8_t *bios_data) |
---|
469 | { |
---|
470 | uint8_t *mp_config_table, *q, *float_pointer_struct; |
---|
471 | int ioapic_id, offset, i, len; |
---|
472 | |
---|
473 | if (smp_cpus <= 1) |
---|
474 | return; |
---|
475 | |
---|
476 | mp_config_table = bios_data + 0xb000; |
---|
477 | q = mp_config_table; |
---|
478 | putstr(&q, "PCMP"); /* "PCMP signature */ |
---|
479 | putle16(&q, 0); /* table length (patched later) */ |
---|
480 | putb(&q, 4); /* spec rev */ |
---|
481 | putb(&q, 0); /* checksum (patched later) */ |
---|
482 | putstr(&q, "QEMUCPU "); /* OEM id */ |
---|
483 | putstr(&q, "0.1 "); /* vendor id */ |
---|
484 | putle32(&q, 0); /* OEM table ptr */ |
---|
485 | putle16(&q, 0); /* OEM table size */ |
---|
486 | putle16(&q, 20); /* entry count */ |
---|
487 | putle32(&q, 0xfee00000); /* local APIC addr */ |
---|
488 | putle16(&q, 0); /* ext table length */ |
---|
489 | putb(&q, 0); /* ext table checksum */ |
---|
490 | putb(&q, 0); /* reserved */ |
---|
491 | |
---|
492 | for(i = 0; i < smp_cpus; i++) { |
---|
493 | putb(&q, 0); /* entry type = processor */ |
---|
494 | putb(&q, i); /* APIC id */ |
---|
495 | putb(&q, 0x11); /* local APIC version number */ |
---|
496 | if (i == 0) |
---|
497 | putb(&q, 3); /* cpu flags: enabled, bootstrap cpu */ |
---|
498 | else |
---|
499 | putb(&q, 1); /* cpu flags: enabled */ |
---|
500 | putb(&q, 0); /* cpu signature */ |
---|
501 | putb(&q, 6); |
---|
502 | putb(&q, 0); |
---|
503 | putb(&q, 0); |
---|
504 | putle16(&q, 0x201); /* feature flags */ |
---|
505 | putle16(&q, 0); |
---|
506 | |
---|
507 | putle16(&q, 0); /* reserved */ |
---|
508 | putle16(&q, 0); |
---|
509 | putle16(&q, 0); |
---|
510 | putle16(&q, 0); |
---|
511 | } |
---|
512 | |
---|
513 | /* isa bus */ |
---|
514 | putb(&q, 1); /* entry type = bus */ |
---|
515 | putb(&q, 0); /* bus ID */ |
---|
516 | putstr(&q, "ISA "); |
---|
517 | |
---|
518 | /* ioapic */ |
---|
519 | ioapic_id = smp_cpus; |
---|
520 | putb(&q, 2); /* entry type = I/O APIC */ |
---|
521 | putb(&q, ioapic_id); /* apic ID */ |
---|
522 | putb(&q, 0x11); /* I/O APIC version number */ |
---|
523 | putb(&q, 1); /* enable */ |
---|
524 | putle32(&q, 0xfec00000); /* I/O APIC addr */ |
---|
525 | |
---|
526 | /* irqs */ |
---|
527 | for(i = 0; i < 16; i++) { |
---|
528 | putb(&q, 3); /* entry type = I/O interrupt */ |
---|
529 | putb(&q, 0); /* interrupt type = vectored interrupt */ |
---|
530 | putb(&q, 0); /* flags: po=0, el=0 */ |
---|
531 | putb(&q, 0); |
---|
532 | putb(&q, 0); /* source bus ID = ISA */ |
---|
533 | putb(&q, i); /* source bus IRQ */ |
---|
534 | putb(&q, ioapic_id); /* dest I/O APIC ID */ |
---|
535 | putb(&q, i); /* dest I/O APIC interrupt in */ |
---|
536 | } |
---|
537 | /* patch length */ |
---|
538 | len = q - mp_config_table; |
---|
539 | mp_config_table[4] = len; |
---|
540 | mp_config_table[5] = len >> 8; |
---|
541 | |
---|
542 | mp_config_table[7] = -mpf_checksum(mp_config_table, q - mp_config_table); |
---|
543 | |
---|
544 | /* align to 16 */ |
---|
545 | offset = q - bios_data; |
---|
546 | offset = (offset + 15) & ~15; |
---|
547 | float_pointer_struct = bios_data + offset; |
---|
548 | |
---|
549 | /* floating pointer structure */ |
---|
550 | q = float_pointer_struct; |
---|
551 | putstr(&q, "_MP_"); |
---|
552 | /* pointer to MP config table */ |
---|
553 | putle32(&q, mp_config_table - bios_data + 0x000f0000); |
---|
554 | |
---|
555 | putb(&q, 1); /* length in 16 byte units */ |
---|
556 | putb(&q, 4); /* MP spec revision */ |
---|
557 | putb(&q, 0); /* checksum (patched later) */ |
---|
558 | putb(&q, 0); /* MP feature byte 1 */ |
---|
559 | |
---|
560 | putb(&q, 0); |
---|
561 | putb(&q, 0); |
---|
562 | putb(&q, 0); |
---|
563 | putb(&q, 0); |
---|
564 | float_pointer_struct[10] = |
---|
565 | -mpf_checksum(float_pointer_struct, q - float_pointer_struct); |
---|
566 | } |
---|
567 | #endif /* !CONFIG_DM */ |
---|
568 | |
---|
569 | |
---|
570 | static const int ide_iobase[2] = { 0x1f0, 0x170 }; |
---|
571 | static const int ide_iobase2[2] = { 0x3f6, 0x376 }; |
---|
572 | static const int ide_irq[2] = { 14, 15 }; |
---|
573 | |
---|
574 | #define NE2000_NB_MAX 6 |
---|
575 | |
---|
576 | static int ne2000_io[NE2000_NB_MAX] = { 0x300, 0x320, 0x340, 0x360, 0x280, 0x380 }; |
---|
577 | static int ne2000_irq[NE2000_NB_MAX] = { 9, 10, 11, 3, 4, 5 }; |
---|
578 | |
---|
579 | static int serial_io[MAX_SERIAL_PORTS] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 }; |
---|
580 | static int serial_irq[MAX_SERIAL_PORTS] = { 4, 3, 4, 3 }; |
---|
581 | |
---|
582 | static int parallel_io[MAX_PARALLEL_PORTS] = { 0x378, 0x278, 0x3bc }; |
---|
583 | static int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 }; |
---|
584 | |
---|
585 | #ifdef HAS_AUDIO |
---|
586 | static void audio_init (PCIBus *pci_bus) |
---|
587 | { |
---|
588 | struct soundhw *c; |
---|
589 | int audio_enabled = 0; |
---|
590 | |
---|
591 | for (c = soundhw; !audio_enabled && c->name; ++c) { |
---|
592 | audio_enabled = c->enabled; |
---|
593 | } |
---|
594 | |
---|
595 | if (audio_enabled) { |
---|
596 | AudioState *s; |
---|
597 | |
---|
598 | s = AUD_init (); |
---|
599 | if (s) { |
---|
600 | for (c = soundhw; c->name; ++c) { |
---|
601 | if (c->enabled) { |
---|
602 | if (c->isa) { |
---|
603 | c->init.init_isa (s); |
---|
604 | } |
---|
605 | else { |
---|
606 | if (pci_bus) { |
---|
607 | c->init.init_pci (pci_bus, s); |
---|
608 | } |
---|
609 | } |
---|
610 | } |
---|
611 | } |
---|
612 | } |
---|
613 | } |
---|
614 | } |
---|
615 | #endif |
---|
616 | |
---|
617 | static void pc_init_ne2k_isa(NICInfo *nd) |
---|
618 | { |
---|
619 | static int nb_ne2k = 0; |
---|
620 | |
---|
621 | if (nb_ne2k == NE2000_NB_MAX) |
---|
622 | return; |
---|
623 | isa_ne2000_init(ne2000_io[nb_ne2k], ne2000_irq[nb_ne2k], nd); |
---|
624 | nb_ne2k++; |
---|
625 | } |
---|
626 | |
---|
627 | #define NOBIOS 1 |
---|
628 | |
---|
629 | /* PC hardware initialisation */ |
---|
630 | static void pc_init1(uint64_t ram_size, int vga_ram_size, char *boot_device, |
---|
631 | DisplayState *ds, const char **fd_filename, int snapshot, |
---|
632 | const char *kernel_filename, const char *kernel_cmdline, |
---|
633 | const char *initrd_filename, time_t timeoffset, |
---|
634 | int pci_enabled) |
---|
635 | { |
---|
636 | #ifndef NOBIOS |
---|
637 | char buf[1024]; |
---|
638 | int ret, initrd_size; |
---|
639 | #endif |
---|
640 | int linux_boot, i; |
---|
641 | #ifndef NOBIOS |
---|
642 | unsigned long bios_offset, vga_bios_offset; |
---|
643 | int bios_size, isa_bios_size; |
---|
644 | #endif /* !NOBIOS */ |
---|
645 | PCIBus *pci_bus; |
---|
646 | int piix3_devfn = -1; |
---|
647 | CPUState *env; |
---|
648 | NICInfo *nd; |
---|
649 | |
---|
650 | linux_boot = (kernel_filename != NULL); |
---|
651 | |
---|
652 | /* init CPUs */ |
---|
653 | for(i = 0; i < smp_cpus; i++) { |
---|
654 | env = cpu_init(); |
---|
655 | #ifndef CONFIG_DM |
---|
656 | if (i != 0) |
---|
657 | env->hflags |= HF_HALTED_MASK; |
---|
658 | if (smp_cpus > 1) { |
---|
659 | /* XXX: enable it in all cases */ |
---|
660 | env->cpuid_features |= CPUID_APIC; |
---|
661 | } |
---|
662 | #endif /* !CONFIG_DM */ |
---|
663 | register_savevm("cpu", i, 3, cpu_save, cpu_load, env); |
---|
664 | qemu_register_reset(main_cpu_reset, env); |
---|
665 | #ifndef CONFIG_DM |
---|
666 | if (pci_enabled) { |
---|
667 | apic_init(env); |
---|
668 | } |
---|
669 | #endif /* !CONFIG_DM */ |
---|
670 | } |
---|
671 | |
---|
672 | /* allocate RAM */ |
---|
673 | #ifndef CONFIG_DM /* HVM domain owns memory */ |
---|
674 | cpu_register_physical_memory(0, ram_size, 0); |
---|
675 | #endif |
---|
676 | |
---|
677 | #ifndef NOBIOS |
---|
678 | /* BIOS load */ |
---|
679 | bios_offset = ram_size + vga_ram_size; |
---|
680 | vga_bios_offset = bios_offset + 256 * 1024; |
---|
681 | |
---|
682 | snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); |
---|
683 | bios_size = get_image_size(buf); |
---|
684 | if (bios_size <= 0 || |
---|
685 | (bios_size % 65536) != 0 || |
---|
686 | bios_size > (256 * 1024)) { |
---|
687 | goto bios_error; |
---|
688 | } |
---|
689 | ret = load_image(buf, phys_ram_base + bios_offset); |
---|
690 | if (ret != bios_size) { |
---|
691 | bios_error: |
---|
692 | fprintf(stderr, "qemu: could not load PC bios '%s'\n", buf); |
---|
693 | exit(1); |
---|
694 | } |
---|
695 | if (bios_size == 65536) { |
---|
696 | bios_add_mptable(phys_ram_base + bios_offset); |
---|
697 | } |
---|
698 | |
---|
699 | /* VGA BIOS load */ |
---|
700 | if (cirrus_vga_enabled) { |
---|
701 | snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_CIRRUS_FILENAME); |
---|
702 | } else { |
---|
703 | snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_FILENAME); |
---|
704 | } |
---|
705 | ret = load_image(buf, phys_ram_base + vga_bios_offset); |
---|
706 | #endif /* !NOBIOS */ |
---|
707 | |
---|
708 | /* setup basic memory access */ |
---|
709 | #ifndef CONFIG_DM /* HVM domain owns memory */ |
---|
710 | cpu_register_physical_memory(0xc0000, 0x10000, |
---|
711 | vga_bios_offset | IO_MEM_ROM); |
---|
712 | #endif |
---|
713 | |
---|
714 | #ifndef NOBIOS |
---|
715 | /* map the last 128KB of the BIOS in ISA space */ |
---|
716 | isa_bios_size = bios_size; |
---|
717 | if (isa_bios_size > (128 * 1024)) |
---|
718 | isa_bios_size = 128 * 1024; |
---|
719 | cpu_register_physical_memory(0xd0000, (192 * 1024) - isa_bios_size, |
---|
720 | IO_MEM_UNASSIGNED); |
---|
721 | cpu_register_physical_memory(0x100000 - isa_bios_size, |
---|
722 | isa_bios_size, |
---|
723 | (bios_offset + bios_size - isa_bios_size) | IO_MEM_ROM); |
---|
724 | /* map all the bios at the top of memory */ |
---|
725 | cpu_register_physical_memory((uint32_t)(-bios_size), |
---|
726 | bios_size, bios_offset | IO_MEM_ROM); |
---|
727 | #endif |
---|
728 | |
---|
729 | bochs_bios_init(); |
---|
730 | |
---|
731 | #ifndef CONFIG_DM |
---|
732 | if (linux_boot) { |
---|
733 | uint8_t bootsect[512]; |
---|
734 | uint8_t old_bootsect[512]; |
---|
735 | |
---|
736 | if (bs_table[0] == NULL) { |
---|
737 | fprintf(stderr, "A disk image must be given for 'hda' when booting a Linux kernel\n"); |
---|
738 | exit(1); |
---|
739 | } |
---|
740 | snprintf(buf, sizeof(buf), "%s/%s", bios_dir, LINUX_BOOT_FILENAME); |
---|
741 | ret = load_image(buf, bootsect); |
---|
742 | if (ret != sizeof(bootsect)) { |
---|
743 | fprintf(stderr, "qemu: could not load linux boot sector '%s'\n", |
---|
744 | buf); |
---|
745 | exit(1); |
---|
746 | } |
---|
747 | |
---|
748 | if (bdrv_read(bs_table[0], 0, old_bootsect, 1) >= 0) { |
---|
749 | /* copy the MSDOS partition table */ |
---|
750 | memcpy(bootsect + 0x1be, old_bootsect + 0x1be, 0x40); |
---|
751 | } |
---|
752 | |
---|
753 | bdrv_set_boot_sector(bs_table[0], bootsect, sizeof(bootsect)); |
---|
754 | |
---|
755 | /* now we can load the kernel */ |
---|
756 | ret = load_kernel(kernel_filename, |
---|
757 | phys_ram_base + KERNEL_LOAD_ADDR, |
---|
758 | phys_ram_base + KERNEL_PARAMS_ADDR); |
---|
759 | if (ret < 0) { |
---|
760 | fprintf(stderr, "qemu: could not load kernel '%s'\n", |
---|
761 | kernel_filename); |
---|
762 | exit(1); |
---|
763 | } |
---|
764 | |
---|
765 | /* load initrd */ |
---|
766 | initrd_size = 0; |
---|
767 | if (initrd_filename) { |
---|
768 | initrd_size = load_image(initrd_filename, phys_ram_base + INITRD_LOAD_ADDR); |
---|
769 | if (initrd_size < 0) { |
---|
770 | fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", |
---|
771 | initrd_filename); |
---|
772 | exit(1); |
---|
773 | } |
---|
774 | } |
---|
775 | if (initrd_size > 0) { |
---|
776 | stl_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x218, INITRD_LOAD_ADDR); |
---|
777 | stl_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x21c, initrd_size); |
---|
778 | } |
---|
779 | pstrcpy(phys_ram_base + KERNEL_CMDLINE_ADDR, 4096, |
---|
780 | kernel_cmdline); |
---|
781 | stw_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x20, 0xA33F); |
---|
782 | stw_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x22, |
---|
783 | KERNEL_CMDLINE_ADDR - KERNEL_PARAMS_ADDR); |
---|
784 | /* loader type */ |
---|
785 | stw_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x210, 0x01); |
---|
786 | } |
---|
787 | #endif /* !CONFIG_DM */ |
---|
788 | |
---|
789 | if (pci_enabled) { |
---|
790 | pci_bus = i440fx_init(); |
---|
791 | piix3_devfn = piix3_init(pci_bus); |
---|
792 | } else { |
---|
793 | pci_bus = NULL; |
---|
794 | } |
---|
795 | |
---|
796 | /* init basic PC hardware */ |
---|
797 | register_ioport_write(0x80, 1, 1, ioport80_write, NULL); |
---|
798 | |
---|
799 | register_ioport_write(0xf0, 1, 1, ioportF0_write, NULL); |
---|
800 | |
---|
801 | if (cirrus_vga_enabled) { |
---|
802 | if (pci_enabled) { |
---|
803 | pci_cirrus_vga_init(pci_bus, |
---|
804 | ds, NULL, ram_size, |
---|
805 | vga_ram_size); |
---|
806 | } else { |
---|
807 | isa_cirrus_vga_init(ds, NULL, ram_size, |
---|
808 | vga_ram_size); |
---|
809 | } |
---|
810 | } else { |
---|
811 | vga_initialize(pci_bus, ds, NULL, ram_size, |
---|
812 | vga_ram_size, 0, 0); |
---|
813 | } |
---|
814 | |
---|
815 | rtc_state = rtc_init(0x70, 8); |
---|
816 | |
---|
817 | register_ioport_read(0x92, 1, 1, ioport92_read, NULL); |
---|
818 | register_ioport_write(0x92, 1, 1, ioport92_write, NULL); |
---|
819 | |
---|
820 | #ifndef CONFIG_DM |
---|
821 | if (pci_enabled) { |
---|
822 | ioapic = ioapic_init(); |
---|
823 | } |
---|
824 | #endif /* !CONFIG_DM */ |
---|
825 | isa_pic = pic_init(pic_irq_request, first_cpu); |
---|
826 | #ifndef CONFIG_DM |
---|
827 | pit = pit_init(0x40, 0); |
---|
828 | pcspk_init(pit); |
---|
829 | #endif /* !CONFIG_DM */ |
---|
830 | #ifndef CONFIG_DM |
---|
831 | if (pci_enabled) { |
---|
832 | pic_set_alt_irq_func(isa_pic, ioapic_set_irq, ioapic); |
---|
833 | } |
---|
834 | #endif /* !CONFIG_DM */ |
---|
835 | |
---|
836 | if (pci_enabled) |
---|
837 | pci_xen_platform_init(pci_bus); |
---|
838 | |
---|
839 | for(i = 0; i < MAX_SERIAL_PORTS; i++) { |
---|
840 | if (serial_hds[i]) { |
---|
841 | serial_init(&pic_set_irq_new, isa_pic, |
---|
842 | serial_io[i], serial_irq[i], serial_hds[i]); |
---|
843 | } |
---|
844 | } |
---|
845 | |
---|
846 | for(i = 0; i < MAX_PARALLEL_PORTS; i++) { |
---|
847 | if (parallel_hds[i]) { |
---|
848 | parallel_init(parallel_io[i], parallel_irq[i], parallel_hds[i]); |
---|
849 | } |
---|
850 | } |
---|
851 | |
---|
852 | for(i = 0; i < nb_nics; i++) { |
---|
853 | nd = &nd_table[i]; |
---|
854 | if (!nd->model) { |
---|
855 | if (pci_enabled) { |
---|
856 | nd->model = "ne2k_pci"; |
---|
857 | } else { |
---|
858 | nd->model = "ne2k_isa"; |
---|
859 | } |
---|
860 | } |
---|
861 | if (strcmp(nd->model, "ne2k_isa") == 0) { |
---|
862 | pc_init_ne2k_isa(nd); |
---|
863 | } else if (pci_enabled) { |
---|
864 | pci_nic_init(pci_bus, nd); |
---|
865 | } else { |
---|
866 | fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd->model); |
---|
867 | exit(1); |
---|
868 | } |
---|
869 | } |
---|
870 | |
---|
871 | if (pci_enabled) { |
---|
872 | pci_piix3_ide_init(pci_bus, bs_table, piix3_devfn + 1); |
---|
873 | } else { |
---|
874 | for(i = 0; i < 2; i++) { |
---|
875 | isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i], |
---|
876 | bs_table[2 * i], bs_table[2 * i + 1]); |
---|
877 | } |
---|
878 | } |
---|
879 | |
---|
880 | if (has_tpm_device()) |
---|
881 | tpm_tis_init(&pic_set_irq_new, isa_pic, 11); |
---|
882 | |
---|
883 | kbd_init(); |
---|
884 | DMA_init(0); |
---|
885 | #ifdef HAS_AUDIO |
---|
886 | audio_init(pci_enabled ? pci_bus : NULL); |
---|
887 | #endif |
---|
888 | |
---|
889 | floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table); |
---|
890 | |
---|
891 | cmos_init(ram_size, boot_device, bs_table, timeoffset); |
---|
892 | |
---|
893 | /* using PIIX4 acpi model */ |
---|
894 | if (pci_enabled && acpi_enabled) |
---|
895 | pci_piix4_acpi_init(pci_bus, piix3_devfn + 2); |
---|
896 | |
---|
897 | if (pci_enabled && usb_enabled) { |
---|
898 | usb_uhci_init(pci_bus, piix3_devfn + (acpi_enabled ? 3 : 2)); |
---|
899 | } |
---|
900 | |
---|
901 | #ifndef CONFIG_DM |
---|
902 | if (pci_enabled && acpi_enabled) { |
---|
903 | piix4_pm_init(pci_bus, piix3_devfn + 3); |
---|
904 | } |
---|
905 | |
---|
906 | #if 0 |
---|
907 | /* ??? Need to figure out some way for the user to |
---|
908 | specify SCSI devices. */ |
---|
909 | if (pci_enabled) { |
---|
910 | void *scsi; |
---|
911 | BlockDriverState *bdrv; |
---|
912 | |
---|
913 | scsi = lsi_scsi_init(pci_bus, -1); |
---|
914 | bdrv = bdrv_new("scsidisk"); |
---|
915 | bdrv_open(bdrv, "scsi_disk.img", 0); |
---|
916 | lsi_scsi_attach(scsi, bdrv, -1); |
---|
917 | bdrv = bdrv_new("scsicd"); |
---|
918 | bdrv_open(bdrv, "scsi_cd.iso", 0); |
---|
919 | bdrv_set_type_hint(bdrv, BDRV_TYPE_CDROM); |
---|
920 | lsi_scsi_attach(scsi, bdrv, -1); |
---|
921 | } |
---|
922 | #endif |
---|
923 | #else |
---|
924 | if (pci_enabled) { |
---|
925 | void *scsi = NULL; |
---|
926 | for (i = 0; i < MAX_SCSI_DISKS ; i++) { |
---|
927 | if (!bs_table[i + MAX_DISKS]) |
---|
928 | continue; |
---|
929 | if (!scsi) |
---|
930 | scsi = lsi_scsi_init(pci_bus, -1); |
---|
931 | lsi_scsi_attach(scsi, bs_table[i + MAX_DISKS], -1); |
---|
932 | } |
---|
933 | } |
---|
934 | #endif /* !CONFIG_DM */ |
---|
935 | /* must be done after all PCI devices are instanciated */ |
---|
936 | /* XXX: should be done in the Bochs BIOS */ |
---|
937 | if (pci_enabled) { |
---|
938 | pci_bios_init(); |
---|
939 | #ifndef CONFIG_DM |
---|
940 | if (acpi_enabled) |
---|
941 | acpi_bios_init(); |
---|
942 | #endif /* !CONFIG_DM */ |
---|
943 | } |
---|
944 | } |
---|
945 | |
---|
946 | static void pc_init_pci(uint64_t ram_size, int vga_ram_size, char *boot_device, |
---|
947 | DisplayState *ds, const char **fd_filename, |
---|
948 | int snapshot, |
---|
949 | const char *kernel_filename, |
---|
950 | const char *kernel_cmdline, |
---|
951 | const char *initrd_filename, |
---|
952 | time_t timeoffset) |
---|
953 | { |
---|
954 | pc_init1(ram_size, vga_ram_size, boot_device, |
---|
955 | ds, fd_filename, snapshot, |
---|
956 | kernel_filename, kernel_cmdline, |
---|
957 | initrd_filename, timeoffset, 1); |
---|
958 | } |
---|
959 | |
---|
960 | static void pc_init_isa(uint64_t ram_size, int vga_ram_size, char *boot_device, |
---|
961 | DisplayState *ds, const char **fd_filename, |
---|
962 | int snapshot, |
---|
963 | const char *kernel_filename, |
---|
964 | const char *kernel_cmdline, |
---|
965 | const char *initrd_filename, |
---|
966 | time_t timeoffset) |
---|
967 | { |
---|
968 | pc_init1(ram_size, vga_ram_size, boot_device, |
---|
969 | ds, fd_filename, snapshot, |
---|
970 | kernel_filename, kernel_cmdline, |
---|
971 | initrd_filename, timeoffset, 0); |
---|
972 | } |
---|
973 | |
---|
974 | QEMUMachine pc_machine = { |
---|
975 | "pc", |
---|
976 | "Standard PC", |
---|
977 | pc_init_pci, |
---|
978 | }; |
---|
979 | |
---|
980 | QEMUMachine isapc_machine = { |
---|
981 | "isapc", |
---|
982 | "ISA-only PC", |
---|
983 | pc_init_isa, |
---|
984 | }; |
---|