[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen-unstable] Add page table setup and handling, including the creation of an m2p table



# HG changeset patch
# User Emmanuel Ackaouy <ack@xxxxxxxxxxxxx>
# Date 1168018470 0
# Node ID f632c0c3697657c0df031820dafeb74bf0b0f5bb
# Parent  4c8f157a3a471f694ccbdefa6f541ea88438b2ab
Add page table setup and handling, including the creation of an m2p table
meaningful to compatibility mode guests.

Signed-off-by: Jan Beulich <jbeulich@xxxxxxxxxx>
---
 xen/arch/x86/domain.c                    |   78 ++++++++++--
 xen/arch/x86/domain_build.c              |  123 ++++++++++++++++----
 xen/arch/x86/domctl.c                    |    7 -
 xen/arch/x86/e820.c                      |   35 +++++
 xen/arch/x86/mm.c                        |  187 +++++++++++++++++++------------
 xen/arch/x86/x86_64/mm.c                 |   72 +++++++++++
 xen/common/compat/kernel.c               |    2 
 xen/include/asm-x86/config.h             |   30 ++++
 xen/include/asm-x86/domain.h             |    4 
 xen/include/asm-x86/mm.h                 |    9 +
 xen/include/asm-x86/page.h               |    5 
 xen/include/asm-x86/x86_32/page-2level.h |    2 
 xen/include/asm-x86/x86_32/page-3level.h |    2 
 xen/include/asm-x86/x86_64/page.h        |    7 -
 xen/include/asm-x86/x86_64/uaccess.h     |    2 
 15 files changed, 451 insertions(+), 114 deletions(-)

diff -r 4c8f157a3a47 -r f632c0c36976 xen/arch/x86/domain.c
--- a/xen/arch/x86/domain.c     Fri Jan 05 17:34:29 2007 +0000
+++ b/xen/arch/x86/domain.c     Fri Jan 05 17:34:30 2007 +0000
@@ -127,6 +127,28 @@ void free_vcpu_struct(struct vcpu *v)
     xfree(v);
 }
 
+#ifdef CONFIG_COMPAT
+static int setup_compat_l4(struct vcpu *v)
+{
+    struct page_info *pg = alloc_domheap_page(NULL);
+    l4_pgentry_t *l4tab;
+
+    if ( !pg )
+        return -ENOMEM;
+    l4tab = copy_page(page_to_virt(pg), idle_pg_table);
+    l4tab[l4_table_offset(LINEAR_PT_VIRT_START)] =
+        l4e_from_page(pg, __PAGE_HYPERVISOR);
+    l4tab[l4_table_offset(PERDOMAIN_VIRT_START)] =
+        l4e_from_paddr(__pa(v->domain->arch.mm_perdomain_l3), 
__PAGE_HYPERVISOR);
+    v->arch.guest_table = pagetable_from_page(pg);
+    v->arch.guest_table_user = v->arch.guest_table;
+
+    return 0;
+}
+#else
+#define setup_compat_l4(v) 0
+#endif
+
 int vcpu_initialise(struct vcpu *v)
 {
     struct domain *d = v->domain;
@@ -161,11 +183,16 @@ int vcpu_initialise(struct vcpu *v)
     v->arch.perdomain_ptes =
         d->arch.mm_perdomain_pt + (v->vcpu_id << GDT_LDT_VCPU_SHIFT);
 
+    if ( IS_COMPAT(d) && (rc = setup_compat_l4(v)) != 0 )
+        return rc;
+
     return 0;
 }
 
 void vcpu_destroy(struct vcpu *v)
 {
+    if ( IS_COMPAT(v->domain) )
+        free_domheap_page(pagetable_get_page(v->arch.guest_table));
 }
 
 int arch_domain_create(struct domain *d)
@@ -219,6 +246,10 @@ int arch_domain_create(struct domain *d)
 
 #endif /* __x86_64__ */
 
+#ifdef CONFIG_COMPAT
+    HYPERVISOR_COMPAT_VIRT_START(d) = __HYPERVISOR_COMPAT_VIRT_START;
+#endif
+
     shadow_domain_init(d);
 
     if ( !is_idle_domain(d) )
@@ -349,18 +380,41 @@ int arch_set_info_guest(
         if ( (rc = (int)set_gdt(v, c->gdt_frames, c->gdt_ents)) != 0 )
             return rc;
 
-        cr3_pfn = gmfn_to_mfn(d, xen_cr3_to_pfn(c->ctrlreg[3]));
-
-        if ( shadow_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) )
-        {
-            destroy_gdt(v);
-            return -EINVAL;
-        }
-
-        v->arch.guest_table = pagetable_from_pfn(cr3_pfn);
+        if ( !IS_COMPAT(d) )
+        {
+            cr3_pfn = gmfn_to_mfn(d, xen_cr3_to_pfn(c->ctrlreg[3]));
+
+            if ( shadow_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) )
+            {
+                destroy_gdt(v);
+                return -EINVAL;
+            }
+
+            v->arch.guest_table = pagetable_from_pfn(cr3_pfn);
+        }
+#ifdef CONFIG_COMPAT
+        else
+        {
+            l4_pgentry_t *l4tab;
+
+            cr3_pfn = gmfn_to_mfn(d, compat_cr3_to_pfn(c->ctrlreg[3]));
+
+            if ( shadow_mode_refcounts(d)
+                 ? !get_page(mfn_to_page(cr3_pfn), d)
+                 : !get_page_and_type(mfn_to_page(cr3_pfn), d,
+                                    PGT_l3_page_table) )
+            {
+                destroy_gdt(v);
+                return -EINVAL;
+            }
+
+            l4tab = __va(pagetable_get_paddr(v->arch.guest_table));
+            *l4tab = l4e_from_pfn(cr3_pfn, 
_PAGE_PRESENT|_PAGE_RW|_PAGE_USER|_PAGE_ACCESSED);
+        }
+#endif
     }    
 
     if ( v->vcpu_id == 0 )
