Commit 330d0414a5968d36edb635c63a729ffa55520e76

Authored by bellard
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
... ... @@ -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;
... ...