Commit 7dea1da4aebe3aa797fd37accf097d5d1a98d51d

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