diff -r 4c8f157a3a47 -r f632c0c36976 xen/arch/x86/domain_build.c
--- a/xen/arch/x86/domain_build.c       Fri Jan 05 17:34:29 2007 +0000
+++ b/xen/arch/x86/domain_build.c       Fri Jan 05 17:34:30 2007 +0000
@@ -91,9 +91,11 @@ string_param("dom0_ioports_disable", opt
 #define L2_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
 #define L3_PROT (_PAGE_PRESENT)
 #elif defined(__x86_64__)
-/* Allow ring-3 access in long mode as guest cannot use ring 1. */
+/* Allow ring-3 access in long mode as guest cannot use ring 1 ... */
 #define BASE_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_USER)
 #define L1_PROT (BASE_PROT|_PAGE_GUEST_KERNEL)
+/* ... except for compatibility mode guests. */
+#define COMPAT_L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED)
 #define L2_PROT (BASE_PROT|_PAGE_DIRTY)
 #define L3_PROT (BASE_PROT|_PAGE_DIRTY)
 #define L4_PROT (BASE_PROT|_PAGE_DIRTY)
@@ -262,8 +264,8 @@ int construct_dom0(struct domain *d,
     start_info_t *si;
     struct vcpu *v = d->vcpu[0];
     const char *p;
-    unsigned long hypercall_page;
-    int hypercall_page_defined;
+    unsigned long long value;
+    int value_defined;
 #if defined(__i386__)
     char *image_start  = (char *)_image_start;  /* use lowmem mappings */
     char *initrd_start = (char *)_initrd_start; /* use lowmem mappings */
@@ -323,6 +325,7 @@ int construct_dom0(struct domain *d,
     rc = parseelfimage(&dsi);
 #ifdef CONFIG_COMPAT
     if ( rc == -ENOSYS
+         && !compat_disabled
          && (rc = parseelf32image(&dsi)) == 0 )
     {
         l1_pgentry_t gdt_l1e;
@@ -370,10 +373,37 @@ int construct_dom0(struct domain *d,
 
 #ifdef CONFIG_COMPAT
     if ( IS_COMPAT(d) )
+    {
+        value = xen_elf32note_numeric(&dsi, XEN_ELFNOTE_HV_START_LOW, 
&value_defined);
         p = xen_elf32note_string(&dsi, XEN_ELFNOTE_FEATURES);
+    }
     else
 #endif
+    {
+        value = xen_elfnote_numeric(&dsi, XEN_ELFNOTE_HV_START_LOW, 
&value_defined);
         p = xen_elfnote_string(&dsi, XEN_ELFNOTE_FEATURES);
+    }
+    if ( value_defined )
+    {
+#if CONFIG_PAGING_LEVELS < 4
+        unsigned long mask = (1UL << L2_PAGETABLE_SHIFT) - 1;
+#else
+        unsigned long mask = !IS_COMPAT(d)
+                             ? (1UL << L4_PAGETABLE_SHIFT) - 1
+                             : (1UL << L2_PAGETABLE_SHIFT) - 1;
+#endif
+
+        value = (value + mask) & ~mask;
+#ifdef CONFIG_COMPAT
+        HYPERVISOR_COMPAT_VIRT_START(d) = max_t(unsigned int, 
m2p_compat_vstart, value);
+        if ( value > (!IS_COMPAT(d) ?
+                      HYPERVISOR_VIRT_START :
+                      __HYPERVISOR_COMPAT_VIRT_START) )
+#else
+        if ( value > HYPERVISOR_VIRT_START )
+#endif
+            panic("Domain 0 expects too high a hypervisor start address.\n");
+    }
     if ( p != NULL )
     {
         parse_features(p,
@@ -400,7 +430,9 @@ int construct_dom0(struct domain *d,
     vinitrd_start    = round_pgup(dsi.v_end);
     vinitrd_end      = vinitrd_start + initrd_len;
     vphysmap_start   = round_pgup(vinitrd_end);
-    vphysmap_end     = vphysmap_start + (nr_pages * sizeof(unsigned long));
+    vphysmap_end     = vphysmap_start + (nr_pages * (!IS_COMPAT(d) ?
+                                                     sizeof(unsigned long) :
+                                                     sizeof(unsigned int)));
     vstartinfo_start = round_pgup(vphysmap_end);
     vstartinfo_end   = (vstartinfo_start +
                         sizeof(struct start_info) +
@@ -429,7 +461,9 @@ int construct_dom0(struct domain *d,
        ((_l) & ~((1UL<<(_s))-1))) >> (_s))
         if ( (1 + /* # L4 */
               NR(dsi.v_start, v_end, L4_PAGETABLE_SHIFT) + /* # L3 */
-              NR(dsi.v_start, v_end, L3_PAGETABLE_SHIFT) + /* # L2 */
+              (!IS_COMPAT(d) ?
+               NR(dsi.v_start, v_end, L3_PAGETABLE_SHIFT) : /* # L2 */
+               4) + /* # compat L2 */
               NR(dsi.v_start, v_end, L2_PAGETABLE_SHIFT))  /* # L1 */
              <= nr_pt_pages )
             break;
@@ -619,8 +653,10 @@ int construct_dom0(struct domain *d,
 #elif defined(__x86_64__)
 
     /* Overlap with Xen protected area? */
-    if ( (dsi.v_start < HYPERVISOR_VIRT_END) &&
-         (v_end > HYPERVISOR_VIRT_START) )
+    if ( !IS_COMPAT(d) ?
+         ((dsi.v_start < HYPERVISOR_VIRT_END) &&
+          (v_end > HYPERVISOR_VIRT_START)) :
+         (v_end > HYPERVISOR_COMPAT_VIRT_START(d)) )
     {
         printk("DOM0 image overlaps with Xen private area.\n");
         return -EINVAL;
@@ -633,8 +669,18 @@ int construct_dom0(struct domain *d,
     }
 
     /* WARNING: The new domain must have its 'processor' field filled in! */
-    maddr_to_page(mpt_alloc)->u.inuse.type_info = PGT_l4_page_table;
-    l4start = l4tab = __va(mpt_alloc); mpt_alloc += PAGE_SIZE;
+    if ( !IS_COMPAT(d) )
+    {
+        maddr_to_page(mpt_alloc)->u.inuse.type_info = PGT_l4_page_table;
+        l4start = l4tab = __va(mpt_alloc); mpt_alloc += PAGE_SIZE;
+    }
+    else
+    {
+        page = alloc_domheap_page(NULL);
+        if ( !page )
+            panic("Not enough RAM for domain 0 PML4.\n");
+        l4start = l4tab = page_to_virt(page);
+    }
     memcpy(l4tab, idle_pg_table, PAGE_SIZE);
     l4tab[l4_table_offset(LINEAR_PT_VIRT_START)] =
         l4e_from_paddr(__pa(l4start), __PAGE_HYPERVISOR);
@@ -679,7 +725,7 @@ int construct_dom0(struct domain *d,
             *l2tab = l2e_from_paddr(__pa(l1start), L2_PROT);
             l2tab++;
         }
-        *l1tab = l1e_from_pfn(mfn, L1_PROT);
+        *l1tab = l1e_from_pfn(mfn, !IS_COMPAT(d) ? L1_PROT : COMPAT_L1_PROT);
         l1tab++;
 
         page = mfn_to_page(mfn);
@@ -689,6 +735,30 @@ int construct_dom0(struct domain *d,
 
         mfn++;
     }
+
+#ifdef CONFIG_COMPAT
+    if ( IS_COMPAT(d) )
+    {
+        /* Ensure the first four L3 entries are all populated. */
+        for ( i = 0, l3tab = l3start; i < 4; ++i, ++l3tab )
+        {
+            if ( !l3e_get_intpte(*l3tab) )
+            {
+                maddr_to_page(mpt_alloc)->u.inuse.type_info = 
PGT_l2_page_table;
+                l2tab = __va(mpt_alloc); mpt_alloc += PAGE_SIZE;
+                clear_page(l2tab);
+                *l3tab = l3e_from_paddr(__pa(l2tab), L3_PROT);
+            }
+            if ( i == 3 )
+                l3e_get_page(*l3tab)->u.inuse.type_info |= PGT_pae_xen_l2;
+        }
+        /* Install read-only guest visible MPT mapping. */
+        l2tab = l3e_to_l2e(l3start[3]);
+        memcpy(&l2tab[COMPAT_L2_PAGETABLE_FIRST_XEN_SLOT(d)],
+               
&compat_idle_pg_table_l2[l2_table_offset(HIRO_COMPAT_MPT_VIRT_START)],
+               COMPAT_L2_PAGETABLE_XEN_SLOTS(d) * sizeof(*l2tab));
+    }
+#endif
 
     /* Pages that are part of page tables must be read only. */
     l4tab = l4start + l4_table_offset(vpt_start);
@@ -708,7 +778,8 @@ int construct_dom0(struct domain *d,
         page->u.inuse.type_info |= PGT_validated | 1;
 
         /* Top-level p.t. is pinned. */
-        if ( (page->u.inuse.type_info & PGT_type_mask) == PGT_l4_page_table )
+        if ( (page->u.inuse.type_info & PGT_type_mask) ==
+             (!IS_COMPAT(d) ? PGT_l4_page_table : PGT_l3_page_table) )
         {
             page->count_info        += 1;
             page->u.inuse.type_info += 1 | PGT_pinned;
@@ -761,26 +832,26 @@ int construct_dom0(struct domain *d,
     if ( IS_COMPAT(d) )
     {
         (void)loadelf32image(&dsi);
-        hypercall_page =
-            xen_elf32note_numeric(&dsi, XEN_ELFNOTE_HYPERCALL_PAGE, 
&hypercall_page_defined);
+        value =
+            xen_elf32note_numeric(&dsi, XEN_ELFNOTE_HYPERCALL_PAGE, 
&value_defined);
     }
     else
 #endif
     {
         (void)loadelfimage(&dsi);
-        hypercall_page =
-            xen_elfnote_numeric(&dsi, XEN_ELFNOTE_HYPERCALL_PAGE, 
&hypercall_page_defined);
-    }
-    if ( hypercall_page_defined )
-    {
-        if ( (hypercall_page < dsi.v_start) || (hypercall_page >= v_end) )
+        value =
+            xen_elfnote_numeric(&dsi, XEN_ELFNOTE_HYPERCALL_PAGE, 
&value_defined);
+    }
+    if ( value_defined )
+    {
+        if ( (value < dsi.v_start) || (value >= v_end) )
         {
             write_ptbase(current);
             local_irq_enable();
             printk("Invalid HYPERCALL_PAGE field in ELF notes.\n");
             return -1;
         }
-        hypercall_page_initialise(d, (void *)hypercall_page);
+        hypercall_page_initialise(d, (void *)(unsigned long)value);
     }
 
     /* Copy the initial ramdisk. */
@@ -798,7 +869,7 @@ int construct_dom0(struct domain *d,
     si->shared_info = virt_to_maddr(d->shared_info);
 
     si->flags        = SIF_PRIVILEGED | SIF_INITDOMAIN;
-    si->pt_base      = vpt_start;
+    si->pt_base      = vpt_start + 2 * PAGE_SIZE * !!IS_COMPAT(d);
     si->nr_pt_frames = nr_pt_pages;
     si->mfn_list     = vphysmap_start;
     sprintf(si->magic, "xen-%i.%i-x86_%d%s",
@@ -814,7 +885,10 @@ int construct_dom0(struct domain *d,
         if ( pfn > REVERSE_START )
             mfn = alloc_epfn - (pfn - REVERSE_START);
 #endif
-        ((unsigned long *)vphysmap_start)[pfn] = mfn;
+        if ( !IS_COMPAT(d) )
+            ((unsigned long *)vphysmap_start)[pfn] = mfn;
+        else
+            ((unsigned int *)vphysmap_start)[pfn] = mfn;
         set_gpfn_from_mfn(mfn, pfn);
     }
     while ( pfn < nr_pages )
@@ -827,7 +901,10 @@ int construct_dom0(struct domain *d,
 #ifndef NDEBUG
 #define pfn (nr_pages - 1 - (pfn - (alloc_epfn - alloc_spfn)))
 #endif
-            ((unsigned long *)vphysmap_start)[pfn] = mfn;
+            if ( !IS_COMPAT(d) )
+                ((unsigned long *)vphysmap_start)[pfn] = mfn;
+            else
+                ((unsigned int *)vphysmap_start)[pfn] = mfn;
             set_gpfn_from_mfn(mfn, pfn);
 #undef pfn
             page++; pfn++;
diff -r 4c8f157a3a47 -r f632c0c36976 xen/arch/x86/domctl.c
--- a/xen/arch/x86/domctl.c     Fri Jan 05 17:34:29 2007 +0000
+++ b/xen/arch/x86/domctl.c     Fri Jan 05 17:34:30 2007 +0000
@@ -311,7 +311,12 @@ void arch_getdomaininfo_ctxt(
     if ( guest_kernel_mode(v, &v->arch.guest_context.user_regs) )
         c->flags |= VGCF_in_kernel;
 
-    c->ctrlreg[3] = xen_pfn_to_cr3(pagetable_get_pfn(v->arch.guest_table));
+    if ( !IS_COMPAT(v->domain) )
+        c->ctrlreg[3] = xen_pfn_to_cr3(pagetable_get_pfn(v->arch.guest_table));
+#ifdef CONFIG_COMPAT
+    else
+        c->ctrlreg[3] = 
compat_pfn_to_cr3(pagetable_get_pfn(v->arch.guest_table));
+#endif
 
     c->vm_assist = v->domain->vm_assist;
 }
diff -r 4c8f157a3a47 -r f632c0c36976 xen/arch/x86/e820.c
--- a/xen/arch/x86/e820.c       Fri Jan 05 17:34:29 2007 +0000
+++ b/xen/arch/x86/e820.c       Fri Jan 05 17:34:30 2007 +0000
@@ -1,6 +1,7 @@
 #include <xen/config.h>
 #include <xen/init.h>
 #include <xen/lib.h>
+#include <xen/compat.h>
 #include <asm/e820.h>
 #include <asm/page.h>
 
@@ -341,6 +342,39 @@ static void __init clip_4gb(void)
 #define clip_4gb() ((void)0)
 #endif
 
+#ifdef CONFIG_COMPAT
+static void __init clip_compat(void)
+{
+    unsigned long long limit;
+    unsigned int i;
+
+    if ( compat_disabled )
+        return;
+    /* 32-bit guests restricted to 166 GB (with current memory allocator). */
+    limit = (unsigned long long)(MACH2PHYS_COMPAT_VIRT_END -
+                                 __HYPERVISOR_COMPAT_VIRT_START) << 10;
+    for ( i = 0; i < e820.nr_map; i++ )
+    {
+        if ( (e820.map[i].addr + e820.map[i].size) <= limit )
+            continue;
+        printk("WARNING: Only the first %Lu GB of the physical memory map "
+               "can be accessed\n"
+               "         by compatibility mode guests. "
+               "Truncating the memory map...\n",
+              limit >> 30);
+        if ( e820.map[i].addr >= limit )
+            e820.nr_map = i;
+        else
+        {
+            e820.map[i].size = limit - e820.map[i].addr;
+            e820.nr_map = i + 1;
+        }
+    }
+}
+#else
+#define clip_compat() ((void)0)
+#endif
+
 static void __init clip_mem(void)
 {
     int i;
@@ -374,6 +408,7 @@ static void __init machine_specific_memo
     *raw_nr = nr;
     (void)copy_e820_map(raw, nr);
     clip_4gb();
+    clip_compat();
     clip_mem();
 }
 
diff -r 4c8f157a3a47 -r f632c0c36976 xen/arch/x86/mm.c
--- a/xen/arch/x86/mm.c Fri Jan 05 17:34:29 2007 +0000
+++ b/xen/arch/x86/mm.c Fri Jan 05 17:34:30 2007 +0000
@@ -126,13 +126,6 @@
  */
 #define MMU_UPDATE_PREEMPTED          (~(~0U>>1))
 
-static void free_l2_table(struct page_info *page);
-static void free_l1_table(struct page_info *page);
-
-static int mod_l2_entry(l2_pgentry_t *, l2_pgentry_t, unsigned long,
-                        unsigned long type);
-static int mod_l1_entry(l1_pgentry_t *, l1_pgentry_t, unsigned long gl1mfn);
-
 /* Used to defer flushing of memory structures. */
 struct percpu_mm_info {
 #define DOP_FLUSH_TLB      (1<<0) /* Flush the local TLB.                    */
@@ -157,6 +150,15 @@ struct page_info *frame_table;
 struct page_info *frame_table;
 unsigned long max_page;
 unsigned long total_pages;
+
+#ifdef CONFIG_COMPAT
+l2_pgentry_t *compat_idle_pg_table_l2 = NULL;
+#define l3_disallow_mask(d) (!IS_COMPAT(d) ? \
+                             L3_DISALLOW_MASK : \
+                             COMPAT_L3_DISALLOW_MASK)
+#else
+#define l3_disallow_mask(d) L3_DISALLOW_MASK
+#endif
 
 void __init init_frametable(void)
 {
@@ -661,9 +663,9 @@ get_page_from_l3e(
     if ( !(l3e_get_flags(l3e) & _PAGE_PRESENT) )
         return 1;
 
-    if ( unlikely((l3e_get_flags(l3e) & L3_DISALLOW_MASK)) )
-    {
-        MEM_LOG("Bad L3 flags %x", l3e_get_flags(l3e) & L3_DISALLOW_MASK);
+    if ( unlikely((l3e_get_flags(l3e) & l3_disallow_mask(d))) )
+    {
+        MEM_LOG("Bad L3 flags %x", l3e_get_flags(l3e) & l3_disallow_mask(d));
         return 0;
     }
 
@@ -700,9 +702,10 @@ get_page_from_l4e(
 #ifdef __x86_64__
 
 #ifdef USER_MAPPINGS_ARE_GLOBAL
-#define adjust_guest_l1e(pl1e)                                               \
+#define adjust_guest_l1e(pl1e, d)                                            \
     do {                                                                     \
-        if ( likely(l1e_get_flags((pl1e)) & _PAGE_PRESENT) )                 \
+        if ( likely(l1e_get_flags((pl1e)) & _PAGE_PRESENT) &&                \
+             likely(!IS_COMPAT(d)) )                                         \
         {                                                                    \
             /* _PAGE_GUEST_KERNEL page cannot have the Global bit set. */    \
             if ( (l1e_get_flags((pl1e)) & (_PAGE_GUEST_KERNEL|_PAGE_GLOBAL)) \
@@ -716,37 +719,53 @@ get_page_from_l4e(
         }                                                                    \
     } while ( 0 )
 #else
-#define adjust_guest_l1e(pl1e)                                  \
+#define adjust_guest_l1e(pl1e, d)                               \
     do {                                                        \
-        if ( likely(l1e_get_flags((pl1e)) & _PAGE_PRESENT) )    \
+        if ( likely(l1e_get_flags((pl1e)) & _PAGE_PRESENT) &&   \
+             likely(!IS_COMPAT(d)) )                            \
             l1e_add_flags((pl1e), _PAGE_USER);                  \
     } while ( 0 )
 #endif
 
-#define adjust_guest_l2e(pl2e)                                  \
+#define adjust_guest_l2e(pl2e, d)                               \
     do {                                                        \
-        if ( likely(l2e_get_flags((pl2e)) & _PAGE_PRESENT) )    \
+        if ( likely(l2e_get_flags((pl2e)) & _PAGE_PRESENT) &&   \
+             likely(!IS_COMPAT(d)) )                            \
             l2e_add_flags((pl2e), _PAGE_USER);                  \
     } while ( 0 )
 
-#define adjust_guest_l3e(pl3e)                                  \
+#define adjust_guest_l3e(pl3e, d)                               \
     do {                                                        \
         if ( likely(l3e_get_flags((pl3e)) & _PAGE_PRESENT) )    \
-            l3e_add_flags((pl3e), _PAGE_USER);                  \
+            l3e_add_flags((pl3e), likely(!IS_COMPAT(d)) ?       \
+                                         _PAGE_USER :           \
+                                         _PAGE_USER|_PAGE_RW);  \
     } while ( 0 )
 
-#define adjust_guest_l4e(pl4e)                                  \
+#define adjust_guest_l4e(pl4e, d)                               \
     do {                                                        \
-        if ( likely(l4e_get_flags((pl4e)) & _PAGE_PRESENT) )    \
+        if ( likely(l4e_get_flags((pl4e)) & _PAGE_PRESENT) &&   \
+             likely(!IS_COMPAT(d)) )                            \
             l4e_add_flags((pl4e), _PAGE_USER);                  \
     } while ( 0 )
 
 #else /* !defined(__x86_64__) */
 
-#define adjust_guest_l1e(_p) ((void)0)
-#define adjust_guest_l2e(_p) ((void)0)
-#define adjust_guest_l3e(_p) ((void)0)
-
+#define adjust_guest_l1e(_p, _d) ((void)(_d))
+#define adjust_guest_l2e(_p, _d) ((void)(_d))
+#define adjust_guest_l3e(_p, _d) ((void)(_d))
+
+#endif
+
+#ifdef CONFIG_COMPAT
+#define unadjust_guest_l3e(pl3e, d)                             \
+    do {                                                        \
+        if ( unlikely(IS_COMPAT(d)) &&                          \
+             likely(l3e_get_flags((pl3e)) & _PAGE_PRESENT) )    \
+            l3e_remove_flags((pl3e), _PAGE_USER|_PAGE_RW|_PAGE_ACCESSED); \
+    } while ( 0 )
+#else
+#define unadjust_guest_l3e(_p, _d) ((void)(_d))
 #endif
 
 void put_page_from_l1e(l1_pgentry_t l1e, struct domain *d)
@@ -850,7 +869,7 @@ static int alloc_l1_table(struct page_in
              unlikely(!get_page_from_l1e(pl1e[i], d)) )
             goto fail;
 
-        adjust_guest_l1e(pl1e[i]);
+        adjust_guest_l1e(pl1e[i], d);
     }
 
     unmap_domain_page(pl1e);
@@ -866,13 +885,20 @@ static int alloc_l1_table(struct page_in
     return 0;
 }
 
-#ifdef CONFIG_X86_PAE
-static int create_pae_xen_mappings(l3_pgentry_t *pl3e)
+#if defined(CONFIG_X86_PAE) || defined(CONFIG_COMPAT)
+static int create_pae_xen_mappings(struct domain *d, l3_pgentry_t *pl3e)
 {
     struct page_info *page;
-    l2_pgentry_t    *pl2e, l2e;
+    l2_pgentry_t    *pl2e;
     l3_pgentry_t     l3e3;
+#ifndef CONFIG_COMPAT
+    l2_pgentry_t     l2e;
     int              i;
+#else
+
+    if ( !IS_COMPAT(d) )
+        return 1;
+#endif
 
     pl3e = (l3_pgentry_t *)((unsigned long)pl3e & PAGE_MASK);
 
@@ -905,6 +931,7 @@ static int create_pae_xen_mappings(l3_pg
 
     /* Xen private mappings. */
     pl2e = map_domain_page(l3e_get_pfn(l3e3));
+#ifndef CONFIG_COMPAT
     memcpy(&pl2e[L2_PAGETABLE_FIRST_XEN_SLOT & (L2_PAGETABLE_ENTRIES-1)],
            &idle_pg_table_l2[L2_PAGETABLE_FIRST_XEN_SLOT],
            L2_PAGETABLE_XEN_SLOTS * sizeof(l2_pgentry_t));
@@ -922,11 +949,20 @@ static int create_pae_xen_mappings(l3_pg
             l2e = l2e_from_pfn(l3e_get_pfn(pl3e[i]), __PAGE_HYPERVISOR);
         l2e_write(&pl2e[l2_table_offset(LINEAR_PT_VIRT_START) + i], l2e);
     }
+#else
+    memcpy(&pl2e[COMPAT_L2_PAGETABLE_FIRST_XEN_SLOT(d)],
+           
&compat_idle_pg_table_l2[l2_table_offset(HIRO_COMPAT_MPT_VIRT_START)],
+           COMPAT_L2_PAGETABLE_XEN_SLOTS(d) * sizeof(*pl2e));
+#endif
     unmap_domain_page(pl2e);
 
     return 1;
 }
-
+#else
+# define create_pae_xen_mappings(d, pl3e) (1)
+#endif
+
+#ifdef CONFIG_X86_PAE
 /* Flush a pgdir update into low-memory caches. */
 static void pae_flush_pgd(
     unsigned long mfn, unsigned int idx, l3_pgentry_t nl3e)
@@ -961,12 +997,8 @@ static void pae_flush_pgd(
 
     flush_tlb_mask(d->domain_dirty_cpumask);
 }
-
-#elif CONFIG_X86_64
-# define create_pae_xen_mappings(pl3e) (1)
+#else
 # define pae_flush_pgd(mfn, idx, nl3e) ((void)0)
-#else
-# define create_pae_xen_mappings(pl3e) (1)
 #endif
 
 static int alloc_l2_table(struct page_info *page, unsigned long type)
@@ -980,11 +1012,11 @@ static int alloc_l2_table(struct page_in
 
     for ( i = 0; i < L2_PAGETABLE_ENTRIES; i++ )
     {
-        if ( is_guest_l2_slot(type, i) &&
+        if ( is_guest_l2_slot(d, type, i) &&
              unlikely(!get_page_from_l2e(pl2e[i], pfn, d)) )
             goto fail;
         
-        adjust_guest_l2e(pl2e[i]);
+        adjust_guest_l2e(pl2e[i], d);
     }
 
 #if CONFIG_PAGING_LEVELS == 2
@@ -1007,7 +1039,7 @@ static int alloc_l2_table(struct page_in
  fail:
     MEM_LOG("Failure in alloc_l2_table: entry %d", i);
     while ( i-- > 0 )
-        if ( is_guest_l2_slot(type, i) )
+        if ( is_guest_l2_slot(d, type, i) )
             put_page_from_l2e(pl2e[i], pfn);
 
     unmap_domain_page(pl2e);
@@ -1039,13 +1071,24 @@ static int alloc_l3_table(struct page_in
 #endif
 
     pl3e = map_domain_page(pfn);
+
+    /*
+     * PAE guests allocate full pages, but aren't required to initialize
+     * more than the first four entries; when running in compatibility
+     * mode, however, the full page is visible to the MMU, and hence all
+     * 512 entries must be valid/verified, which is most easily achieved
+     * by clearing them out.
+     */
+    if ( IS_COMPAT(d) )
+        memset(pl3e + 4, 0, (L3_PAGETABLE_ENTRIES - 4) * sizeof(*pl3e));
+
     for ( i = 0; i < L3_PAGETABLE_ENTRIES; i++ )
     {
-#ifdef CONFIG_X86_PAE
-        if ( i == 3 )
+#if defined(CONFIG_X86_PAE) || defined(CONFIG_COMPAT)
+        if ( (CONFIG_PAGING_LEVELS < 4 || IS_COMPAT(d)) && i == 3 )
         {
             if ( !(l3e_get_flags(pl3e[i]) & _PAGE_PRESENT) ||
-                 (l3e_get_flags(pl3e[i]) & L3_DISALLOW_MASK) ||
+                 (l3e_get_flags(pl3e[i]) & l3_disallow_mask(d)) ||
                  !get_page_and_type_from_pagenr(l3e_get_pfn(pl3e[i]),
                                                 PGT_l2_page_table |
                                                 PGT_pae_xen_l2,
@@ -1058,10 +1101,10 @@ static int alloc_l3_table(struct page_in
              unlikely(!get_page_from_l3e(pl3e[i], pfn, d)) )
             goto fail;
         
-        adjust_guest_l3e(pl3e[i]);
-    }
-
-    if ( !create_pae_xen_mappings(pl3e) )
+        adjust_guest_l3e(pl3e[i], d);
+    }
+
+    if ( !create_pae_xen_mappings(d, pl3e) )
         goto fail;
 
     unmap_domain_page(pl3e);
@@ -1094,7 +1137,7 @@ static int alloc_l4_table(struct page_in
              unlikely(!get_page_from_l4e(pl4e[i], pfn, d)) )
             goto fail;
 
-        adjust_guest_l4e(pl4e[i]);
+        adjust_guest_l4e(pl4e[i], d);
     }
 
     /* Xen private mappings. */
@@ -1142,6 +1185,9 @@ static void free_l1_table(struct page_in
 
 static void free_l2_table(struct page_info *page)
 {
+#ifdef CONFIG_COMPAT
+    struct domain *d = page_get_owner(page);
+#endif
     unsigned long pfn = page_to_mfn(page);
     l2_pgentry_t *pl2e;
     int i;
@@ -1149,7 +1195,7 @@ static void free_l2_table(struct page_in
     pl2e = map_domain_page(pfn);
 
     for ( i = 0; i < L2_PAGETABLE_ENTRIES; i++ )
-        if ( is_guest_l2_slot(page->u.inuse.type_info, i) )
+        if ( is_guest_l2_slot(d, page->u.inuse.type_info, i) )
             put_page_from_l2e(pl2e[i], pfn);
 
     unmap_domain_page(pl2e);
@@ -1162,6 +1208,7 @@ static void free_l2_table(struct page_in
 
 static void free_l3_table(struct page_info *page)
 {
+    struct domain *d = page_get_owner(page);
     unsigned long pfn = page_to_mfn(page);
     l3_pgentry_t *pl3e;
     int           i;
@@ -1170,7 +1217,10 @@ static void free_l3_table(struct page_in
 
     for ( i = 0; i < L3_PAGETABLE_ENTRIES; i++ )
         if ( is_guest_l3_slot(i) )
+        {
             put_page_from_l3e(pl3e[i], pfn);
+            unadjust_guest_l3e(pl3e[i], d);
+        }
 
     unmap_domain_page(pl3e);
 }
@@ -1270,7 +1320,7 @@ static int mod_l1_entry(l1_pgentry_t *pl
             return 0;
         }
 
-        adjust_guest_l1e(nl1e);
+        adjust_guest_l1e(nl1e, d);
 
         /* Fast path for identical mapping, r/w and presence. */
         if ( !l1e_has_changed(ol1e, nl1e, _PAGE_RW | _PAGE_PRESENT) )
@@ -1303,8 +1353,9 @@ static int mod_l2_entry(l2_pgentry_t *pl
                         unsigned long type)
 {
     l2_pgentry_t ol2e;
-
-    if ( unlikely(!is_guest_l2_slot(type,pgentry_ptr_to_slot(pl2e))) )
+    struct domain *d = current->domain;
+
+    if ( unlikely(!is_guest_l2_slot(d, type, pgentry_ptr_to_slot(pl2e))) )
     {
         MEM_LOG("Illegal L2 update attempt in Xen-private area %p", pl2e);
         return 0;
@@ -1322,7 +1373,7 @@ static int mod_l2_entry(l2_pgentry_t *pl
             return 0;
         }
 
-        adjust_guest_l2e(nl2e);
+        adjust_guest_l2e(nl2e, d);
 
         /* Fast path for identical mapping and presence. */
         if ( !l2e_has_changed(ol2e, nl2e, _PAGE_PRESENT))
@@ -1354,6 +1405,7 @@ static int mod_l3_entry(l3_pgentry_t *pl
                         unsigned long pfn)
 {
     l3_pgentry_t ol3e;
+    struct domain *d = current->domain;
     int okay;
 
     if ( unlikely(!is_guest_l3_slot(pgentry_ptr_to_slot(pl3e))) )
@@ -1362,12 +1414,13 @@ static int mod_l3_entry(l3_pgentry_t *pl
         return 0;
     }
 
-#ifdef CONFIG_X86_PAE
+#if defined(CONFIG_X86_PAE) || defined(CONFIG_COMPAT)
     /*
      * Disallow updates to final L3 slot. It contains Xen mappings, and it
      * would be a pain to ensure they remain continuously valid throughout.
      */
-    if ( pgentry_ptr_to_slot(pl3e) >= 3 )
+    if ( (CONFIG_PAGING_LEVELS < 4 || IS_COMPAT(d)) &&
+         pgentry_ptr_to_slot(pl3e) >= 3 )
         return 0;
 #endif 
 
@@ -1376,14 +1429,14 @@ static int mod_l3_entry(l3_pgentry_t *pl
 
     if ( l3e_get_flags(nl3e) & _PAGE_PRESENT )
     {
-        if ( unlikely(l3e_get_flags(nl3e) & L3_DISALLOW_MASK) )
+        if ( unlikely(l3e_get_flags(nl3e) & l3_disallow_mask(d)) )
         {
             MEM_LOG("Bad L3 flags %x",
-                    l3e_get_flags(nl3e) & L3_DISALLOW_MASK);
+                    l3e_get_flags(nl3e) & l3_disallow_mask(d));
             return 0;
         }
 
-        adjust_guest_l3e(nl3e);
+        adjust_guest_l3e(nl3e, d);
 
         /* Fast path for identical mapping and presence. */
         if (!l3e_has_changed(ol3e, nl3e, _PAGE_PRESENT))
@@ -1403,7 +1456,7 @@ static int mod_l3_entry(l3_pgentry_t *pl
         return 0;
     }
 
-    okay = create_pae_xen_mappings(pl3e);
+    okay = create_pae_xen_mappings(d, pl3e);
     BUG_ON(!okay);
 
     pae_flush_pgd(pfn, pgentry_ptr_to_slot(pl3e), nl3e);
@@ -1441,7 +1494,7 @@ static int mod_l4_entry(l4_pgentry_t *pl
             return 0;
         }
 
-        adjust_guest_l4e(nl4e);
+        adjust_guest_l4e(nl4e, current->domain);
 
         /* Fast path for identical mapping and presence. */
         if (!l4e_has_changed(ol4e, nl4e, _PAGE_PRESENT))
@@ -2265,8 +2318,7 @@ int do_mmu_update(
                 case PGT_l2_page_table:
                 {
                     l2_pgentry_t l2e = l2e_from_intpte(req.val);
-                    okay = mod_l2_entry(
-                        (l2_pgentry_t *)va, l2e, mfn, type_info);
+                    okay = mod_l2_entry(va, l2e, mfn, type_info);
                 }
                 break;
 #if CONFIG_PAGING_LEVELS >= 3
@@ -2279,11 +2331,12 @@ int do_mmu_update(
 #endif
 #if CONFIG_PAGING_LEVELS >= 4
                 case PGT_l4_page_table:
-                {
-                    l4_pgentry_t l4e = l4e_from_intpte(req.val);
-                    okay = mod_l4_entry(va, l4e, mfn);
-                }
-                break;
+                    if ( !IS_COMPAT(FOREIGNDOM) )
+                    {
+                        l4_pgentry_t l4e = l4e_from_intpte(req.val);
+                        okay = mod_l4_entry(va, l4e, mfn);
+                    }
+                    break;
 #endif
                 }
 
@@ -2387,7 +2440,7 @@ static int create_grant_pte_mapping(
 
     ASSERT(spin_is_locked(&d->big_lock));
 
-    adjust_guest_l1e(nl1e);
+    adjust_guest_l1e(nl1e, d);
 
     gmfn = pte_addr >> PAGE_SHIFT;
     mfn = gmfn_to_mfn(d, gmfn);
@@ -2508,7 +2561,7 @@ static int create_grant_va_mapping(
     
     ASSERT(spin_is_locked(&d->big_lock));
 
-    adjust_guest_l1e(nl1e);
+    adjust_guest_l1e(nl1e, d);
 
     pl1e = guest_map_l1e(v, va, &gl1mfn);
     if ( !pl1e )
@@ -3173,7 +3226,7 @@ static int ptwr_emulated_update(
         }
     }
 
-    adjust_guest_l1e(nl1e);
+    adjust_guest_l1e(nl1e, d);
 
     /* Checked successfully: do the update (write or cmpxchg). */
     pl1e = map_domain_page(page_to_mfn(page));
diff -r 4c8f157a3a47 -r f632c0c36976 xen/arch/x86/x86_64/mm.c
--- a/xen/arch/x86/x86_64/mm.c  Fri Jan 05 17:34:29 2007 +0000
+++ b/xen/arch/x86/x86_64/mm.c  Fri Jan 05 17:34:30 2007 +0000
@@ -31,6 +31,10 @@
 #include <asm/msr.h>
 #include <public/memory.h>
 
+#ifdef CONFIG_COMPAT
+unsigned int m2p_compat_vstart = __HYPERVISOR_COMPAT_VIRT_START;
+#endif
+
 struct page_info *alloc_xen_pagetable(void)
 {
     extern int early_boot;
@@ -121,6 +125,47 @@ void __init paging_init(void)
         l2_ro_mpt++;
     }
 
+#ifdef CONFIG_COMPAT
+    if ( !compat_disabled )
+    {
+        /* Create user-accessible L2 directory to map the MPT for 
compatibility guests. */
+        BUILD_BUG_ON(l4_table_offset(RDWR_MPT_VIRT_START) !=
+                     l4_table_offset(HIRO_COMPAT_MPT_VIRT_START));
+        l3_ro_mpt = 
l4e_to_l3e(idle_pg_table[l4_table_offset(HIRO_COMPAT_MPT_VIRT_START)]);
+        if ( (l2_pg = alloc_domheap_page(NULL)) == NULL )
+            goto nomem;
+        compat_idle_pg_table_l2 = l2_ro_mpt = clear_page(page_to_virt(l2_pg));
+        l3e_write(&l3_ro_mpt[l3_table_offset(HIRO_COMPAT_MPT_VIRT_START)],
+                  l3e_from_page(l2_pg, __PAGE_HYPERVISOR));
+        l2_ro_mpt += l2_table_offset(HIRO_COMPAT_MPT_VIRT_START);
+        /*
+         * Allocate and map the compatibility mode machine-to-phys table.
+        */
+        mpt_size = (mpt_size >> 1) + (1UL << (L2_PAGETABLE_SHIFT - 1));
+        if ( mpt_size > RDWR_COMPAT_MPT_VIRT_END - RDWR_COMPAT_MPT_VIRT_START )
+            mpt_size = RDWR_COMPAT_MPT_VIRT_END - RDWR_COMPAT_MPT_VIRT_START;
+        mpt_size &= ~((1UL << L2_PAGETABLE_SHIFT) - 1UL);
+        if ( m2p_compat_vstart + mpt_size < MACH2PHYS_COMPAT_VIRT_END )
+            m2p_compat_vstart = MACH2PHYS_COMPAT_VIRT_END - mpt_size;
+        for ( i = 0; i < (mpt_size >> L2_PAGETABLE_SHIFT); i++ )
+        {
+            if ( (l1_pg = alloc_domheap_pages(NULL, PAGETABLE_ORDER, 0)) == 
NULL )
+                goto nomem;
+            map_pages_to_xen(
+                RDWR_COMPAT_MPT_VIRT_START + (i << L2_PAGETABLE_SHIFT),
+                page_to_mfn(l1_pg),
+                1UL << PAGETABLE_ORDER,
+                PAGE_HYPERVISOR);
+            memset((void *)(RDWR_COMPAT_MPT_VIRT_START + (i << 
L2_PAGETABLE_SHIFT)),
+                   0x55,
+                   1UL << L2_PAGETABLE_SHIFT);
+            /* NB. Cannot be GLOBAL as the pt entries get copied into per-VM 
space. */
+            l2e_write(l2_ro_mpt, l2e_from_page(l1_pg, 
_PAGE_PSE|_PAGE_PRESENT));
+            l2_ro_mpt++;
+        }
+    }
+#endif
+
     /* Set up linear page table mapping. */
     l4e_write(&idle_pg_table[l4_table_offset(LINEAR_PT_VIRT_START)],
               l4e_from_paddr(__pa(idle_pg_table), __PAGE_HYPERVISOR));
@@ -182,6 +227,30 @@ void subarch_init_memory(void)
             share_xen_page_with_privileged_guests(page, XENSHARE_readonly);
         }
     }
+#ifdef CONFIG_COMPAT
+    if ( !compat_disabled )
+    {
+        for ( v  = RDWR_COMPAT_MPT_VIRT_START;
+              v != RDWR_COMPAT_MPT_VIRT_END;
+              v += 1 << L2_PAGETABLE_SHIFT )
+        {
+            l3e = l4e_to_l3e(idle_pg_table[l4_table_offset(v)])[
+                l3_table_offset(v)];
+            if ( !(l3e_get_flags(l3e) & _PAGE_PRESENT) )
+                continue;
+            l2e = l3e_to_l2e(l3e)[l2_table_offset(v)];
+            if ( !(l2e_get_flags(l2e) & _PAGE_PRESENT) )
+                continue;
+            m2p_start_mfn = l2e_get_pfn(l2e);
+
+            for ( i = 0; i < L1_PAGETABLE_ENTRIES; i++ )
+            {
+                struct page_info *page = mfn_to_page(m2p_start_mfn + i);
+                share_xen_page_with_privileged_guests(page, XENSHARE_readonly);
+            }
+        }
+    }
+#endif
 }
 
 long subarch_memory_op(int op, XEN_GUEST_HANDLE(void) arg)
@@ -189,7 +258,8 @@ long subarch_memory_op(int op, XEN_GUEST
     struct xen_machphys_mfn_list xmml;
     l3_pgentry_t l3e;
     l2_pgentry_t l2e;
-    unsigned long mfn, v;
+    unsigned long v;
+    xen_pfn_t mfn;
     unsigned int i;
     long rc = 0;
 
diff -r 4c8f157a3a47 -r f632c0c36976 xen/common/compat/kernel.c
--- a/xen/common/compat/kernel.c        Fri Jan 05 17:34:29 2007 +0000
+++ b/xen/common/compat/kernel.c        Fri Jan 05 17:34:30 2007 +0000
@@ -27,7 +27,7 @@ CHECK_TYPE(capabilities_info);
 #define xen_platform_parameters compat_platform_parameters
 #define xen_platform_parameters_t compat_platform_parameters_t
 #undef HYPERVISOR_VIRT_START
-#define HYPERVISOR_VIRT_START HYPERVISOR_COMPAT_VIRT_START
+#define HYPERVISOR_VIRT_START HYPERVISOR_COMPAT_VIRT_START(current->domain)
 
 #define xen_changeset_info compat_changeset_info
 #define xen_changeset_info_t compat_changeset_info_t
diff -r 4c8f157a3a47 -r f632c0c36976 xen/include/asm-x86/config.h
--- a/xen/include/asm-x86/config.h      Fri Jan 05 17:34:29 2007 +0000
+++ b/xen/include/asm-x86/config.h      Fri Jan 05 17:34:30 2007 +0000
@@ -129,7 +129,11 @@
  *    Page-frame information array.
  *  0xffff828800000000 - 0xffff828bffffffff [16GB,  2^34 bytes, PML4:261]
  *    ioremap()/fixmap area.
- *  0xffff828c00000000 - 0xffff82ffffffffff [464GB,             PML4:261]
+ *  0xffff828c00000000 - 0xffff828c3fffffff [1GB,   2^30 bytes, PML4:261]
+ *    Compatibility machine-to-phys translation table.
+ *  0xffff828c40000000 - 0xffff828c7fffffff [1GB,   2^30 bytes, PML4:261]
+ *    High read-only compatibility machine-to-phys translation table.
+ *  0xffff828c80000000 - 0xffff82ffffffffff [462GB,             PML4:261]
  *    Reserved for future use.
  *  0xffff830000000000 - 0xffff83ffffffffff [1TB,   2^40 bytes, PML4:262-263]
  *    1:1 direct mapping of all physical memory. Xen and its heap live here.
@@ -178,17 +182,33 @@
 /* Slot 261: ioremap()/fixmap area (16GB). */
 #define IOREMAP_VIRT_START      (FRAMETABLE_VIRT_END)
 #define IOREMAP_VIRT_END        (IOREMAP_VIRT_START + (16UL<<30))
+/* Slot 261: compatibility machine-to-phys conversion table (1GB). */
+#define RDWR_COMPAT_MPT_VIRT_START IOREMAP_VIRT_END
+#define RDWR_COMPAT_MPT_VIRT_END (RDWR_COMPAT_MPT_VIRT_START + (1UL << 30))
+/* Slot 261: high read-only compatibility machine-to-phys conversion table 
(1GB). */
+#define HIRO_COMPAT_MPT_VIRT_START RDWR_COMPAT_MPT_VIRT_END
+#define HIRO_COMPAT_MPT_VIRT_END (HIRO_COMPAT_MPT_VIRT_START + (1UL << 30))
 /* Slot 262-263: A direct 1:1 mapping of all of physical memory. */
 #define DIRECTMAP_VIRT_START    (PML4_ADDR(262))
 #define DIRECTMAP_VIRT_END      (DIRECTMAP_VIRT_START + PML4_ENTRY_BYTES*2)
 
+#ifndef __ASSEMBLY__
+
+/* This is not a fixed value, just a lower limit. */
 #define __HYPERVISOR_COMPAT_VIRT_START 0xF5800000
-#define HYPERVISOR_COMPAT_VIRT_START   \
-    mk_unsigned_long(__HYPERVISOR_COMPAT_VIRT_START)
+#define HYPERVISOR_COMPAT_VIRT_START(d) ((d)->arch.hv_compat_vstart)
 #define MACH2PHYS_COMPAT_VIRT_START    HYPERVISOR_COMPAT_VIRT_START
 #define MACH2PHYS_COMPAT_VIRT_END      0xFFE00000
-#define MACH2PHYS_COMPAT_NR_ENTRIES    \
-    ((MACH2PHYS_COMPAT_VIRT_END-MACH2PHYS_COMPAT_VIRT_START)>>2)
+#define MACH2PHYS_COMPAT_NR_ENTRIES(d) \
+    ((MACH2PHYS_COMPAT_VIRT_END-MACH2PHYS_COMPAT_VIRT_START(d))>>2)
+
+#define COMPAT_L2_PAGETABLE_FIRST_XEN_SLOT(d) \
+    l2_table_offset(HYPERVISOR_COMPAT_VIRT_START(d))
+#define COMPAT_L2_PAGETABLE_LAST_XEN_SLOT  l2_table_offset(~0U)
+#define COMPAT_L2_PAGETABLE_XEN_SLOTS(d) \
+    (COMPAT_L2_PAGETABLE_LAST_XEN_SLOT - COMPAT_L2_PAGETABLE_FIRST_XEN_SLOT(d) 
+ 1)
+
+#endif
 
 #define PGT_base_page_table     PGT_l4_page_table
 
diff -r 4c8f157a3a47 -r f632c0c36976 xen/include/asm-x86/domain.h
--- a/xen/include/asm-x86/domain.h      Fri Jan 05 17:34:29 2007 +0000
+++ b/xen/include/asm-x86/domain.h      Fri Jan 05 17:34:30 2007 +0000
@@ -98,6 +98,10 @@ struct arch_domain
     struct mapcache mapcache;
 #endif
 
+#ifdef CONFIG_COMPAT
+    unsigned int hv_compat_vstart;
+#endif
+
     /* I/O-port admin-specified access capabilities. */
     struct rangeset *ioport_caps;
 
diff -r 4c8f157a3a47 -r f632c0c36976 xen/include/asm-x86/mm.h
--- a/xen/include/asm-x86/mm.h  Fri Jan 05 17:34:29 2007 +0000
+++ b/xen/include/asm-x86/mm.h  Fri Jan 05 17:34:30 2007 +0000
@@ -257,7 +257,16 @@ int check_descriptor(const struct domain
 #define INVALID_M2P_ENTRY        (~0UL)
 #define VALID_M2P(_e)            (!((_e) & (1UL<<(BITS_PER_LONG-1))))
 
+#ifdef CONFIG_COMPAT
+#define compat_machine_to_phys_mapping ((unsigned int 
*)RDWR_COMPAT_MPT_VIRT_START)
+#define set_gpfn_from_mfn(mfn, pfn) \
+    ((void)(compat_disabled || \
+            (mfn) >= (RDWR_COMPAT_MPT_VIRT_END - RDWR_COMPAT_MPT_VIRT_START) / 
4 || \
+            (compat_machine_to_phys_mapping[(mfn)] = (unsigned int)(pfn))), \
+     machine_to_phys_mapping[(mfn)] = (pfn))
+#else
 #define set_gpfn_from_mfn(mfn, pfn) (machine_to_phys_mapping[(mfn)] = (pfn))
+#endif
 #define get_gpfn_from_mfn(mfn)      (machine_to_phys_mapping[(mfn)])
 
 
diff -r 4c8f157a3a47 -r f632c0c36976 xen/include/asm-x86/page.h
--- a/xen/include/asm-x86/page.h        Fri Jan 05 17:34:29 2007 +0000
+++ b/xen/include/asm-x86/page.h        Fri Jan 05 17:34:30 2007 +0000
@@ -206,6 +206,7 @@ typedef struct { u64 pfn; } pagetable_t;
 typedef struct { u64 pfn; } pagetable_t;
 #endif
 #define pagetable_get_paddr(x)  ((paddr_t)(x).pfn << PAGE_SHIFT)
+#define pagetable_get_page(x)   mfn_to_page((x).pfn)
 #define pagetable_get_pfn(x)    ((x).pfn)
 #define pagetable_is_null(x)    ((x).pfn == 0)
 #define pagetable_from_pfn(pfn) ((pagetable_t) { (pfn) })
@@ -287,6 +288,10 @@ extern l2_pgentry_t   idle_pg_table_l2[R
 #else
 extern root_pgentry_t idle_pg_table[ROOT_PAGETABLE_ENTRIES];
 extern l2_pgentry_t   idle_pg_table_l2[ROOT_PAGETABLE_ENTRIES];
+#ifdef CONFIG_COMPAT
+extern l2_pgentry_t  *compat_idle_pg_table_l2;
+extern unsigned int   m2p_compat_vstart;
+#endif
 #endif
 void paging_init(void);
 void setup_idle_pagetable(void);
diff -r 4c8f157a3a47 -r f632c0c36976 xen/include/asm-x86/x86_32/page-2level.h
--- a/xen/include/asm-x86/x86_32/page-2level.h  Fri Jan 05 17:34:29 2007 +0000
+++ b/xen/include/asm-x86/x86_32/page-2level.h  Fri Jan 05 17:34:30 2007 +0000
@@ -42,7 +42,7 @@ typedef l2_pgentry_t root_pgentry_t;
 
 /* misc */
 #define is_guest_l1_slot(_s)    (1)
-#define is_guest_l2_slot(_t,_s) ((_s) < L2_PAGETABLE_FIRST_XEN_SLOT)
+#define is_guest_l2_slot(_d, _t,_s) ((_s) < L2_PAGETABLE_FIRST_XEN_SLOT)
 
 /*
  * PTE pfn and flags:
diff -r 4c8f157a3a47 -r f632c0c36976 xen/include/asm-x86/x86_32/page-3level.h
--- a/xen/include/asm-x86/x86_32/page-3level.h  Fri Jan 05 17:34:29 2007 +0000
+++ b/xen/include/asm-x86/x86_32/page-3level.h  Fri Jan 05 17:34:30 2007 +0000
@@ -67,7 +67,7 @@ typedef l3_pgentry_t root_pgentry_t;
 
 /* misc */
 #define is_guest_l1_slot(s)    (1)
-#define is_guest_l2_slot(t,s)                                              \
+#define is_guest_l2_slot(d,t,s)                                            \
     ( !((t) & PGT_pae_xen_l2) ||                                           \
       ((s) < (L2_PAGETABLE_FIRST_XEN_SLOT & (L2_PAGETABLE_ENTRIES - 1))) )
 #define is_guest_l3_slot(s)    (1)
diff -r 4c8f157a3a47 -r f632c0c36976 xen/include/asm-x86/x86_64/page.h
--- a/xen/include/asm-x86/x86_64/page.h Fri Jan 05 17:34:29 2007 +0000
+++ b/xen/include/asm-x86/x86_64/page.h Fri Jan 05 17:34:30 2007 +0000
@@ -54,7 +54,10 @@ typedef l4_pgentry_t root_pgentry_t;
 #define l4_linear_offset(_a) (((_a) & VADDR_MASK) >> L4_PAGETABLE_SHIFT)
 
 #define is_guest_l1_slot(_s) (1)
-#define is_guest_l2_slot(_t, _s) (1)
+#define is_guest_l2_slot(_d, _t, _s)                   \
+    ( !IS_COMPAT(_d) ||                                \
+      !((_t) & PGT_pae_xen_l2) ||                      \
+      ((_s) < COMPAT_L2_PAGETABLE_FIRST_XEN_SLOT(_d)) )
 #define is_guest_l3_slot(_s) (1)
 #define is_guest_l4_slot(_s)                   \
     (((_s) < ROOT_PAGETABLE_FIRST_XEN_SLOT) || \
@@ -93,6 +96,8 @@ typedef l4_pgentry_t root_pgentry_t;
 #define L3_DISALLOW_MASK (BASE_DISALLOW_MASK | 0x180U /* must-be-zero */)
 #define L4_DISALLOW_MASK (BASE_DISALLOW_MASK | 0x180U /* must-be-zero */)
 
+#define COMPAT_L3_DISALLOW_MASK 0xFFFFF1E6U /* must-be-zero */
+
 #define PAGE_HYPERVISOR         (__PAGE_HYPERVISOR         | _PAGE_GLOBAL)
 #define PAGE_HYPERVISOR_NOCACHE (__PAGE_HYPERVISOR_NOCACHE | _PAGE_GLOBAL)
 
diff -r 4c8f157a3a47 -r f632c0c36976 xen/include/asm-x86/x86_64/uaccess.h
--- a/xen/include/asm-x86/x86_64/uaccess.h      Fri Jan 05 17:34:29 2007 +0000
+++ b/xen/include/asm-x86/x86_64/uaccess.h      Fri Jan 05 17:34:30 2007 +0000
@@ -18,7 +18,7 @@
 #ifdef CONFIG_COMPAT
 
 #define __compat_addr_ok(addr) \
-    ((unsigned long)(addr) < HYPERVISOR_COMPAT_VIRT_START)
+    ((unsigned long)(addr) < HYPERVISOR_COMPAT_VIRT_START(current->domain))
 
 #define compat_access_ok(addr, size) __compat_addr_ok((addr) + (size))
 

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.