aboutsummaryrefslogtreecommitdiffstats
path: root/xen/arch/x86/hvm/emulate.c
diff options
context:
space:
mode:
authorAndres Lagar-Cavilla <andres@lagarcavilla.org>2012-03-14 11:07:40 -0400
committerAndres Lagar-Cavilla <andres@lagarcavilla.org>2012-03-14 11:07:40 -0400
commit9f3c3bd33a1cb934a5065ff5b3f6cdc319d2bb81 (patch)
tree6d309f5e456bc499326eb4fa9ffa43c40be9d0d1 /xen/arch/x86/hvm/emulate.c
parentde0f8c7cc2a266f4ad569e0202464a8870d3a318 (diff)
downloadxen-9f3c3bd33a1cb934a5065ff5b3f6cdc319d2bb81.tar.gz
xen-9f3c3bd33a1cb934a5065ff5b3f6cdc319d2bb81.tar.bz2
xen-9f3c3bd33a1cb934a5065ff5b3f6cdc319d2bb81.zip
x86/mm: Fix deadlock between p2m and event channel locks.
The hvm io emulation code holds the p2m lock for the duration of the emulation, which may include sending an event to qemu. On a separate path, map_domain_pirq grabs the event channel and p2m locks in opposite order. Fix this by ensuring liveness of the ram_gfn used by io emulation, with a page ref. Reported-by: "Hao, Xudong" <xudong.hao@intel.com> Signed-off-by: "Hao, Xudong" <xudong.hao@intel.com> Signed-off-by: Andres Lagar-Cavilla <andres@lagarcavilla.org> Acked-by: Tim Deegan <tim@xen.org> Committed-by: Tim Deegan <tim@xen.org>
Diffstat (limited to 'xen/arch/x86/hvm/emulate.c')
-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;
}