mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-09 10:34:58 -06:00
quick and dirty CMOS irq emulation (windows install uses it) - emm386 keyboard fix (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
This commit is contained in:
parent
4ce900b44c
commit
7dea1da4ae
1 changed files with 118 additions and 12 deletions
130
vl.c
130
vl.c
|
@ -61,6 +61,8 @@
|
||||||
/* output Bochs bios info messages */
|
/* output Bochs bios info messages */
|
||||||
//#define DEBUG_BIOS
|
//#define DEBUG_BIOS
|
||||||
|
|
||||||
|
//#define DEBUG_CMOS
|
||||||
|
|
||||||
/* debug PIC */
|
/* debug PIC */
|
||||||
//#define DEBUG_PIC
|
//#define DEBUG_PIC
|
||||||
|
|
||||||
|
@ -73,6 +75,8 @@
|
||||||
/* debug PC keyboard : only mouse */
|
/* debug PC keyboard : only mouse */
|
||||||
//#define DEBUG_MOUSE
|
//#define DEBUG_MOUSE
|
||||||
|
|
||||||
|
//#define DEBUG_SERIAL
|
||||||
|
|
||||||
#define PHYS_RAM_BASE 0xac000000
|
#define PHYS_RAM_BASE 0xac000000
|
||||||
#define PHYS_RAM_MAX_SIZE (256 * 1024 * 1024)
|
#define PHYS_RAM_MAX_SIZE (256 * 1024 * 1024)
|
||||||
|
|
||||||
|
@ -197,7 +201,8 @@ struct __attribute__ ((packed)) linux_params {
|
||||||
#define KERNEL_CS 0x10
|
#define KERNEL_CS 0x10
|
||||||
#define KERNEL_DS 0x18
|
#define KERNEL_DS 0x18
|
||||||
|
|
||||||
#define MAX_IOPORTS 4096
|
/* XXX: use a two level table to limit memory usage */
|
||||||
|
#define MAX_IOPORTS 65536
|
||||||
|
|
||||||
static const char *bios_dir = CONFIG_QEMU_SHAREDIR;
|
static const char *bios_dir = CONFIG_QEMU_SHAREDIR;
|
||||||
char phys_ram_file[1024];
|
char phys_ram_file[1024];
|
||||||
|
@ -461,6 +466,39 @@ void cmos_ioport_write(CPUX86State *env, uint32_t addr, uint32_t data)
|
||||||
{
|
{
|
||||||
if (addr == 0x70) {
|
if (addr == 0x70) {
|
||||||
cmos_index = data & 0x7f;
|
cmos_index = data & 0x7f;
|
||||||
|
} else {
|
||||||
|
#ifdef DEBUG_CMOS
|
||||||
|
printf("cmos: write index=0x%02x val=0x%02x\n",
|
||||||
|
cmos_index, data);
|
||||||
|
#endif
|
||||||
|
switch(addr) {
|
||||||
|
case RTC_SECONDS_ALARM:
|
||||||
|
case RTC_MINUTES_ALARM:
|
||||||
|
case RTC_HOURS_ALARM:
|
||||||
|
/* XXX: not supported */
|
||||||
|
cmos_data[cmos_index] = data;
|
||||||
|
break;
|
||||||
|
case RTC_SECONDS:
|
||||||
|
case RTC_MINUTES:
|
||||||
|
case RTC_HOURS:
|
||||||
|
case RTC_DAY_OF_WEEK:
|
||||||
|
case RTC_DAY_OF_MONTH:
|
||||||
|
case RTC_MONTH:
|
||||||
|
case RTC_YEAR:
|
||||||
|
cmos_data[cmos_index] = data;
|
||||||
|
break;
|
||||||
|
case RTC_REG_A:
|
||||||
|
case RTC_REG_B:
|
||||||
|
cmos_data[cmos_index] = data;
|
||||||
|
break;
|
||||||
|
case RTC_REG_C:
|
||||||
|
case RTC_REG_D:
|
||||||
|
/* cannot write to them */
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
cmos_data[cmos_index] = data;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -471,13 +509,22 @@ uint32_t cmos_ioport_read(CPUX86State *env, uint32_t addr)
|
||||||
if (addr == 0x70) {
|
if (addr == 0x70) {
|
||||||
return 0xff;
|
return 0xff;
|
||||||
} else {
|
} else {
|
||||||
/* toggle update-in-progress bit for Linux (same hack as
|
|
||||||
plex86) */
|
|
||||||
ret = cmos_data[cmos_index];
|
ret = cmos_data[cmos_index];
|
||||||
if (cmos_index == RTC_REG_A)
|
switch(cmos_index) {
|
||||||
|
case RTC_REG_A:
|
||||||
|
/* toggle update-in-progress bit for Linux (same hack as
|
||||||
|
plex86) */
|
||||||
cmos_data[RTC_REG_A] ^= 0x80;
|
cmos_data[RTC_REG_A] ^= 0x80;
|
||||||
else if (cmos_index == RTC_REG_C)
|
break;
|
||||||
|
case RTC_REG_C:
|
||||||
|
pic_set_irq(8, 0);
|
||||||
cmos_data[RTC_REG_C] = 0x00;
|
cmos_data[RTC_REG_C] = 0x00;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#ifdef DEBUG_CMOS
|
||||||
|
printf("cmos: read index=0x%02x val=0x%02x\n",
|
||||||
|
cmos_index, ret);
|
||||||
|
#endif
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -675,7 +722,7 @@ int cpu_x86_get_pic_interrupt(CPUX86State *env)
|
||||||
irq,
|
irq,
|
||||||
(double)(cpu_get_ticks() - irq_time[irq]) * 1000000.0 / ticks_per_sec);
|
(double)(cpu_get_ticks() - irq_time[irq]) * 1000000.0 / ticks_per_sec);
|
||||||
#endif
|
#endif
|
||||||
#ifdef DEBUG_PIC
|
#if defined(DEBUG_PIC)
|
||||||
printf("pic_interrupt: irq=%d\n", irq);
|
printf("pic_interrupt: irq=%d\n", irq);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1191,6 +1238,28 @@ void pit_init(void)
|
||||||
#define UART_IIR_RDI 0x04 /* Receiver data interrupt */
|
#define UART_IIR_RDI 0x04 /* Receiver data interrupt */
|
||||||
#define UART_IIR_RLSI 0x06 /* Receiver line status interrupt */
|
#define UART_IIR_RLSI 0x06 /* Receiver line status interrupt */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* These are the definitions for the Modem Control Register
|
||||||
|
*/
|
||||||
|
#define UART_MCR_LOOP 0x10 /* Enable loopback test mode */
|
||||||
|
#define UART_MCR_OUT2 0x08 /* Out2 complement */
|
||||||
|
#define UART_MCR_OUT1 0x04 /* Out1 complement */
|
||||||
|
#define UART_MCR_RTS 0x02 /* RTS complement */
|
||||||
|
#define UART_MCR_DTR 0x01 /* DTR complement */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* These are the definitions for the Modem Status Register
|
||||||
|
*/
|
||||||
|
#define UART_MSR_DCD 0x80 /* Data Carrier Detect */
|
||||||
|
#define UART_MSR_RI 0x40 /* Ring Indicator */
|
||||||
|
#define UART_MSR_DSR 0x20 /* Data Set Ready */
|
||||||
|
#define UART_MSR_CTS 0x10 /* Clear to Send */
|
||||||
|
#define UART_MSR_DDCD 0x08 /* Delta DCD */
|
||||||
|
#define UART_MSR_TERI 0x04 /* Trailing edge ring indicator */
|
||||||
|
#define UART_MSR_DDSR 0x02 /* Delta DSR */
|
||||||
|
#define UART_MSR_DCTS 0x01 /* Delta CTS */
|
||||||
|
#define UART_MSR_ANY_DELTA 0x0F /* Any of the delta bits! */
|
||||||
|
|
||||||
#define UART_LSR_TEMT 0x40 /* Transmitter empty */
|
#define UART_LSR_TEMT 0x40 /* Transmitter empty */
|
||||||
#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */
|
#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */
|
||||||
#define UART_LSR_BI 0x10 /* Break interrupt indicator */
|
#define UART_LSR_BI 0x10 /* Break interrupt indicator */
|
||||||
|
@ -1209,6 +1278,9 @@ typedef struct SerialState {
|
||||||
uint8_t lsr; /* read only */
|
uint8_t lsr; /* read only */
|
||||||
uint8_t msr;
|
uint8_t msr;
|
||||||
uint8_t scr;
|
uint8_t scr;
|
||||||
|
/* NOTE: this hidden state is necessary for tx irq generation as
|
||||||
|
it can be reset while reading iir */
|
||||||
|
int thr_ipending;
|
||||||
} SerialState;
|
} SerialState;
|
||||||
|
|
||||||
SerialState serial_ports[1];
|
SerialState serial_ports[1];
|
||||||
|
@ -1219,7 +1291,7 @@ void serial_update_irq(void)
|
||||||
|
|
||||||
if ((s->lsr & UART_LSR_DR) && (s->ier & UART_IER_RDI)) {
|
if ((s->lsr & UART_LSR_DR) && (s->ier & UART_IER_RDI)) {
|
||||||
s->iir = UART_IIR_RDI;
|
s->iir = UART_IIR_RDI;
|
||||||
} else if ((s->lsr & UART_LSR_THRE) && (s->ier & UART_IER_THRI)) {
|
} else if (s->thr_ipending && (s->ier & UART_IER_THRI)) {
|
||||||
s->iir = UART_IIR_THRI;
|
s->iir = UART_IIR_THRI;
|
||||||
} else {
|
} else {
|
||||||
s->iir = UART_IIR_NO_INT;
|
s->iir = UART_IIR_NO_INT;
|
||||||
|
@ -1238,12 +1310,16 @@ void serial_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val)
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
addr &= 7;
|
addr &= 7;
|
||||||
|
#ifdef DEBUG_SERIAL
|
||||||
|
printf("serial: write addr=0x%02x val=0x%02x\n", addr, val);
|
||||||
|
#endif
|
||||||
switch(addr) {
|
switch(addr) {
|
||||||
default:
|
default:
|
||||||
case 0:
|
case 0:
|
||||||
if (s->lcr & UART_LCR_DLAB) {
|
if (s->lcr & UART_LCR_DLAB) {
|
||||||
s->divider = (s->divider & 0xff00) | val;
|
s->divider = (s->divider & 0xff00) | val;
|
||||||
} else {
|
} else {
|
||||||
|
s->thr_ipending = 0;
|
||||||
s->lsr &= ~UART_LSR_THRE;
|
s->lsr &= ~UART_LSR_THRE;
|
||||||
serial_update_irq();
|
serial_update_irq();
|
||||||
|
|
||||||
|
@ -1251,6 +1327,7 @@ void serial_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val)
|
||||||
do {
|
do {
|
||||||
ret = write(1, &ch, 1);
|
ret = write(1, &ch, 1);
|
||||||
} while (ret != 1);
|
} while (ret != 1);
|
||||||
|
s->thr_ipending = 1;
|
||||||
s->lsr |= UART_LSR_THRE;
|
s->lsr |= UART_LSR_THRE;
|
||||||
s->lsr |= UART_LSR_TEMT;
|
s->lsr |= UART_LSR_TEMT;
|
||||||
serial_update_irq();
|
serial_update_irq();
|
||||||
|
@ -1309,6 +1386,10 @@ uint32_t serial_ioport_read(CPUX86State *env, uint32_t addr)
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
ret = s->iir;
|
ret = s->iir;
|
||||||
|
/* reset THR pending bit */
|
||||||
|
if ((ret & 0x7) == UART_IIR_THRI)
|
||||||
|
s->thr_ipending = 0;
|
||||||
|
serial_update_irq();
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
ret = s->lcr;
|
ret = s->lcr;
|
||||||
|
@ -1320,12 +1401,23 @@ uint32_t serial_ioport_read(CPUX86State *env, uint32_t addr)
|
||||||
ret = s->lsr;
|
ret = s->lsr;
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
ret = s->msr;
|
if (s->mcr & UART_MCR_LOOP) {
|
||||||
|
/* in loopback, the modem output pins are connected to the
|
||||||
|
inputs */
|
||||||
|
ret = (s->mcr & 0x0c) << 4;
|
||||||
|
ret |= (s->mcr & 0x02) << 3;
|
||||||
|
ret |= (s->mcr & 0x01) << 5;
|
||||||
|
} else {
|
||||||
|
ret = s->msr;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 7:
|
case 7:
|
||||||
ret = s->scr;
|
ret = s->scr;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
#ifdef DEBUG_SERIAL
|
||||||
|
printf("serial: read addr=0x%02x val=0x%02x\n", addr, ret);
|
||||||
|
#endif
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1388,7 +1480,8 @@ void serial_init(void)
|
||||||
SerialState *s = &serial_ports[0];
|
SerialState *s = &serial_ports[0];
|
||||||
|
|
||||||
s->lsr = UART_LSR_TEMT | UART_LSR_THRE;
|
s->lsr = UART_LSR_TEMT | UART_LSR_THRE;
|
||||||
|
s->iir = UART_IIR_NO_INT;
|
||||||
|
|
||||||
register_ioport_write(0x3f8, 8, serial_ioport_write, 1);
|
register_ioport_write(0x3f8, 8, serial_ioport_write, 1);
|
||||||
register_ioport_read(0x3f8, 8, serial_ioport_read, 1);
|
register_ioport_read(0x3f8, 8, serial_ioport_read, 1);
|
||||||
}
|
}
|
||||||
|
@ -2108,14 +2201,20 @@ uint32_t kbd_read_data(CPUX86State *env, uint32_t addr)
|
||||||
{
|
{
|
||||||
KBDState *s = &kbd_state;
|
KBDState *s = &kbd_state;
|
||||||
KBDQueue *q;
|
KBDQueue *q;
|
||||||
int val;
|
int val, index;
|
||||||
|
|
||||||
q = &s->queues[0]; /* first check KBD data */
|
q = &s->queues[0]; /* first check KBD data */
|
||||||
if (q->count == 0)
|
if (q->count == 0)
|
||||||
q = &s->queues[1]; /* then check AUX data */
|
q = &s->queues[1]; /* then check AUX data */
|
||||||
if (q->count == 0) {
|
if (q->count == 0) {
|
||||||
/* XXX: return something else ? */
|
/* NOTE: if no data left, we return the last keyboard one
|
||||||
val = 0;
|
(needed for EMM386) */
|
||||||
|
/* XXX: need a timer to do things correctly */
|
||||||
|
q = &s->queues[0];
|
||||||
|
index = q->rptr - 1;
|
||||||
|
if (index < 0)
|
||||||
|
index = KBD_QUEUE_SIZE - 1;
|
||||||
|
val = q->data[index];
|
||||||
} else {
|
} else {
|
||||||
val = q->data[q->rptr];
|
val = q->data[q->rptr];
|
||||||
if (++q->rptr == KBD_QUEUE_SIZE)
|
if (++q->rptr == KBD_QUEUE_SIZE)
|
||||||
|
@ -2730,6 +2829,10 @@ int main_loop(void *opaque)
|
||||||
pic_set_irq(0, 1);
|
pic_set_irq(0, 1);
|
||||||
pic_set_irq(0, 0);
|
pic_set_irq(0, 0);
|
||||||
timer_irq_pending = 0;
|
timer_irq_pending = 0;
|
||||||
|
/* XXX: RTC test */
|
||||||
|
if (cmos_data[RTC_REG_B] & 0x40) {
|
||||||
|
pic_set_irq(8, 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* VGA */
|
/* VGA */
|
||||||
|
@ -3116,6 +3219,9 @@ int main(int argc, char **argv)
|
||||||
env->idt.limit = 0xffff;
|
env->idt.limit = 0xffff;
|
||||||
env->gdt.limit = 0xffff;
|
env->gdt.limit = 0xffff;
|
||||||
env->ldt.limit = 0xffff;
|
env->ldt.limit = 0xffff;
|
||||||
|
env->ldt.flags = DESC_P_MASK;
|
||||||
|
env->tr.limit = 0xffff;
|
||||||
|
env->tr.flags = DESC_P_MASK;
|
||||||
|
|
||||||
/* not correct (CS base=0xffff0000) */
|
/* not correct (CS base=0xffff0000) */
|
||||||
cpu_x86_load_seg_cache(env, R_CS, 0xf000, (uint8_t *)0x000f0000, 0xffff, 0);
|
cpu_x86_load_seg_cache(env, R_CS, 0xf000, (uint8_t *)0x000f0000, 0xffff, 0);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue