[PAE] Fix support for pgdirs above 4GB. Requires an interface change so that %cr3
authorkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Fri, 2 Jun 2006 10:46:24 +0000 (11:46 +0100)
committerkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Fri, 2 Jun 2006 10:46:24 +0000 (11:46 +0100)
is extended to include high-order address bits at bottom of %cr3 value.
Guests who understand this interface change publish the fact by setting the
option 'PAE=yes[extended-cr3]' in their __xen_guest section.
Signed-off-by: Keir Fraser <keir@xensource.com>
linux-2.6-xen-sparse/arch/i386/kernel/head-xen.S
linux-2.6-xen-sparse/drivers/xen/core/smpboot.c
linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/system.h
xen/arch/x86/dom0_ops.c
xen/arch/x86/domain.c
xen/arch/x86/traps.c
xen/include/public/arch-x86_32.h
xen/include/public/arch-x86_64.h

index 00ec0c2a5e157f172eb4f9d790745f222962e5ac..25ce03247b21fbdb8169d68bb9c0ba2976cfc594 100644 (file)
@@ -173,7 +173,7 @@ ENTRY(cpu_gdt_table)
        .ascii           "|pae_pgdir_above_4gb"
        .ascii           "|supervisor_mode_kernel"
 #ifdef CONFIG_X86_PAE
-       .ascii  ",PAE=yes"
+       .ascii  ",PAE=yes[extended-cr3]"
 #else
        .ascii  ",PAE=no"
 #endif
index 6396a482d4d97f617c64e64cc22f81c425ddda34..613f835f3f22bb388ea4d01e23794459571894f3 100644 (file)
@@ -208,7 +208,7 @@ void cpu_initialize_context(unsigned int cpu)
        ctxt.failsafe_callback_cs  = __KERNEL_CS;
        ctxt.failsafe_callback_eip = (unsigned long)failsafe_callback;
 
-       ctxt.ctrlreg[3] = virt_to_mfn(swapper_pg_dir) << PAGE_SHIFT;
+       ctxt.ctrlreg[3] = xen_pfn_to_cr3(virt_to_mfn(swapper_pg_dir));
 #else /* __x86_64__ */
        ctxt.user_regs.cs = __KERNEL_CS;
        ctxt.user_regs.esp = idle->thread.rsp0 - sizeof(struct pt_regs);
@@ -220,7 +220,7 @@ void cpu_initialize_context(unsigned int cpu)
        ctxt.failsafe_callback_eip = (unsigned long)failsafe_callback;
        ctxt.syscall_callback_eip  = (unsigned long)system_call;
 
-       ctxt.ctrlreg[3] = virt_to_mfn(init_level4_pgt) << PAGE_SHIFT;
+       ctxt.ctrlreg[3] = xen_pfn_to_cr3(virt_to_mfn(init_level4_pgt));
 
        ctxt.gs_base_kernel = (unsigned long)(cpu_pda(cpu));
 #endif
index 2626b98908d451f7ab34430a67bf4ab53aa6ff37..3b7ce63148c23f6330e56864787083734c6d8f1a 100644 (file)
@@ -116,10 +116,12 @@ __asm__ __volatile__ ("movw %%dx,%1\n\t" \
        __asm__ ( \
                "movl %%cr3,%0\n\t" \
                :"=r" (__dummy)); \
-       machine_to_phys(__dummy); \
+       __dummy = xen_cr3_to_pfn(__dummy); \
+       mfn_to_pfn(__dummy) << PAGE_SHIFT; \
 })
 #define write_cr3(x) ({                                                \
-       maddr_t __dummy = phys_to_machine(x);                   \
+       unsigned int __dummy = pfn_to_mfn((x) >> PAGE_SHIFT);   \
+       __dummy = xen_pfn_to_cr3(__dummy);                      \
        __asm__ __volatile__("movl %0,%%cr3": :"r" (__dummy));  \
 })
 
index a88e1889e90dbf46b09c91acdbcdbcd981c71f7b..bfd491f25d59aa2b69eb5b6a448e10302de1399b 100644 (file)
@@ -467,7 +467,7 @@ void arch_getdomaininfo_ctxt(
     if ( hvm_guest(v) )
         c->flags |= VGCF_HVM_GUEST;
 
-    c->ctrlreg[3] = pagetable_get_paddr(v->arch.guest_table);
+    c->ctrlreg[3] = xen_pfn_to_cr3(pagetable_get_pfn(v->arch.guest_table));
 
     c->vm_assist = v->domain->vm_assist;
 }
