Commit 330d0414a5968d36edb635c63a729ffa55520e76
1 parent
3802ce26
keyboard emulation - accepts to boot with Bochs BIOS and LGPL'ed VGA BIOS
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@338 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
605 additions
and
92 deletions
vl.c
... | ... | @@ -52,10 +52,28 @@ |
52 | 52 | |
53 | 53 | #define DEBUG_LOGFILE "/tmp/vl.log" |
54 | 54 | #define DEFAULT_NETWORK_SCRIPT "/etc/vl-ifup" |
55 | +#define BIOS_FILENAME "bios.bin" | |
56 | +#define VGABIOS_FILENAME "vgabios.bin" | |
55 | 57 | |
56 | 58 | //#define DEBUG_UNUSED_IOPORT |
59 | + | |
57 | 60 | //#define DEBUG_IRQ_LATENCY |
58 | 61 | |
62 | +/* output Bochs bios info messages */ | |
63 | +//#define DEBUG_BIOS | |
64 | + | |
65 | +/* debug IDE devices */ | |
66 | +//#define DEBUG_IDE | |
67 | + | |
68 | +/* debug PIC */ | |
69 | +//#define DEBUG_PIC | |
70 | + | |
71 | +/* debug NE2000 card */ | |
72 | +//#define DEBUG_NE2000 | |
73 | + | |
74 | +/* debug PC keyboard */ | |
75 | +//#define DEBUG_KBD | |
76 | + | |
59 | 77 | #define PHYS_RAM_BASE 0xac000000 |
60 | 78 | #define PHYS_RAM_MAX_SIZE (256 * 1024 * 1024) |
61 | 79 | |
... | ... | @@ -185,6 +203,7 @@ typedef uint32_t (IOPortReadFunc)(CPUX86State *env, uint32_t address); |
185 | 203 | |
186 | 204 | #define MAX_IOPORTS 4096 |
187 | 205 | |
206 | +static const char *interp_prefix = CONFIG_QEMU_PREFIX; | |
188 | 207 | char phys_ram_file[1024]; |
189 | 208 | CPUX86State *global_env; |
190 | 209 | CPUX86State *cpu_single_env; |
... | ... | @@ -216,15 +235,15 @@ void default_ioport_writeb(CPUX86State *env, uint32_t address, uint32_t data) |
216 | 235 | uint32_t default_ioport_readw(CPUX86State *env, uint32_t address) |
217 | 236 | { |
218 | 237 | uint32_t data; |
219 | - data = ioport_read_table[0][address](env, address); | |
220 | - data |= ioport_read_table[0][address + 1](env, address + 1) << 8; | |
238 | + data = ioport_read_table[0][address & (MAX_IOPORTS - 1)](env, address); | |
239 | + data |= ioport_read_table[0][(address + 1) & (MAX_IOPORTS - 1)](env, address + 1) << 8; | |
221 | 240 | return data; |
222 | 241 | } |
223 | 242 | |
224 | 243 | void default_ioport_writew(CPUX86State *env, uint32_t address, uint32_t data) |
225 | 244 | { |
226 | - ioport_write_table[0][address](env, address, data & 0xff); | |
227 | - ioport_write_table[0][address + 1](env, address + 1, (data >> 8) & 0xff); | |
245 | + ioport_write_table[0][address & (MAX_IOPORTS - 1)](env, address, data & 0xff); | |
246 | + ioport_write_table[0][(address + 1) & (MAX_IOPORTS - 1)](env, address + 1, (data >> 8) & 0xff); | |
228 | 247 | } |
229 | 248 | |
230 | 249 | uint32_t default_ioport_readl(CPUX86State *env, uint32_t address) |
... | ... | @@ -516,6 +535,7 @@ void cmos_init(void) |
516 | 535 | { |
517 | 536 | struct tm *tm; |
518 | 537 | time_t ti; |
538 | + int val; | |
519 | 539 | |
520 | 540 | ti = time(NULL); |
521 | 541 | tm = gmtime(&ti); |
... | ... | @@ -532,8 +552,27 @@ void cmos_init(void) |
532 | 552 | cmos_data[RTC_REG_C] = 0x00; |
533 | 553 | cmos_data[RTC_REG_D] = 0x80; |
534 | 554 | |
555 | + /* various important CMOS locations needed by PC/Bochs bios */ | |
556 | + | |
535 | 557 | cmos_data[REG_EQUIPMENT_BYTE] = 0x02; /* FPU is there */ |
536 | 558 | |
559 | + /* memory size */ | |
560 | + val = (phys_ram_size / 1024) - 1024; | |
561 | + if (val > 65535) | |
562 | + val = 65535; | |
563 | + cmos_data[0x17] = val; | |
564 | + cmos_data[0x18] = val >> 8; | |
565 | + cmos_data[0x30] = val; | |
566 | + cmos_data[0x31] = val >> 8; | |
567 | + | |
568 | + val = (phys_ram_size / 65536) - ((16 * 1024 * 1024) / 65536); | |
569 | + if (val > 65535) | |
570 | + val = 65535; | |
571 | + cmos_data[0x34] = val; | |
572 | + cmos_data[0x35] = val >> 8; | |
573 | + | |
574 | + cmos_data[0x3d] = 0x02; /* hard drive boot */ | |
575 | + | |
537 | 576 | register_ioport_write(0x70, 2, cmos_ioport_write, 1); |
538 | 577 | register_ioport_read(0x70, 2, cmos_ioport_read, 1); |
539 | 578 | } |
... | ... | @@ -541,8 +580,6 @@ void cmos_init(void) |
541 | 580 | /***********************************************************/ |
542 | 581 | /* 8259 pic emulation */ |
543 | 582 | |
544 | -//#define DEBUG_PIC | |
545 | - | |
546 | 583 | typedef struct PicState { |
547 | 584 | uint8_t last_irr; /* edge detection */ |
548 | 585 | uint8_t irr; /* interrupt request register */ |
... | ... | @@ -1360,8 +1397,6 @@ void serial_init(void) |
1360 | 1397 | /***********************************************************/ |
1361 | 1398 | /* ne2000 emulation */ |
1362 | 1399 | |
1363 | -//#define DEBUG_NE2000 | |
1364 | - | |
1365 | 1400 | #define NE2000_IOPORT 0x300 |
1366 | 1401 | #define NE2000_IRQ 9 |
1367 | 1402 | |
... | ... | @@ -1827,8 +1862,6 @@ void ne2000_init(void) |
1827 | 1862 | /***********************************************************/ |
1828 | 1863 | /* ide emulation */ |
1829 | 1864 | |
1830 | -//#define DEBUG_IDE | |
1831 | - | |
1832 | 1865 | /* Bits of HD_STATUS */ |
1833 | 1866 | #define ERR_STAT 0x01 |
1834 | 1867 | #define INDEX_STAT 0x02 |
... | ... | @@ -2352,16 +2385,50 @@ uint32_t ide_status_read(CPUX86State *env, uint32_t addr) |
2352 | 2385 | int ret; |
2353 | 2386 | ret = s->status; |
2354 | 2387 | #ifdef DEBUG_IDE |
2355 | - printf("ide: read addr=0x%x val=%02x\n", addr, ret); | |
2388 | + printf("ide: read status val=%02x\n", ret); | |
2356 | 2389 | #endif |
2357 | 2390 | return ret; |
2358 | 2391 | } |
2359 | 2392 | |
2360 | 2393 | void ide_cmd_write(CPUX86State *env, uint32_t addr, uint32_t val) |
2361 | 2394 | { |
2362 | - IDEState *s = &ide_state[0]; | |
2395 | + IDEState *s; | |
2396 | + int i; | |
2397 | + | |
2398 | +#ifdef DEBUG_IDE | |
2399 | + printf("ide: write control val=%02x\n", val); | |
2400 | +#endif | |
2363 | 2401 | /* common for both drives */ |
2364 | - s->cmd = val; | |
2402 | + if (!(ide_state[0].cmd & IDE_CMD_RESET) && | |
2403 | + (val & IDE_CMD_RESET)) { | |
2404 | + /* reset low to high */ | |
2405 | + for(i = 0;i < 2; i++) { | |
2406 | + s = &ide_state[i]; | |
2407 | + s->status = BUSY_STAT | SEEK_STAT; | |
2408 | + s->error = 0x01; | |
2409 | + } | |
2410 | + } else if ((ide_state[0].cmd & IDE_CMD_RESET) && | |
2411 | + !(val & IDE_CMD_RESET)) { | |
2412 | + /* high to low */ | |
2413 | + for(i = 0;i < 2; i++) { | |
2414 | + s = &ide_state[i]; | |
2415 | + s->status = READY_STAT; | |
2416 | + /* set hard disk drive ID */ | |
2417 | + s->select &= 0xf0; /* clear head */ | |
2418 | + s->nsector = 1; | |
2419 | + s->sector = 1; | |
2420 | + if (s->nb_sectors == 0) { | |
2421 | + /* no disk present */ | |
2422 | + s->lcyl = 0x12; | |
2423 | + s->hcyl = 0x34; | |
2424 | + } else { | |
2425 | + s->lcyl = 0; | |
2426 | + s->hcyl = 0; | |
2427 | + } | |
2428 | + } | |
2429 | + } | |
2430 | + | |
2431 | + ide_state[0].cmd = val; | |
2365 | 2432 | } |
2366 | 2433 | |
2367 | 2434 | void ide_data_writew(CPUX86State *env, uint32_t addr, uint32_t val) |
... | ... | @@ -2439,14 +2506,17 @@ void ide_init(void) |
2439 | 2506 | s->bs = bs_table[i]; |
2440 | 2507 | if (s->bs) { |
2441 | 2508 | bdrv_get_geometry(s->bs, &nb_sectors); |
2442 | - cylinders = nb_sectors / (16 * 63); | |
2443 | - if (cylinders > 16383) | |
2444 | - cylinders = 16383; | |
2445 | - else if (cylinders < 2) | |
2446 | - cylinders = 2; | |
2447 | - s->cylinders = cylinders; | |
2448 | - s->heads = 16; | |
2449 | - s->sectors = 63; | |
2509 | + if (s->cylinders == 0) { | |
2510 | + /* if no geometry, use a LBA compatible one */ | |
2511 | + cylinders = nb_sectors / (16 * 63); | |
2512 | + if (cylinders > 16383) | |
2513 | + cylinders = 16383; | |
2514 | + else if (cylinders < 2) | |
2515 | + cylinders = 2; | |
2516 | + s->cylinders = cylinders; | |
2517 | + s->heads = 16; | |
2518 | + s->sectors = 63; | |
2519 | + } | |
2450 | 2520 | s->nb_sectors = nb_sectors; |
2451 | 2521 | } |
2452 | 2522 | s->irq = 14; |
... | ... | @@ -2465,34 +2535,402 @@ void ide_init(void) |
2465 | 2535 | } |
2466 | 2536 | |
2467 | 2537 | /***********************************************************/ |
2468 | -/* simulate reset (stop qemu) */ | |
2538 | +/* keyboard emulation */ | |
2539 | + | |
2540 | +/* Keyboard Controller Commands */ | |
2541 | +#define KBD_CCMD_READ_MODE 0x20 /* Read mode bits */ | |
2542 | +#define KBD_CCMD_WRITE_MODE 0x60 /* Write mode bits */ | |
2543 | +#define KBD_CCMD_GET_VERSION 0xA1 /* Get controller version */ | |
2544 | +#define KBD_CCMD_MOUSE_DISABLE 0xA7 /* Disable mouse interface */ | |
2545 | +#define KBD_CCMD_MOUSE_ENABLE 0xA8 /* Enable mouse interface */ | |
2546 | +#define KBD_CCMD_TEST_MOUSE 0xA9 /* Mouse interface test */ | |
2547 | +#define KBD_CCMD_SELF_TEST 0xAA /* Controller self test */ | |
2548 | +#define KBD_CCMD_KBD_TEST 0xAB /* Keyboard interface test */ | |
2549 | +#define KBD_CCMD_KBD_DISABLE 0xAD /* Keyboard interface disable */ | |
2550 | +#define KBD_CCMD_KBD_ENABLE 0xAE /* Keyboard interface enable */ | |
2551 | +#define KBD_CCMD_READ_INPORT 0xC0 /* read input port */ | |
2552 | +#define KBD_CCMD_READ_OUTPORT 0xD0 /* read output port */ | |
2553 | +#define KBD_CCMD_WRITE_OUTPORT 0xD1 /* write output port */ | |
2554 | +#define KBD_CCMD_WRITE_OBUF 0xD2 | |
2555 | +#define KBD_CCMD_WRITE_AUX_OBUF 0xD3 /* Write to output buffer as if | |
2556 | + initiated by the auxiliary device */ | |
2557 | +#define KBD_CCMD_WRITE_MOUSE 0xD4 /* Write the following byte to the mouse */ | |
2558 | +#define KBD_CCMD_ENABLE_A20 0xDD | |
2559 | +#define KBD_CCMD_DISABLE_A20 0xDF | |
2560 | +#define KBD_CCMD_RESET 0xFE | |
2561 | + | |
2562 | +/* Keyboard Commands */ | |
2563 | +#define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */ | |
2564 | +#define KBD_CMD_ECHO 0xEE | |
2565 | +#define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */ | |
2566 | +#define KBD_CMD_ENABLE 0xF4 /* Enable scanning */ | |
2567 | +#define KBD_CMD_RESET_DISABLE 0xF5 /* reset and disable scanning */ | |
2568 | +#define KBD_CMD_RESET_ENABLE 0xF6 /* reset and enable scanning */ | |
2569 | +#define KBD_CMD_RESET 0xFF /* Reset */ | |
2570 | + | |
2571 | +/* Keyboard Replies */ | |
2572 | +#define KBD_REPLY_POR 0xAA /* Power on reset */ | |
2573 | +#define KBD_REPLY_ACK 0xFA /* Command ACK */ | |
2574 | +#define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */ | |
2575 | + | |
2576 | +/* Status Register Bits */ | |
2577 | +#define KBD_STAT_OBF 0x01 /* Keyboard output buffer full */ | |
2578 | +#define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */ | |
2579 | +#define KBD_STAT_SELFTEST 0x04 /* Self test successful */ | |
2580 | +#define KBD_STAT_CMD 0x08 /* Last write was a command write (0=data) */ | |
2581 | +#define KBD_STAT_UNLOCKED 0x10 /* Zero if keyboard locked */ | |
2582 | +#define KBD_STAT_MOUSE_OBF 0x20 /* Mouse output buffer full */ | |
2583 | +#define KBD_STAT_GTO 0x40 /* General receive/xmit timeout */ | |
2584 | +#define KBD_STAT_PERR 0x80 /* Parity error */ | |
2585 | + | |
2586 | +/* Controller Mode Register Bits */ | |
2587 | +#define KBD_MODE_KBD_INT 0x01 /* Keyboard data generate IRQ1 */ | |
2588 | +#define KBD_MODE_MOUSE_INT 0x02 /* Mouse data generate IRQ12 */ | |
2589 | +#define KBD_MODE_SYS 0x04 /* The system flag (?) */ | |
2590 | +#define KBD_MODE_NO_KEYLOCK 0x08 /* The keylock doesn't affect the keyboard if set */ | |
2591 | +#define KBD_MODE_DISABLE_KBD 0x10 /* Disable keyboard interface */ | |
2592 | +#define KBD_MODE_DISABLE_MOUSE 0x20 /* Disable mouse interface */ | |
2593 | +#define KBD_MODE_KCC 0x40 /* Scan code conversion to PC format */ | |
2594 | +#define KBD_MODE_RFU 0x80 | |
2595 | + | |
2596 | +/* Mouse Commands */ | |
2597 | +#define AUX_SET_RES 0xE8 /* Set resolution */ | |
2598 | +#define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */ | |
2599 | +#define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */ | |
2600 | +#define AUX_GET_SCALE 0xE9 /* Get scaling factor */ | |
2601 | +#define AUX_SET_STREAM 0xEA /* Set stream mode */ | |
2602 | +#define AUX_SET_SAMPLE 0xF3 /* Set sample rate */ | |
2603 | +#define AUX_ENABLE_DEV 0xF4 /* Enable aux device */ | |
2604 | +#define AUX_DISABLE_DEV 0xF5 /* Disable aux device */ | |
2605 | +#define AUX_RESET 0xFF /* Reset aux device */ | |
2606 | +#define AUX_ACK 0xFA /* Command byte ACK. */ | |
2607 | + | |
2608 | +#define KBD_QUEUE_SIZE 64 | |
2609 | + | |
2610 | +typedef struct { | |
2611 | + uint8_t data[KBD_QUEUE_SIZE]; | |
2612 | + int rptr, wptr, count; | |
2613 | +} KBDQueue; | |
2614 | + | |
2615 | +enum KBDWriteState { | |
2616 | + KBD_STATE_CMD = 0, | |
2617 | + KBD_STATE_LED, | |
2618 | +}; | |
2469 | 2619 | |
2620 | +typedef struct KBDState { | |
2621 | + KBDQueue queues[2]; | |
2622 | + uint8_t write_cmd; /* if non zero, write data to port 60 is expected */ | |
2623 | + uint8_t status; | |
2624 | + uint8_t mode; | |
2625 | + int kbd_write_cmd; | |
2626 | + int scan_enabled; | |
2627 | +} KBDState; | |
2628 | + | |
2629 | +KBDState kbd_state; | |
2470 | 2630 | int reset_requested; |
2631 | +int a20_enabled; | |
2632 | + | |
2633 | +static void kbd_update_irq(KBDState *s) | |
2634 | +{ | |
2635 | + int level; | |
2636 | + | |
2637 | + level = ((s->status & KBD_STAT_OBF) && (s->mode & KBD_MODE_KBD_INT)); | |
2638 | + pic_set_irq(1, level); | |
2639 | + | |
2640 | + level = ((s->status & KBD_STAT_MOUSE_OBF) && (s->mode & KBD_MODE_MOUSE_INT)); | |
2641 | + pic_set_irq(12, level); | |
2642 | +} | |
2643 | + | |
2644 | +static void kbd_queue(KBDState *s, int b, int aux) | |
2645 | +{ | |
2646 | + KBDQueue *q = &kbd_state.queues[aux]; | |
2647 | + | |
2648 | + if (q->count >= KBD_QUEUE_SIZE) | |
2649 | + return; | |
2650 | + q->data[q->wptr] = b; | |
2651 | + if (++q->wptr == KBD_QUEUE_SIZE) | |
2652 | + q->wptr = 0; | |
2653 | + q->count++; | |
2654 | + s->status |= KBD_STAT_OBF; | |
2655 | + if (aux) | |
2656 | + s->status |= KBD_STAT_MOUSE_OBF; | |
2657 | + kbd_update_irq(s); | |
2658 | +} | |
2471 | 2659 | |
2472 | 2660 | uint32_t kbd_read_status(CPUX86State *env, uint32_t addr) |
2473 | 2661 | { |
2474 | - return 0; | |
2662 | + KBDState *s = &kbd_state; | |
2663 | + int val; | |
2664 | + val = s->status; | |
2665 | +#if defined(DEBUG_KBD) && 0 | |
2666 | + printf("kbd: read status=0x%02x\n", val); | |
2667 | +#endif | |
2668 | + return val; | |
2475 | 2669 | } |
2476 | 2670 | |
2477 | 2671 | void kbd_write_command(CPUX86State *env, uint32_t addr, uint32_t val) |
2478 | 2672 | { |
2673 | + KBDState *s = &kbd_state; | |
2674 | + | |
2675 | +#ifdef DEBUG_KBD | |
2676 | + printf("kbd: write cmd=0x%02x\n", val); | |
2677 | +#endif | |
2479 | 2678 | switch(val) { |
2480 | - case 0xfe: | |
2679 | + case KBD_CCMD_READ_MODE: | |
2680 | + kbd_queue(s, s->mode, 0); | |
2681 | + break; | |
2682 | + case KBD_CCMD_WRITE_MODE: | |
2683 | + case KBD_CCMD_WRITE_OBUF: | |
2684 | + case KBD_CCMD_WRITE_AUX_OBUF: | |
2685 | + case KBD_CCMD_WRITE_MOUSE: | |
2686 | + case KBD_CCMD_WRITE_OUTPORT: | |
2687 | + s->write_cmd = val; | |
2688 | + break; | |
2689 | + case KBD_CCMD_MOUSE_DISABLE: | |
2690 | + s->mode |= KBD_MODE_DISABLE_MOUSE; | |
2691 | + break; | |
2692 | + case KBD_CCMD_MOUSE_ENABLE: | |
2693 | + s->mode &= ~KBD_MODE_DISABLE_MOUSE; | |
2694 | + break; | |
2695 | + case KBD_CCMD_TEST_MOUSE: | |
2696 | + kbd_queue(s, 0x00, 0); | |
2697 | + break; | |
2698 | + case KBD_CCMD_SELF_TEST: | |
2699 | + s->status |= KBD_STAT_SELFTEST; | |
2700 | + kbd_queue(s, 0x55, 0); | |
2701 | + break; | |
2702 | + case KBD_CCMD_KBD_TEST: | |
2703 | + kbd_queue(s, 0x00, 0); | |
2704 | + break; | |
2705 | + case KBD_CCMD_KBD_DISABLE: | |
2706 | + s->mode |= KBD_MODE_DISABLE_KBD; | |
2707 | + break; | |
2708 | + case KBD_CCMD_KBD_ENABLE: | |
2709 | + s->mode &= ~KBD_MODE_DISABLE_KBD; | |
2710 | + break; | |
2711 | + case KBD_CCMD_READ_INPORT: | |
2712 | + kbd_queue(s, 0x00, 0); | |
2713 | + break; | |
2714 | + case KBD_CCMD_READ_OUTPORT: | |
2715 | + /* XXX: check that */ | |
2716 | + val = 0x01 | (a20_enabled << 1); | |
2717 | + if (s->status & KBD_STAT_OBF) | |
2718 | + val |= 0x10; | |
2719 | + if (s->status & KBD_STAT_MOUSE_OBF) | |
2720 | + val |= 0x20; | |
2721 | + kbd_queue(s, val, 0); | |
2722 | + break; | |
2723 | + case KBD_CCMD_ENABLE_A20: | |
2724 | + a20_enabled = 1; | |
2725 | + break; | |
2726 | + case KBD_CCMD_DISABLE_A20: | |
2727 | + a20_enabled = 0; | |
2728 | + break; | |
2729 | + case KBD_CCMD_RESET: | |
2481 | 2730 | reset_requested = 1; |
2482 | 2731 | cpu_x86_interrupt(global_env, CPU_INTERRUPT_EXIT); |
2483 | 2732 | break; |
2484 | 2733 | default: |
2734 | + fprintf(stderr, "vl: unsupported keyboard cmd=0x%02x\n", val); | |
2735 | + break; | |
2736 | + } | |
2737 | +} | |
2738 | + | |
2739 | +uint32_t kbd_read_data(CPUX86State *env, uint32_t addr) | |
2740 | +{ | |
2741 | + KBDState *s = &kbd_state; | |
2742 | + KBDQueue *q; | |
2743 | + int val; | |
2744 | + | |
2745 | + q = &s->queues[1]; /* first check AUX data */ | |
2746 | + if (q->count == 0) | |
2747 | + q = &s->queues[0]; /* then check KBD data */ | |
2748 | + if (q->count == 0) { | |
2749 | + /* XXX: return something else ? */ | |
2750 | + val = 0; | |
2751 | + } else { | |
2752 | + val = q->data[q->rptr]; | |
2753 | + if (++q->rptr == KBD_QUEUE_SIZE) | |
2754 | + q->rptr = 0; | |
2755 | + q->count--; | |
2756 | + } | |
2757 | + if (s->queues[1].count == 0) { | |
2758 | + s->status &= ~KBD_STAT_MOUSE_OBF; | |
2759 | + if (s->queues[0].count == 0) | |
2760 | + s->status &= ~KBD_STAT_OBF; | |
2761 | + kbd_update_irq(s); | |
2762 | + } | |
2763 | + | |
2764 | +#ifdef DEBUG_KBD | |
2765 | + printf("kbd: read data=0x%02x\n", val); | |
2766 | +#endif | |
2767 | + return val; | |
2768 | +} | |
2769 | + | |
2770 | +static void kbd_reset_keyboard(KBDState *s) | |
2771 | +{ | |
2772 | + s->scan_enabled = 1; | |
2773 | +} | |
2774 | + | |
2775 | +static void kbd_write_keyboard(KBDState *s, int val) | |
2776 | +{ | |
2777 | + switch(s->kbd_write_cmd) { | |
2778 | + default: | |
2779 | + case -1: | |
2780 | + switch(val) { | |
2781 | + case 0x00: | |
2782 | + kbd_queue(s, KBD_REPLY_ACK, 0); | |
2783 | + break; | |
2784 | + case 0x05: | |
2785 | + kbd_queue(s, KBD_REPLY_RESEND, 0); | |
2786 | + break; | |
2787 | + case KBD_CMD_ECHO: | |
2788 | + kbd_queue(s, KBD_CMD_ECHO, 0); | |
2789 | + break; | |
2790 | + case KBD_CMD_ENABLE: | |
2791 | + s->scan_enabled = 1; | |
2792 | + kbd_queue(s, KBD_REPLY_ACK, 0); | |
2793 | + break; | |
2794 | + case KBD_CMD_SET_LEDS: | |
2795 | + case KBD_CMD_SET_RATE: | |
2796 | + s->kbd_write_cmd = val; | |
2797 | + break; | |
2798 | + case KBD_CMD_RESET_DISABLE: | |
2799 | + kbd_reset_keyboard(s); | |
2800 | + s->scan_enabled = 0; | |
2801 | + kbd_queue(s, KBD_REPLY_ACK, 0); | |
2802 | + break; | |
2803 | + case KBD_CMD_RESET_ENABLE: | |
2804 | + kbd_reset_keyboard(s); | |
2805 | + s->scan_enabled = 1; | |
2806 | + kbd_queue(s, KBD_REPLY_ACK, 0); | |
2807 | + break; | |
2808 | + case KBD_CMD_RESET: | |
2809 | + kbd_reset_keyboard(s); | |
2810 | + kbd_queue(s, KBD_REPLY_ACK, 0); | |
2811 | + kbd_queue(s, KBD_REPLY_POR, 0); | |
2812 | + break; | |
2813 | + default: | |
2814 | + kbd_queue(s, KBD_REPLY_ACK, 0); | |
2815 | + break; | |
2816 | + } | |
2817 | + break; | |
2818 | + case KBD_CMD_SET_LEDS: | |
2819 | + kbd_queue(s, KBD_REPLY_ACK, 0); | |
2820 | + break; | |
2821 | + case KBD_CMD_SET_RATE: | |
2822 | + kbd_queue(s, KBD_REPLY_ACK, 0); | |
2823 | + break; | |
2824 | + } | |
2825 | + s->kbd_write_cmd = -1; | |
2826 | +} | |
2827 | + | |
2828 | +void kbd_write_data(CPUX86State *env, uint32_t addr, uint32_t val) | |
2829 | +{ | |
2830 | + KBDState *s = &kbd_state; | |
2831 | + | |
2832 | +#ifdef DEBUG_KBD | |
2833 | + printf("kbd: write data=0x%02x\n", val); | |
2834 | +#endif | |
2835 | + | |
2836 | + switch(s->write_cmd) { | |
2837 | + case 0: | |
2838 | + kbd_write_keyboard(s, val); | |
2839 | + break; | |
2840 | + case KBD_CCMD_WRITE_MODE: | |
2841 | + s->mode = val; | |
2842 | + kbd_update_irq(s); | |
2843 | + break; | |
2844 | + case KBD_CCMD_WRITE_OBUF: | |
2845 | + kbd_queue(s, val, 0); | |
2846 | + break; | |
2847 | + case KBD_CCMD_WRITE_AUX_OBUF: | |
2848 | + kbd_queue(s, val, 1); | |
2849 | + break; | |
2850 | + case KBD_CCMD_WRITE_OUTPORT: | |
2851 | + a20_enabled = (val >> 1) & 1; | |
2852 | + if (!(val & 1)) { | |
2853 | + reset_requested = 1; | |
2854 | + cpu_x86_interrupt(global_env, CPU_INTERRUPT_EXIT); | |
2855 | + } | |
2856 | + break; | |
2857 | + default: | |
2485 | 2858 | break; |
2486 | 2859 | } |
2860 | + s->write_cmd = 0; | |
2861 | +} | |
2862 | + | |
2863 | +void kbd_reset(KBDState *s) | |
2864 | +{ | |
2865 | + KBDQueue *q; | |
2866 | + int i; | |
2867 | + | |
2868 | + s->kbd_write_cmd = -1; | |
2869 | + s->mode = KBD_MODE_KBD_INT | KBD_MODE_MOUSE_INT; | |
2870 | + s->status = KBD_MODE_SYS | KBD_MODE_NO_KEYLOCK; | |
2871 | + for(i = 0; i < 2; i++) { | |
2872 | + q = &s->queues[i]; | |
2873 | + q->rptr = 0; | |
2874 | + q->wptr = 0; | |
2875 | + q->count = 0; | |
2876 | + } | |
2487 | 2877 | } |
2488 | 2878 | |
2489 | 2879 | void kbd_init(void) |
2490 | 2880 | { |
2881 | + kbd_reset(&kbd_state); | |
2882 | + register_ioport_read(0x60, 1, kbd_read_data, 1); | |
2883 | + register_ioport_write(0x60, 1, kbd_write_data, 1); | |
2491 | 2884 | register_ioport_read(0x64, 1, kbd_read_status, 1); |
2492 | 2885 | register_ioport_write(0x64, 1, kbd_write_command, 1); |
2493 | 2886 | } |
2494 | 2887 | |
2495 | 2888 | /***********************************************************/ |
2889 | +/* Bochs BIOS debug ports */ | |
2890 | + | |
2891 | +void bochs_bios_write(CPUX86State *env, uint32_t addr, uint32_t val) | |
2892 | +{ | |
2893 | + switch(addr) { | |
2894 | + /* Bochs BIOS messages */ | |
2895 | + case 0x400: | |
2896 | + case 0x401: | |
2897 | + fprintf(stderr, "BIOS panic at rombios.c, line %d\n", val); | |
2898 | + exit(1); | |
2899 | + case 0x402: | |
2900 | + case 0x403: | |
2901 | +#ifdef DEBUG_BIOS | |
2902 | + fprintf(stderr, "%c", val); | |
2903 | +#endif | |
2904 | + break; | |
2905 | + | |
2906 | + /* LGPL'ed VGA BIOS messages */ | |
2907 | + case 0x501: | |
2908 | + case 0x502: | |
2909 | + fprintf(stderr, "VGA BIOS panic, line %d\n", val); | |
2910 | + exit(1); | |
2911 | + case 0x500: | |
2912 | + case 0x503: | |
2913 | +#ifdef DEBUG_BIOS | |
2914 | + fprintf(stderr, "%c", val); | |
2915 | +#endif | |
2916 | + break; | |
2917 | + } | |
2918 | +} | |
2919 | + | |
2920 | +void bochs_bios_init(void) | |
2921 | +{ | |
2922 | + register_ioport_write(0x400, 1, bochs_bios_write, 2); | |
2923 | + register_ioport_write(0x401, 1, bochs_bios_write, 2); | |
2924 | + register_ioport_write(0x402, 1, bochs_bios_write, 1); | |
2925 | + register_ioport_write(0x403, 1, bochs_bios_write, 1); | |
2926 | + | |
2927 | + register_ioport_write(0x501, 1, bochs_bios_write, 2); | |
2928 | + register_ioport_write(0x502, 1, bochs_bios_write, 2); | |
2929 | + register_ioport_write(0x500, 1, bochs_bios_write, 1); | |
2930 | + register_ioport_write(0x503, 1, bochs_bios_write, 1); | |
2931 | +} | |
2932 | + | |
2933 | +/***********************************************************/ | |
2496 | 2934 | /* cpu signal handler */ |
2497 | 2935 | static void host_segv_handler(int host_signum, siginfo_t *info, |
2498 | 2936 | void *puc) |
... | ... | @@ -2625,7 +3063,7 @@ int main_loop(void *opaque) |
2625 | 3063 | void help(void) |
2626 | 3064 | { |
2627 | 3065 | printf("Virtual Linux version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n" |
2628 | - "usage: vl [options] bzImage [kernel parameters...]\n" | |
3066 | + "usage: vl [options] [bzImage [kernel parameters...]]\n" | |
2629 | 3067 | "\n" |
2630 | 3068 | "'bzImage' is a Linux kernel image (PAGE_OFFSET must be defined\n" |
2631 | 3069 | "to 0x90000000 in asm/page.h and arch/i386/vmlinux.lds)\n" |
... | ... | @@ -2638,10 +3076,12 @@ void help(void) |
2638 | 3076 | "-m megs set virtual RAM size to megs MB\n" |
2639 | 3077 | "-n script set network init script [default=%s]\n" |
2640 | 3078 | "\n" |
2641 | - "Debug options:\n" | |
3079 | + "Debug/Expert options:\n" | |
2642 | 3080 | "-s wait gdb connection to port %d\n" |
2643 | 3081 | "-p port change gdb connection port\n" |
2644 | 3082 | "-d output log in /tmp/vl.log\n" |
3083 | + "-hdachs c,h,s force hard disk 0 geometry for non LBA disk images\n" | |
3084 | + "-L path set the directory for the BIOS and VGA BIOS\n" | |
2645 | 3085 | "\n" |
2646 | 3086 | "During emulation, use C-a h to get terminal commands:\n", |
2647 | 3087 | DEFAULT_NETWORK_SCRIPT, DEFAULT_GDBSTUB_PORT); |
... | ... | @@ -2654,13 +3094,14 @@ struct option long_options[] = { |
2654 | 3094 | { "hda", 1, NULL, 0, }, |
2655 | 3095 | { "hdb", 1, NULL, 0, }, |
2656 | 3096 | { "snapshot", 0, NULL, 0, }, |
3097 | + { "hdachs", 1, NULL, 0, }, | |
2657 | 3098 | { NULL, 0, NULL, 0 }, |
2658 | 3099 | }; |
2659 | 3100 | |
2660 | 3101 | int main(int argc, char **argv) |
2661 | 3102 | { |
2662 | 3103 | int c, ret, initrd_size, i, use_gdbstub, gdbstub_port, long_index; |
2663 | - int snapshot; | |
3104 | + int snapshot, linux_boot; | |
2664 | 3105 | struct linux_params *params; |
2665 | 3106 | struct sigaction act; |
2666 | 3107 | struct itimerval itv; |
... | ... | @@ -2678,8 +3119,9 @@ int main(int argc, char **argv) |
2678 | 3119 | use_gdbstub = 0; |
2679 | 3120 | gdbstub_port = DEFAULT_GDBSTUB_PORT; |
2680 | 3121 | snapshot = 0; |
3122 | + linux_boot = 0; | |
2681 | 3123 | for(;;) { |
2682 | - c = getopt_long_only(argc, argv, "hm:dn:sp:", long_options, &long_index); | |
3124 | + c = getopt_long_only(argc, argv, "hm:dn:sp:L:", long_options, &long_index); | |
2683 | 3125 | if (c == -1) |
2684 | 3126 | break; |
2685 | 3127 | switch(c) { |
... | ... | @@ -2697,6 +3139,28 @@ int main(int argc, char **argv) |
2697 | 3139 | case 3: |
2698 | 3140 | snapshot = 1; |
2699 | 3141 | break; |
3142 | + case 4: | |
3143 | + { | |
3144 | + int cyls, heads, secs; | |
3145 | + const char *p; | |
3146 | + p = optarg; | |
3147 | + cyls = strtol(p, (char **)&p, 0); | |
3148 | + if (*p != ',') | |
3149 | + goto chs_fail; | |
3150 | + p++; | |
3151 | + heads = strtol(p, (char **)&p, 0); | |
3152 | + if (*p != ',') | |
3153 | + goto chs_fail; | |
3154 | + p++; | |
3155 | + secs = strtol(p, (char **)&p, 0); | |
3156 | + if (*p != '\0') | |
3157 | + goto chs_fail; | |
3158 | + ide_state[0].cylinders = cyls; | |
3159 | + ide_state[0].heads = heads; | |
3160 | + ide_state[0].sectors = secs; | |
3161 | + chs_fail: ; | |
3162 | + } | |
3163 | + break; | |
2700 | 3164 | } |
2701 | 3165 | break; |
2702 | 3166 | case 'h': |
... | ... | @@ -2724,9 +3188,15 @@ int main(int argc, char **argv) |
2724 | 3188 | case 'p': |
2725 | 3189 | gdbstub_port = atoi(optarg); |
2726 | 3190 | break; |
3191 | + case 'L': | |
3192 | + interp_prefix = optarg; | |
3193 | + break; | |
2727 | 3194 | } |
2728 | 3195 | } |
2729 | - if (optind >= argc) | |
3196 | + | |
3197 | + linux_boot = (optind < argc); | |
3198 | + | |
3199 | + if (!linux_boot && hd_filename[0] == '\0') | |
2730 | 3200 | help(); |
2731 | 3201 | |
2732 | 3202 | /* init debug */ |
... | ... | @@ -2781,46 +3251,119 @@ int main(int argc, char **argv) |
2781 | 3251 | } |
2782 | 3252 | } |
2783 | 3253 | |
2784 | - /* now we can load the kernel */ | |
2785 | - ret = load_kernel(argv[optind], phys_ram_base + KERNEL_LOAD_ADDR); | |
2786 | - if (ret < 0) { | |
2787 | - fprintf(stderr, "vl: could not load kernel '%s'\n", argv[optind]); | |
2788 | - exit(1); | |
2789 | - } | |
3254 | + /* init CPU state */ | |
3255 | + env = cpu_init(); | |
3256 | + global_env = env; | |
3257 | + cpu_single_env = env; | |
3258 | + | |
3259 | + init_ioports(); | |
2790 | 3260 | |
2791 | - /* load initrd */ | |
2792 | - initrd_size = 0; | |
2793 | - if (initrd_filename) { | |
2794 | - initrd_size = load_image(initrd_filename, phys_ram_base + INITRD_LOAD_ADDR); | |
2795 | - if (initrd_size < 0) { | |
2796 | - fprintf(stderr, "vl: could not load initial ram disk '%s'\n", | |
2797 | - initrd_filename); | |
3261 | + if (linux_boot) { | |
3262 | + /* now we can load the kernel */ | |
3263 | + ret = load_kernel(argv[optind], phys_ram_base + KERNEL_LOAD_ADDR); | |
3264 | + if (ret < 0) { | |
3265 | + fprintf(stderr, "vl: could not load kernel '%s'\n", argv[optind]); | |
2798 | 3266 | exit(1); |
2799 | 3267 | } |
2800 | - } | |
3268 | + | |
3269 | + /* load initrd */ | |
3270 | + initrd_size = 0; | |
3271 | + if (initrd_filename) { | |
3272 | + initrd_size = load_image(initrd_filename, phys_ram_base + INITRD_LOAD_ADDR); | |
3273 | + if (initrd_size < 0) { | |
3274 | + fprintf(stderr, "vl: could not load initial ram disk '%s'\n", | |
3275 | + initrd_filename); | |
3276 | + exit(1); | |
3277 | + } | |
3278 | + } | |
3279 | + | |
3280 | + /* init kernel params */ | |
3281 | + params = (void *)(phys_ram_base + KERNEL_PARAMS_ADDR); | |
3282 | + memset(params, 0, sizeof(struct linux_params)); | |
3283 | + params->mount_root_rdonly = 0; | |
3284 | + params->cl_magic = 0xA33F; | |
3285 | + params->cl_offset = params->commandline - (uint8_t *)params; | |
3286 | + params->alt_mem_k = (phys_ram_size / 1024) - 1024; | |
3287 | + for(i = optind + 1; i < argc; i++) { | |
3288 | + if (i != optind + 1) | |
3289 | + pstrcat(params->commandline, sizeof(params->commandline), " "); | |
3290 | + pstrcat(params->commandline, sizeof(params->commandline), argv[i]); | |
3291 | + } | |
3292 | + params->loader_type = 0x01; | |
3293 | + if (initrd_size > 0) { | |
3294 | + params->initrd_start = INITRD_LOAD_ADDR; | |
3295 | + params->initrd_size = initrd_size; | |
3296 | + } | |
3297 | + params->orig_video_lines = 25; | |
3298 | + params->orig_video_cols = 80; | |
3299 | + | |
3300 | + /* setup basic memory access */ | |
3301 | + env->cr[0] = 0x00000033; | |
3302 | + cpu_x86_init_mmu(env); | |
3303 | + | |
3304 | + memset(params->idt_table, 0, sizeof(params->idt_table)); | |
3305 | + | |
3306 | + params->gdt_table[2] = 0x00cf9a000000ffffLL; /* KERNEL_CS */ | |
3307 | + params->gdt_table[3] = 0x00cf92000000ffffLL; /* KERNEL_DS */ | |
3308 | + | |
3309 | + env->idt.base = (void *)params->idt_table; | |
3310 | + env->idt.limit = sizeof(params->idt_table) - 1; | |
3311 | + env->gdt.base = (void *)params->gdt_table; | |
3312 | + env->gdt.limit = sizeof(params->gdt_table) - 1; | |
3313 | + | |
3314 | + cpu_x86_load_seg(env, R_CS, KERNEL_CS); | |
3315 | + cpu_x86_load_seg(env, R_DS, KERNEL_DS); | |
3316 | + cpu_x86_load_seg(env, R_ES, KERNEL_DS); | |
3317 | + cpu_x86_load_seg(env, R_SS, KERNEL_DS); | |
3318 | + cpu_x86_load_seg(env, R_FS, KERNEL_DS); | |
3319 | + cpu_x86_load_seg(env, R_GS, KERNEL_DS); | |
3320 | + | |
3321 | + env->eip = KERNEL_LOAD_ADDR; | |
3322 | + env->regs[R_ESI] = KERNEL_PARAMS_ADDR; | |
3323 | + env->eflags = 0x2; | |
2801 | 3324 | |
2802 | - /* init kernel params */ | |
2803 | - params = (void *)(phys_ram_base + KERNEL_PARAMS_ADDR); | |
2804 | - memset(params, 0, sizeof(struct linux_params)); | |
2805 | - params->mount_root_rdonly = 0; | |
2806 | - params->cl_magic = 0xA33F; | |
2807 | - params->cl_offset = params->commandline - (uint8_t *)params; | |
2808 | - params->alt_mem_k = (phys_ram_size / 1024) - 1024; | |
2809 | - for(i = optind + 1; i < argc; i++) { | |
2810 | - if (i != optind + 1) | |
2811 | - pstrcat(params->commandline, sizeof(params->commandline), " "); | |
2812 | - pstrcat(params->commandline, sizeof(params->commandline), argv[i]); | |
2813 | - } | |
2814 | - params->loader_type = 0x01; | |
2815 | - if (initrd_size > 0) { | |
2816 | - params->initrd_start = INITRD_LOAD_ADDR; | |
2817 | - params->initrd_size = initrd_size; | |
3325 | + } else { | |
3326 | + char buf[1024]; | |
3327 | + | |
3328 | + /* RAW PC boot */ | |
3329 | + | |
3330 | + /* BIOS load */ | |
3331 | + snprintf(buf, sizeof(buf), "%s/%s", interp_prefix, BIOS_FILENAME); | |
3332 | + ret = load_image(buf, phys_ram_base + 0x000f0000); | |
3333 | + if (ret != 0x10000) { | |
3334 | + fprintf(stderr, "vl: could not load PC bios '%s'\n", BIOS_FILENAME); | |
3335 | + exit(1); | |
3336 | + } | |
3337 | + | |
3338 | + /* VGA BIOS load */ | |
3339 | + snprintf(buf, sizeof(buf), "%s/%s", interp_prefix, VGABIOS_FILENAME); | |
3340 | + ret = load_image(buf, phys_ram_base + 0x000c0000); | |
3341 | + | |
3342 | + /* setup basic memory access */ | |
3343 | + env->cr[0] = 0x60000010; | |
3344 | + cpu_x86_init_mmu(env); | |
3345 | + | |
3346 | + env->idt.limit = 0xffff; | |
3347 | + env->gdt.limit = 0xffff; | |
3348 | + env->ldt.limit = 0xffff; | |
3349 | + | |
3350 | + /* not correct (CS base=0xffff0000) */ | |
3351 | + cpu_x86_load_seg(env, R_CS, 0xf000); | |
3352 | + cpu_x86_load_seg(env, R_DS, 0); | |
3353 | + cpu_x86_load_seg(env, R_ES, 0); | |
3354 | + cpu_x86_load_seg(env, R_SS, 0); | |
3355 | + cpu_x86_load_seg(env, R_FS, 0); | |
3356 | + cpu_x86_load_seg(env, R_GS, 0); | |
3357 | + | |
3358 | + env->eip = 0xfff0; | |
3359 | + env->regs[R_EDX] = 0x600; /* indicate P6 processor */ | |
3360 | + | |
3361 | + env->eflags = 0x2; | |
3362 | + | |
3363 | + bochs_bios_init(); | |
2818 | 3364 | } |
2819 | - params->orig_video_lines = 25; | |
2820 | - params->orig_video_cols = 80; | |
2821 | 3365 | |
2822 | 3366 | /* init basic PC hardware */ |
2823 | - init_ioports(); | |
2824 | 3367 | register_ioport_write(0x80, 1, ioport80_write, 1); |
2825 | 3368 | |
2826 | 3369 | register_ioport_write(0x3d4, 2, vga_ioport_write, 1); |
... | ... | @@ -2843,36 +3386,6 @@ int main(int argc, char **argv) |
2843 | 3386 | act.sa_sigaction = host_alarm_handler; |
2844 | 3387 | sigaction(SIGALRM, &act, NULL); |
2845 | 3388 | |
2846 | - /* init CPU state */ | |
2847 | - env = cpu_init(); | |
2848 | - global_env = env; | |
2849 | - cpu_single_env = env; | |
2850 | - | |
2851 | - /* setup basic memory access */ | |
2852 | - env->cr[0] = 0x00000033; | |
2853 | - cpu_x86_init_mmu(env); | |
2854 | - | |
2855 | - memset(params->idt_table, 0, sizeof(params->idt_table)); | |
2856 | - | |
2857 | - params->gdt_table[2] = 0x00cf9a000000ffffLL; /* KERNEL_CS */ | |
2858 | - params->gdt_table[3] = 0x00cf92000000ffffLL; /* KERNEL_DS */ | |
2859 | - | |
2860 | - env->idt.base = (void *)params->idt_table; | |
2861 | - env->idt.limit = sizeof(params->idt_table) - 1; | |
2862 | - env->gdt.base = (void *)params->gdt_table; | |
2863 | - env->gdt.limit = sizeof(params->gdt_table) - 1; | |
2864 | - | |
2865 | - cpu_x86_load_seg(env, R_CS, KERNEL_CS); | |
2866 | - cpu_x86_load_seg(env, R_DS, KERNEL_DS); | |
2867 | - cpu_x86_load_seg(env, R_ES, KERNEL_DS); | |
2868 | - cpu_x86_load_seg(env, R_SS, KERNEL_DS); | |
2869 | - cpu_x86_load_seg(env, R_FS, KERNEL_DS); | |
2870 | - cpu_x86_load_seg(env, R_GS, KERNEL_DS); | |
2871 | - | |
2872 | - env->eip = KERNEL_LOAD_ADDR; | |
2873 | - env->regs[R_ESI] = KERNEL_PARAMS_ADDR; | |
2874 | - env->eflags = 0x2; | |
2875 | - | |
2876 | 3389 | itv.it_interval.tv_sec = 0; |
2877 | 3390 | itv.it_interval.tv_usec = 1000; |
2878 | 3391 | itv.it_value.tv_sec = 0; | ... | ... |