aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--xen/arch/x86/hvm/emulate.c38
1 files changed, 29 insertions, 9 deletions
diff --git a/xen/arch/x86/hvm/emulate.c b/xen/arch/x86/hvm/emulate.c
index c2d089df56..d661bb5dd3 100644
--- a/xen/arch/x86/hvm/emulate.c
+++ b/xen/arch/x86/hvm/emulate.c
@@ -77,6 +77,17 @@ static int hvmemul_do_io(
return X86EMUL_RETRY;
}
+ /* Maintain a ref on the mfn to ensure liveness. Put the gfn
+ * to avoid potential deadlock wrt event channel lock, later. */
+ if ( mfn_valid(mfn_x(ram_mfn)) )
+ if ( !get_page(mfn_to_page(mfn_x(ram_mfn)),
+ curr->domain) )
+ {
+ put_gfn(curr->domain, ram_gfn);
+ return X86EMUL_RETRY;
+ }
+ put_gfn(curr->domain, ram_gfn);
+
/*
* Weird-sized accesses have undefined behaviour: we discard writes
* and read all-ones.
@@ -87,7 +98,8 @@ static int hvmemul_do_io(
ASSERT(p_data != NULL); /* cannot happen with a REP prefix */
if ( dir == IOREQ_READ )
memset(p_data, ~0, size);
- put_gfn(curr->domain, ram_gfn);
+ if ( mfn_valid(mfn_x(ram_mfn)) )
+ put_page(mfn_to_page(mfn_x(ram_mfn)));
return X86EMUL_UNHANDLEABLE;
}
@@ -108,7 +120,8 @@ static int hvmemul_do_io(
unsigned int bytes = vio->mmio_large_write_bytes;
if ( (addr >= pa) && ((addr + size) <= (pa + bytes)) )
{
- put_gfn(curr->domain, ram_gfn);
+ if ( mfn_valid(mfn_x(ram_mfn)) )
+ put_page(mfn_to_page(mfn_x(ram_mfn)));
return X86EMUL_OKAY;
}
}
@@ -120,7 +133,8 @@ static int hvmemul_do_io(
{
memcpy(p_data, &vio->mmio_large_read[addr - pa],
size);
- put_gfn(curr->domain, ram_gfn);
+ if ( mfn_valid(mfn_x(ram_mfn)) )
+ put_page(mfn_to_page(mfn_x(ram_mfn)));
return X86EMUL_OKAY;
}
}
@@ -134,7 +148,8 @@ static int hvmemul_do_io(
vio->io_state = HVMIO_none;
if ( p_data == NULL )
{
- put_gfn(curr->domain, ram_gfn);
+ if ( mfn_valid(mfn_x(ram_mfn)) )
+ put_page(mfn_to_page(mfn_x(ram_mfn)));
return X86EMUL_UNHANDLEABLE;
}
goto finish_access;
@@ -144,11 +159,13 @@ static int hvmemul_do_io(
(addr == (vio->mmio_large_write_pa +
vio->mmio_large_write_bytes)) )
{
- put_gfn(curr->domain, ram_gfn);
+ if ( mfn_valid(mfn_x(ram_mfn)) )
+ put_page(mfn_to_page(mfn_x(ram_mfn)));
return X86EMUL_RETRY;
}
default:
- put_gfn(curr->domain, ram_gfn);
+ if ( mfn_valid(mfn_x(ram_mfn)) )
+ put_page(mfn_to_page(mfn_x(ram_mfn)));
return X86EMUL_UNHANDLEABLE;
}
@@ -156,7 +173,8 @@ static int hvmemul_do_io(
{
gdprintk(XENLOG_WARNING, "WARNING: io already pending (%d)?\n",
p->state);
- put_gfn(curr->domain, ram_gfn);
+ if ( mfn_valid(mfn_x(ram_mfn)) )
+ put_page(mfn_to_page(mfn_x(ram_mfn)));
return X86EMUL_UNHANDLEABLE;
}
@@ -208,7 +226,8 @@ static int hvmemul_do_io(
if ( rc != X86EMUL_OKAY )
{
- put_gfn(curr->domain, ram_gfn);
+ if ( mfn_valid(mfn_x(ram_mfn)) )
+ put_page(mfn_to_page(mfn_x(ram_mfn)));
return rc;
}
@@ -244,7 +263,8 @@ static int hvmemul_do_io(
}
}
- put_gfn(curr->domain, ram_gfn);
+ if ( mfn_valid(mfn_x(ram_mfn)) )
+ put_page(mfn_to_page(mfn_x(ram_mfn)));
return X86EMUL_OKAY;
}