mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 18:50:05 +01:00
[HVM] Fix PIC IO intercept: addresses are physical, not virtual.
Signed-off-by: Xiaohui Xin <xiaohui.xin@intel.com> Signed-off-by: Xiaowei Yang <xiaowei.yang@intel.com> Signed-off-by: Xin Li <xin.b.li@intel.com>
This commit is contained in:
1 parent
ad5b45d12e
commit
b2e0105ec9
2 files changed
+33
-32
No files matched your search
+22
-23
@@ -498,19 +498,19 @@ void pic_init(struct hvm_virpic *s, void (*irq_request)(void *, int),
|
||||
|
||||
static int intercept_pic_io(ioreq_t *p)
|
||||
{
|
||||
struct hvm_virpic *pic;
|
||||
struct vcpu *v = current;
|
||||
struct hvm_virpic *pic;
|
||||
uint32_t data;
|
||||
unsigned long flags;
|
||||
|
||||
if ( p->size != 1 || p->count != 1) {
|
||||
|
||||
if ( p->size != 1 || p->count != 1 ) {
|
||||
printk("PIC_IO wrong access size %d!\n", (int)p->size);
|
||||
return 1;
|
||||
}
|
||||
pic = &v->domain->arch.hvm_domain.vpic;
|
||||
if ( p->dir == 0 ) {
|
||||
if (p->pdata_valid)
|
||||
(void)hvm_copy_from_guest_virt(
|
||||
|
||||
pic = ¤t->domain->arch.hvm_domain.vpic;
|
||||
if ( p->dir == IOREQ_WRITE ) {
|
||||
if ( p->pdata_valid )
|
||||
(void)hvm_copy_from_guest_phys(
|
||||
&data, (unsigned long)p->u.pdata, p->size);
|
||||
else
|
||||
data = p->u.data;
|
||||
@@ -524,10 +524,10 @@ static int intercept_pic_io(ioreq_t *p)
|
||||
data = pic_ioport_read(
|
||||
(void*)&pic->pics[p->addr>>7], (uint32_t) p->addr);
|
||||
spin_unlock_irqrestore(&pic->lock, flags);
|
||||
if (p->pdata_valid)
|
||||
(void)hvm_copy_to_guest_virt(
|
||||
if ( p->pdata_valid )
|
||||
(void)hvm_copy_to_guest_phys(
|
||||
(unsigned long)p->u.pdata, &data, p->size);
|
||||
else
|
||||
else
|
||||
p->u.data = (u64)data;
|
||||
}
|
||||
return 1;
|
||||
@@ -535,42 +535,41 @@ static int intercept_pic_io(ioreq_t *p)
|
||||
|
||||
static int intercept_elcr_io(ioreq_t *p)
|
||||
{
|
||||
struct hvm_virpic *s;
|
||||
struct vcpu *v = current;
|
||||
struct hvm_virpic *s;
|
||||
uint32_t data;
|
||||
unsigned long flags;
|
||||
|
||||
|
||||
if ( p->size != 1 || p->count != 1 ) {
|
||||
printk("PIC_IO wrong access size %d!\n", (int)p->size);
|
||||
return 1;
|
||||
}
|
||||
|
||||
s = &v->domain->arch.hvm_domain.vpic;
|
||||
if ( p->dir == 0 ) {
|
||||
if (p->pdata_valid)
|
||||
(void)hvm_copy_from_guest_virt(
|
||||
s = ¤t->domain->arch.hvm_domain.vpic;
|
||||
if ( p->dir == IOREQ_WRITE ) {
|
||||
if ( p->pdata_valid )
|
||||
(void)hvm_copy_from_guest_phys(
|
||||
&data, (unsigned long)p->u.pdata, p->size);
|
||||
else
|
||||
data = p->u.data;
|
||||
spin_lock_irqsave(&s->lock, flags);
|
||||
elcr_ioport_write((void*)&s->pics[p->addr&1],
|
||||
(uint32_t) p->addr, (uint32_t)( data & 0xff));
|
||||
get_sp(current->domain)->sp_global.pic_elcr =
|
||||
get_sp(current->domain)->sp_global.pic_elcr =
|
||||
s->pics[0].elcr | ((u16)s->pics[1].elcr << 8);
|
||||
spin_unlock_irqrestore(&s->lock, flags);
|
||||
}
|
||||
else {
|
||||
data = (u64) elcr_ioport_read(
|
||||
(void*)&s->pics[p->addr&1], (uint32_t) p->addr);
|
||||
if (p->pdata_valid)
|
||||
(void)hvm_copy_to_guest_virt(
|
||||
if ( p->pdata_valid )
|
||||
(void)hvm_copy_to_guest_phys(
|
||||
(unsigned long)p->u.pdata, &data, p->size);
|
||||
else
|
||||
else
|
||||
p->u.data = (u64)data;
|
||||
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void register_pic_io_hook (void)
|
||||
{
|
||||
register_portio_handler(0x20, 2, intercept_pic_io);
|
||||
|
||||
@@ -730,13 +730,13 @@ void send_pio_req(struct cpu_user_regs *regs, unsigned long port,
|
||||
vcpu_iodata_t *vio;
|
||||
ioreq_t *p;
|
||||
|
||||
if (size == 0 || count == 0) {
|
||||
if ( size == 0 || count == 0 ) {
|
||||
printf("null pio request? port %lx, count %lx, size %d, value %lx, dir %d, pvalid %d.\n",
|
||||
port, count, size, value, dir, pvalid);
|
||||
}
|
||||
|
||||
vio = get_vio(v->domain, v->vcpu_id);
|
||||
if (vio == NULL) {
|
||||
if ( vio == NULL ) {
|
||||
printk("bad shared page: %lx\n", (unsigned long) vio);
|
||||
domain_crash_synchronous();
|
||||
}
|
||||
@@ -745,6 +745,7 @@ void send_pio_req(struct cpu_user_regs *regs, unsigned long port,
|
||||
if ( p->state != STATE_INVALID )
|
||||
printk("WARNING: send pio with something already pending (%d)?\n",
|
||||
p->state);
|
||||
|
||||
p->dir = dir;
|
||||
p->pdata_valid = pvalid;
|
||||
|
||||
@@ -752,19 +753,20 @@ void send_pio_req(struct cpu_user_regs *regs, unsigned long port,
|
||||
p->size = size;
|
||||
p->addr = port;
|
||||
p->count = count;
|
||||
p->df = regs->eflags & EF_DF ? 1 : 0;
|
||||
p->df = regs->eflags & X86_EFLAGS_DF ? 1 : 0;
|
||||
|
||||
p->io_count++;
|
||||
|
||||
if (pvalid) {
|
||||
if (hvm_paging_enabled(current))
|
||||
p->u.data = shadow_gva_to_gpa(current, value);
|
||||
if ( pvalid ) /* get physical address of data */
|
||||
{
|
||||
if ( hvm_paging_enabled(current) )
|
||||
p->u.pdata = (void *)shadow_gva_to_gpa(current, value);
|
||||
else
|
||||
p->u.pdata = (void *) value; /* guest VA == guest PA */
|
||||
} else
|
||||
p->u.pdata = (void *)value; /* guest VA == guest PA */
|
||||
} else if ( dir == IOREQ_WRITE )
|
||||
p->u.data = value;
|
||||
|
||||
if (hvm_portio_intercept(p)) {
|
||||
if ( hvm_portio_intercept(p) ) {
|
||||
p->state = STATE_IORESP_READY;
|
||||
hvm_io_assist(v);
|
||||
return;
|
||||
|
||||