Revision 330d0414
b/vl.c | ||
---|---|---|
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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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; |
Also available in: Unified diff