# 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
|