mirror of
https://git.FreeBSD.org/src.git
synced 2025-01-02 12:20:51 +00:00
Respect the destination operand size of the 'Input from Port' instruction.
Approved by: grehan (co-mentor)
This commit is contained in:
parent
cb18b57c6d
commit
d6aa08c3ef
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=264648
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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_ */
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user