Commit 313aa567104a63fbe84d6ec2eeff5b5c81cb3524
1 parent
4cbf74b6
added VGA emulation - added PS/2 mouse and keyboard emulation - use SDL for VGA display
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@356 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
2 changed files
with
454 additions
and
120 deletions
vl.c
... | ... | @@ -74,6 +74,9 @@ |
74 | 74 | /* debug PC keyboard */ |
75 | 75 | //#define DEBUG_KBD |
76 | 76 | |
77 | +/* debug PC keyboard : only mouse */ | |
78 | +//#define DEBUG_MOUSE | |
79 | + | |
77 | 80 | #define PHYS_RAM_BASE 0xac000000 |
78 | 81 | #define PHYS_RAM_MAX_SIZE (256 * 1024 * 1024) |
79 | 82 | |
... | ... | @@ -81,6 +84,8 @@ |
81 | 84 | #define INITRD_LOAD_ADDR 0x00400000 |
82 | 85 | #define KERNEL_PARAMS_ADDR 0x00090000 |
83 | 86 | |
87 | +#define GUI_REFRESH_INTERVAL 30 | |
88 | + | |
84 | 89 | #define MAX_DISKS 2 |
85 | 90 | |
86 | 91 | /* from plex86 (BSD license) */ |
... | ... | @@ -198,9 +203,6 @@ struct __attribute__ ((packed)) linux_params { |
198 | 203 | #define KERNEL_CS 0x10 |
199 | 204 | #define KERNEL_DS 0x18 |
200 | 205 | |
201 | -typedef void (IOPortWriteFunc)(CPUX86State *env, uint32_t address, uint32_t data); | |
202 | -typedef uint32_t (IOPortReadFunc)(CPUX86State *env, uint32_t address); | |
203 | - | |
204 | 206 | #define MAX_IOPORTS 4096 |
205 | 207 | |
206 | 208 | static const char *interp_prefix = CONFIG_QEMU_PREFIX; |
... | ... | @@ -212,6 +214,11 @@ int loglevel; |
212 | 214 | IOPortReadFunc *ioport_read_table[3][MAX_IOPORTS]; |
213 | 215 | IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS]; |
214 | 216 | BlockDriverState *bs_table[MAX_DISKS]; |
217 | +int vga_ram_size; | |
218 | +static DisplayState display_state; | |
219 | +int nodisp; | |
220 | +int term_inited; | |
221 | +int64_t ticks_per_sec; | |
215 | 222 | |
216 | 223 | /***********************************************************/ |
217 | 224 | /* x86 io ports */ |
... | ... | @@ -431,49 +438,6 @@ void hw_error(const char *fmt, ...) |
431 | 438 | } |
432 | 439 | |
433 | 440 | /***********************************************************/ |
434 | -/* vga emulation */ | |
435 | -static uint8_t vga_index; | |
436 | -static uint8_t vga_regs[256]; | |
437 | -static int last_cursor_pos; | |
438 | - | |
439 | -void update_console_messages(void) | |
440 | -{ | |
441 | - int c, i, cursor_pos, eol; | |
442 | - | |
443 | - cursor_pos = vga_regs[0x0f] | (vga_regs[0x0e] << 8); | |
444 | - eol = 0; | |
445 | - for(i = last_cursor_pos; i < cursor_pos; i++) { | |
446 | - c = phys_ram_base[0xb8000 + (i) * 2]; | |
447 | - if (c >= ' ') { | |
448 | - putchar(c); | |
449 | - eol = 0; | |
450 | - } else { | |
451 | - if (!eol) | |
452 | - putchar('\n'); | |
453 | - eol = 1; | |
454 | - } | |
455 | - } | |
456 | - fflush(stdout); | |
457 | - last_cursor_pos = cursor_pos; | |
458 | -} | |
459 | - | |
460 | -/* just to see first Linux console messages, we intercept cursor position */ | |
461 | -void vga_ioport_write(CPUX86State *env, uint32_t addr, uint32_t data) | |
462 | -{ | |
463 | - switch(addr) { | |
464 | - case 0x3d4: | |
465 | - vga_index = data; | |
466 | - break; | |
467 | - case 0x3d5: | |
468 | - vga_regs[vga_index] = data; | |
469 | - if (vga_index == 0x0f) | |
470 | - update_console_messages(); | |
471 | - break; | |
472 | - } | |
473 | - | |
474 | -} | |
475 | - | |
476 | -/***********************************************************/ | |
477 | 441 | /* cmos emulation */ |
478 | 442 | |
479 | 443 | #define RTC_SECONDS 0 |
... | ... | @@ -555,6 +519,7 @@ void cmos_init(void) |
555 | 519 | /* various important CMOS locations needed by PC/Bochs bios */ |
556 | 520 | |
557 | 521 | cmos_data[REG_EQUIPMENT_BYTE] = 0x02; /* FPU is there */ |
522 | + cmos_data[REG_EQUIPMENT_BYTE] |= 0x04; /* PS/2 mouse installed */ | |
558 | 523 | |
559 | 524 | /* memory size */ |
560 | 525 | val = (phys_ram_size / 1024) - 1024; |
... | ... | @@ -674,13 +639,13 @@ static void pic_update_irq(void) |
674 | 639 | int64_t irq_time[16]; |
675 | 640 | int64_t cpu_get_ticks(void); |
676 | 641 | #endif |
677 | -#ifdef DEBUG_PIC | |
642 | +#if defined(DEBUG_PIC) | |
678 | 643 | int irq_level[16]; |
679 | 644 | #endif |
680 | 645 | |
681 | 646 | void pic_set_irq(int irq, int level) |
682 | 647 | { |
683 | -#ifdef DEBUG_PIC | |
648 | +#if defined(DEBUG_PIC) | |
684 | 649 | if (level != irq_level[irq]) { |
685 | 650 | printf("pic_set_irq: irq=%d level=%d\n", irq, level); |
686 | 651 | irq_level[irq] = level; |
... | ... | @@ -702,7 +667,9 @@ int cpu_x86_get_pic_interrupt(CPUX86State *env) |
702 | 667 | /* signal the pic that the irq was acked by the CPU */ |
703 | 668 | irq = pic_irq_requested; |
704 | 669 | #ifdef DEBUG_IRQ_LATENCY |
705 | - printf("IRQ%d latency=%Ld\n", irq, cpu_get_ticks() - irq_time[irq]); | |
670 | + printf("IRQ%d latency=%0.3fus\n", | |
671 | + irq, | |
672 | + (double)(cpu_get_ticks() - irq_time[irq]) * 1000000.0 / ticks_per_sec); | |
706 | 673 | #endif |
707 | 674 | #ifdef DEBUG_PIC |
708 | 675 | printf("pic_interrupt: irq=%d\n", irq); |
... | ... | @@ -761,18 +728,22 @@ void pic_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) |
761 | 728 | } |
762 | 729 | if (val == 0xa0) |
763 | 730 | s->priority_add = (s->priority_add + 1) & 7; |
731 | + pic_update_irq(); | |
764 | 732 | break; |
765 | 733 | case 0x60 ... 0x67: |
766 | 734 | priority = val & 7; |
767 | 735 | s->isr &= ~(1 << priority); |
736 | + pic_update_irq(); | |
768 | 737 | break; |
769 | 738 | case 0xc0 ... 0xc7: |
770 | 739 | s->priority_add = (val + 1) & 7; |
740 | + pic_update_irq(); | |
771 | 741 | break; |
772 | 742 | case 0xe0 ... 0xe7: |
773 | 743 | priority = val & 7; |
774 | 744 | s->isr &= ~(1 << priority); |
775 | 745 | s->priority_add = (priority + 1) & 7; |
746 | + pic_update_irq(); | |
776 | 747 | break; |
777 | 748 | } |
778 | 749 | } |
... | ... | @@ -861,8 +832,6 @@ int speaker_data_on; |
861 | 832 | int dummy_refresh_clock; |
862 | 833 | int pit_min_timer_count = 0; |
863 | 834 | |
864 | -int64_t ticks_per_sec; | |
865 | - | |
866 | 835 | int64_t get_clock(void) |
867 | 836 | { |
868 | 837 | struct timeval tv; |
... | ... | @@ -1354,37 +1323,6 @@ void serial_received_byte(SerialState *s, int ch) |
1354 | 1323 | } |
1355 | 1324 | } |
1356 | 1325 | |
1357 | -/* init terminal so that we can grab keys */ | |
1358 | -static struct termios oldtty; | |
1359 | - | |
1360 | -static void term_exit(void) | |
1361 | -{ | |
1362 | - tcsetattr (0, TCSANOW, &oldtty); | |
1363 | -} | |
1364 | - | |
1365 | -static void term_init(void) | |
1366 | -{ | |
1367 | - struct termios tty; | |
1368 | - | |
1369 | - tcgetattr (0, &tty); | |
1370 | - oldtty = tty; | |
1371 | - | |
1372 | - tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP | |
1373 | - |INLCR|IGNCR|ICRNL|IXON); | |
1374 | - tty.c_oflag |= OPOST; | |
1375 | - tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN|ISIG); | |
1376 | - tty.c_cflag &= ~(CSIZE|PARENB); | |
1377 | - tty.c_cflag |= CS8; | |
1378 | - tty.c_cc[VMIN] = 1; | |
1379 | - tty.c_cc[VTIME] = 0; | |
1380 | - | |
1381 | - tcsetattr (0, TCSANOW, &tty); | |
1382 | - | |
1383 | - atexit(term_exit); | |
1384 | - | |
1385 | - fcntl(0, F_SETFL, O_NONBLOCK); | |
1386 | -} | |
1387 | - | |
1388 | 1326 | void serial_init(void) |
1389 | 1327 | { |
1390 | 1328 | SerialState *s = &serial_ports[0]; |
... | ... | @@ -1393,8 +1331,6 @@ void serial_init(void) |
1393 | 1331 | |
1394 | 1332 | register_ioport_write(0x3f8, 8, serial_ioport_write, 1); |
1395 | 1333 | register_ioport_read(0x3f8, 8, serial_ioport_read, 1); |
1396 | - | |
1397 | - term_init(); | |
1398 | 1334 | } |
1399 | 1335 | |
1400 | 1336 | /***********************************************************/ |
... | ... | @@ -2597,69 +2533,111 @@ void ide_init(void) |
2597 | 2533 | #define KBD_MODE_RFU 0x80 |
2598 | 2534 | |
2599 | 2535 | /* Mouse Commands */ |
2600 | -#define AUX_SET_RES 0xE8 /* Set resolution */ | |
2601 | 2536 | #define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */ |
2602 | 2537 | #define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */ |
2538 | +#define AUX_SET_RES 0xE8 /* Set resolution */ | |
2603 | 2539 | #define AUX_GET_SCALE 0xE9 /* Get scaling factor */ |
2604 | 2540 | #define AUX_SET_STREAM 0xEA /* Set stream mode */ |
2541 | +#define AUX_POLL 0xEB /* Poll */ | |
2542 | +#define AUX_RESET_WRAP 0xEC /* Reset wrap mode */ | |
2543 | +#define AUX_SET_WRAP 0xEE /* Set wrap mode */ | |
2544 | +#define AUX_SET_REMOTE 0xF0 /* Set remote mode */ | |
2545 | +#define AUX_GET_TYPE 0xF2 /* Get type */ | |
2605 | 2546 | #define AUX_SET_SAMPLE 0xF3 /* Set sample rate */ |
2606 | 2547 | #define AUX_ENABLE_DEV 0xF4 /* Enable aux device */ |
2607 | 2548 | #define AUX_DISABLE_DEV 0xF5 /* Disable aux device */ |
2549 | +#define AUX_SET_DEFAULT 0xF6 | |
2608 | 2550 | #define AUX_RESET 0xFF /* Reset aux device */ |
2609 | 2551 | #define AUX_ACK 0xFA /* Command byte ACK. */ |
2610 | 2552 | |
2611 | -#define KBD_QUEUE_SIZE 64 | |
2553 | +#define MOUSE_STATUS_REMOTE 0x40 | |
2554 | +#define MOUSE_STATUS_ENABLED 0x20 | |
2555 | +#define MOUSE_STATUS_SCALE21 0x10 | |
2556 | + | |
2557 | +#define KBD_QUEUE_SIZE 256 | |
2612 | 2558 | |
2613 | 2559 | typedef struct { |
2614 | 2560 | uint8_t data[KBD_QUEUE_SIZE]; |
2615 | 2561 | int rptr, wptr, count; |
2616 | 2562 | } KBDQueue; |
2617 | 2563 | |
2618 | -enum KBDWriteState { | |
2619 | - KBD_STATE_CMD = 0, | |
2620 | - KBD_STATE_LED, | |
2621 | -}; | |
2622 | - | |
2623 | 2564 | typedef struct KBDState { |
2624 | 2565 | KBDQueue queues[2]; |
2625 | 2566 | uint8_t write_cmd; /* if non zero, write data to port 60 is expected */ |
2626 | 2567 | uint8_t status; |
2627 | 2568 | uint8_t mode; |
2569 | + /* keyboard state */ | |
2628 | 2570 | int kbd_write_cmd; |
2629 | 2571 | int scan_enabled; |
2572 | + /* mouse state */ | |
2573 | + int mouse_write_cmd; | |
2574 | + uint8_t mouse_status; | |
2575 | + uint8_t mouse_resolution; | |
2576 | + uint8_t mouse_sample_rate; | |
2577 | + uint8_t mouse_wrap; | |
2578 | + uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */ | |
2579 | + uint8_t mouse_detect_state; | |
2580 | + int mouse_dx; /* current values, needed for 'poll' mode */ | |
2581 | + int mouse_dy; | |
2582 | + int mouse_dz; | |
2583 | + uint8_t mouse_buttons; | |
2630 | 2584 | } KBDState; |
2631 | 2585 | |
2632 | 2586 | KBDState kbd_state; |
2633 | 2587 | int reset_requested; |
2634 | 2588 | int a20_enabled; |
2635 | 2589 | |
2590 | +/* update irq and KBD_STAT_[MOUSE_]OBF */ | |
2636 | 2591 | static void kbd_update_irq(KBDState *s) |
2637 | 2592 | { |
2638 | - int level; | |
2639 | - | |
2640 | - level = ((s->status & KBD_STAT_OBF) && (s->mode & KBD_MODE_KBD_INT)); | |
2641 | - pic_set_irq(1, level); | |
2642 | - | |
2643 | - level = ((s->status & KBD_STAT_MOUSE_OBF) && (s->mode & KBD_MODE_MOUSE_INT)); | |
2644 | - pic_set_irq(12, level); | |
2593 | + int irq12_level, irq1_level; | |
2594 | + | |
2595 | + irq1_level = 0; | |
2596 | + irq12_level = 0; | |
2597 | + s->status &= ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF); | |
2598 | + if (s->queues[0].count != 0 || | |
2599 | + s->queues[1].count != 0) { | |
2600 | + s->status |= KBD_STAT_OBF; | |
2601 | + if (s->queues[1].count != 0) { | |
2602 | + s->status |= KBD_STAT_MOUSE_OBF; | |
2603 | + if (s->mode & KBD_MODE_MOUSE_INT) | |
2604 | + irq12_level = 1; | |
2605 | + } else { | |
2606 | + if (s->mode & KBD_MODE_KBD_INT) | |
2607 | + irq1_level = 1; | |
2608 | + } | |
2609 | + } | |
2610 | + pic_set_irq(1, irq1_level); | |
2611 | + pic_set_irq(12, irq12_level); | |
2645 | 2612 | } |
2646 | 2613 | |
2647 | 2614 | static void kbd_queue(KBDState *s, int b, int aux) |
2648 | 2615 | { |
2649 | 2616 | KBDQueue *q = &kbd_state.queues[aux]; |
2650 | 2617 | |
2618 | +#if defined(DEBUG_MOUSE) || defined(DEBUG_KBD) | |
2619 | + if (aux) | |
2620 | + printf("mouse event: 0x%02x\n", b); | |
2621 | +#ifdef DEBUG_KBD | |
2622 | + else | |
2623 | + printf("kbd event: 0x%02x\n", b); | |
2624 | +#endif | |
2625 | +#endif | |
2651 | 2626 | if (q->count >= KBD_QUEUE_SIZE) |
2652 | 2627 | return; |
2653 | 2628 | q->data[q->wptr] = b; |
2654 | 2629 | if (++q->wptr == KBD_QUEUE_SIZE) |
2655 | 2630 | q->wptr = 0; |
2656 | 2631 | q->count++; |
2657 | - s->status |= KBD_STAT_OBF; | |
2658 | - if (aux) | |
2659 | - s->status |= KBD_STAT_MOUSE_OBF; | |
2660 | 2632 | kbd_update_irq(s); |
2661 | 2633 | } |
2662 | 2634 | |
2635 | +void kbd_put_keycode(int keycode) | |
2636 | +{ | |
2637 | + KBDState *s = &kbd_state; | |
2638 | + kbd_queue(s, keycode, 0); | |
2639 | +} | |
2640 | + | |
2663 | 2641 | uint32_t kbd_read_status(CPUX86State *env, uint32_t addr) |
2664 | 2642 | { |
2665 | 2643 | KBDState *s = &kbd_state; |
... | ... | @@ -2745,9 +2723,9 @@ uint32_t kbd_read_data(CPUX86State *env, uint32_t addr) |
2745 | 2723 | KBDQueue *q; |
2746 | 2724 | int val; |
2747 | 2725 | |
2748 | - q = &s->queues[1]; /* first check AUX data */ | |
2726 | + q = &s->queues[0]; /* first check KBD data */ | |
2749 | 2727 | if (q->count == 0) |
2750 | - q = &s->queues[0]; /* then check KBD data */ | |
2728 | + q = &s->queues[1]; /* then check AUX data */ | |
2751 | 2729 | if (q->count == 0) { |
2752 | 2730 | /* XXX: return something else ? */ |
2753 | 2731 | val = 0; |
... | ... | @@ -2756,14 +2734,14 @@ uint32_t kbd_read_data(CPUX86State *env, uint32_t addr) |
2756 | 2734 | if (++q->rptr == KBD_QUEUE_SIZE) |
2757 | 2735 | q->rptr = 0; |
2758 | 2736 | q->count--; |
2737 | + /* reading deasserts IRQ */ | |
2738 | + if (q == &s->queues[0]) | |
2739 | + pic_set_irq(1, 0); | |
2740 | + else | |
2741 | + pic_set_irq(12, 0); | |
2759 | 2742 | } |
2760 | - if (s->queues[1].count == 0) { | |
2761 | - s->status &= ~KBD_STAT_MOUSE_OBF; | |
2762 | - if (s->queues[0].count == 0) | |
2763 | - s->status &= ~KBD_STAT_OBF; | |
2764 | - kbd_update_irq(s); | |
2765 | - } | |
2766 | - | |
2743 | + /* reassert IRQs if data left */ | |
2744 | + kbd_update_irq(s); | |
2767 | 2745 | #ifdef DEBUG_KBD |
2768 | 2746 | printf("kbd: read data=0x%02x\n", val); |
2769 | 2747 | #endif |
... | ... | @@ -2820,12 +2798,212 @@ static void kbd_write_keyboard(KBDState *s, int val) |
2820 | 2798 | break; |
2821 | 2799 | case KBD_CMD_SET_LEDS: |
2822 | 2800 | kbd_queue(s, KBD_REPLY_ACK, 0); |
2801 | + s->kbd_write_cmd = -1; | |
2823 | 2802 | break; |
2824 | 2803 | case KBD_CMD_SET_RATE: |
2825 | 2804 | kbd_queue(s, KBD_REPLY_ACK, 0); |
2805 | + s->kbd_write_cmd = -1; | |
2806 | + break; | |
2807 | + } | |
2808 | +} | |
2809 | + | |
2810 | +static void kbd_mouse_send_packet(KBDState *s) | |
2811 | +{ | |
2812 | + unsigned int b; | |
2813 | + int dx1, dy1, dz1; | |
2814 | + | |
2815 | + dx1 = s->mouse_dx; | |
2816 | + dy1 = s->mouse_dy; | |
2817 | + dz1 = s->mouse_dz; | |
2818 | + /* XXX: increase range to 8 bits ? */ | |
2819 | + if (dx1 > 127) | |
2820 | + dx1 = 127; | |
2821 | + else if (dx1 < -127) | |
2822 | + dx1 = -127; | |
2823 | + if (dy1 > 127) | |
2824 | + dy1 = 127; | |
2825 | + else if (dy1 < -127) | |
2826 | + dy1 = -127; | |
2827 | + b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07); | |
2828 | + kbd_queue(s, b, 1); | |
2829 | + kbd_queue(s, dx1 & 0xff, 1); | |
2830 | + kbd_queue(s, dy1 & 0xff, 1); | |
2831 | + /* extra byte for IMPS/2 or IMEX */ | |
2832 | + switch(s->mouse_type) { | |
2833 | + default: | |
2834 | + break; | |
2835 | + case 3: | |
2836 | + if (dz1 > 127) | |
2837 | + dz1 = 127; | |
2838 | + else if (dz1 < -127) | |
2839 | + dz1 = -127; | |
2840 | + kbd_queue(s, dz1 & 0xff, 1); | |
2841 | + break; | |
2842 | + case 4: | |
2843 | + if (dz1 > 7) | |
2844 | + dz1 = 7; | |
2845 | + else if (dz1 < -7) | |
2846 | + dz1 = -7; | |
2847 | + b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1); | |
2848 | + kbd_queue(s, b, 1); | |
2849 | + break; | |
2850 | + } | |
2851 | + | |
2852 | + /* update deltas */ | |
2853 | + s->mouse_dx -= dx1; | |
2854 | + s->mouse_dy -= dy1; | |
2855 | + s->mouse_dz -= dz1; | |
2856 | +} | |
2857 | + | |
2858 | +void kbd_mouse_event(int dx, int dy, int dz, int buttons_state) | |
2859 | +{ | |
2860 | + KBDState *s = &kbd_state; | |
2861 | + | |
2862 | + /* check if deltas are recorded when disabled */ | |
2863 | + if (!(s->mouse_status & MOUSE_STATUS_ENABLED)) | |
2864 | + return; | |
2865 | + | |
2866 | + s->mouse_dx += dx; | |
2867 | + s->mouse_dy -= dy; | |
2868 | + s->mouse_dz += dz; | |
2869 | + s->mouse_buttons = buttons_state; | |
2870 | + | |
2871 | + if (!(s->mouse_status & MOUSE_STATUS_REMOTE) && | |
2872 | + (s->queues[1].count < (KBD_QUEUE_SIZE - 16))) { | |
2873 | + for(;;) { | |
2874 | + /* if not remote, send event. Multiple events are sent if | |
2875 | + too big deltas */ | |
2876 | + kbd_mouse_send_packet(s); | |
2877 | + if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0) | |
2878 | + break; | |
2879 | + } | |
2880 | + } | |
2881 | +} | |
2882 | + | |
2883 | +static void kbd_write_mouse(KBDState *s, int val) | |
2884 | +{ | |
2885 | +#ifdef DEBUG_MOUSE | |
2886 | + printf("kbd: write mouse 0x%02x\n", val); | |
2887 | +#endif | |
2888 | + switch(s->mouse_write_cmd) { | |
2889 | + default: | |
2890 | + case -1: | |
2891 | + /* mouse command */ | |
2892 | + if (s->mouse_wrap) { | |
2893 | + if (val == AUX_RESET_WRAP) { | |
2894 | + s->mouse_wrap = 0; | |
2895 | + kbd_queue(s, AUX_ACK, 1); | |
2896 | + return; | |
2897 | + } else if (val != AUX_RESET) { | |
2898 | + kbd_queue(s, val, 1); | |
2899 | + return; | |
2900 | + } | |
2901 | + } | |
2902 | + switch(val) { | |
2903 | + case AUX_SET_SCALE11: | |
2904 | + s->mouse_status &= ~MOUSE_STATUS_SCALE21; | |
2905 | + kbd_queue(s, AUX_ACK, 1); | |
2906 | + break; | |
2907 | + case AUX_SET_SCALE21: | |
2908 | + s->mouse_status |= MOUSE_STATUS_SCALE21; | |
2909 | + kbd_queue(s, AUX_ACK, 1); | |
2910 | + break; | |
2911 | + case AUX_SET_STREAM: | |
2912 | + s->mouse_status &= ~MOUSE_STATUS_REMOTE; | |
2913 | + kbd_queue(s, AUX_ACK, 1); | |
2914 | + break; | |
2915 | + case AUX_SET_WRAP: | |
2916 | + s->mouse_wrap = 1; | |
2917 | + kbd_queue(s, AUX_ACK, 1); | |
2918 | + break; | |
2919 | + case AUX_SET_REMOTE: | |
2920 | + s->mouse_status |= MOUSE_STATUS_REMOTE; | |
2921 | + kbd_queue(s, AUX_ACK, 1); | |
2922 | + break; | |
2923 | + case AUX_GET_TYPE: | |
2924 | + kbd_queue(s, AUX_ACK, 1); | |
2925 | + kbd_queue(s, s->mouse_type, 1); | |
2926 | + break; | |
2927 | + case AUX_SET_RES: | |
2928 | + case AUX_SET_SAMPLE: | |
2929 | + s->mouse_write_cmd = val; | |
2930 | + kbd_queue(s, AUX_ACK, 1); | |
2931 | + break; | |
2932 | + case AUX_GET_SCALE: | |
2933 | + kbd_queue(s, AUX_ACK, 1); | |
2934 | + kbd_queue(s, s->mouse_status, 1); | |
2935 | + kbd_queue(s, s->mouse_resolution, 1); | |
2936 | + kbd_queue(s, s->mouse_sample_rate, 1); | |
2937 | + break; | |
2938 | + case AUX_POLL: | |
2939 | + kbd_queue(s, AUX_ACK, 1); | |
2940 | + kbd_mouse_send_packet(s); | |
2941 | + break; | |
2942 | + case AUX_ENABLE_DEV: | |
2943 | + s->mouse_status |= MOUSE_STATUS_ENABLED; | |
2944 | + kbd_queue(s, AUX_ACK, 1); | |
2945 | + break; | |
2946 | + case AUX_DISABLE_DEV: | |
2947 | + s->mouse_status &= ~MOUSE_STATUS_ENABLED; | |
2948 | + kbd_queue(s, AUX_ACK, 1); | |
2949 | + break; | |
2950 | + case AUX_SET_DEFAULT: | |
2951 | + s->mouse_sample_rate = 100; | |
2952 | + s->mouse_resolution = 2; | |
2953 | + s->mouse_status = 0; | |
2954 | + kbd_queue(s, AUX_ACK, 1); | |
2955 | + break; | |
2956 | + case AUX_RESET: | |
2957 | + s->mouse_sample_rate = 100; | |
2958 | + s->mouse_resolution = 2; | |
2959 | + s->mouse_status = 0; | |
2960 | + kbd_queue(s, AUX_ACK, 1); | |
2961 | + kbd_queue(s, 0xaa, 1); | |
2962 | + kbd_queue(s, s->mouse_type, 1); | |
2963 | + break; | |
2964 | + default: | |
2965 | + break; | |
2966 | + } | |
2967 | + break; | |
2968 | + case AUX_SET_SAMPLE: | |
2969 | + s->mouse_sample_rate = val; | |
2970 | +#if 0 | |
2971 | + /* detect IMPS/2 or IMEX */ | |
2972 | + switch(s->mouse_detect_state) { | |
2973 | + default: | |
2974 | + case 0: | |
2975 | + if (val == 200) | |
2976 | + s->mouse_detect_state = 1; | |
2977 | + break; | |
2978 | + case 1: | |
2979 | + if (val == 100) | |
2980 | + s->mouse_detect_state = 2; | |
2981 | + else if (val == 200) | |
2982 | + s->mouse_detect_state = 3; | |
2983 | + else | |
2984 | + s->mouse_detect_state = 0; | |
2985 | + break; | |
2986 | + case 2: | |
2987 | + if (val == 80) | |
2988 | + s->mouse_type = 3; /* IMPS/2 */ | |
2989 | + s->mouse_detect_state = 0; | |
2990 | + break; | |
2991 | + case 3: | |
2992 | + if (val == 80) | |
2993 | + s->mouse_type = 4; /* IMEX */ | |
2994 | + s->mouse_detect_state = 0; | |
2995 | + break; | |
2996 | + } | |
2997 | +#endif | |
2998 | + kbd_queue(s, AUX_ACK, 1); | |
2999 | + s->mouse_write_cmd = -1; | |
3000 | + break; | |
3001 | + case AUX_SET_RES: | |
3002 | + s->mouse_resolution = val; | |
3003 | + kbd_queue(s, AUX_ACK, 1); | |
3004 | + s->mouse_write_cmd = -1; | |
2826 | 3005 | break; |
2827 | 3006 | } |
2828 | - s->kbd_write_cmd = -1; | |
2829 | 3007 | } |
2830 | 3008 | |
2831 | 3009 | void kbd_write_data(CPUX86State *env, uint32_t addr, uint32_t val) |
... | ... | @@ -2857,6 +3035,9 @@ void kbd_write_data(CPUX86State *env, uint32_t addr, uint32_t val) |
2857 | 3035 | cpu_x86_interrupt(global_env, CPU_INTERRUPT_EXIT); |
2858 | 3036 | } |
2859 | 3037 | break; |
3038 | + case KBD_CCMD_WRITE_MOUSE: | |
3039 | + kbd_write_mouse(s, val); | |
3040 | + break; | |
2860 | 3041 | default: |
2861 | 3042 | break; |
2862 | 3043 | } |
... | ... | @@ -2869,8 +3050,9 @@ void kbd_reset(KBDState *s) |
2869 | 3050 | int i; |
2870 | 3051 | |
2871 | 3052 | s->kbd_write_cmd = -1; |
3053 | + s->mouse_write_cmd = -1; | |
2872 | 3054 | s->mode = KBD_MODE_KBD_INT | KBD_MODE_MOUSE_INT; |
2873 | - s->status = KBD_MODE_SYS | KBD_MODE_NO_KEYLOCK; | |
3055 | + s->status = KBD_STAT_CMD | KBD_STAT_UNLOCKED; | |
2874 | 3056 | for(i = 0; i < 2; i++) { |
2875 | 3057 | q = &s->queues[i]; |
2876 | 3058 | q->rptr = 0; |
... | ... | @@ -2934,6 +3116,63 @@ void bochs_bios_init(void) |
2934 | 3116 | } |
2935 | 3117 | |
2936 | 3118 | /***********************************************************/ |
3119 | +/* dumb display */ | |
3120 | + | |
3121 | +/* init terminal so that we can grab keys */ | |
3122 | +static struct termios oldtty; | |
3123 | + | |
3124 | +static void term_exit(void) | |
3125 | +{ | |
3126 | + tcsetattr (0, TCSANOW, &oldtty); | |
3127 | +} | |
3128 | + | |
3129 | +static void term_init(void) | |
3130 | +{ | |
3131 | + struct termios tty; | |
3132 | + | |
3133 | + tcgetattr (0, &tty); | |
3134 | + oldtty = tty; | |
3135 | + | |
3136 | + tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP | |
3137 | + |INLCR|IGNCR|ICRNL|IXON); | |
3138 | + tty.c_oflag |= OPOST; | |
3139 | + tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN|ISIG); | |
3140 | + tty.c_cflag &= ~(CSIZE|PARENB); | |
3141 | + tty.c_cflag |= CS8; | |
3142 | + tty.c_cc[VMIN] = 1; | |
3143 | + tty.c_cc[VTIME] = 0; | |
3144 | + | |
3145 | + tcsetattr (0, TCSANOW, &tty); | |
3146 | + | |
3147 | + atexit(term_exit); | |
3148 | + | |
3149 | + fcntl(0, F_SETFL, O_NONBLOCK); | |
3150 | +} | |
3151 | + | |
3152 | +static void dumb_update(DisplayState *ds, int x, int y, int w, int h) | |
3153 | +{ | |
3154 | +} | |
3155 | + | |
3156 | +static void dumb_resize(DisplayState *ds, int w, int h) | |
3157 | +{ | |
3158 | +} | |
3159 | + | |
3160 | +static void dumb_refresh(DisplayState *ds) | |
3161 | +{ | |
3162 | + vga_update_display(); | |
3163 | +} | |
3164 | + | |
3165 | +void dumb_display_init(DisplayState *ds) | |
3166 | +{ | |
3167 | + ds->data = NULL; | |
3168 | + ds->linesize = 0; | |
3169 | + ds->depth = 0; | |
3170 | + ds->dpy_update = dumb_update; | |
3171 | + ds->dpy_resize = dumb_resize; | |
3172 | + ds->dpy_refresh = dumb_refresh; | |
3173 | +} | |
3174 | + | |
3175 | +/***********************************************************/ | |
2937 | 3176 | /* cpu signal handler */ |
2938 | 3177 | static void host_segv_handler(int host_signum, siginfo_t *info, |
2939 | 3178 | void *puc) |
... | ... | @@ -2947,6 +3186,9 @@ static void host_segv_handler(int host_signum, siginfo_t *info, |
2947 | 3186 | static int timer_irq_pending; |
2948 | 3187 | static int timer_irq_count; |
2949 | 3188 | |
3189 | +static int timer_ms; | |
3190 | +static int gui_refresh_pending, gui_refresh_count; | |
3191 | + | |
2950 | 3192 | static void host_alarm_handler(int host_signum, siginfo_t *info, |
2951 | 3193 | void *puc) |
2952 | 3194 | { |
... | ... | @@ -2958,9 +3200,17 @@ static void host_alarm_handler(int host_signum, siginfo_t *info, |
2958 | 3200 | if (timer_irq_count > 2) |
2959 | 3201 | timer_irq_count = 2; |
2960 | 3202 | timer_irq_count--; |
3203 | + timer_irq_pending = 1; | |
3204 | + } | |
3205 | + gui_refresh_count += timer_ms; | |
3206 | + if (gui_refresh_count >= GUI_REFRESH_INTERVAL) { | |
3207 | + gui_refresh_count = 0; | |
3208 | + gui_refresh_pending = 1; | |
3209 | + } | |
3210 | + | |
3211 | + if (gui_refresh_pending || timer_irq_pending) { | |
2961 | 3212 | /* just exit from the cpu to have a chance to handle timers */ |
2962 | 3213 | cpu_x86_interrupt(global_env, CPU_INTERRUPT_EXIT); |
2963 | - timer_irq_pending = 1; | |
2964 | 3214 | } |
2965 | 3215 | } |
2966 | 3216 | |
... | ... | @@ -2988,6 +3238,14 @@ int main_loop(void *opaque) |
2988 | 3238 | uint8_t ch; |
2989 | 3239 | CPUState *env = global_env; |
2990 | 3240 | |
3241 | + if (nodisp && !term_inited) { | |
3242 | + /* initialize terminal only there so that the user has a | |
3243 | + chance to stop QEMU with Ctrl-C before the gdb connection | |
3244 | + is launched */ | |
3245 | + term_inited = 1; | |
3246 | + term_init(); | |
3247 | + } | |
3248 | + | |
2991 | 3249 | for(;;) { |
2992 | 3250 | |
2993 | 3251 | ret = cpu_x86_exec(env); |
... | ... | @@ -3059,6 +3317,12 @@ int main_loop(void *opaque) |
3059 | 3317 | pic_set_irq(0, 0); |
3060 | 3318 | timer_irq_pending = 0; |
3061 | 3319 | } |
3320 | + | |
3321 | + /* VGA */ | |
3322 | + if (gui_refresh_pending) { | |
3323 | + display_state.dpy_refresh(&display_state); | |
3324 | + gui_refresh_pending = 0; | |
3325 | + } | |
3062 | 3326 | } |
3063 | 3327 | return EXCP_INTERRUPT; |
3064 | 3328 | } |
... | ... | @@ -3098,31 +3362,35 @@ struct option long_options[] = { |
3098 | 3362 | { "hdb", 1, NULL, 0, }, |
3099 | 3363 | { "snapshot", 0, NULL, 0, }, |
3100 | 3364 | { "hdachs", 1, NULL, 0, }, |
3365 | + { "nodisp", 0, NULL, 0, }, | |
3101 | 3366 | { NULL, 0, NULL, 0 }, |
3102 | 3367 | }; |
3103 | 3368 | |
3104 | 3369 | int main(int argc, char **argv) |
3105 | 3370 | { |
3106 | 3371 | int c, ret, initrd_size, i, use_gdbstub, gdbstub_port, long_index; |
3107 | - int snapshot, linux_boot; | |
3372 | + int snapshot, linux_boot, total_ram_size; | |
3108 | 3373 | struct linux_params *params; |
3109 | 3374 | struct sigaction act; |
3110 | 3375 | struct itimerval itv; |
3111 | 3376 | CPUX86State *env; |
3112 | 3377 | const char *tmpdir, *initrd_filename; |
3113 | 3378 | const char *hd_filename[MAX_DISKS]; |
3114 | - | |
3379 | + DisplayState *ds = &display_state; | |
3380 | + | |
3115 | 3381 | /* we never want that malloc() uses mmap() */ |
3116 | 3382 | mallopt(M_MMAP_THRESHOLD, 4096 * 1024); |
3117 | 3383 | initrd_filename = NULL; |
3118 | 3384 | for(i = 0; i < MAX_DISKS; i++) |
3119 | 3385 | hd_filename[i] = NULL; |
3120 | 3386 | phys_ram_size = 32 * 1024 * 1024; |
3387 | + vga_ram_size = VGA_RAM_SIZE; | |
3121 | 3388 | pstrcpy(network_script, sizeof(network_script), DEFAULT_NETWORK_SCRIPT); |
3122 | 3389 | use_gdbstub = 0; |
3123 | 3390 | gdbstub_port = DEFAULT_GDBSTUB_PORT; |
3124 | 3391 | snapshot = 0; |
3125 | 3392 | linux_boot = 0; |
3393 | + nodisp = 0; | |
3126 | 3394 | for(;;) { |
3127 | 3395 | c = getopt_long_only(argc, argv, "hm:dn:sp:L:", long_options, &long_index); |
3128 | 3396 | if (c == -1) |
... | ... | @@ -3164,6 +3432,9 @@ int main(int argc, char **argv) |
3164 | 3432 | chs_fail: ; |
3165 | 3433 | } |
3166 | 3434 | break; |
3435 | + case 5: | |
3436 | + nodisp = 1; | |
3437 | + break; | |
3167 | 3438 | } |
3168 | 3439 | break; |
3169 | 3440 | case 'h': |
... | ... | @@ -3232,9 +3503,11 @@ int main(int argc, char **argv) |
3232 | 3503 | phys_ram_file); |
3233 | 3504 | exit(1); |
3234 | 3505 | } |
3235 | - ftruncate(phys_ram_fd, phys_ram_size); | |
3506 | + total_ram_size = phys_ram_size + vga_ram_size; | |
3507 | + ftruncate(phys_ram_fd, total_ram_size); | |
3236 | 3508 | unlink(phys_ram_file); |
3237 | - phys_ram_base = mmap(get_mmap_addr(phys_ram_size), phys_ram_size, | |
3509 | + phys_ram_base = mmap(get_mmap_addr(total_ram_size), | |
3510 | + total_ram_size, | |
3238 | 3511 | PROT_WRITE | PROT_READ, MAP_SHARED | MAP_FIXED, |
3239 | 3512 | phys_ram_fd, 0); |
3240 | 3513 | if (phys_ram_base == MAP_FAILED) { |
... | ... | @@ -3261,6 +3534,9 @@ int main(int argc, char **argv) |
3261 | 3534 | |
3262 | 3535 | init_ioports(); |
3263 | 3536 | |
3537 | + /* allocate RAM */ | |
3538 | + cpu_register_physical_memory(0, phys_ram_size, 0); | |
3539 | + | |
3264 | 3540 | if (linux_boot) { |
3265 | 3541 | /* now we can load the kernel */ |
3266 | 3542 | ret = load_kernel(argv[optind], phys_ram_base + KERNEL_LOAD_ADDR); |
... | ... | @@ -3366,11 +3642,23 @@ int main(int argc, char **argv) |
3366 | 3642 | bochs_bios_init(); |
3367 | 3643 | } |
3368 | 3644 | |
3645 | + /* terminal init */ | |
3646 | + if (nodisp) { | |
3647 | + dumb_display_init(ds); | |
3648 | + } else { | |
3649 | +#ifdef CONFIG_SDL | |
3650 | + sdl_display_init(ds); | |
3651 | + /* the pthreads modify sigaction. We don't want that. */ | |
3652 | +#define sigaction __sigaction | |
3653 | +#else | |
3654 | + dumb_display_init(ds); | |
3655 | +#endif | |
3656 | + } | |
3369 | 3657 | /* init basic PC hardware */ |
3370 | 3658 | register_ioport_write(0x80, 1, ioport80_write, 1); |
3371 | 3659 | |
3372 | - register_ioport_write(0x3d4, 2, vga_ioport_write, 1); | |
3373 | - | |
3660 | + vga_init(ds, phys_ram_base + phys_ram_size, phys_ram_size, | |
3661 | + vga_ram_size); | |
3374 | 3662 | cmos_init(); |
3375 | 3663 | pic_init(); |
3376 | 3664 | pit_init(); |
... | ... | @@ -3378,7 +3666,7 @@ int main(int argc, char **argv) |
3378 | 3666 | ne2000_init(); |
3379 | 3667 | ide_init(); |
3380 | 3668 | kbd_init(); |
3381 | - | |
3669 | + | |
3382 | 3670 | /* setup cpu signal handlers for MMU / self modifying code handling */ |
3383 | 3671 | sigfillset(&act.sa_mask); |
3384 | 3672 | act.sa_flags = SA_SIGINFO; |
... | ... | @@ -3397,6 +3685,7 @@ int main(int argc, char **argv) |
3397 | 3685 | /* we probe the tick duration of the kernel to inform the user if |
3398 | 3686 | the emulated kernel requested a too high timer frequency */ |
3399 | 3687 | getitimer(ITIMER_REAL, &itv); |
3688 | + timer_ms = itv.it_interval.tv_usec / 1000; | |
3400 | 3689 | pit_min_timer_count = ((uint64_t)itv.it_interval.tv_usec * PIT_FREQ) / |
3401 | 3690 | 1000000; |
3402 | 3691 | ... | ... |
vl.h
... | ... | @@ -25,7 +25,22 @@ |
25 | 25 | #define VL_H |
26 | 26 | |
27 | 27 | /* vl.c */ |
28 | +struct CPUX86State; | |
29 | +extern int reset_requested; | |
30 | + | |
31 | +typedef void (IOPortWriteFunc)(struct CPUX86State *env, uint32_t address, uint32_t data); | |
32 | +typedef uint32_t (IOPortReadFunc)(struct CPUX86State *env, uint32_t address); | |
33 | + | |
28 | 34 | void *get_mmap_addr(unsigned long size); |
35 | +int register_ioport_read(int start, int length, IOPortReadFunc *func, int size); | |
36 | +int register_ioport_write(int start, int length, IOPortWriteFunc *func, int size); | |
37 | + | |
38 | +void kbd_put_keycode(int keycode); | |
39 | + | |
40 | +#define MOUSE_EVENT_LBUTTON 0x01 | |
41 | +#define MOUSE_EVENT_RBUTTON 0x02 | |
42 | +#define MOUSE_EVENT_MBUTTON 0x04 | |
43 | +void kbd_mouse_event(int dx, int dy, int dz, int buttons_state); | |
29 | 44 | |
30 | 45 | /* block.c */ |
31 | 46 | typedef struct BlockDriverState BlockDriverState; |
... | ... | @@ -52,4 +67,34 @@ struct cow_header_v2 { |
52 | 67 | uint32_t sectorsize; |
53 | 68 | }; |
54 | 69 | |
70 | +/* vga.c */ | |
71 | + | |
72 | +#define VGA_RAM_SIZE (8192 * 1024) | |
73 | + | |
74 | +typedef struct DisplayState { | |
75 | + uint8_t *data; | |
76 | + int linesize; | |
77 | + int depth; | |
78 | + void (*dpy_update)(struct DisplayState *s, int x, int y, int w, int h); | |
79 | + void (*dpy_resize)(struct DisplayState *s, int w, int h); | |
80 | + void (*dpy_refresh)(struct DisplayState *s); | |
81 | +} DisplayState; | |
82 | + | |
83 | +static inline void dpy_update(DisplayState *s, int x, int y, int w, int h) | |
84 | +{ | |
85 | + s->dpy_update(s, x, y, w, h); | |
86 | +} | |
87 | + | |
88 | +static inline void dpy_resize(DisplayState *s, int w, int h) | |
89 | +{ | |
90 | + s->dpy_resize(s, w, h); | |
91 | +} | |
92 | + | |
93 | +int vga_init(DisplayState *ds, uint8_t *vga_ram_base, | |
94 | + unsigned long vga_ram_offset, int vga_ram_size); | |
95 | +void vga_update_display(void); | |
96 | + | |
97 | +/* sdl.c */ | |
98 | +void sdl_display_init(DisplayState *ds); | |
99 | + | |
55 | 100 | #endif /* VL_H */ | ... | ... |