# HG changeset patch
# User Emmanuel Ackaouy <ack@xxxxxxxxxxxxx>
# Date 1171915087 0
# Node ID 9c2e6f8f3aa7a4e2a1f3af3204789568edf975cd
# Parent 0b882c911b885a51308eee3ec80bc4a5a230d7ce
[XEN] 32on64 shadowing / live migration support for PV PAE compat guests
PAE compat guests on 64bit hypervisors are shadowed
using 4-on-4 with special handling for the top level
L4 page and the L2E M2P mappings.
Signed-off-by: Emmanuel Ackaouy <ack@xxxxxxxxxxxxx>
---
xen/arch/x86/mm.c | 24 +++--
xen/arch/x86/mm/shadow/common.c | 52 ++++++++---
xen/arch/x86/mm/shadow/multi.c | 172 ++++++++++++++++++++++----------------
xen/arch/x86/mm/shadow/private.h | 17 +--
xen/arch/x86/mm/shadow/types.h | 1
xen/include/asm-x86/x86_64/page.h | 10 +-
6 files changed, 172 insertions(+), 104 deletions(-)
diff -r 0b882c911b88 -r 9c2e6f8f3aa7 xen/arch/x86/mm.c
--- a/xen/arch/x86/mm.c Mon Feb 19 16:16:53 2007 +0000
+++ b/xen/arch/x86/mm.c Mon Feb 19 19:58:07 2007 +0000
@@ -1147,7 +1147,7 @@ static int alloc_l4_table(struct page_in
for ( i = 0; i < L4_PAGETABLE_ENTRIES; i++ )
{
- if ( is_guest_l4_slot(i) &&
+ if ( is_guest_l4_slot(d, i) &&
unlikely(!get_page_from_l4e(pl4e[i], pfn, d)) )
goto fail;
@@ -1173,7 +1173,7 @@ static int alloc_l4_table(struct page_in
fail:
MEM_LOG("Failure in alloc_l4_table: entry %d", i);
while ( i-- > 0 )
- if ( is_guest_l4_slot(i) )
+ if ( is_guest_l4_slot(d, i) )
put_page_from_l4e(pl4e[i], pfn);
return 0;
@@ -1248,12 +1248,13 @@ static void free_l3_table(struct page_in
static void free_l4_table(struct page_info *page)
{
+ struct domain *d = page_get_owner(page);
unsigned long pfn = page_to_mfn(page);
l4_pgentry_t *pl4e = page_to_virt(page);
int i;
for ( i = 0; i < L4_PAGETABLE_ENTRIES; i++ )
- if ( is_guest_l4_slot(i) )
+ if ( is_guest_l4_slot(d, i) )
put_page_from_l4e(pl4e[i], pfn);
}
@@ -1480,13 +1481,14 @@ static int mod_l3_entry(l3_pgentry_t *pl
#if CONFIG_PAGING_LEVELS >= 4
/* Update the L4 entry at pl4e to new value nl4e. pl4e is within frame pfn. */
-static int mod_l4_entry(l4_pgentry_t *pl4e,
+static int mod_l4_entry(struct domain *d,
+ l4_pgentry_t *pl4e,
l4_pgentry_t nl4e,
unsigned long pfn)
{
l4_pgentry_t ol4e;
- if ( unlikely(!is_guest_l4_slot(pgentry_ptr_to_slot(pl4e))) )
+ if ( unlikely(!is_guest_l4_slot(d, pgentry_ptr_to_slot(pl4e))) )
{
MEM_LOG("Illegal L4 update attempt in Xen-private area %p", pl4e);
return 0;
@@ -1777,9 +1779,13 @@ int new_guest_cr3(unsigned long mfn)
{
okay = paging_mode_refcounts(d)
? 0 /* Old code was broken, but what should it be? */
- : mod_l4_entry(__va(pagetable_get_paddr(v->arch.guest_table)),
- l4e_from_pfn(mfn, (_PAGE_PRESENT|_PAGE_RW|
- _PAGE_USER|_PAGE_ACCESSED)), 0);
+ : mod_l4_entry(
+ d,
+ __va(pagetable_get_paddr(v->arch.guest_table)),
+ l4e_from_pfn(
+ mfn,
+ (_PAGE_PRESENT|_PAGE_RW|_PAGE_USER|_PAGE_ACCESSED)),
+ pagetable_get_pfn(v->arch.guest_table));
if ( unlikely(!okay) )
{
MEM_LOG("Error while installing new compat baseptr %lx", mfn);
@@ -2339,7 +2345,7 @@ int do_mmu_update(
if ( !IS_COMPAT(FOREIGNDOM) )
{
l4_pgentry_t l4e = l4e_from_intpte(req.val);
- okay = mod_l4_entry(va, l4e, mfn);
+ okay = mod_l4_entry(d, va, l4e, mfn);
}
break;
#endif
diff -r 0b882c911b88 -r 9c2e6f8f3aa7 xen/arch/x86/mm/shadow/common.c
--- a/xen/arch/x86/mm/shadow/common.c Mon Feb 19 16:16:53 2007 +0000
+++ b/xen/arch/x86/mm/shadow/common.c Mon Feb 19 19:58:07 2007 +0000
@@ -485,7 +485,11 @@ void shadow_demote(struct vcpu *v, mfn_t
{
struct page_info *page = mfn_to_page(gmfn);
- ASSERT(test_bit(_PGC_page_table, &page->count_info));
+#ifdef CONFIG_COMPAT
+ if ( !IS_COMPAT(v->domain) || type != SH_type_l4_64_shadow )
+#endif
+ ASSERT(test_bit(_PGC_page_table, &page->count_info));
+
ASSERT(test_bit(type, &page->shadow_flags));
clear_bit(type, &page->shadow_flags);
@@ -567,6 +571,9 @@ sh_validate_guest_entry(struct vcpu *v,
if ( page->shadow_flags & SHF_L2_64 )
result |= SHADOW_INTERNAL_NAME(sh_map_and_validate_gl2e, 4, 4)
(v, gmfn, entry, size);
+ if ( page->shadow_flags & SHF_L2H_64 )
+ result |= SHADOW_INTERNAL_NAME(sh_map_and_validate_gl2he, 4, 4)
+ (v, gmfn, entry, size);
if ( page->shadow_flags & SHF_L3_64 )
result |= SHADOW_INTERNAL_NAME(sh_map_and_validate_gl3e, 4, 4)
(v, gmfn, entry, size);
@@ -575,7 +582,7 @@ sh_validate_guest_entry(struct vcpu *v,
(v, gmfn, entry, size);
#else /* 32-bit/PAE hypervisor does not support 64-bit guests */
ASSERT((page->shadow_flags
- & (SHF_L4_64|SHF_L3_64|SHF_L2_64|SHF_L1_64)) == 0);
+ & (SHF_L4_64|SHF_L3_64|SHF_L2H_64|SHF_L2_64|SHF_L1_64)) == 0);
#endif
return result;
@@ -705,7 +712,7 @@ shadow_order(unsigned int shadow_type)
shadow_order(unsigned int shadow_type)
{
#if CONFIG_PAGING_LEVELS > 2
- static const u32 type_to_order[16] = {
+ static const u32 type_to_order[SH_type_unused] = {
0, /* SH_type_none */
1, /* SH_type_l1_32_shadow */
1, /* SH_type_fl1_32_shadow */
@@ -717,12 +724,13 @@ shadow_order(unsigned int shadow_type)
0, /* SH_type_l1_64_shadow */
0, /* SH_type_fl1_64_shadow */
0, /* SH_type_l2_64_shadow */
+ 0, /* SH_type_l2h_64_shadow */
0, /* SH_type_l3_64_shadow */
0, /* SH_type_l4_64_shadow */
2, /* SH_type_p2m_table */
0 /* SH_type_monitor_table */
};
- ASSERT(shadow_type < 16);
+ ASSERT(shadow_type < SH_type_unused);
return type_to_order[shadow_type];
#else /* 32-bit Xen only ever shadows 32-bit guests on 32-bit shadows. */
return 0;
@@ -1564,6 +1572,9 @@ void sh_destroy_shadow(struct vcpu *v, m
t == SH_type_fl1_pae_shadow ||
t == SH_type_fl1_64_shadow ||
t == SH_type_monitor_table ||
+#ifdef CONFIG_COMPAT
+ (IS_COMPAT(v->domain) && t == SH_type_l4_64_shadow) ||
+#endif
(page_get_owner(mfn_to_page(_mfn(sp->backpointer)))
== v->domain));
@@ -1605,6 +1616,8 @@ void sh_destroy_shadow(struct vcpu *v, m
case SH_type_fl1_64_shadow:
SHADOW_INTERNAL_NAME(sh_destroy_l1_shadow, 4, 4)(v, smfn);
break;
+ case SH_type_l2h_64_shadow:
+ ASSERT( IS_COMPAT(v->domain) );
case SH_type_l2_64_shadow:
SHADOW_INTERNAL_NAME(sh_destroy_l2_shadow, 4, 4)(v, smfn);
break;
@@ -1633,7 +1646,7 @@ int sh_remove_write_access(struct vcpu *
unsigned long fault_addr)
{
/* Dispatch table for getting per-type functions */
- static hash_callback_t callbacks[16] = {
+ static hash_callback_t callbacks[SH_type_unused] = {
NULL, /* none */
#if CONFIG_PAGING_LEVELS == 2
SHADOW_INTERNAL_NAME(sh_rm_write_access_from_l1,2,2), /* l1_32 */
@@ -1660,6 +1673,7 @@ int sh_remove_write_access(struct vcpu *
NULL, /* fl1_64 */
#endif
NULL, /* l2_64 */
+ NULL, /* l2h_64 */
NULL, /* l3_64 */
NULL, /* l4_64 */
NULL, /* p2m */
@@ -1822,7 +1836,7 @@ int sh_remove_all_mappings(struct vcpu *
int expected_count, do_locking;
/* Dispatch table for getting per-type functions */
- static hash_callback_t callbacks[16] = {
+ static hash_callback_t callbacks[SH_type_unused] = {
NULL, /* none */
#if CONFIG_PAGING_LEVELS == 2
SHADOW_INTERNAL_NAME(sh_rm_mappings_from_l1,2,2), /* l1_32 */
@@ -1849,6 +1863,7 @@ int sh_remove_all_mappings(struct vcpu *
NULL, /* fl1_64 */
#endif
NULL, /* l2_64 */
+ NULL, /* l2h_64 */
NULL, /* l3_64 */
NULL, /* l4_64 */
NULL, /* p2m */
@@ -1956,6 +1971,7 @@ static int sh_remove_shadow_via_pointer(
#if CONFIG_PAGING_LEVELS >= 4
case SH_type_l1_64_shadow:
case SH_type_l2_64_shadow:
+ case SH_type_l2h_64_shadow:
case SH_type_l3_64_shadow:
case SH_type_l4_64_shadow:
SHADOW_INTERNAL_NAME(sh_clear_shadow_entry,4,4)(v, vaddr, pmfn);
@@ -1991,7 +2007,7 @@ void sh_remove_shadows(struct vcpu *v, m
/* Dispatch table for getting per-type functions: each level must
* be called with the function to remove a lower-level shadow. */
- static hash_callback_t callbacks[16] = {
+ static hash_callback_t callbacks[SH_type_unused] = {
NULL, /* none */
NULL, /* l1_32 */
NULL, /* fl1_32 */
@@ -2013,10 +2029,12 @@ void sh_remove_shadows(struct vcpu *v, m
NULL, /* fl1_64 */
#if CONFIG_PAGING_LEVELS >= 4
SHADOW_INTERNAL_NAME(sh_remove_l1_shadow,4,4), /* l2_64 */
+ SHADOW_INTERNAL_NAME(sh_remove_l1_shadow,4,4), /* l2h_64 */
SHADOW_INTERNAL_NAME(sh_remove_l2_shadow,4,4), /* l3_64 */
SHADOW_INTERNAL_NAME(sh_remove_l3_shadow,4,4), /* l4_64 */
#else
NULL, /* l2_64 */
+ NULL, /* l2h_64 */
NULL, /* l3_64 */
NULL, /* l4_64 */
#endif
@@ -2025,7 +2043,7 @@ void sh_remove_shadows(struct vcpu *v, m
};
/* Another lookup table, for choosing which mask to use */
- static unsigned int masks[16] = {
+ static unsigned int masks[SH_type_unused] = {
0, /* none */
1 << SH_type_l2_32_shadow, /* l1_32 */
0, /* fl1_32 */
@@ -2035,9 +2053,11 @@ void sh_remove_shadows(struct vcpu *v, m
0, /* fl1_pae */
0, /* l2_pae */
0, /* l2h_pae */
- 1 << SH_type_l2_64_shadow, /* l1_64 */
+ ((1 << SH_type_l2h_64_shadow)
+ | (1 << SH_type_l2_64_shadow)), /* l1_64 */
0, /* fl1_64 */
1 << SH_type_l3_64_shadow, /* l2_64 */
+ 1 << SH_type_l3_64_shadow, /* l2h_64 */
1 << SH_type_l4_64_shadow, /* l3_64 */
0, /* l4_64 */
0, /* p2m */
@@ -2088,6 +2108,7 @@ void sh_remove_shadows(struct vcpu *v, m
#if CONFIG_PAGING_LEVELS >= 4
if ( sh_flags & SHF_L1_64 ) DO_UNSHADOW(SH_type_l1_64_shadow);
if ( sh_flags & SHF_L2_64 ) DO_UNSHADOW(SH_type_l2_64_shadow);
+ if ( sh_flags & SHF_L2H_64 ) DO_UNSHADOW(SH_type_l2h_64_shadow);
if ( sh_flags & SHF_L3_64 ) DO_UNSHADOW(SH_type_l3_64_shadow);
if ( sh_flags & SHF_L4_64 ) DO_UNSHADOW(SH_type_l4_64_shadow);
#endif
@@ -2157,10 +2178,7 @@ static void sh_update_paging_modes(struc
/// PV guest
///
#if CONFIG_PAGING_LEVELS == 4
- if ( pv_32bit_guest(v) )
- v->arch.paging.mode = &SHADOW_INTERNAL_NAME(sh_paging_mode,3,3);
- else
- v->arch.paging.mode = &SHADOW_INTERNAL_NAME(sh_paging_mode,4,4);
+ v->arch.paging.mode = &SHADOW_INTERNAL_NAME(sh_paging_mode,4,4);
#elif CONFIG_PAGING_LEVELS == 3
v->arch.paging.mode = &SHADOW_INTERNAL_NAME(sh_paging_mode,3,3);
#elif CONFIG_PAGING_LEVELS == 2
@@ -2691,6 +2709,11 @@ static int shadow_log_dirty_enable(struc
goto out;
}
+#if (SHADOW_OPTIMIZATIONS & SHOPT_LINUX_L3_TOPLEVEL)
+ if ( IS_COMPAT(d) )
+ d->arch.paging.shadow.opt_flags = SHOPT_LINUX_L3_TOPLEVEL;
+#endif
+
ret = sh_alloc_log_dirty_bitmap(d);
if ( ret != 0 )
{
@@ -3016,7 +3039,7 @@ void shadow_audit_tables(struct vcpu *v)
void shadow_audit_tables(struct vcpu *v)
{
/* Dispatch table for getting per-type functions */
- static hash_callback_t callbacks[16] = {
+ static hash_callback_t callbacks[SH_type_unused] = {
NULL, /* none */
#if CONFIG_PAGING_LEVELS == 2
SHADOW_INTERNAL_NAME(sh_audit_l1_table,2,2), /* l1_32 */
@@ -3034,6 +3057,7 @@ void shadow_audit_tables(struct vcpu *v)
SHADOW_INTERNAL_NAME(sh_audit_l1_table,4,4), /* l1_64 */
SHADOW_INTERNAL_NAME(sh_audit_fl1_table,4,4), /* fl1_64 */
SHADOW_INTERNAL_NAME(sh_audit_l2_table,4,4), /* l2_64 */
+ SHADOW_INTERNAL_NAME(sh_audit_l2_table,4,4), /* l2h_64 */
SHADOW_INTERNAL_NAME(sh_audit_l3_table,4,4), /* l3_64 */
SHADOW_INTERNAL_NAME(sh_audit_l4_table,4,4), /* l4_64 */
#endif /* CONFIG_PAGING_LEVELS >= 4 */
diff -r 0b882c911b88 -r 9c2e6f8f3aa7 xen/arch/x86/mm/shadow/multi.c
--- a/xen/arch/x86/mm/shadow/multi.c Mon Feb 19 16:16:53 2007 +0000
+++ b/xen/arch/x86/mm/shadow/multi.c Mon Feb 19 19:58:07 2007 +0000
@@ -162,8 +162,13 @@ set_shadow_status(struct vcpu *v, mfn_t
else
mfn_to_shadow_page(smfn)->logdirty = 0;
- res = get_page(mfn_to_page(gmfn), d);
- ASSERT(res == 1);
+#ifdef CONFIG_COMPAT
+ if ( !IS_COMPAT(d) || shadow_type != SH_type_l4_64_shadow )
+#endif
+ {
+ res = get_page(mfn_to_page(gmfn), d);
+ ASSERT(res == 1);
+ }
shadow_hash_insert(v, mfn_x(gmfn), shadow_type, smfn);
}
@@ -185,7 +190,10 @@ delete_shadow_status(struct vcpu *v, mfn
v->domain->domain_id, v->vcpu_id,
mfn_x(gmfn), shadow_type, mfn_x(smfn));
shadow_hash_delete(v, mfn_x(gmfn), shadow_type, smfn);
- put_page(mfn_to_page(gmfn));
+#ifdef CONFIG_COMPAT
+ if ( !IS_COMPAT(v->domain) || shadow_type != SH_type_l4_64_shadow )
+#endif
+ put_page(mfn_to_page(gmfn));
}
/**************************************************************************/
@@ -764,7 +772,7 @@ _sh_propagate(struct vcpu *v,
// PV guests in 64-bit mode use two different page tables for user vs
// supervisor permissions, making the guest's _PAGE_USER bit irrelevant.
// It is always shadowed as present...
- if ( (GUEST_PAGING_LEVELS == 4) && !is_hvm_domain(d) )
+ if ( (GUEST_PAGING_LEVELS == 4) && !IS_COMPAT(d) && !is_hvm_domain(d) )
{
sflags |= _PAGE_USER;
}
@@ -1233,9 +1241,10 @@ do {
#if GUEST_PAGING_LEVELS == 2 && SHADOW_PAGING_LEVELS > 2
/* 32-bit l2 on PAE/64: four pages, touch every second entry, and avoid Xen */
-#define SHADOW_FOREACH_L2E(_sl2mfn, _sl2e, _gl2p, _done, _xen, _code) \
+#define SHADOW_FOREACH_L2E(_sl2mfn, _sl2e, _gl2p, _done, _dom, _code) \
do { \
int _i, _j, __done = 0; \
+ int _xen = !shadow_mode_external(_dom); \
ASSERT(mfn_to_shadow_page(_sl2mfn)->type == SH_type_l2_32_shadow); \
for ( _j = 0; _j < 4 && !__done; _j++ ) \
{ \
@@ -1259,9 +1268,10 @@ do {
#elif GUEST_PAGING_LEVELS == 2
/* 32-bit on 32-bit: avoid Xen entries */
-#define SHADOW_FOREACH_L2E(_sl2mfn, _sl2e, _gl2p, _done, _xen, _code) \
+#define SHADOW_FOREACH_L2E(_sl2mfn, _sl2e, _gl2p, _done, _dom, _code) \
do { \
int _i; \
+ int _xen = !shadow_mode_external(_dom); \
shadow_l2e_t *_sp = map_shadow_page((_sl2mfn)); \
ASSERT(mfn_to_shadow_page(_sl2mfn)->type == SH_type_l2_32_shadow); \
for ( _i = 0; _i < SHADOW_L2_PAGETABLE_ENTRIES; _i++ ) \
@@ -1281,9 +1291,10 @@ do {
#elif GUEST_PAGING_LEVELS == 3
/* PAE: if it's an l2h, don't touch Xen mappings */
-#define SHADOW_FOREACH_L2E(_sl2mfn, _sl2e, _gl2p, _done, _xen, _code) \
+#define SHADOW_FOREACH_L2E(_sl2mfn, _sl2e, _gl2p, _done, _dom, _code) \
do { \
int _i; \
+ int _xen = !shadow_mode_external(_dom); \
shadow_l2e_t *_sp = map_shadow_page((_sl2mfn)); \
ASSERT(mfn_to_shadow_page(_sl2mfn)->type == SH_type_l2_pae_shadow \
|| mfn_to_shadow_page(_sl2mfn)->type == SH_type_l2h_pae_shadow);\
@@ -1304,21 +1315,29 @@ do {
#else
-/* 64-bit l2: touch all entries */
-#define SHADOW_FOREACH_L2E(_sl2mfn, _sl2e, _gl2p, _done, _xen, _code) \
-do { \
- int _i; \
- shadow_l2e_t *_sp = map_shadow_page((_sl2mfn)); \
- ASSERT(mfn_to_shadow_page(_sl2mfn)->type == SH_type_l2_64_shadow); \
- for ( _i = 0; _i < SHADOW_L2_PAGETABLE_ENTRIES; _i++ ) \
- { \
- (_sl2e) = _sp + _i; \
- if ( shadow_l2e_get_flags(*(_sl2e)) & _PAGE_PRESENT ) \
- {_code} \
- if ( _done ) break; \
- increment_ptr_to_guest_entry(_gl2p); \
- } \
- unmap_shadow_page(_sp); \
+/* 64-bit l2: touch all entries except for PAE compat guests. */
+#define SHADOW_FOREACH_L2E(_sl2mfn, _sl2e, _gl2p, _done, _dom, _code) \
+do { \
+ int _i; \
+ int _xen = !shadow_mode_external(_dom); \
+ shadow_l2e_t *_sp = map_shadow_page((_sl2mfn)); \
+ ASSERT(mfn_to_shadow_page(_sl2mfn)->type == SH_type_l2_64_shadow || \
+ mfn_to_shadow_page(_sl2mfn)->type == SH_type_l2h_64_shadow); \
+ for ( _i = 0; _i < SHADOW_L2_PAGETABLE_ENTRIES; _i++ ) \
+ { \
+ if ( (!(_xen)) \
+ || !IS_COMPAT(_dom) \
+ || mfn_to_shadow_page(_sl2mfn)->type != SH_type_l2h_64_shadow \
+ || (_i < COMPAT_L2_PAGETABLE_FIRST_XEN_SLOT(_dom)) ) \
+ { \
+ (_sl2e) = _sp + _i; \
+ if ( shadow_l2e_get_flags(*(_sl2e)) & _PAGE_PRESENT ) \
+ {_code} \
+ if ( _done ) break; \
+ increment_ptr_to_guest_entry(_gl2p); \
+ } \
+ } \
+ unmap_shadow_page(_sp); \
} while (0)
#endif /* different kinds of l2 */
@@ -1343,14 +1362,15 @@ do {
} while (0)
/* 64-bit l4: avoid Xen mappings */
-#define SHADOW_FOREACH_L4E(_sl4mfn, _sl4e, _gl4p, _done, _xen, _code) \
+#define SHADOW_FOREACH_L4E(_sl4mfn, _sl4e, _gl4p, _done, _dom, _code) \
do { \
+ shadow_l4e_t *_sp = map_shadow_page((_sl4mfn)); \
+ int _xen = !shadow_mode_external(_dom); \
int _i; \
- shadow_l4e_t *_sp = map_shadow_page((_sl4mfn)); \
ASSERT(mfn_to_shadow_page(_sl4mfn)->type == SH_type_l4_64_shadow); \
for ( _i = 0; _i < SHADOW_L4_PAGETABLE_ENTRIES; _i++ ) \
{ \
- if ( (!(_xen)) || is_guest_l4_slot(_i) ) \
+ if ( (!(_xen)) || is_guest_l4_slot(_dom, _i) ) \
{ \
(_sl4e) = _sp + _i; \
if ( shadow_l4e_get_flags(*(_sl4e)) & _PAGE_PRESENT ) \
@@ -1417,17 +1437,25 @@ void sh_install_xen_entries_in_l4(struct
__PAGE_HYPERVISOR);
}
+ if ( IS_COMPAT(v->domain) )
+ {
+ /* install compat arg xlat entry */
+ sl4e[shadow_l4_table_offset(COMPAT_ARG_XLAT_VIRT_BASE)] =
+ shadow_l4e_from_mfn(
+ page_to_mfn(virt_to_page(d->arch.mm_arg_xlat_l3)),
+ __PAGE_HYPERVISOR);
+ }
+
sh_unmap_domain_page(sl4e);
}
#endif
-#if (CONFIG_PAGING_LEVELS == 3 || defined(CONFIG_COMPAT)) &&
GUEST_PAGING_LEVELS == 3
+#if CONFIG_PAGING_LEVELS >= 3 && GUEST_PAGING_LEVELS >= 3
// For 3-on-3 PV guests, we need to make sure the xen mappings are in
// place, which means that we need to populate the l2h entry in the l3
// table.
-void sh_install_xen_entries_in_l2h(struct vcpu *v,
- mfn_t sl2hmfn)
+static void sh_install_xen_entries_in_l2h(struct vcpu *v, mfn_t sl2hmfn)
{
struct domain *d = v->domain;
shadow_l2e_t *sl2e;
@@ -1489,9 +1517,10 @@ void sh_install_xen_entries_in_l2h(struc
#else
/* Copy the common Xen mappings from the idle domain */
- memcpy(&sl2e[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(*sl2e));
+ memcpy(
+ &sl2e[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(*sl2e));
#endif
@@ -1617,8 +1646,11 @@ sh_make_shadow(struct vcpu *v, mfn_t gmf
case SH_type_l4_shadow:
sh_install_xen_entries_in_l4(v, gmfn, smfn); break;
#endif
-#if CONFIG_PAGING_LEVELS == 3 && GUEST_PAGING_LEVELS == 3
+#if CONFIG_PAGING_LEVELS >= 3 && GUEST_PAGING_LEVELS >= 3
case SH_type_l2h_shadow:
+#ifdef CONFIG_COMPAT
+ ASSERT( IS_COMPAT(v->domain) );
+#endif
sh_install_xen_entries_in_l2h(v, smfn); break;
#endif
#if CONFIG_PAGING_LEVELS == 2 && GUEST_PAGING_LEVELS == 2
@@ -1832,12 +1864,21 @@ static shadow_l2e_t * shadow_get_and_cre
{
int r;
shadow_l3e_t new_sl3e;
+ unsigned int t = SH_type_l2_shadow;
+
+#ifdef CONFIG_COMPAT
+ /* Tag compat L2 containing hypervisor (m2p) mappings */
+ if ( IS_COMPAT(v->domain) &&
+ guest_l4_table_offset(gw->va) == 0 &&
+ guest_l3_table_offset(gw->va) == 3 )
+ t = SH_type_l2h_shadow;
+#endif
/* No l2 shadow installed: find and install it. */
- *sl2mfn = get_shadow_status(v, gw->l2mfn, SH_type_l2_shadow);
+ *sl2mfn = get_shadow_status(v, gw->l2mfn, t);
if ( !mfn_valid(*sl2mfn) )
{
/* No l2 shadow of this page exists at all: make one. */
- *sl2mfn = sh_make_shadow(v, gw->l2mfn, SH_type_l2_shadow);
+ *sl2mfn = sh_make_shadow(v, gw->l2mfn, t);
}
/* Install the new sl2 table in the sl3e */
l3e_propagate_from_guest(v, gw->l3e, gw->l3mfn,
@@ -1958,7 +1999,6 @@ void sh_destroy_l4_shadow(struct vcpu *v
shadow_l4e_t *sl4e;
u32 t = mfn_to_shadow_page(smfn)->type;
mfn_t gmfn, sl4mfn;
- int xen_mappings;
SHADOW_DEBUG(DESTROY_SHADOW,
"%s(%05lx)\n", __func__, mfn_x(smfn));
@@ -1969,9 +2009,8 @@ void sh_destroy_l4_shadow(struct vcpu *v
delete_shadow_status(v, gmfn, t, smfn);
shadow_demote(v, gmfn, t);
/* Decrement refcounts of all the old entries */
- xen_mappings = (!shadow_mode_external(v->domain));
sl4mfn = smfn;
- SHADOW_FOREACH_L4E(sl4mfn, sl4e, 0, 0, xen_mappings, {
+ SHADOW_FOREACH_L4E(sl4mfn, sl4e, 0, 0, v->domain, {
if ( shadow_l4e_get_flags(*sl4e) & _PAGE_PRESENT )
{
sh_put_ref(v, shadow_l4e_get_mfn(*sl4e),
@@ -2019,12 +2058,15 @@ void sh_destroy_l2_shadow(struct vcpu *v
shadow_l2e_t *sl2e;
u32 t = mfn_to_shadow_page(smfn)->type;
mfn_t gmfn, sl2mfn;
- int xen_mappings;
SHADOW_DEBUG(DESTROY_SHADOW,
"%s(%05lx)\n", __func__, mfn_x(smfn));
- ASSERT(t == SH_type_l2_shadow
- || t == SH_type_l2h_pae_shadow);
+
+#if GUEST_PAGING_LEVELS >= 3
+ ASSERT(t == SH_type_l2_shadow || t == SH_type_l2h_shadow);
+#else
+ ASSERT(t == SH_type_l2_shadow);
+#endif
/* Record that the guest page isn't shadowed any more (in this type) */
gmfn = _mfn(mfn_to_shadow_page(smfn)->backpointer);
@@ -2033,11 +2075,7 @@ void sh_destroy_l2_shadow(struct vcpu *v
/* Decrement refcounts of all the old entries */
sl2mfn = smfn;
- xen_mappings = (!shadow_mode_external(v->domain) &&
- ((GUEST_PAGING_LEVELS == 2) ||
- ((GUEST_PAGING_LEVELS == 3) &&
- (t == SH_type_l2h_pae_shadow))));
- SHADOW_FOREACH_L2E(sl2mfn, sl2e, 0, 0, xen_mappings, {
+ SHADOW_FOREACH_L2E(sl2mfn, sl2e, 0, 0, v->domain, {
if ( shadow_l2e_get_flags(*sl2e) & _PAGE_PRESENT )
sh_put_ref(v, shadow_l2e_get_mfn(*sl2e),
(((paddr_t)mfn_x(sl2mfn)) << PAGE_SHIFT)
@@ -2138,8 +2176,7 @@ void sh_unhook_32b_mappings(struct vcpu
void sh_unhook_32b_mappings(struct vcpu *v, mfn_t sl2mfn)
{
shadow_l2e_t *sl2e;
- int xen_mappings = !shadow_mode_external(v->domain);
- SHADOW_FOREACH_L2E(sl2mfn, sl2e, 0, 0, xen_mappings, {
+ SHADOW_FOREACH_L2E(sl2mfn, sl2e, 0, 0, v->domain, {
(void) shadow_set_l2e(v, sl2e, shadow_l2e_empty(), sl2mfn);
});
}
@@ -2150,8 +2187,7 @@ void sh_unhook_pae_mappings(struct vcpu
/* Walk a PAE l2 shadow, unhooking entries from all the subshadows */
{
shadow_l2e_t *sl2e;
- int xen_mappings = !shadow_mode_external(v->domain);
- SHADOW_FOREACH_L2E(sl2mfn, sl2e, 0, 0, xen_mappings, {
+ SHADOW_FOREACH_L2E(sl2mfn, sl2e, 0, 0, v->domain, {
(void) shadow_set_l2e(v, sl2e, shadow_l2e_empty(), sl2mfn);
});
}
@@ -2161,8 +2197,7 @@ void sh_unhook_64b_mappings(struct vcpu
void sh_unhook_64b_mappings(struct vcpu *v, mfn_t sl4mfn)
{
shadow_l4e_t *sl4e;
- int xen_mappings = !shadow_mode_external(v->domain);
- SHADOW_FOREACH_L4E(sl4mfn, sl4e, 0, 0, xen_mappings, {
+ SHADOW_FOREACH_L4E(sl4mfn, sl4e, 0, 0, v->domain, {
(void) shadow_set_l4e(v, sl4e, shadow_l4e_empty(), sl4mfn);
});
}
@@ -2208,7 +2243,7 @@ static int validate_gl4e(struct vcpu *v,
{
int shadow_index = (((unsigned long)sl4p & ~PAGE_MASK) /
sizeof(shadow_l4e_t));
- int reserved_xen_slot = !is_guest_l4_slot(shadow_index);
+ int reserved_xen_slot = !is_guest_l4_slot(v->domain, shadow_index);
if ( unlikely(reserved_xen_slot) )
{
@@ -2471,7 +2506,7 @@ sh_map_and_validate_gl2he(struct vcpu *v
sh_map_and_validate_gl2he(struct vcpu *v, mfn_t gl2mfn,
void *new_gl2p, u32 size)
{
-#if GUEST_PAGING_LEVELS == 3
+#if GUEST_PAGING_LEVELS >= 3
return sh_map_and_validate(v, gl2mfn, new_gl2p, size,
SH_type_l2h_shadow,
shadow_l2_index,
@@ -3346,7 +3381,12 @@ sh_set_toplevel_shadow(struct vcpu *v,
#if SHADOW_OPTIMIZATIONS & SHOPT_EARLY_UNSHADOW
/* Once again OK to unhook entries from this table if we see fork/exit */
- ASSERT(sh_mfn_is_a_page_table(gmfn));
+#if CONFIG_PAGING_LEVELS == 4
+ if ( IS_COMPAT(d) )
+ ASSERT(!sh_mfn_is_a_page_table(gmfn));
+ else
+#endif
+ ASSERT(sh_mfn_is_a_page_table(gmfn));
mfn_to_page(gmfn)->shadow_flags &= ~SHF_unhooked_mappings;
#endif
@@ -3754,7 +3794,7 @@ void sh_clear_shadow_entry(struct vcpu *
case SH_type_l1_shadow:
(void) shadow_set_l1e(v, ep, shadow_l1e_empty(), smfn); break;
case SH_type_l2_shadow:
-#if GUEST_PAGING_LEVELS == 3
+#if GUEST_PAGING_LEVELS >= 3
case SH_type_l2h_shadow:
#endif
(void) shadow_set_l2e(v, ep, shadow_l2e_empty(), smfn); break;
@@ -3774,11 +3814,8 @@ int sh_remove_l1_shadow(struct vcpu *v,
shadow_l2e_t *sl2e;
int done = 0;
int flags;
-#if GUEST_PAGING_LEVELS != 4
- int xen_mappings = !shadow_mode_external(v->domain);
-#endif
- SHADOW_FOREACH_L2E(sl2mfn, sl2e, 0, done, xen_mappings,
+ SHADOW_FOREACH_L2E(sl2mfn, sl2e, 0, done, v->domain,
{
flags = shadow_l2e_get_flags(*sl2e);
if ( (flags & _PAGE_PRESENT)
@@ -3821,9 +3858,9 @@ int sh_remove_l3_shadow(struct vcpu *v,
{
shadow_l4e_t *sl4e;
int done = 0;
- int flags, xen_mappings = !shadow_mode_external(v->domain);
+ int flags;
- SHADOW_FOREACH_L4E(sl4mfn, sl4e, 0, done, xen_mappings,
+ SHADOW_FOREACH_L4E(sl4mfn, sl4e, 0, done, v->domain,
{
flags = shadow_l4e_get_flags(*sl4e);
if ( (flags & _PAGE_PRESENT)
@@ -4196,14 +4233,11 @@ int sh_audit_l2_table(struct vcpu *v, mf
gfn_t gfn;
char *s;
int done = 0;
-#if GUEST_PAGING_LEVELS != 4
- int xen_mappings = !shadow_mode_external(v->domain);
-#endif
/* Follow the backpointer */
gl2mfn = _mfn(mfn_to_shadow_page(sl2mfn)->backpointer);
gl2e = gp = sh_map_domain_page(gl2mfn);
- SHADOW_FOREACH_L2E(sl2mfn, sl2e, &gl2e, done, xen_mappings, {
+ SHADOW_FOREACH_L2E(sl2mfn, sl2e, &gl2e, done, v->domain, {
s = sh_audit_flags(v, 2, guest_l2e_get_flags(*gl2e),
shadow_l2e_get_flags(*sl2e));
@@ -4255,10 +4289,11 @@ int sh_audit_l3_table(struct vcpu *v, mf
gfn = guest_l3e_get_gfn(*gl3e);
mfn = shadow_l3e_get_mfn(*sl3e);
gmfn = get_shadow_status(v, audit_gfn_to_mfn(v, gfn, gl3mfn),
- (GUEST_PAGING_LEVELS == 3
+ ((GUEST_PAGING_LEVELS == 3 ||
+ IS_COMPAT(v->domain))
&& !shadow_mode_external(v->domain)
&& (guest_index(gl3e) % 4) == 3)
- ? SH_type_l2h_pae_shadow
+ ? SH_type_l2h_shadow
: SH_type_l2_shadow);
if ( mfn_x(gmfn) != mfn_x(mfn) )
AUDIT_FAIL(3, "bad translation: gfn %" SH_PRI_gfn
@@ -4278,12 +4313,11 @@ int sh_audit_l4_table(struct vcpu *v, mf
gfn_t gfn;
char *s;
int done = 0;
- int xen_mappings = !shadow_mode_external(v->domain);
/* Follow the backpointer */
gl4mfn = _mfn(mfn_to_shadow_page(sl4mfn)->backpointer);
gl4e = gp = sh_map_domain_page(gl4mfn);
- SHADOW_FOREACH_L4E(sl4mfn, sl4e, &gl4e, done, xen_mappings,
+ SHADOW_FOREACH_L4E(sl4mfn, sl4e, &gl4e, done, v->domain,
{
s = sh_audit_flags(v, 4, guest_l4e_get_flags(*gl4e),
shadow_l4e_get_flags(*sl4e));
diff -r 0b882c911b88 -r 9c2e6f8f3aa7 xen/arch/x86/mm/shadow/private.h
--- a/xen/arch/x86/mm/shadow/private.h Mon Feb 19 16:16:53 2007 +0000
+++ b/xen/arch/x86/mm/shadow/private.h Mon Feb 19 19:58:07 2007 +0000
@@ -269,12 +269,13 @@ static inline void shadow_check_page_str
#define SH_type_l1_64_shadow (8U) /* shadowing a 64-bit L1 page */
#define SH_type_fl1_64_shadow (9U) /* L1 shadow for 64-bit 2M superpg */
#define SH_type_l2_64_shadow (10U) /* shadowing a 64-bit L2 page */
-#define SH_type_l3_64_shadow (11U) /* shadowing a 64-bit L3 page */
-#define SH_type_l4_64_shadow (12U) /* shadowing a 64-bit L4 page */
-#define SH_type_max_shadow (12U)
-#define SH_type_p2m_table (13U) /* in use as the p2m table */
-#define SH_type_monitor_table (14U) /* in use as a monitor table */
-#define SH_type_unused (15U)
+#define SH_type_l2h_64_shadow (11U) /* shadowing a compat PAE L2 high page */
+#define SH_type_l3_64_shadow (12U) /* shadowing a 64-bit L3 page */
+#define SH_type_l4_64_shadow (13U) /* shadowing a 64-bit L4 page */
+#define SH_type_max_shadow (13U)
+#define SH_type_p2m_table (14U) /* in use as the p2m table */
+#define SH_type_monitor_table (15U) /* in use as a monitor table */
+#define SH_type_unused (16U)
/*
* What counts as a pinnable shadow?
@@ -325,12 +326,13 @@ static inline int sh_type_is_pinnable(st
#define SHF_L1_64 (1u << SH_type_l1_64_shadow)
#define SHF_FL1_64 (1u << SH_type_fl1_64_shadow)
#define SHF_L2_64 (1u << SH_type_l2_64_shadow)
+#define SHF_L2H_64 (1u << SH_type_l2h_64_shadow)
#define SHF_L3_64 (1u << SH_type_l3_64_shadow)
#define SHF_L4_64 (1u << SH_type_l4_64_shadow)
#define SHF_32 (SHF_L1_32|SHF_FL1_32|SHF_L2_32)
#define SHF_PAE (SHF_L1_PAE|SHF_FL1_PAE|SHF_L2_PAE|SHF_L2H_PAE)
-#define SHF_64 (SHF_L1_64|SHF_FL1_64|SHF_L2_64|SHF_L3_64|SHF_L4_64)
+#define SHF_64 (SHF_L1_64|SHF_FL1_64|SHF_L2_64|SHF_L2H_64|SHF_L3_64|SHF_L4_64)
/* Used for hysteresis when automatically unhooking mappings on fork/exit */
#define SHF_unhooked_mappings (1u<<31)
@@ -367,7 +369,6 @@ void shadow_unhook_mappings(struct vcpu
/* Install the xen mappings in various flavours of shadow */
void sh_install_xen_entries_in_l4(struct vcpu *v, mfn_t gl4mfn, mfn_t sl4mfn);
-void sh_install_xen_entries_in_l2h(struct vcpu *v, mfn_t sl2hmfn);
void sh_install_xen_entries_in_l2(struct vcpu *v, mfn_t gl2mfn, mfn_t sl2mfn);
/* Update the shadows in response to a pagetable write from Xen */
diff -r 0b882c911b88 -r 9c2e6f8f3aa7 xen/arch/x86/mm/shadow/types.h
--- a/xen/arch/x86/mm/shadow/types.h Mon Feb 19 16:16:53 2007 +0000
+++ b/xen/arch/x86/mm/shadow/types.h Mon Feb 19 19:58:07 2007 +0000
@@ -389,6 +389,7 @@ static inline guest_l4e_t guest_l4e_from
#define SH_type_l1_shadow SH_type_l1_64_shadow
#define SH_type_fl1_shadow SH_type_fl1_64_shadow
#define SH_type_l2_shadow SH_type_l2_64_shadow
+#define SH_type_l2h_shadow SH_type_l2h_64_shadow
#define SH_type_l3_shadow SH_type_l3_64_shadow
#define SH_type_l4_shadow SH_type_l4_64_shadow
#endif
diff -r 0b882c911b88 -r 9c2e6f8f3aa7 xen/include/asm-x86/x86_64/page.h
--- a/xen/include/asm-x86/x86_64/page.h Mon Feb 19 16:16:53 2007 +0000
+++ b/xen/include/asm-x86/x86_64/page.h Mon Feb 19 19:58:07 2007 +0000
@@ -59,9 +59,11 @@ typedef l4_pgentry_t root_pgentry_t;
!((_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) || \
- ((_s) > ROOT_PAGETABLE_LAST_XEN_SLOT))
+#define is_guest_l4_slot(_d, _s) \
+ ( IS_COMPAT(_d) \
+ ? ((_s) == 0) \
+ : (((_s) < ROOT_PAGETABLE_FIRST_XEN_SLOT) || \
+ ((_s) > ROOT_PAGETABLE_LAST_XEN_SLOT)))
#define root_get_pfn l4e_get_pfn
#define root_get_flags l4e_get_flags
@@ -96,7 +98,7 @@ typedef l4_pgentry_t root_pgentry_t;
#define L3_DISALLOW_MASK (BASE_DISALLOW_MASK)
#define L4_DISALLOW_MASK (BASE_DISALLOW_MASK)
-#define COMPAT_L3_DISALLOW_MASK 0xFFFFF1E6U
+#define COMPAT_L3_DISALLOW_MASK L3_DISALLOW_MASK
#define PAGE_HYPERVISOR (__PAGE_HYPERVISOR | _PAGE_GLOBAL)
#define PAGE_HYPERVISOR_NOCACHE (__PAGE_HYPERVISOR_NOCACHE | _PAGE_GLOBAL)
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|