1193 lines
45 KiB
Diff
1193 lines
45 KiB
Diff
|
Add page table setup and handling, including the creation of an m2p table
|
||
|
meaningful to compatibility mode guests.
|
||
|
|
||
|
Index: 2007-01-31/xen/arch/x86/domain.c
|
||
|
===================================================================
|
||
|
--- 2007-01-31.orig/xen/arch/x86/domain.c 2007-01-31 09:29:10.000000000 +0100
|
||
|
+++ 2007-01-31/xen/arch/x86/domain.c 2007-01-31 09:29:11.000000000 +0100
|
||
|
@@ -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)
|
||
|
@@ -218,6 +245,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_lock_init(d);
|
||
|
for ( i = 0; i <= SHADOW_MAX_ORDER; i++ )
|
||
|
INIT_LIST_HEAD(&d->arch.shadow.freelists[i]);
|
||
|
@@ -353,18 +384,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) )
|
||
|
+ if ( !IS_COMPAT(d) )
|
||
|
{
|
||
|
- destroy_gdt(v);
|
||
|
- return -EINVAL;
|
||
|
+ 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]));
|
||
|
|
||
|
- v->arch.guest_table = pagetable_from_pfn(cr3_pfn);
|
||
|
+ 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
|
||
|
}
|
||
|
|
||
|
/* Shadow: make sure the domain has enough shadow memory to
|
||
|
Index: 2007-01-31/xen/arch/x86/domain_build.c
|
||
|
===================================================================
|
||
|
--- 2007-01-31.orig/xen/arch/x86/domain_build.c 2007-01-31 09:29:10.000000000 +0100
|
||
|
+++ 2007-01-31/xen/arch/x86/domain_build.c 2007-01-31 09:29:11.000000000 +0100
|
||
|
@@ -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);
|
||
|
@@ -690,6 +736,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);
|
||
|
l3start = l3tab = l4e_to_l3e(*l4tab);
|
||
|
@@ -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);
|
||
|
+ value =
|
||
|
+ xen_elfnote_numeric(&dsi, XEN_ELFNOTE_HYPERCALL_PAGE, &value_defined);
|
||
|
}
|
||
|
- if ( hypercall_page_defined )
|
||
|
+ if ( value_defined )
|
||
|
{
|
||
|
- if ( (hypercall_page < dsi.v_start) || (hypercall_page >= v_end) )
|
||
|
+ 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++;
|
||
|
Index: 2007-01-31/xen/arch/x86/domctl.c
|
||
|
===================================================================
|
||
|
--- 2007-01-31.orig/xen/arch/x86/domctl.c 2006-12-13 11:15:53.000000000 +0100
|
||
|
+++ 2007-01-31/xen/arch/x86/domctl.c 2007-01-31 09:29:11.000000000 +0100
|
||
|
@@ -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;
|
||
|
}
|
||
|
Index: 2007-01-31/xen/arch/x86/e820.c
|
||
|
===================================================================
|
||
|
--- 2007-01-31.orig/xen/arch/x86/e820.c 2006-12-13 11:15:53.000000000 +0100
|
||
|
+++ 2007-01-31/xen/arch/x86/e820.c 2007-01-31 09:29:11.000000000 +0100
|
||
|
@@ -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();
|
||
|
}
|
||
|
|
||
|
Index: 2007-01-31/xen/arch/x86/mm.c
|
||
|
===================================================================
|
||
|
--- 2007-01-31.orig/xen/arch/x86/mm.c 2007-01-31 09:29:03.000000000 +0100
|
||
|
+++ 2007-01-31/xen/arch/x86/mm.c 2007-01-31 09:29:11.000000000 +0100
|
||
|
@@ -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. */
|
||
|
@@ -158,6 +151,15 @@ 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)
|
||
|
{
|
||
|
unsigned long nr_pages, page_step, i, mfn;
|
||
|
@@ -629,9 +631,9 @@ get_page_from_l3e(
|
||
|
if ( !(l3e_get_flags(l3e) & _PAGE_PRESENT) )
|
||
|
return 1;
|
||
|
|
||
|
- if ( unlikely((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);
|
||
|
+ MEM_LOG("Bad L3 flags %x", l3e_get_flags(l3e) & l3_disallow_mask(d));
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
@@ -668,9 +670,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)) \
|
||
|
@@ -684,39 +687,55 @@ 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)
|
||
|
{
|
||
|
unsigned long pfn = l1e_get_pfn(l1e);
|
||
|
@@ -818,7 +837,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);
|
||
|
@@ -834,13 +853,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);
|
||
|
|
||
|
@@ -873,6 +899,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));
|
||
|
@@ -890,11 +917,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)
|
||
|
@@ -929,12 +965,8 @@ static void pae_flush_pgd(
|
||
|
|
||
|
flush_tlb_mask(d->domain_dirty_cpumask);
|
||
|
}
|
||
|
-
|
||
|
-#elif CONFIG_X86_64
|
||
|
-# define create_pae_xen_mappings(pl3e) (1)
|
||
|
-# define pae_flush_pgd(mfn, idx, nl3e) ((void)0)
|
||
|
#else
|
||
|
-# define create_pae_xen_mappings(pl3e) (1)
|
||
|
+# define pae_flush_pgd(mfn, idx, nl3e) ((void)0)
|
||
|
#endif
|
||
|
|
||
|
static int alloc_l2_table(struct page_info *page, unsigned long type)
|
||
|
@@ -948,11 +980,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
|
||
|
@@ -975,7 +1007,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);
|
||
|
@@ -1007,13 +1039,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,
|
||
|
@@ -1026,10 +1069,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]);
|
||
|
+ adjust_guest_l3e(pl3e[i], d);
|
||
|
}
|
||
|
|
||
|
- if ( !create_pae_xen_mappings(pl3e) )
|
||
|
+ if ( !create_pae_xen_mappings(d, pl3e) )
|
||
|
goto fail;
|
||
|
|
||
|
unmap_domain_page(pl3e);
|
||
|
@@ -1062,7 +1105,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. */
|
||
|
@@ -1110,6 +1153,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;
|
||
|
@@ -1117,7 +1163,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);
|
||
|
@@ -1130,6 +1176,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;
|
||
|
@@ -1138,7 +1185,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);
|
||
|
}
|
||
|
@@ -1234,7 +1284,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) )
|
||
|
@@ -1297,8 +1347,9 @@ static int mod_l2_entry(l2_pgentry_t *pl
|
||
|
unsigned long type)
|
||
|
{
|
||
|
l2_pgentry_t ol2e;
|
||
|
+ struct domain *d = current->domain;
|
||
|
|
||
|
- if ( unlikely(!is_guest_l2_slot(type,pgentry_ptr_to_slot(pl2e))) )
|
||
|
+ 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;
|
||
|
@@ -1316,7 +1367,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))
|
||
|
@@ -1348,6 +1399,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))) )
|
||
|
@@ -1356,12 +1408,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
|
||
|
|
||
|
@@ -1370,14 +1423,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))
|
||
|
@@ -1397,7 +1450,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);
|
||
|
@@ -1435,7 +1488,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))
|
||
|
@@ -2259,8 +2312,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
|
||
|
@@ -2273,11 +2325,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
|
||
|
}
|
||
|
|
||
|
@@ -2385,7 +2438,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);
|
||
|
@@ -2506,7 +2559,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 )
|
||
|
@@ -3181,7 +3234,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));
|
||
|
Index: 2007-01-31/xen/arch/x86/x86_64/mm.c
|
||
|
===================================================================
|
||
|
--- 2007-01-31.orig/xen/arch/x86/x86_64/mm.c 2007-01-31 09:29:03.000000000 +0100
|
||
|
+++ 2007-01-31/xen/arch/x86/x86_64/mm.c 2007-01-31 09:29:11.000000000 +0100
|
||
|
@@ -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;
|
||
|
|
||
|
Index: 2007-01-31/xen/common/compat/kernel.c
|
||
|
===================================================================
|
||
|
--- 2007-01-31.orig/xen/common/compat/kernel.c 2007-01-31 09:29:09.000000000 +0100
|
||
|
+++ 2007-01-31/xen/common/compat/kernel.c 2007-01-31 09:29:11.000000000 +0100
|
||
|
@@ -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
|
||
|
Index: 2007-01-31/xen/include/asm-x86/config.h
|
||
|
===================================================================
|
||
|
--- 2007-01-31.orig/xen/include/asm-x86/config.h 2007-01-31 09:29:03.000000000 +0100
|
||
|
+++ 2007-01-31/xen/include/asm-x86/config.h 2007-01-31 09:29:11.000000000 +0100
|
||
|
@@ -133,7 +133,11 @@ extern unsigned long _end; /* standard E
|
||
|
* 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.
|
||
|
@@ -182,17 +186,33 @@ extern unsigned long _end; /* standard E
|
||
|
/* 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
|
||
|
|
||
|
Index: 2007-01-31/xen/include/asm-x86/domain.h
|
||
|
===================================================================
|
||
|
--- 2007-01-31.orig/xen/include/asm-x86/domain.h 2007-01-31 09:19:50.000000000 +0100
|
||
|
+++ 2007-01-31/xen/include/asm-x86/domain.h 2007-01-31 09:29:11.000000000 +0100
|
||
|
@@ -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;
|
||
|
|
||
|
Index: 2007-01-31/xen/include/asm-x86/mm.h
|
||
|
===================================================================
|
||
|
--- 2007-01-31.orig/xen/include/asm-x86/mm.h 2007-01-31 09:29:03.000000000 +0100
|
||
|
+++ 2007-01-31/xen/include/asm-x86/mm.h 2007-01-31 09:29:11.000000000 +0100
|
||
|
@@ -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)])
|
||
|
|
||
|
|
||
|
Index: 2007-01-31/xen/include/asm-x86/page.h
|
||
|
===================================================================
|
||
|
--- 2007-01-31.orig/xen/include/asm-x86/page.h 2007-01-31 09:19:50.000000000 +0100
|
||
|
+++ 2007-01-31/xen/include/asm-x86/page.h 2007-01-31 09:29:11.000000000 +0100
|
||
|
@@ -206,6 +206,7 @@ typedef struct { u32 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) })
|
||
|
@@ -284,6 +285,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);
|
||
|
Index: 2007-01-31/xen/include/asm-x86/x86_32/page-2level.h
|
||
|
===================================================================
|
||
|
--- 2007-01-31.orig/xen/include/asm-x86/x86_32/page-2level.h 2006-12-15 16:33:59.000000000 +0100
|
||
|
+++ 2007-01-31/xen/include/asm-x86/x86_32/page-2level.h 2007-01-31 09:29:11.000000000 +0100
|
||
|
@@ -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:
|
||
|
Index: 2007-01-31/xen/include/asm-x86/x86_32/page-3level.h
|
||
|
===================================================================
|
||
|
--- 2007-01-31.orig/xen/include/asm-x86/x86_32/page-3level.h 2006-12-15 16:33:59.000000000 +0100
|
||
|
+++ 2007-01-31/xen/include/asm-x86/x86_32/page-3level.h 2007-01-31 09:29:11.000000000 +0100
|
||
|
@@ -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)
|
||
|
Index: 2007-01-31/xen/include/asm-x86/x86_64/page.h
|
||
|
===================================================================
|
||
|
--- 2007-01-31.orig/xen/include/asm-x86/x86_64/page.h 2006-12-15 16:33:59.000000000 +0100
|
||
|
+++ 2007-01-31/xen/include/asm-x86/x86_64/page.h 2007-01-31 09:29:11.000000000 +0100
|
||
|
@@ -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)
|
||
|
|
||
|
Index: 2007-01-31/xen/include/asm-x86/x86_64/uaccess.h
|
||
|
===================================================================
|
||
|
--- 2007-01-31.orig/xen/include/asm-x86/x86_64/uaccess.h 2007-01-31 09:29:09.000000000 +0100
|
||
|
+++ 2007-01-31/xen/include/asm-x86/x86_64/uaccess.h 2007-01-31 09:29:11.000000000 +0100
|
||
|
@@ -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))
|
||
|
|