# HG changeset patch
# User Keir Fraser <keir@xxxxxxxxxxxxx>
# Date 1172876247 0
# Node ID d5ca4c37b3c53688cd556af6730017b902da5bc2
# Parent 87087954247ac63165482c1e59fd3b1ea23fd22f
x86/64: Save/restore user pagetable pointer for x86/64 PV guests.
Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx>
---
tools/libxc/xc_linux_restore.c | 24 +++++++++++++++++++++++-
tools/libxc/xc_linux_save.c | 16 ++++++++++++++--
xen/arch/x86/domain.c | 25 +++++++++++++++++++++++++
xen/arch/x86/domctl.c | 7 +++++++
xen/include/public/arch-x86/xen.h | 1 +
5 files changed, 70 insertions(+), 3 deletions(-)
diff -r 87087954247a -r d5ca4c37b3c5 tools/libxc/xc_linux_restore.c
--- a/tools/libxc/xc_linux_restore.c Fri Mar 02 16:57:24 2007 +0000
+++ b/tools/libxc/xc_linux_restore.c Fri Mar 02 22:57:27 2007 +0000
@@ -19,7 +19,7 @@ static unsigned long max_mfn;
/* virtual starting address of the hypervisor */
static unsigned long hvirt_start;
-/* #levels of page tables used by the currrent guest */
+/* #levels of page tables used by the current guest */
static unsigned int pt_levels;
/* total number of pages used by the current guest */
@@ -857,6 +857,28 @@ int xc_linux_restore(int xc_handle, int
ctxt.ctrlreg[3] = xen_pfn_to_cr3(p2m[pfn]);
+ /* Guest pagetable (x86/64) stored in otherwise-unused CR1. */
+ if ( (pt_levels == 4) && ctxt.ctrlreg[1] )
+ {
+ pfn = xen_cr3_to_pfn(ctxt.ctrlreg[1]);
+
+ if (pfn >= max_pfn) {
+ ERROR("User PT base is bad: pfn=%lu max_pfn=%lu type=%08lx",
+ pfn, max_pfn, pfn_type[pfn]);
+ goto out;
+ }
+
+ if ( (pfn_type[pfn] & XEN_DOMCTL_PFINFO_LTABTYPE_MASK) !=
+ ((unsigned long)pt_levels<<XEN_DOMCTL_PFINFO_LTAB_SHIFT) ) {
+ ERROR("User PT base is bad. pfn=%lu nr=%lu type=%08lx %08lx",
+ pfn, max_pfn, pfn_type[pfn],
+ (unsigned long)pt_levels<<XEN_DOMCTL_PFINFO_LTAB_SHIFT);
+ goto out;
+ }
+
+ ctxt.ctrlreg[1] = xen_pfn_to_cr3(p2m[pfn]);
+ }
+
domctl.cmd = XEN_DOMCTL_setvcpucontext;
domctl.domain = (domid_t)dom;
domctl.u.vcpucontext.vcpu = i;
diff -r 87087954247a -r d5ca4c37b3c5 tools/libxc/xc_linux_save.c
--- a/tools/libxc/xc_linux_save.c Fri Mar 02 16:57:24 2007 +0000
+++ b/tools/libxc/xc_linux_save.c Fri Mar 02 22:57:27 2007 +0000
@@ -34,7 +34,7 @@ static unsigned long max_mfn;
/* virtual starting address of the hypervisor */
static unsigned long hvirt_start;
-/* #levels of page tables used by the currrent guest */
+/* #levels of page tables used by the current guest */
static unsigned int pt_levels;
/* total number of pages used by the current guest */
@@ -491,7 +491,7 @@ static int canonicalize_pagetable(unsign
** reserved hypervisor mappings. This depends on the current
** page table type as well as the number of paging levels.
*/
- xen_start = xen_end = pte_last = PAGE_SIZE / ((pt_levels == 2)? 4 : 8);
+ xen_start = xen_end = pte_last = PAGE_SIZE / ((pt_levels == 2) ? 4 : 8);
if (pt_levels == 2 && type == XEN_DOMCTL_PFINFO_L2TAB)
xen_start = (hvirt_start >> L2_PAGETABLE_SHIFT);
@@ -1279,6 +1279,18 @@ int xc_linux_save(int xc_handle, int io_
ctxt.ctrlreg[3] =
xen_pfn_to_cr3(mfn_to_pfn(xen_cr3_to_pfn(ctxt.ctrlreg[3])));
+ /* Guest pagetable (x86/64) stored in otherwise-unused CR1. */
+ if ( (pt_levels == 4) && ctxt.ctrlreg[1] )
+ {
+ if ( !MFN_IS_IN_PSEUDOPHYS_MAP(xen_cr3_to_pfn(ctxt.ctrlreg[1])) ) {
+ ERROR("PT base is not in range of pseudophys map");
+ goto out;
+ }
+ /* Least-significant bit means 'valid PFN'. */
+ ctxt.ctrlreg[1] = 1 |
+ xen_pfn_to_cr3(mfn_to_pfn(xen_cr3_to_pfn(ctxt.ctrlreg[1])));
+ }
+
if (!write_exact(io_fd, &ctxt, sizeof(ctxt))) {
ERROR("Error when writing to state file (1) (errno %d)", errno);
goto out;
diff -r 87087954247a -r d5ca4c37b3c5 xen/arch/x86/domain.c
--- a/xen/arch/x86/domain.c Fri Mar 02 16:57:24 2007 +0000
+++ b/xen/arch/x86/domain.c Fri Mar 02 22:57:27 2007 +0000
@@ -641,6 +641,31 @@ int arch_set_info_guest(
}
v->arch.guest_table = pagetable_from_pfn(cr3_pfn);
+
+#ifdef __x86_64__
+ if ( c.nat->ctrlreg[1] )
+ {
+ cr3_pfn = gmfn_to_mfn(d, xen_cr3_to_pfn(c.nat->ctrlreg[1]));
+
+ if ( !mfn_valid(cr3_pfn) ||
+ (paging_mode_refcounts(d)
+ ? !get_page(mfn_to_page(cr3_pfn), d)
+ : !get_page_and_type(mfn_to_page(cr3_pfn), d,
+ PGT_base_page_table)) )
+ {
+ cr3_pfn = pagetable_get_pfn(v->arch.guest_table);
+ v->arch.guest_table = pagetable_null();
+ if ( paging_mode_refcounts(d) )
+ put_page(mfn_to_page(cr3_pfn));
+ else
+ put_page_and_type(mfn_to_page(cr3_pfn));
+ destroy_gdt(v);
+ return -EINVAL;
+ }
+
+ v->arch.guest_table_user = pagetable_from_pfn(cr3_pfn);
+ }
+#endif
}
#ifdef CONFIG_COMPAT
else
diff -r 87087954247a -r d5ca4c37b3c5 xen/arch/x86/domctl.c
--- a/xen/arch/x86/domctl.c Fri Mar 02 16:57:24 2007 +0000
+++ b/xen/arch/x86/domctl.c Fri Mar 02 22:57:27 2007 +0000
@@ -470,8 +470,15 @@ void arch_get_info_guest(struct vcpu *v,
c(user_regs.eflags |= v->arch.iopl << 12);
if ( !IS_COMPAT(v->domain) )
+ {
c.nat->ctrlreg[3] = xen_pfn_to_cr3(
pagetable_get_pfn(v->arch.guest_table));
+#ifdef __x86_64__
+ if ( !pagetable_is_null(v->arch.guest_table_user) )
+ c.nat->ctrlreg[1] = xen_pfn_to_cr3(
+ pagetable_get_pfn(v->arch.guest_table_user));
+#endif
+ }
#ifdef CONFIG_COMPAT
else
{
diff -r 87087954247a -r d5ca4c37b3c5 xen/include/public/arch-x86/xen.h
--- a/xen/include/public/arch-x86/xen.h Fri Mar 02 16:57:24 2007 +0000
+++ b/xen/include/public/arch-x86/xen.h Fri Mar 02 22:57:27 2007 +0000
@@ -132,6 +132,7 @@ struct vcpu_guest_context {
unsigned long ldt_base, ldt_ents; /* LDT (linear address, # ents) */
unsigned long gdt_frames[16], gdt_ents; /* GDT (machine frames, # ents) */
unsigned long kernel_ss, kernel_sp; /* Virtual TSS (only SS1/SP1) */
+ /* NB. User pagetable on x86/64 is placed in ctrlreg[1]. */
unsigned long ctrlreg[8]; /* CR0-CR7 (control registers) */
unsigned long debugreg[8]; /* DB0-DB7 (debug registers) */
#ifdef __i386__
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|