# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1261031275 0
# Node ID 410eb65969cb142b8b32490d7f1454859cc3a7f2
# Parent 1165acfea711ef33798d12fb5078e3b31faa3e44
Memory paging support for HVM guest emulation.
A new HVMCOPY return value, HVMCOPY_gfn_paged_out is defined to indicate that
a gfn was paged out. This value and PFEC_page_paged, as appropriate, are
caught and passed up as X86EMUL_RETRY to the emulator. This will cause the
emulator to keep retrying the operation until is succeeds (once the page has
been paged in).
Signed-off-by: Patrick Colp <Patrick.Colp@xxxxxxxxxx>
---
xen/arch/x86/hvm/emulate.c | 21 +++++++++++++++++
xen/arch/x86/hvm/hvm.c | 22 ++++++++++++++++++
xen/arch/x86/hvm/intercept.c | 45 +++++++++++++++++++++-----------------
xen/arch/x86/hvm/io.c | 42 ++++++++++++++++++++++-------------
xen/include/asm-x86/hvm/support.h | 3 +-
5 files changed, 97 insertions(+), 36 deletions(-)
diff -r 1165acfea711 -r 410eb65969cb xen/arch/x86/hvm/emulate.c
--- a/xen/arch/x86/hvm/emulate.c Thu Dec 17 06:27:55 2009 +0000
+++ b/xen/arch/x86/hvm/emulate.c Thu Dec 17 06:27:55 2009 +0000
@@ -56,7 +56,18 @@ static int hvmemul_do_io(
int value_is_ptr = (p_data == NULL);
struct vcpu *curr = current;
ioreq_t *p = get_ioreq(curr);
+ unsigned long ram_gfn = paddr_to_pfn(ram_gpa);
+ p2m_type_t p2mt;
+ mfn_t ram_mfn;
int rc;
+
+ /* Check for paged out page */
+ ram_mfn = gfn_to_mfn(current->domain, ram_gfn, &p2mt);
+ if ( p2m_is_paging(p2mt) )
+ {
+ p2m_mem_paging_populate(curr->domain, ram_gfn);
+ return X86EMUL_RETRY;
+ }
/*
* Weird-sized accesses have undefined behaviour: we discard writes
@@ -271,6 +282,8 @@ static int hvmemul_linear_to_phys(
}
else if ( (pfn = paging_gva_to_gfn(curr, addr, &pfec)) == INVALID_GFN )
{
+ if ( pfec == PFEC_page_paged )
+ return X86EMUL_RETRY;
hvm_inject_exception(TRAP_page_fault, pfec, addr);
return X86EMUL_EXCEPTION;
}
@@ -286,6 +299,8 @@ static int hvmemul_linear_to_phys(
/* Is it contiguous with the preceding PFNs? If not then we're done. */
if ( (npfn == INVALID_GFN) || (npfn != (pfn + (reverse ? -i : i))) )
{
+ if ( pfec == PFEC_page_paged )
+ return X86EMUL_RETRY;
done /= bytes_per_rep;
if ( done == 0 )
{
@@ -424,6 +439,8 @@ static int __hvmemul_read(
if ( rc != X86EMUL_OKAY )
return rc;
return hvmemul_do_mmio(gpa, &reps, bytes, 0, IOREQ_READ, 0, p_data);
+ case HVMCOPY_gfn_paged_out:
+ return X86EMUL_RETRY;
default:
break;
}
@@ -514,6 +531,8 @@ static int hvmemul_write(
return rc;
return hvmemul_do_mmio(gpa, &reps, bytes, 0,
IOREQ_WRITE, 0, p_data);
+ case HVMCOPY_gfn_paged_out:
+ return X86EMUL_RETRY;
default:
break;
}
@@ -687,6 +706,8 @@ static int hvmemul_rep_movs(
xfree(buf);
+ if ( rc == HVMCOPY_gfn_paged_out )
+ return X86EMUL_RETRY;
if ( rc != HVMCOPY_okay )
{
gdprintk(XENLOG_WARNING, "Failed memory-to-memory REP MOVS: sgpa=%"
diff -r 1165acfea711 -r 410eb65969cb xen/arch/x86/hvm/hvm.c
--- a/xen/arch/x86/hvm/hvm.c Thu Dec 17 06:27:55 2009 +0000
+++ b/xen/arch/x86/hvm/hvm.c Thu Dec 17 06:27:55 2009 +0000
@@ -314,6 +314,11 @@ static int hvm_set_ioreq_page(
mfn = mfn_x(gfn_to_mfn(d, gmfn, &p2mt));
if ( !p2m_is_ram(p2mt) )
return -EINVAL;
+ if ( p2m_is_paging(p2mt) )
+ {
+ p2m_mem_paging_populate(d, gmfn);
+ return -ENOENT;
+ }
ASSERT(mfn_valid(mfn));
page = mfn_to_page(mfn);
@@ -1318,6 +1323,8 @@ static void *hvm_map_entry(unsigned long
* we still treat it as a kernel-mode read (i.e. no access checks). */
pfec = PFEC_page_present;
gfn = paging_gva_to_gfn(current, va, &pfec);
+ if ( pfec == PFEC_page_paged )
+ return NULL;
mfn = mfn_x(gfn_to_mfn_current(gfn, &p2mt));
if ( p2m_is_paging(p2mt) )
{
@@ -1546,6 +1553,8 @@ void hvm_task_switch(
&tss, prev_tr.base, sizeof(tss), PFEC_page_present);
if ( rc == HVMCOPY_bad_gva_to_gfn )
goto out;
+ if ( rc == HVMCOPY_gfn_paged_out )
+ goto out;
eflags = regs->eflags;
if ( taskswitch_reason == TSW_iret )
@@ -1582,10 +1591,14 @@ void hvm_task_switch(
prev_tr.base, &tss, sizeof(tss), PFEC_page_present);
if ( rc == HVMCOPY_bad_gva_to_gfn )
goto out;
+ if ( rc == HVMCOPY_gfn_paged_out )
+ goto out;
rc = hvm_copy_from_guest_virt(
&tss, tr.base, sizeof(tss), PFEC_page_present);
if ( rc == HVMCOPY_bad_gva_to_gfn )
+ goto out;
+ if ( rc == HVMCOPY_gfn_paged_out )
goto out;
if ( hvm_set_cr3(tss.cr3) )
@@ -1622,6 +1635,8 @@ void hvm_task_switch(
tr.base, &tss, sizeof(tss), PFEC_page_present);
if ( rc == HVMCOPY_bad_gva_to_gfn )
exn_raised = 1;
+ if ( rc == HVMCOPY_gfn_paged_out )
+ goto out;
if ( (tss.trace & 1) && !exn_raised )
hvm_inject_exception(TRAP_debug, tss_sel & 0xfff8, 0);
@@ -1681,6 +1696,8 @@ static enum hvm_copy_result __hvm_copy(
gfn = paging_gva_to_gfn(curr, addr, &pfec);
if ( gfn == INVALID_GFN )
{
+ if ( pfec == PFEC_page_paged )
+ return HVMCOPY_gfn_paged_out;
if ( flags & HVMCOPY_fault )
hvm_inject_exception(TRAP_page_fault, pfec, addr);
return HVMCOPY_bad_gva_to_gfn;
@@ -1693,6 +1710,11 @@ static enum hvm_copy_result __hvm_copy(
mfn = mfn_x(gfn_to_mfn_current(gfn, &p2mt));
+ if ( p2m_is_paging(p2mt) )
+ {
+ p2m_mem_paging_populate(curr->domain, gfn);
+ return HVMCOPY_gfn_paged_out;
+ }
if ( p2m_is_grant(p2mt) )
return HVMCOPY_unhandleable;
if ( !p2m_is_ram(p2mt) )
diff -r 1165acfea711 -r 410eb65969cb xen/arch/x86/hvm/intercept.c
--- a/xen/arch/x86/hvm/intercept.c Thu Dec 17 06:27:55 2009 +0000
+++ b/xen/arch/x86/hvm/intercept.c Thu Dec 17 06:27:55 2009 +0000
@@ -72,30 +72,31 @@ static int hvm_mmio_access(struct vcpu *
{
for ( i = 0; i < p->count; i++ )
{
- rc = read_handler(
- v,
- p->addr + (sign * i * p->size),
- p->size, &data);
- if ( rc != X86EMUL_OKAY )
- break;
- (void)hvm_copy_to_guest_phys(
- p->data + (sign * i * p->size),
- &data,
- p->size);
+ rc = read_handler(v, p->addr + (sign * i * p->size), p->size,
+ &data);
+ if ( rc != X86EMUL_OKAY )
+ break;
+ if ( hvm_copy_to_guest_phys(p->data + (sign * i * p->size), &data,
+ p->size) == HVMCOPY_gfn_paged_out )
+ {
+ rc = X86EMUL_RETRY;
+ break;
+ }
}
}
else
{
for ( i = 0; i < p->count; i++ )
{
- (void)hvm_copy_from_guest_phys(
- &data,
- p->data + (sign * i * p->size),
- p->size);
- rc = write_handler(
- v,
- p->addr + (sign * i * p->size),
- p->size, data);
+ if ( hvm_copy_from_guest_phys(&data,
+ p->data + (sign * i * p->size),
+ p->size) == HVMCOPY_gfn_paged_out )
+ {
+ rc = X86EMUL_RETRY;
+ break;
+ }
+ rc = write_handler(v, p->addr + (sign * i * p->size), p->size,
+ data);
if ( rc != X86EMUL_OKAY )
break;
}
@@ -190,8 +191,12 @@ int hvm_io_intercept(ioreq_t *p, int typ
int i;
unsigned long addr, size;
- if ( (type == HVM_PORTIO) && (dpci_ioport_intercept(p)) )
- return X86EMUL_OKAY;
+ if ( type == HVM_PORTIO )
+ {
+ int rc = dpci_ioport_intercept(p);
+ if ( (rc == X86EMUL_OKAY) || (rc == X86EMUL_RETRY) )
+ return rc;
+ }
for ( i = 0; i < handler->num_slot; i++ )
{
diff -r 1165acfea711 -r 410eb65969cb xen/arch/x86/hvm/io.c
--- a/xen/arch/x86/hvm/io.c Thu Dec 17 06:27:55 2009 +0000
+++ b/xen/arch/x86/hvm/io.c Thu Dec 17 06:27:55 2009 +0000
@@ -239,7 +239,7 @@ void hvm_io_assist(void)
vcpu_end_shutdown_deferral(curr);
}
-static void dpci_ioport_read(uint32_t mport, ioreq_t *p)
+static int dpci_ioport_read(uint32_t mport, ioreq_t *p)
{
int i, sign = p->df ? -1 : 1;
uint32_t data = 0;
@@ -262,14 +262,19 @@ static void dpci_ioport_read(uint32_t mp
}
if ( p->data_is_ptr )
- (void)hvm_copy_to_guest_phys(
- p->data + (sign * i * p->size), &data, p->size);
+ {
+ if ( hvm_copy_to_guest_phys(p->data + (sign * i * p->size), &data,
+ p->size) == HVMCOPY_gfn_paged_out )
+ return X86EMUL_RETRY;
+ }
else
p->data = data;
}
-}
-
-static void dpci_ioport_write(uint32_t mport, ioreq_t *p)
+
+ return X86EMUL_OKAY;
+}
+
+static int dpci_ioport_write(uint32_t mport, ioreq_t *p)
{
int i, sign = p->df ? -1 : 1;
uint32_t data;
@@ -278,8 +283,11 @@ static void dpci_ioport_write(uint32_t m
{
data = p->data;
if ( p->data_is_ptr )
- (void)hvm_copy_from_guest_phys(
- &data, p->data + (sign * i * p->size), p->size);
+ {
+ if ( hvm_copy_from_guest_phys(&data, p->data + (sign * i *
p->size),
+ p->size) == HVMCOPY_gfn_paged_out )
+ return X86EMUL_RETRY;
+ }
switch ( p->size )
{
@@ -296,6 +304,8 @@ static void dpci_ioport_write(uint32_t m
BUG();
}
}
+
+ return X86EMUL_OKAY;
}
int dpci_ioport_intercept(ioreq_t *p)
@@ -305,6 +315,7 @@ int dpci_ioport_intercept(ioreq_t *p)
struct g2m_ioport *g2m_ioport;
unsigned int mport, gport = p->addr;
unsigned int s = 0, e = 0;
+ int rc;
list_for_each_entry( g2m_ioport, &hd->g2m_ioport_list, list )
{
@@ -314,7 +325,7 @@ int dpci_ioport_intercept(ioreq_t *p)
goto found;
}
- return 0;
+ return X86EMUL_UNHANDLEABLE;
found:
mport = (gport - s) + g2m_ioport->mport;
@@ -323,22 +334,23 @@ int dpci_ioport_intercept(ioreq_t *p)
{
gdprintk(XENLOG_ERR, "Error: access to gport=0x%x denied!\n",
(uint32_t)p->addr);
- return 0;
+ return X86EMUL_UNHANDLEABLE;
}
switch ( p->dir )
{
case IOREQ_READ:
- dpci_ioport_read(mport, p);
+ rc = dpci_ioport_read(mport, p);
break;
case IOREQ_WRITE:
- dpci_ioport_write(mport, p);
+ rc = dpci_ioport_write(mport, p);
break;
default:
gdprintk(XENLOG_ERR, "Error: couldn't handle p->dir = %d", p->dir);
- }
-
- return 1;
+ rc = X86EMUL_UNHANDLEABLE;
+ }
+
+ return rc;
}
/*
diff -r 1165acfea711 -r 410eb65969cb xen/include/asm-x86/hvm/support.h
--- a/xen/include/asm-x86/hvm/support.h Thu Dec 17 06:27:55 2009 +0000
+++ b/xen/include/asm-x86/hvm/support.h Thu Dec 17 06:27:55 2009 +0000
@@ -72,7 +72,8 @@ enum hvm_copy_result {
HVMCOPY_okay = 0,
HVMCOPY_bad_gva_to_gfn,
HVMCOPY_bad_gfn_to_mfn,
- HVMCOPY_unhandleable
+ HVMCOPY_unhandleable,
+ HVMCOPY_gfn_paged_out,
};
/*
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|