Commit 7dea1da4aebe3aa797fd37accf097d5d1a98d51d
1 parent
4ce900b4
quick and dirty CMOS irq emulation (windows install uses it) - emm386 keyboard f…
…ix (need a better way...) - better serial emulation (windows install uses it) - LDT and TR caches init fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@461 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
118 additions
and
12 deletions
vl.c
... | ... | @@ -61,6 +61,8 @@ |
61 | 61 | /* output Bochs bios info messages */ |
62 | 62 | //#define DEBUG_BIOS |
63 | 63 | |
64 | +//#define DEBUG_CMOS | |
65 | + | |
64 | 66 | /* debug PIC */ |
65 | 67 | //#define DEBUG_PIC |
66 | 68 | |
... | ... | @@ -73,6 +75,8 @@ |
73 | 75 | /* debug PC keyboard : only mouse */ |
74 | 76 | //#define DEBUG_MOUSE |
75 | 77 | |
78 | +//#define DEBUG_SERIAL | |
79 | + | |
76 | 80 | #define PHYS_RAM_BASE 0xac000000 |
77 | 81 | #define PHYS_RAM_MAX_SIZE (256 * 1024 * 1024) |
78 | 82 | |
... | ... | @@ -197,7 +201,8 @@ struct __attribute__ ((packed)) linux_params { |
197 | 201 | #define KERNEL_CS 0x10 |
198 | 202 | #define KERNEL_DS 0x18 |
199 | 203 | |
200 | -#define MAX_IOPORTS 4096 | |
204 | +/* XXX: use a two level table to limit memory usage */ | |
205 | +#define MAX_IOPORTS 65536 | |
201 | 206 | |
202 | 207 | static const char *bios_dir = CONFIG_QEMU_SHAREDIR; |
203 | 208 | char phys_ram_file[1024]; |
... | ... | @@ -461,6 +466,39 @@ void cmos_ioport_write(CPUX86State *env, uint32_t addr, uint32_t data) |
461 | 466 | { |
462 | 467 | if (addr == 0x70) { |
463 | 468 | cmos_index = data & 0x7f; |
469 | + } else { | |
470 | +#ifdef DEBUG_CMOS | |
471 | + printf("cmos: write index=0x%02x val=0x%02x\n", | |
472 | + cmos_index, data); | |
473 | +#endif | |
474 | + switch(addr) { | |
475 | + case RTC_SECONDS_ALARM: | |
476 | + case RTC_MINUTES_ALARM: | |
477 | + case RTC_HOURS_ALARM: | |
478 | + /* XXX: not supported */ | |
479 | + cmos_data[cmos_index] = data; | |
480 | + break; | |
481 | + case RTC_SECONDS: | |
482 | + case RTC_MINUTES: | |
483 | + case RTC_HOURS: | |
484 | + case RTC_DAY_OF_WEEK: | |
485 | + case RTC_DAY_OF_MONTH: | |
486 | + case RTC_MONTH: | |
487 | + case RTC_YEAR: | |
488 | + cmos_data[cmos_index] = data; | |
489 | + break; | |
490 | + case RTC_REG_A: | |
491 | + case RTC_REG_B: | |
492 | + cmos_data[cmos_index] = data; | |
493 | + break; | |
494 | + case RTC_REG_C: | |
495 | + case RTC_REG_D: | |
496 | + /* cannot write to them */ | |
497 | + break; | |
498 | + default: | |
499 | + cmos_data[cmos_index] = data; | |
500 | + break; | |
501 | + } | |
464 | 502 | } |
465 | 503 | } |
466 | 504 | |
... | ... | @@ -471,13 +509,22 @@ uint32_t cmos_ioport_read(CPUX86State *env, uint32_t addr) |
471 | 509 | if (addr == 0x70) { |
472 | 510 | return 0xff; |
473 | 511 | } else { |
474 | - /* toggle update-in-progress bit for Linux (same hack as | |
475 | - plex86) */ | |
476 | 512 | ret = cmos_data[cmos_index]; |
477 | - if (cmos_index == RTC_REG_A) | |
513 | + switch(cmos_index) { | |
514 | + case RTC_REG_A: | |
515 | + /* toggle update-in-progress bit for Linux (same hack as | |
516 | + plex86) */ | |
478 | 517 | cmos_data[RTC_REG_A] ^= 0x80; |
479 | - else if (cmos_index == RTC_REG_C) | |
518 | + break; | |
519 | + case RTC_REG_C: | |
520 | + pic_set_irq(8, 0); | |
480 | 521 | cmos_data[RTC_REG_C] = 0x00; |
522 | + break; | |
523 | + } | |
524 | +#ifdef DEBUG_CMOS | |
525 | + printf("cmos: read index=0x%02x val=0x%02x\n", | |
526 | + cmos_index, ret); | |
527 | +#endif | |
481 | 528 | return ret; |
482 | 529 | } |
483 | 530 | } |
... | ... | @@ -675,7 +722,7 @@ int cpu_x86_get_pic_interrupt(CPUX86State *env) |
675 | 722 | irq, |
676 | 723 | (double)(cpu_get_ticks() - irq_time[irq]) * 1000000.0 / ticks_per_sec); |
677 | 724 | #endif |
678 | -#ifdef DEBUG_PIC | |
725 | +#if defined(DEBUG_PIC) | |
679 | 726 | printf("pic_interrupt: irq=%d\n", irq); |
680 | 727 | #endif |
681 | 728 | |
... | ... | @@ -1191,6 +1238,28 @@ void pit_init(void) |
1191 | 1238 | #define UART_IIR_RDI 0x04 /* Receiver data interrupt */ |
1192 | 1239 | #define UART_IIR_RLSI 0x06 /* Receiver line status interrupt */ |
1193 | 1240 | |
1241 | +/* | |
1242 | + * These are the definitions for the Modem Control Register | |
1243 | + */ | |
1244 | +#define UART_MCR_LOOP 0x10 /* Enable loopback test mode */ | |
1245 | +#define UART_MCR_OUT2 0x08 /* Out2 complement */ | |
1246 | +#define UART_MCR_OUT1 0x04 /* Out1 complement */ | |
1247 | +#define UART_MCR_RTS 0x02 /* RTS complement */ | |
1248 | +#define UART_MCR_DTR 0x01 /* DTR complement */ | |
1249 | + | |
1250 | +/* | |
1251 | + * These are the definitions for the Modem Status Register | |
1252 | + */ | |
1253 | +#define UART_MSR_DCD 0x80 /* Data Carrier Detect */ | |
1254 | +#define UART_MSR_RI 0x40 /* Ring Indicator */ | |
1255 | +#define UART_MSR_DSR 0x20 /* Data Set Ready */ | |
1256 | +#define UART_MSR_CTS 0x10 /* Clear to Send */ | |
1257 | +#define UART_MSR_DDCD 0x08 /* Delta DCD */ | |
1258 | +#define UART_MSR_TERI 0x04 /* Trailing edge ring indicator */ | |
1259 | +#define UART_MSR_DDSR 0x02 /* Delta DSR */ | |
1260 | +#define UART_MSR_DCTS 0x01 /* Delta CTS */ | |
1261 | +#define UART_MSR_ANY_DELTA 0x0F /* Any of the delta bits! */ | |
1262 | + | |
1194 | 1263 | #define UART_LSR_TEMT 0x40 /* Transmitter empty */ |
1195 | 1264 | #define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */ |
1196 | 1265 | #define UART_LSR_BI 0x10 /* Break interrupt indicator */ |
... | ... | @@ -1209,6 +1278,9 @@ typedef struct SerialState { |
1209 | 1278 | uint8_t lsr; /* read only */ |
1210 | 1279 | uint8_t msr; |
1211 | 1280 | uint8_t scr; |
1281 | + /* NOTE: this hidden state is necessary for tx irq generation as | |
1282 | + it can be reset while reading iir */ | |
1283 | + int thr_ipending; | |
1212 | 1284 | } SerialState; |
1213 | 1285 | |
1214 | 1286 | SerialState serial_ports[1]; |
... | ... | @@ -1219,7 +1291,7 @@ void serial_update_irq(void) |
1219 | 1291 | |
1220 | 1292 | if ((s->lsr & UART_LSR_DR) && (s->ier & UART_IER_RDI)) { |
1221 | 1293 | s->iir = UART_IIR_RDI; |
1222 | - } else if ((s->lsr & UART_LSR_THRE) && (s->ier & UART_IER_THRI)) { | |
1294 | + } else if (s->thr_ipending && (s->ier & UART_IER_THRI)) { | |
1223 | 1295 | s->iir = UART_IIR_THRI; |
1224 | 1296 | } else { |
1225 | 1297 | s->iir = UART_IIR_NO_INT; |
... | ... | @@ -1238,12 +1310,16 @@ void serial_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) |
1238 | 1310 | int ret; |
1239 | 1311 | |
1240 | 1312 | addr &= 7; |
1313 | +#ifdef DEBUG_SERIAL | |
1314 | + printf("serial: write addr=0x%02x val=0x%02x\n", addr, val); | |
1315 | +#endif | |
1241 | 1316 | switch(addr) { |
1242 | 1317 | default: |
1243 | 1318 | case 0: |
1244 | 1319 | if (s->lcr & UART_LCR_DLAB) { |
1245 | 1320 | s->divider = (s->divider & 0xff00) | val; |
1246 | 1321 | } else { |
1322 | + s->thr_ipending = 0; | |
1247 | 1323 | s->lsr &= ~UART_LSR_THRE; |
1248 | 1324 | serial_update_irq(); |
1249 | 1325 | |
... | ... | @@ -1251,6 +1327,7 @@ void serial_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) |
1251 | 1327 | do { |
1252 | 1328 | ret = write(1, &ch, 1); |
1253 | 1329 | } while (ret != 1); |
1330 | + s->thr_ipending = 1; | |
1254 | 1331 | s->lsr |= UART_LSR_THRE; |
1255 | 1332 | s->lsr |= UART_LSR_TEMT; |
1256 | 1333 | serial_update_irq(); |
... | ... | @@ -1309,6 +1386,10 @@ uint32_t serial_ioport_read(CPUX86State *env, uint32_t addr) |
1309 | 1386 | break; |
1310 | 1387 | case 2: |
1311 | 1388 | ret = s->iir; |
1389 | + /* reset THR pending bit */ | |
1390 | + if ((ret & 0x7) == UART_IIR_THRI) | |
1391 | + s->thr_ipending = 0; | |
1392 | + serial_update_irq(); | |
1312 | 1393 | break; |
1313 | 1394 | case 3: |
1314 | 1395 | ret = s->lcr; |
... | ... | @@ -1320,12 +1401,23 @@ uint32_t serial_ioport_read(CPUX86State *env, uint32_t addr) |
1320 | 1401 | ret = s->lsr; |
1321 | 1402 | break; |
1322 | 1403 | case 6: |
1323 | - ret = s->msr; | |
1404 | + if (s->mcr & UART_MCR_LOOP) { | |
1405 | + /* in loopback, the modem output pins are connected to the | |
1406 | + inputs */ | |
1407 | + ret = (s->mcr & 0x0c) << 4; | |
1408 | + ret |= (s->mcr & 0x02) << 3; | |
1409 | + ret |= (s->mcr & 0x01) << 5; | |
1410 | + } else { | |
1411 | + ret = s->msr; | |
1412 | + } | |
1324 | 1413 | break; |
1325 | 1414 | case 7: |
1326 | 1415 | ret = s->scr; |
1327 | 1416 | break; |
1328 | 1417 | } |
1418 | +#ifdef DEBUG_SERIAL | |
1419 | + printf("serial: read addr=0x%02x val=0x%02x\n", addr, ret); | |
1420 | +#endif | |
1329 | 1421 | return ret; |
1330 | 1422 | } |
1331 | 1423 | |
... | ... | @@ -1388,7 +1480,8 @@ void serial_init(void) |
1388 | 1480 | SerialState *s = &serial_ports[0]; |
1389 | 1481 | |
1390 | 1482 | s->lsr = UART_LSR_TEMT | UART_LSR_THRE; |
1391 | - | |
1483 | + s->iir = UART_IIR_NO_INT; | |
1484 | + | |
1392 | 1485 | register_ioport_write(0x3f8, 8, serial_ioport_write, 1); |
1393 | 1486 | register_ioport_read(0x3f8, 8, serial_ioport_read, 1); |
1394 | 1487 | } |
... | ... | @@ -2108,14 +2201,20 @@ uint32_t kbd_read_data(CPUX86State *env, uint32_t addr) |
2108 | 2201 | { |
2109 | 2202 | KBDState *s = &kbd_state; |
2110 | 2203 | KBDQueue *q; |
2111 | - int val; | |
2204 | + int val, index; | |
2112 | 2205 | |
2113 | 2206 | q = &s->queues[0]; /* first check KBD data */ |
2114 | 2207 | if (q->count == 0) |
2115 | 2208 | q = &s->queues[1]; /* then check AUX data */ |
2116 | 2209 | if (q->count == 0) { |
2117 | - /* XXX: return something else ? */ | |
2118 | - val = 0; | |
2210 | + /* NOTE: if no data left, we return the last keyboard one | |
2211 | + (needed for EMM386) */ | |
2212 | + /* XXX: need a timer to do things correctly */ | |
2213 | + q = &s->queues[0]; | |
2214 | + index = q->rptr - 1; | |
2215 | + if (index < 0) | |
2216 | + index = KBD_QUEUE_SIZE - 1; | |
2217 | + val = q->data[index]; | |
2119 | 2218 | } else { |
2120 | 2219 | val = q->data[q->rptr]; |
2121 | 2220 | if (++q->rptr == KBD_QUEUE_SIZE) |
... | ... | @@ -2730,6 +2829,10 @@ int main_loop(void *opaque) |
2730 | 2829 | pic_set_irq(0, 1); |
2731 | 2830 | pic_set_irq(0, 0); |
2732 | 2831 | timer_irq_pending = 0; |
2832 | + /* XXX: RTC test */ | |
2833 | + if (cmos_data[RTC_REG_B] & 0x40) { | |
2834 | + pic_set_irq(8, 1); | |
2835 | + } | |
2733 | 2836 | } |
2734 | 2837 | |
2735 | 2838 | /* VGA */ |
... | ... | @@ -3116,6 +3219,9 @@ int main(int argc, char **argv) |
3116 | 3219 | env->idt.limit = 0xffff; |
3117 | 3220 | env->gdt.limit = 0xffff; |
3118 | 3221 | env->ldt.limit = 0xffff; |
3222 | + env->ldt.flags = DESC_P_MASK; | |
3223 | + env->tr.limit = 0xffff; | |
3224 | + env->tr.flags = DESC_P_MASK; | |
3119 | 3225 | |
3120 | 3226 | /* not correct (CS base=0xffff0000) */ |
3121 | 3227 | cpu_x86_load_seg_cache(env, R_CS, 0xf000, (uint8_t *)0x000f0000, 0xffff, 0); | ... | ... |