index 12721e1c67a513c108a5ef4949b6580300797e1f..e8b2d647a766cee6668b70f4b64cf7f88bff5597 100644 (file)
@@ -259,7 +259,7 @@ int arch_set_info_guest(
     struct vcpu *v, struct vcpu_guest_context *c)
 {
     struct domain *d = v->domain;
-    unsigned long phys_basetab = INVALID_MFN;
+    unsigned long cr3_pfn;
     int i, rc;
 
     if ( !(c->flags & VGCF_HVM_GUEST) )
@@ -322,12 +322,8 @@ int arch_set_info_guest(
 
     if ( !(c->flags & VGCF_HVM_GUEST) )
     {
-        phys_basetab = c->ctrlreg[3];
-        phys_basetab =
-            (gmfn_to_mfn(d, phys_basetab >> PAGE_SHIFT) << PAGE_SHIFT) |
-            (phys_basetab & ~PAGE_MASK);
-
-        v->arch.guest_table = pagetable_from_paddr(phys_basetab);
+        cr3_pfn = gmfn_to_mfn(d, xen_cr3_to_pfn(c->ctrlreg[3]));
+        v->arch.guest_table = pagetable_from_pfn(cr3_pfn);
     }
 
     if ( (rc = (int)set_gdt(v, c->gdt_frames, c->gdt_ents)) != 0 )
@@ -342,7 +338,7 @@ int arch_set_info_guest(
     }
     else if ( shadow_mode_refcounts(d) )
     {
-        if ( !get_page(mfn_to_page(phys_basetab>>PAGE_SHIFT), d) )
+        if ( !get_page(mfn_to_page(cr3_pfn), d) )
         {
             destroy_gdt(v);
             return -EINVAL;
@@ -350,7 +346,7 @@ int arch_set_info_guest(
     }
     else
     {
-        if ( !get_page_and_type(mfn_to_page(phys_basetab>>PAGE_SHIFT), d,
+        if ( !get_page_and_type(mfn_to_page(cr3_pfn), d,
                                 PGT_base_page_table) )
         {
             destroy_gdt(v);
index 86bb175523ee81b975712127f75c6d09d9f9b8af..74de928a374e77aa2c99572497188a92074279d2 100644 (file)
@@ -1034,8 +1034,8 @@ static int emulate_privileged_op(struct cpu_user_regs *regs)
             break;
             
         case 3: /* Read CR3 */
-            *reg = pfn_to_paddr(mfn_to_gmfn(v->domain,
-                                    pagetable_get_pfn(v->arch.guest_table)));
+            *reg = xen_pfn_to_cr3(mfn_to_gmfn(
+                v->domain, pagetable_get_pfn(v->arch.guest_table)));
             break;
 
         case 4: /* Read CR4 */
@@ -1085,7 +1085,7 @@ static int emulate_privileged_op(struct cpu_user_regs *regs)
         case 3: /* Write CR3 */
             LOCK_BIGLOCK(v->domain);
             cleanup_writable_pagetable(v->domain);
-            (void)new_guest_cr3(gmfn_to_mfn(v->domain, paddr_to_pfn(*reg)));
+            (void)new_guest_cr3(gmfn_to_mfn(v->domain, xen_cr3_to_pfn(*reg)));
             UNLOCK_BIGLOCK(v->domain);
             break;
 
index 1dd1d52baffdd72dd84604bb062952351903e158..2a43ae53acda6b4673b98f17faffcc1c02cc0f11 100644 (file)
@@ -158,6 +158,14 @@ struct vcpu_guest_context {
 typedef struct vcpu_guest_context vcpu_guest_context_t;
 DEFINE_XEN_GUEST_HANDLE(vcpu_guest_context_t);
 
+/*
+ * Page-directory addresses above 4GB do not fit into architectural %cr3.
+ * When accessing %cr3, or equivalent field in vcpu_guest_context, guests
+ * must use the following accessor macros to pack/unpack valid MFNs.
+ */
+#define xen_pfn_to_cr3(pfn) (((unsigned)(pfn) << 12) | ((unsigned)(pfn) >> 20))
+#define xen_cr3_to_pfn(cr3) (((unsigned)(cr3) >> 12) | ((unsigned)(cr3) << 20))
+
 struct arch_shared_info {
     unsigned long max_pfn;                  /* max pfn that appears in table */
     /* Frame containing list of mfns containing list of mfns containing p2m. */
index 409d0d0efb2a7edbb4f35084639606e7f8e0e684..0b0ca809ca90a8f71e9fedcfc3ef3ef9d795fc54 100644 (file)
@@ -234,6 +234,9 @@ struct vcpu_guest_context {
 typedef struct vcpu_guest_context vcpu_guest_context_t;
 DEFINE_XEN_GUEST_HANDLE(vcpu_guest_context_t);
 
+#define xen_pfn_to_cr3(pfn) ((unsigned long)(pfn) << 12)
+#define xen_cr3_to_pfn(cr3) ((unsigned long)(cr3) >> 12)
+
 struct arch_shared_info {
     unsigned long max_pfn;                  /* max pfn that appears in table */
     /* Frame containing list of mfns containing list of mfns containing p2m. */