Respect the destination operand size of the 'Input from Port' instruction.

Approved by:	grehan (co-mentor)
This commit is contained in:
Tycho Nightingale 2014-04-18 15:22:56 +00:00
parent cb18b57c6d
commit d6aa08c3ef
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=264648
7 changed files with 117 additions and 53 deletions

View File

@ -517,7 +517,8 @@ vatpic_intr_accepted(struct vm *vm, int vector)
}
static int
vatpic_read(struct vatpic *vatpic, struct atpic *atpic, struct vm_exit *vmexit)
vatpic_read(struct vatpic *vatpic, struct atpic *atpic, bool in, int port,
int bytes, uint32_t *eax)
{
VATPIC_LOCK(vatpic);
@ -526,16 +527,16 @@ vatpic_read(struct vatpic *vatpic, struct atpic *atpic, struct vm_exit *vmexit)
VATPIC_UNLOCK(vatpic);
return (-1);
} else {
if (vmexit->u.inout.port & ICU_IMR_OFFSET) {
if (port & ICU_IMR_OFFSET) {
/* read interrrupt mask register */
vmexit->u.inout.eax = atpic->mask;
*eax = atpic->mask;
} else {
if (atpic->rd_cmd_reg == OCW3_RIS) {
/* read interrupt service register */
vmexit->u.inout.eax = atpic->service;
*eax = atpic->service;
} else {
/* read interrupt request register */
vmexit->u.inout.eax = atpic->request;
*eax = atpic->request;
}
}
}
@ -547,17 +548,17 @@ vatpic_read(struct vatpic *vatpic, struct atpic *atpic, struct vm_exit *vmexit)
}
static int
vatpic_write(struct vatpic *vatpic, struct atpic *atpic,
struct vm_exit *vmexit)
vatpic_write(struct vatpic *vatpic, struct atpic *atpic, bool in, int port,
int bytes, uint32_t *eax)
{
int error;
uint8_t val;
val = vmexit->u.inout.eax;
val = *eax;
VATPIC_LOCK(vatpic);
if (vmexit->u.inout.port & ICU_IMR_OFFSET) {
if (port & ICU_IMR_OFFSET) {
if (atpic->ready) {
error = vatpic_ocw1(vatpic, atpic, val);
} else {
@ -594,7 +595,8 @@ vatpic_write(struct vatpic *vatpic, struct atpic *atpic,
}
int
vatpic_master_handler(void *vm, int vcpuid, struct vm_exit *vmexit)
vatpic_master_handler(void *vm, int vcpuid, bool in, int port, int bytes,
uint32_t *eax)
{
struct vatpic *vatpic;
struct atpic *atpic;
@ -602,18 +604,19 @@ vatpic_master_handler(void *vm, int vcpuid, struct vm_exit *vmexit)
vatpic = vm_atpic(vm);
atpic = &vatpic->atpic[0];
if (vmexit->u.inout.bytes != 1)
if (bytes != 1)
return (-1);
if (vmexit->u.inout.in) {
return (vatpic_read(vatpic, atpic, vmexit));
if (in) {
return (vatpic_read(vatpic, atpic, in, port, bytes, eax));
}
return (vatpic_write(vatpic, atpic, vmexit));
return (vatpic_write(vatpic, atpic, in, port, bytes, eax));
}
int
vatpic_slave_handler(void *vm, int vcpuid, struct vm_exit *vmexit)
vatpic_slave_handler(void *vm, int vcpuid, bool in, int port, int bytes,
uint32_t *eax)
{
struct vatpic *vatpic;
struct atpic *atpic;
@ -621,35 +624,36 @@ vatpic_slave_handler(void *vm, int vcpuid, struct vm_exit *vmexit)
vatpic = vm_atpic(vm);
atpic = &vatpic->atpic[1];
if (vmexit->u.inout.bytes != 1)
if (bytes != 1)
return (-1);
if (vmexit->u.inout.in) {
return (vatpic_read(vatpic, atpic, vmexit));
if (in) {
return (vatpic_read(vatpic, atpic, in, port, bytes, eax));
}
return (vatpic_write(vatpic, atpic, vmexit));
return (vatpic_write(vatpic, atpic, in, port, bytes, eax));
}
int
vatpic_elc_handler(void *vm, int vcpuid, struct vm_exit *vmexit)
vatpic_elc_handler(void *vm, int vcpuid, bool in, int port, int bytes,
uint32_t *eax)
{
struct vatpic *vatpic;
bool is_master;
vatpic = vm_atpic(vm);
is_master = (vmexit->u.inout.port == IO_ELCR1);
is_master = (port == IO_ELCR1);
if (vmexit->u.inout.bytes != 1)
if (bytes != 1)
return (-1);
VATPIC_LOCK(vatpic);
if (vmexit->u.inout.in) {
if (in) {
if (is_master)
vmexit->u.inout.eax = vatpic->elc[0];
*eax = vatpic->elc[0];
else
vmexit->u.inout.eax = vatpic->elc[1];
*eax = vatpic->elc[1];
} else {
/*
* For the master PIC the cascade channel (IRQ2), the
@ -662,9 +666,9 @@ vatpic_elc_handler(void *vm, int vcpuid, struct vm_exit *vmexit)
* be programmed for level mode.
*/
if (is_master)
vatpic->elc[0] = (vmexit->u.inout.eax & 0xf8);
vatpic->elc[0] = (*eax & 0xf8);
else
vatpic->elc[1] = (vmexit->u.inout.eax & 0xde);
vatpic->elc[1] = (*eax & 0xde);
}
VATPIC_UNLOCK(vatpic);

View File

@ -39,9 +39,12 @@
struct vatpic *vatpic_init(struct vm *vm);
void vatpic_cleanup(struct vatpic *vatpic);
int vatpic_master_handler(void *vm, int vcpuid, struct vm_exit *vmexit);
int vatpic_slave_handler(void *vm, int vcpuid, struct vm_exit *vmexit);
int vatpic_elc_handler(void *vm, int vcpuid, struct vm_exit *vmexit);
int vatpic_master_handler(void *vm, int vcpuid, bool in, int port, int bytes,
uint32_t *eax);
int vatpic_slave_handler(void *vm, int vcpuid, bool in, int port, int bytes,
uint32_t *eax);
int vatpic_elc_handler(void *vm, int vcpuid, bool in, int port, int bytes,
uint32_t *eax);
int vatpic_assert_irq(struct vm *vm, int irq);
int vatpic_deassert_irq(struct vm *vm, int irq);

View File

@ -253,24 +253,23 @@ vatpit_update_mode(struct vatpit *vatpit, uint8_t val)
}
int
vatpit_handler(void *vm, int vcpuid, struct vm_exit *vmexit)
vatpit_handler(void *vm, int vcpuid, bool in, int port, int bytes,
uint32_t *eax)
{
struct vatpit *vatpit;
struct channel *c;
int port;
uint8_t val;
int error;
vatpit = vm_atpit(vm);
if (vmexit->u.inout.bytes != 1)
if (bytes != 1)
return (-1);
val = vmexit->u.inout.eax;
port = vmexit->u.inout.port;
val = *eax;
if (port == TIMER_MODE) {
if (vmexit->u.inout.in) {
if (in) {
VM_CTR0(vatpit->vm, "vatpit attempt to read mode");
return (-1);
}
@ -283,12 +282,12 @@ vatpit_handler(void *vm, int vcpuid, struct vm_exit *vmexit)
}
/* counter ports */
KASSERT(port >= TIMER_CNTR0 && vmexit->u.inout.port <= TIMER_CNTR2,
KASSERT(port >= TIMER_CNTR0 && port <= TIMER_CNTR2,
("invalid port 0x%x", port));
c = &vatpit->channel[port - TIMER_CNTR0];
VATPIT_LOCK(vatpit);
if (vmexit->u.inout.in) {
if (in) {
/*
* The spec says that once the output latch is completely
* read it should revert to "following" the counter. Use
@ -303,12 +302,12 @@ vatpit_handler(void *vm, int vcpuid, struct vm_exit *vmexit)
if (c->frbyte)
tmp >>= 8;
tmp &= 0xff;
vmexit->u.inout.eax = tmp;
*eax = tmp;
c->frbyte ^= 1;
} else
vmexit->u.inout.eax = c->ol[--c->olbyte];
*eax = c->ol[--c->olbyte];
} else {
c->cr[c->crbyte++] = vmexit->u.inout.eax;
c->cr[c->crbyte++] = *eax;
if (c->crbyte == 2) {
c->frbyte = 0;
c->crbyte = 0;
@ -329,18 +328,19 @@ vatpit_handler(void *vm, int vcpuid, struct vm_exit *vmexit)
}
int
vatpit_nmisc_handler(void *vm, int vcpuid, struct vm_exit *vmexit)
vatpit_nmisc_handler(void *vm, int vcpuid, bool in, int port, int bytes,
uint32_t *eax)
{
struct vatpit *vatpit;
vatpit = vm_atpit(vm);
if (vmexit->u.inout.in) {
if (in) {
VATPIT_LOCK(vatpit);
if (vatpit_get_out(vatpit, 2))
vmexit->u.inout.eax = TMR2_OUT_STS;
*eax = TMR2_OUT_STS;
else
vmexit->u.inout.eax = 0;
*eax = 0;
VATPIT_UNLOCK(vatpit);
}

View File

@ -37,7 +37,9 @@
struct vatpit *vatpit_init(struct vm *vm);
void vatpit_cleanup(struct vatpit *vatpit);
int vatpit_handler(void *vm, int vcpuid, struct vm_exit *vmexit);
int vatpit_nmisc_handler(void *vm, int vcpuid, struct vm_exit *vmexit);
int vatpit_handler(void *vm, int vcpuid, bool in, int port, int bytes,
uint32_t *eax);
int vatpit_nmisc_handler(void *vm, int vcpuid, bool in, int port, int bytes,
uint32_t *eax);
#endif /* _VATPIT_H_ */

View File

@ -59,6 +59,8 @@ int
emulate_ioport(struct vm *vm, int vcpuid, struct vm_exit *vmexit)
{
ioport_handler_func_t handler;
uint32_t mask, val;
int error;
if (vmexit->u.inout.port >= MAX_IOPORTS)
return (-1);
@ -67,5 +69,39 @@ emulate_ioport(struct vm *vm, int vcpuid, struct vm_exit *vmexit)
if (handler == NULL)
return (-1);
return ((*handler)(vm, vcpuid, vmexit));
if (!vmexit->u.inout.in) {
switch (vmexit->u.inout.bytes) {
case 1:
mask = 0xff;
break;
case 2:
mask = 0xffff;
break;
default:
mask = 0xffffffff;
break;
}
val = vmexit->u.inout.eax & mask;
}
error = (*handler)(vm, vcpuid, vmexit->u.inout.in,
vmexit->u.inout.port, vmexit->u.inout.bytes, &val);
if (!error && vmexit->u.inout.in) {
switch (vmexit->u.inout.bytes) {
case 1:
mask = 0xff;
break;
case 2:
mask = 0xffff;
break;
default:
mask = 0xffffffff;
break;
}
vmexit->u.inout.eax &= ~mask;
vmexit->u.inout.eax |= val & mask;
}
return (error);
}

View File

@ -30,7 +30,7 @@
#define _VMM_IOPORT_H_
typedef int (*ioport_handler_func_t)(void *vm, int vcpuid,
struct vm_exit *vmexit);
bool in, int port, int bytes, uint32_t *val);
int emulate_ioport(struct vm *vm, int vcpuid, struct vm_exit *vmexit);

View File

@ -95,9 +95,10 @@ emulate_inout(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
uint32_t *eax, int strict)
{
int flags;
uint32_t mask;
uint32_t mask, val;
inout_func_t handler;
void *arg;
int error;
assert(port < MAX_IOPORTS);
@ -118,16 +119,34 @@ emulate_inout(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
mask = 0xffffffff;
break;
}
*eax = *eax & mask;
val = *eax & mask;
}
flags = inout_handlers[port].flags;
arg = inout_handlers[port].arg;
if ((in && (flags & IOPORT_F_IN)) || (!in && (flags & IOPORT_F_OUT)))
return ((*handler)(ctx, vcpu, in, port, bytes, eax, arg));
error = (*handler)(ctx, vcpu, in, port, bytes, &val, arg);
else
return (-1);
error = -1;
if (!error && in) {
switch (bytes) {
case 1:
mask = 0xff;
break;
case 2:
mask = 0xffff;
break;
default:
mask = 0xffffffff;
break;
}
*eax &= ~mask;
*eax |= val & mask;
}
return (error);
}
void