# HG changeset patch
# User kaf24@xxxxxxxxxxxxxxxxxxxx
# Node ID 8b87d43412bf79367c57ce65da3aed124061c9cc
# Parent 95cfc001ddd1befa7af36067b7505f2ba119a3b5
This patch is to boot 32-bit VMX guest on the 64-bit host.
Double-compile is used to make both 64-bit guest and 32-bit guest can
work, the shadow page-table uses current 64-bit shadow code's structure
to simulate 32-bit guest's 2-level page-table.
Signed-off-by: Chengyuan Li <chengyuan.li@xxxxxxxxx>
Signed-off-by: Xiaohui Xin <xiaohui.xin@xxxxxxxxx>
Signed-off-by: Jun Nakajima <jun.nakajima@xxxxxxxxx>
diff -r 95cfc001ddd1 -r 8b87d43412bf xen/arch/x86/Makefile
--- a/xen/arch/x86/Makefile Fri Sep 2 09:02:13 2005
+++ b/xen/arch/x86/Makefile Fri Sep 2 09:43:32 2005
@@ -17,7 +17,7 @@
OBJS := $(patsubst shadow%.o,,$(OBJS)) # drop all
ifeq ($(TARGET_SUBARCH),x86_64)
- OBJS += shadow.o shadow_public.o # x86_64: new code
+ OBJS += shadow.o shadow_public.o shadow_guest32.o # x86_64: new code
endif
ifeq ($(TARGET_SUBARCH),x86_32)
ifneq ($(pae),n)
diff -r 95cfc001ddd1 -r 8b87d43412bf xen/arch/x86/shadow.c
--- a/xen/arch/x86/shadow.c Fri Sep 2 09:02:13 2005
+++ b/xen/arch/x86/shadow.c Fri Sep 2 09:43:32 2005
@@ -53,6 +53,9 @@
struct domain *d, unsigned long gpfn, unsigned long gmfn);
static void shadow_map_into_current(struct vcpu *v,
unsigned long va, unsigned int from, unsigned int to);
+static inline void validate_bl2e_change( struct domain *d,
+ guest_root_pgentry_t *new_gle_p, pgentry_64_t *shadow_l3, int index);
+
#endif
/********
@@ -217,10 +220,38 @@
}
else
{
- page = alloc_domheap_page(NULL);
- void *l1 = map_domain_page(page_to_pfn(page));
- memset(l1, 0, PAGE_SIZE);
- unmap_domain_page(l1);
+ if (d->arch.ops->guest_paging_levels == PAGING_L2)
+ {
+#if CONFIG_PAGING_LEVELS >= 4
+ /* For 32-bit VMX guest, 2 shadow L1s to simulate 1 guest L1
+ * So need allocate 2 continues shadow L1 each time.
+ */
+ page = alloc_domheap_pages(NULL, SL1_ORDER, 0);
+ if (!page)
+ domain_crash_synchronous();
+
+ void *l1_0 = map_domain_page(page_to_pfn(page));
+ memset(l1_0,0,PAGE_SIZE);
+ unmap_domain_page(l1_0);
+ void *l1_1 = map_domain_page(page_to_pfn(page+1));
+ memset(l1_1,0,PAGE_SIZE);
+ unmap_domain_page(l1_1);
+#else
+ page = alloc_domheap_page(NULL);
+ if (!page)
+ domain_crash_synchronous();
+ void *l1 = map_domain_page(page_to_pfn(page));
+ memset(l1, 0, PAGE_SIZE);
+ unmap_domain_page(l1);
+#endif
+ }
+ else
+ {
+ page = alloc_domheap_page(NULL);
+ void *l1 = map_domain_page(page_to_pfn(page));
+ memset(l1, 0, PAGE_SIZE);
+ unmap_domain_page(l1);
+ }
}
}
else {
@@ -331,7 +362,21 @@
fail:
FSH_LOG("promotion of pfn=%lx mfn=%lx failed! external gnttab refs?",
gpfn, gmfn);
- free_domheap_page(page);
+ if (psh_type == PGT_l1_shadow)
+ {
+ if (d->arch.ops->guest_paging_levels == PAGING_L2)
+ {
+#if CONFIG_PAGING_LEVELS >=4
+ free_domheap_pages(page, SL1_ORDER);
+#else
+ free_domheap_page(page);
+#endif
+ }
+ else
+ free_domheap_page(page);
+ }
+ else
+ free_domheap_page(page);
return 0;
}
@@ -478,8 +523,10 @@
{
struct vcpu *v = current;
struct domain *d = v->domain;
- l1_pgentry_t *gpl1e, *spl1e;
- l2_pgentry_t gl2e, sl2e;
+ l1_pgentry_t *spl1e;
+ l2_pgentry_t sl2e;
+ guest_l1_pgentry_t *gpl1e;
+ guest_l2_pgentry_t gl2e;
unsigned long gl1pfn, gl1mfn, sl1mfn;
int i, init_table = 0;
@@ -523,28 +570,49 @@
ASSERT( !(l2e_get_flags(old_sl2e) & _PAGE_PRESENT) );
#endif
- if ( !get_shadow_ref(sl1mfn) )
- BUG();
- l2pde_general(d, &gl2e, &sl2e, sl1mfn);
- __guest_set_l2e(v, va, &gl2e);
- __shadow_set_l2e(v, va, &sl2e);
+#if CONFIG_PAGING_LEVELS >=4
+ if (d->arch.ops->guest_paging_levels == PAGING_L2)
+ {
+ /* for 32-bit VMX guest on 64-bit host,
+ * need update two L2 entries each time
+ */
+ if ( !get_shadow_ref(sl1mfn))
+ BUG();
+ l2pde_general(d, &gl2e, &sl2e, sl1mfn);
+ __guest_set_l2e(v, va, &gl2e);
+ __shadow_set_l2e(v, va & ~((1<<L2_PAGETABLE_SHIFT_32) - 1), &sl2e);
+ if ( !get_shadow_ref(sl1mfn+1))
+ BUG();
+ sl2e = l2e_empty();
+ l2pde_general(d, &gl2e, &sl2e, sl1mfn+1);
+ __shadow_set_l2e(v,((va & ~((1<<L2_PAGETABLE_SHIFT_32) - 1)) + (1 <<
L2_PAGETABLE_SHIFT)) , &sl2e);
+ } else
+#endif
+ {
+ if ( !get_shadow_ref(sl1mfn) )
+ BUG();
+ l2pde_general(d, &gl2e, &sl2e, sl1mfn);
+ __guest_set_l2e(v, va, &gl2e);
+ __shadow_set_l2e(v, va , &sl2e);
+ }
if ( init_table )
{
l1_pgentry_t sl1e;
- int index = l1_table_offset(va);
+ int index = guest_l1_table_offset(va);
int min = 1, max = 0;
unsigned long entries, pt_va;
l1_pgentry_t tmp_sl1e;
- l1_pgentry_t tmp_gl1e;//Prepare for double compile
-
-
- entries = PAGE_SIZE / sizeof(l1_pgentry_t);
+ guest_l1_pgentry_t tmp_gl1e;//Prepare for double compile
+
+
+ entries = PAGE_SIZE / sizeof(guest_l1_pgentry_t);
pt_va = ((va >> L1_PAGETABLE_SHIFT) & ~(entries - 1)) <<
L1_PAGETABLE_SHIFT;
- gpl1e = (l1_pgentry_t *) __guest_get_l1e(v, pt_va, &tmp_gl1e);
-
- entries = PAGE_SIZE / sizeof(l1_pgentry_t);
+ gpl1e = (guest_l1_pgentry_t *) __guest_get_l1e(v, pt_va, &tmp_gl1e);
+
+ /* If the PGT_l1_shadow has two continual pages */
+ entries = PAGE_SIZE / sizeof(guest_l1_pgentry_t); //1024 entry!!!
pt_va = ((va >> L1_PAGETABLE_SHIFT) & ~(entries - 1)) <<
L1_PAGETABLE_SHIFT;
spl1e = (l1_pgentry_t *) __shadow_get_l1e(v, pt_va, &tmp_sl1e);
@@ -555,7 +623,7 @@
spl1e = &(shadow_linear_pg_table[l1_linear_offset(va) &
~(L1_PAGETABLE_ENTRIES-1)]);*/
- for ( i = 0; i < L1_PAGETABLE_ENTRIES; i++ )
+ for ( i = 0; i < GUEST_L1_PAGETABLE_ENTRIES; i++ )
{
l1pte_propagate_from_guest(d, gpl1e[i], &sl1e);
if ( (l1e_get_flags(sl1e) & _PAGE_PRESENT) &&
@@ -584,7 +652,7 @@
}
}
-static void
+static void
shadow_set_l1e(unsigned long va, l1_pgentry_t new_spte, int create_l1_shadow)
{
struct vcpu *v = current;
@@ -616,7 +684,7 @@
perfc_incrc(shadow_set_l1e_unlinked);
if ( !get_shadow_ref(sl1mfn) )
BUG();
- l2pde_general(d, &gpde, &sl2e, sl1mfn);
+ l2pde_general(d, (guest_l2_pgentry_t *)&gpde, &sl2e, sl1mfn);
__guest_set_l2e(v, va, &gpde);
__shadow_set_l2e(v, va, &sl2e);
}
@@ -651,6 +719,7 @@
shadow_update_min_max(l2e_get_pfn(sl2e), l1_table_offset(va));
}
+#if CONFIG_PAGING_LEVELS <= 3
static void shadow_invlpg_32(struct vcpu *v, unsigned long va)
{
struct domain *d = v->domain;
@@ -679,6 +748,7 @@
shadow_unlock(d);
}
+#endif
static struct out_of_sync_entry *
shadow_alloc_oos_entry(struct domain *d)
@@ -759,8 +829,8 @@
length = max - min + 1;
perfc_incr_histo(snapshot_copies, length, PT_UPDATES);
- min *= sizeof(l1_pgentry_t);
- length *= sizeof(l1_pgentry_t);
+ min *= sizeof(guest_l1_pgentry_t);
+ length *= sizeof(guest_l1_pgentry_t);
original = map_domain_page(gmfn);
snapshot = map_domain_page(smfn);
@@ -841,7 +911,7 @@
__shadow_get_l4e(v, va, &sl4e);
if ( !(l4e_get_flags(sl4e) & _PAGE_PRESENT)) {
- shadow_map_into_current(v, va, L3, L4);
+ shadow_map_into_current(v, va, PAGING_L3, PAGING_L4);
}
if (!__shadow_get_l3e(v, va, &sl3e)) {
@@ -849,7 +919,7 @@
}
if ( !(l3e_get_flags(sl3e) & _PAGE_PRESENT)) {
- shadow_map_into_current(v, va, L2, L3);
+ shadow_map_into_current(v, va, PAGING_L2, PAGING_L3);
}
}
#endif
@@ -887,11 +957,11 @@
* Returns 0 otherwise.
*/
static int snapshot_entry_matches(
- struct domain *d, l1_pgentry_t *guest_pt,
+ struct domain *d, guest_l1_pgentry_t *guest_pt,
unsigned long gpfn, unsigned index)
{
unsigned long smfn = __shadow_status(d, gpfn, PGT_snapshot);
- l1_pgentry_t *snapshot, gpte; // could be L1s or L2s or ...
+ guest_l1_pgentry_t *snapshot, gpte; // could be L1s or L2s or ...
int entries_match;
perfc_incrc(snapshot_entry_matches_calls);
@@ -908,7 +978,7 @@
// This could probably be smarter, but this is sufficent for
// our current needs.
//
- entries_match = !l1e_has_changed(gpte, snapshot[index],
+ entries_match = !guest_l1e_has_changed(gpte, snapshot[index],
PAGE_FLAG_MASK);
unmap_domain_page(snapshot);
@@ -936,10 +1006,10 @@
unsigned long l2mfn = pagetable_get_pfn(v->arch.guest_table);
#endif
unsigned long l2pfn = __mfn_to_gpfn(d, l2mfn);
- l2_pgentry_t l2e;
+ guest_l2_pgentry_t l2e;
unsigned long l1pfn, l1mfn;
- l1_pgentry_t *guest_pt;
- l1_pgentry_t tmp_gle;
+ guest_l1_pgentry_t *guest_pt;
+ guest_l1_pgentry_t tmp_gle;
unsigned long pt_va;
ASSERT(shadow_lock_is_acquired(d));
@@ -948,7 +1018,7 @@
perfc_incrc(shadow_out_of_sync_calls);
#if CONFIG_PAGING_LEVELS >= 4
- if (d->arch.ops->guest_paging_levels == L4) { /* Mode F */
+ if (d->arch.ops->guest_paging_levels == PAGING_L4) { /* Mode F */
pgentry_64_t le;
unsigned long gmfn;
unsigned long gpfn;
@@ -956,9 +1026,9 @@
gmfn = l2mfn;
gpfn = l2pfn;
- guest_pt = (l1_pgentry_t *)v->arch.guest_vtable;
-
- for (i = L4; i >= L3; i--) {
+ guest_pt = (guest_l1_pgentry_t *)v->arch.guest_vtable;
+
+ for (i = PAGING_L4; i >= PAGING_L3; i--) {
if ( page_out_of_sync(&frame_table[gmfn]) &&
!snapshot_entry_matches(
d, guest_pt, gpfn, table_offset_64(va, i)) )
@@ -972,7 +1042,7 @@
if ( !VALID_MFN(gmfn) )
return 0;
/* Todo: check!*/
- guest_pt = (l1_pgentry_t *)map_domain_page(gmfn);
+ guest_pt = (guest_l1_pgentry_t *)map_domain_page(gmfn);
}
@@ -986,13 +1056,13 @@
#endif
if ( page_out_of_sync(&frame_table[l2mfn]) &&
- !snapshot_entry_matches(d, (l1_pgentry_t *)v->arch.guest_vtable,
- l2pfn, l2_table_offset(va)) )
+ !snapshot_entry_matches(d, (guest_l1_pgentry_t *)v->arch.guest_vtable,
+ l2pfn, guest_l2_table_offset(va)) )
return 1;
__guest_get_l2e(v, va, &l2e);
- if ( !(l2e_get_flags(l2e) & _PAGE_PRESENT) ||
- (l2e_get_flags(l2e) & _PAGE_PSE))
+ if ( !(guest_l2e_get_flags(l2e) & _PAGE_PRESENT) ||
+ (guest_l2e_get_flags(l2e) & _PAGE_PSE))
return 0;
l1pfn = l2e_get_pfn(l2e);
@@ -1001,20 +1071,20 @@
// If the l1 pfn is invalid, it can't be out of sync...
if ( !VALID_MFN(l1mfn) )
return 0;
-
- pt_va = ((va >> L1_PAGETABLE_SHIFT) & ~(L1_PAGETABLE_ENTRIES - 1))
+
+ pt_va = ((va >> L1_PAGETABLE_SHIFT) & ~(GUEST_L1_PAGETABLE_ENTRIES - 1))
<< L1_PAGETABLE_SHIFT;
- guest_pt = (l1_pgentry_t *) __guest_get_l1e(v, pt_va, &tmp_gle);
+ guest_pt = (guest_l1_pgentry_t *) __guest_get_l1e(v, pt_va, &tmp_gle);
if ( page_out_of_sync(&frame_table[l1mfn]) &&
!snapshot_entry_matches(
- d, guest_pt, l1pfn, l1_table_offset(va)) )
+ d, guest_pt, l1pfn, guest_l1_table_offset(va)) )
return 1;
return 0;
}
-#define GPFN_TO_GPTEPAGE(_gpfn) ((_gpfn) / (PAGE_SIZE / sizeof(l1_pgentry_t)))
+#define GPFN_TO_GPTEPAGE(_gpfn) ((_gpfn) / (PAGE_SIZE /
sizeof(guest_l1_pgentry_t)))
static inline unsigned long
predict_writable_pte_page(struct domain *d, unsigned long gpfn)
{
@@ -1108,7 +1178,7 @@
return (found == max_refs_to_find);
}
- i = readonly_gpfn & (L1_PAGETABLE_ENTRIES - 1);
+ i = readonly_gpfn & (GUEST_L1_PAGETABLE_ENTRIES - 1);
if ( !l1e_has_changed(pt[i], match, flags) && fix_entry(i) )
{
perfc_incrc(remove_write_fast_exit);
@@ -1117,7 +1187,7 @@
return found;
}
- for (i = 0; i < L1_PAGETABLE_ENTRIES; i++)
+ for (i = 0; i < GUEST_L1_PAGETABLE_ENTRIES; i++)
{
if ( unlikely(!l1e_has_changed(pt[i], match, flags)) && fix_entry(i) )
break;
@@ -1282,15 +1352,15 @@
switch ( stype ) {
case PGT_l1_shadow:
{
- l1_pgentry_t *guest1 = guest;
+ guest_l1_pgentry_t *guest1 = guest;
l1_pgentry_t *shadow1 = shadow;
- l1_pgentry_t *snapshot1 = snapshot;
+ guest_l1_pgentry_t *snapshot1 = snapshot;
ASSERT(VM_ASSIST(d, VMASST_TYPE_writable_pagetables) ||
shadow_mode_write_all(d));
if ( !shadow_mode_refcounts(d) )
- revalidate_l1(d, guest1, snapshot1);
+ revalidate_l1(d, (l1_pgentry_t *)guest1, (l1_pgentry_t
*)snapshot1);
if ( !smfn )
break;
@@ -1301,7 +1371,7 @@
for ( i = min_shadow; i <= max_shadow; i++ )
{
if ( (i < min_snapshot) || (i > max_snapshot) ||
- l1e_has_changed(guest1[i], snapshot1[i], PAGE_FLAG_MASK) )
+ guest_l1e_has_changed(guest1[i], snapshot1[i],
PAGE_FLAG_MASK) )
{
need_flush |= validate_pte_change(d, guest1[i],
&shadow1[i]);
@@ -1431,32 +1501,36 @@
{
int max = -1;
- l4_pgentry_t *guest4 = guest;
+ guest_root_pgentry_t *guest_root = guest;
l4_pgentry_t *shadow4 = shadow;
- l4_pgentry_t *snapshot4 = snapshot;
+ guest_root_pgentry_t *snapshot_root = snapshot;
changed = 0;
- for ( i = 0; i < L4_PAGETABLE_ENTRIES; i++ )
+ for ( i = 0; i < GUEST_ROOT_PAGETABLE_ENTRIES; i++ )
{
if ( !is_guest_l4_slot(i) && !external )
continue;
- l4_pgentry_t new_l4e = guest4[i];
- if ( l4e_has_changed(new_l4e, snapshot4[i], PAGE_FLAG_MASK))
+ guest_root_pgentry_t new_root_e = guest_root[i];
+ if ( root_entry_has_changed(
+ new_root_e, snapshot_root[i], PAGE_FLAG_MASK))
{
- need_flush |= validate_entry_change(
- d, (pgentry_64_t *)&new_l4e,
- (pgentry_64_t *)&shadow4[i],
shadow_type_to_level(stype));
-
+ if (d->arch.ops->guest_paging_levels == PAGING_L4) {
+ need_flush |= validate_entry_change(
+ d, (pgentry_64_t *)&new_root_e,
+ (pgentry_64_t *)&shadow4[i],
shadow_type_to_level(stype));
+ } else {
+ validate_bl2e_change(d, &new_root_e, shadow, i);
+ }
changed++;
ESH_LOG("%d: shadow4 mfn: %lx, shadow root: %lx\n", i,
smfn, pagetable_get_paddr(current->arch.shadow_table));
}
- if ( l4e_get_intpte(new_l4e) != 0 ) /* FIXME: check flags? */
+ if ( guest_root_get_intpte(new_root_e) != 0 ) /* FIXME: check
flags? */
max = i;
// Need a better solution in the long term.
- if ( !(l4e_get_flags(new_l4e) & _PAGE_PRESENT) &&
- unlikely(l4e_get_intpte(new_l4e) != 0) &&
+ if ( !(guest_root_get_flags(new_root_e) & _PAGE_PRESENT) &&
+ unlikely(guest_root_get_intpte(new_root_e) != 0) &&
!unshadow &&
(frame_table[smfn].u.inuse.type_info & PGT_pinned) )
unshadow = 1;
@@ -1555,8 +1629,14 @@
if ( shadow_mode_translate(d) )
need_flush |= resync_all(d, PGT_hl2_shadow);
#endif
- need_flush |= resync_all(d, PGT_l2_shadow);
- need_flush |= resync_all(d, PGT_l3_shadow);
+
+ /*
+ * Fixme: for i386 host
+ */
+ if (d->arch.ops->guest_paging_levels == PAGING_L4) {
+ need_flush |= resync_all(d, PGT_l2_shadow);
+ need_flush |= resync_all(d, PGT_l3_shadow);
+ }
need_flush |= resync_all(d, PGT_l4_shadow);
if ( need_flush && !unlikely(shadow_mode_external(d)) )
@@ -1566,11 +1646,11 @@
}
static inline int l1pte_write_fault(
- struct vcpu *v, l1_pgentry_t *gpte_p, l1_pgentry_t *spte_p,
+ struct vcpu *v, guest_l1_pgentry_t *gpte_p, l1_pgentry_t *spte_p,
unsigned long va)
{
struct domain *d = v->domain;
- l1_pgentry_t gpte = *gpte_p;
+ guest_l1_pgentry_t gpte = *gpte_p;
l1_pgentry_t spte;
unsigned long gpfn = l1e_get_pfn(gpte);
unsigned long gmfn = __gpfn_to_mfn(d, gpfn);
@@ -1585,8 +1665,8 @@
}
ASSERT(l1e_get_flags(gpte) & _PAGE_RW);
- l1e_add_flags(gpte, _PAGE_DIRTY | _PAGE_ACCESSED);
- spte = l1e_from_pfn(gmfn, l1e_get_flags(gpte) & ~_PAGE_GLOBAL);
+ guest_l1e_add_flags(gpte, _PAGE_DIRTY | _PAGE_ACCESSED);
+ spte = l1e_from_pfn(gmfn, guest_l1e_get_flags(gpte) & ~_PAGE_GLOBAL);
SH_VVLOG("l1pte_write_fault: updating spte=0x%" PRIpte " gpte=0x%" PRIpte,
l1e_get_intpte(spte), l1e_get_intpte(gpte));
@@ -1604,9 +1684,9 @@
}
static inline int l1pte_read_fault(
- struct domain *d, l1_pgentry_t *gpte_p, l1_pgentry_t *spte_p)
+ struct domain *d, guest_l1_pgentry_t *gpte_p, l1_pgentry_t *spte_p)
{
- l1_pgentry_t gpte = *gpte_p;
+ guest_l1_pgentry_t gpte = *gpte_p;
l1_pgentry_t spte = *spte_p;
unsigned long pfn = l1e_get_pfn(gpte);
unsigned long mfn = __gpfn_to_mfn(d, pfn);
@@ -1618,10 +1698,10 @@
return 0;
}
- l1e_add_flags(gpte, _PAGE_ACCESSED);
- spte = l1e_from_pfn(mfn, l1e_get_flags(gpte) & ~_PAGE_GLOBAL);
-
- if ( shadow_mode_log_dirty(d) || !(l1e_get_flags(gpte) & _PAGE_DIRTY) ||
+ guest_l1e_add_flags(gpte, _PAGE_ACCESSED);
+ spte = l1e_from_pfn(mfn, guest_l1e_get_flags(gpte) & ~_PAGE_GLOBAL);
+
+ if ( shadow_mode_log_dirty(d) || !(guest_l1e_get_flags(gpte) &
_PAGE_DIRTY) ||
mfn_is_page_table(mfn) )
{
l1e_remove_flags(spte, _PAGE_RW);
@@ -1634,7 +1714,7 @@
return 1;
}
-
+#if CONFIG_PAGING_LEVELS <= 3
static int shadow_fault_32(unsigned long va, struct cpu_user_regs *regs)
{
l1_pgentry_t gpte, spte, orig_gpte;
@@ -1768,6 +1848,7 @@
shadow_unlock(d);
return 0;
}
+#endif
static int do_update_va_mapping(unsigned long va,
l1_pgentry_t val,
@@ -1787,7 +1868,7 @@
//
__shadow_sync_va(v, va);
- l1pte_propagate_from_guest(d, val, &spte);
+ l1pte_propagate_from_guest(d, *(guest_l1_pgentry_t *)&val, &spte);
shadow_set_l1e(va, spte, 0);
/*
@@ -1848,7 +1929,7 @@
#if CONFIG_PAGING_LEVELS == 2
unsigned long hl2mfn;
#endif
-
+
int max_mode = ( shadow_mode_external(d) ? SHM_external
: shadow_mode_translate(d) ? SHM_translate
: shadow_mode_enabled(d) ? SHM_enable
@@ -1954,17 +2035,6 @@
#endif
}
-struct shadow_ops MODE_A_HANDLER = {
- .guest_paging_levels = 2,
- .invlpg = shadow_invlpg_32,
- .fault = shadow_fault_32,
- .update_pagetables = shadow_update_pagetables,
- .sync_all = sync_all,
- .remove_all_write_access = remove_all_write_access,
- .do_update_va_mapping = do_update_va_mapping,
- .mark_mfn_out_of_sync = mark_mfn_out_of_sync,
- .is_out_of_sync = is_out_of_sync,
-};
/************************************************************************/
/************************************************************************/
@@ -2445,12 +2515,90 @@
BUG(); /* not implemenated yet */
return 42;
}
+static unsigned long gva_to_gpa_pae(unsigned long gva)
+{
+ BUG();
+ return 43;
+}
#endif
#if CONFIG_PAGING_LEVELS >= 4
/****************************************************************************/
/* 64-bit shadow-mode code testing */
/****************************************************************************/
+/*
+ * validate_bl2e_change()
+ * The code is for 32-bit VMX gues on 64-bit host.
+ * To sync guest L2.
+ */
+
+static inline void
+validate_bl2e_change(
+ struct domain *d,
+ guest_root_pgentry_t *new_gle_p,
+ pgentry_64_t *shadow_l3,
+ int index)
+{
+ int sl3_idx, sl2_idx;
+ unsigned long sl2mfn, sl1mfn;
+ pgentry_64_t *sl2_p;
+
+ /* Using guest l2 pte index to get shadow l3&l2 index
+ * index: 0 ~ 1023, PAGETABLE_ENTRIES: 512
+ */
+ sl3_idx = index / (PAGETABLE_ENTRIES / 2);
+ sl2_idx = (index % (PAGETABLE_ENTRIES / 2)) * 2;
+
+ sl2mfn = entry_get_pfn(shadow_l3[sl3_idx]);
+ sl2_p = (pgentry_64_t *)map_domain_page(sl2mfn);
+
+ validate_pde_change(
+ d, *(guest_l2_pgentry_t *)new_gle_p, (l2_pgentry_t *)&sl2_p[sl2_idx]);
+
+ /* Mapping the second l1 shadow page */
+ if (entry_get_flags(sl2_p[sl2_idx]) & _PAGE_PRESENT) {
+ sl1mfn = entry_get_pfn(sl2_p[sl2_idx]);
+ sl2_p[sl2_idx + 1] =
+ entry_from_pfn(sl1mfn + 1, entry_get_flags(sl2_p[sl2_idx]));
+ }
+ unmap_domain_page(sl2_p);
+
+}
+
+/*
+ * init_bl2() is for 32-bit VMX guest on 64-bit host
+ * Using 1 shadow L4(l3) and 4 shadow L2s to simulate guest L2
+ */
+static inline unsigned long init_bl2(l4_pgentry_t *spl4e, unsigned long smfn)
+{
+ unsigned int count;
+ unsigned long sl2mfn;
+ struct pfn_info *page;
+
+ memset(spl4e, 0, PAGE_SIZE);
+
+ /* Map the self entry, L4&L3 share the same page */
+ spl4e[PAE_SHADOW_SELF_ENTRY] = l4e_from_pfn(smfn, __PAGE_HYPERVISOR);
+
+ /* Allocate 4 shadow L2s */
+ page = alloc_domheap_pages(NULL, SL2_ORDER, 0);
+ if (!page)
+ domain_crash_synchronous();
+
+ for (count = 0; count < PDP_ENTRIES; count++)
+ {
+ sl2mfn = page_to_pfn(page+count);
+ void *l2 = map_domain_page(sl2mfn);
+ memset(l2, 0, PAGE_SIZE);
+ unmap_domain_page(l2);
+ spl4e[count] = l4e_from_pfn(sl2mfn, _PAGE_PRESENT);
+ }
+
+ unmap_domain_page(spl4e);
+ return smfn;
+
+
+}
static unsigned long shadow_l4_table(
struct domain *d, unsigned long gpfn, unsigned long gmfn)
@@ -2464,11 +2612,16 @@
if ( unlikely(!(smfn = alloc_shadow_page(d, gpfn, gmfn, PGT_l4_shadow))) )
{
- printk("Couldn't alloc an L2 shadow for pfn=%lx mfn=%lx\n", gpfn,
gmfn);
+ printk("Couldn't alloc an L4 shadow for pfn=%lx mfn=%lx\n", gpfn,
gmfn);
BUG(); /* XXX Deal gracefully with failure. */
}
spl4e = (l4_pgentry_t *)map_domain_page(smfn);
+
+ if (d->arch.ops->guest_paging_levels == PAGING_L2) {
+ return init_bl2(spl4e, smfn);
+ }
+
/* Install hypervisor and 4x linear p.t. mapings. */
if ( (PGT_base_page_table == PGT_l4_page_table) &&
!shadow_mode_external(d) )
@@ -2576,7 +2729,7 @@
pgentry_64_t gle, sle;
unsigned long gpfn, smfn;
- if (from == L1 && to == L2) {
+ if (from == PAGING_L1 && to == PAGING_L2) {
shadow_map_l1_into_current_l2(va);
return;
}
@@ -2608,7 +2761,7 @@
if (!(l4e_get_flags(sl4e) & _PAGE_PRESENT)) {
if (create_l2_shadow) {
perfc_incrc(shadow_set_l3e_force_map);
- shadow_map_into_current(v, va, L3, L4);
+ shadow_map_into_current(v, va, PAGING_L3, PAGING_L4);
__shadow_get_l4e(v, va, &sl4e);
} else {
printk("For non VMX shadow, create_l1_shadow:%d\n",
create_l2_shadow);
@@ -2619,7 +2772,7 @@
if (!(l3e_get_flags(sl3e) & _PAGE_PRESENT)) {
if (create_l2_shadow) {
perfc_incrc(shadow_set_l2e_force_map);
- shadow_map_into_current(v, va, L2, L3);
+ shadow_map_into_current(v, va, PAGING_L2, PAGING_L3);
__shadow_get_l3e(v, va, &sl3e);
} else {
printk("For non VMX shadow, create_l1_shadow:%d\n",
create_l2_shadow);
@@ -2655,8 +2808,15 @@
l1_pgentry_t old_spte;
l1_pgentry_t sl1e = *(l1_pgentry_t *)sl1e_p;
int i;
-
- for (i = L4; i >= L2; i--) {
+ unsigned long orig_va = 0;
+
+ if (d->arch.ops->guest_paging_levels == PAGING_L2) {
+ /* This is for 32-bit VMX guest on 64-bit host */
+ orig_va = va;
+ va = va & (~((1<<L2_PAGETABLE_SHIFT_32)-1));
+ }
+
+ for (i = PAGING_L4; i >= PAGING_L2; i--) {
if (!__rw_entry(v, va, &sle, SHADOW_ENTRY | GET_ENTRY | i)) {
printk("<%s> i = %d\n", __func__, i);
BUG();
@@ -2672,9 +2832,13 @@
#endif
}
}
- if(i < L4)
+ if(i < PAGING_L4)
shadow_update_min_max(entry_get_pfn(sle_up), table_offset_64(va,
i));
sle_up = sle;
+ }
+
+ if (d->arch.ops->guest_paging_levels == PAGING_L2) {
+ va = orig_va;
}
if ( shadow_mode_refcounts(d) )
@@ -2692,9 +2856,13 @@
}
__shadow_set_l1e(v, va, &sl1e);
- shadow_update_min_max(entry_get_pfn(sle_up), table_offset_64(va, L1));
-}
-
+
+ shadow_update_min_max(entry_get_pfn(sle_up), guest_l1_table_offset(va));
+}
+
+/* As 32-bit guest don't support 4M page yet,
+ * we don't concern double compile for this function
+ */
static inline int l2e_rw_fault(
struct vcpu *v, l2_pgentry_t *gl2e_p, unsigned long va, int rw)
{
@@ -2825,12 +2993,120 @@
}
+/*
+ * Check P, R/W, U/S bits in the guest page table.
+ * If the fault belongs to guest return 1,
+ * else return 0.
+ */
+#if defined( GUEST_PGENTRY_32 )
+static inline int guest_page_fault(struct vcpu *v,
+ unsigned long va, unsigned int error_code,
+ guest_l2_pgentry_t *gpl2e, guest_l1_pgentry_t *gpl1e)
+{
+ /* The following check for 32-bit guest on 64-bit host */
+
+ __guest_get_l2e(v, va, gpl2e);
+
+ /* Check the guest L2 page-table entry first*/
+ if (unlikely(!(guest_l2e_get_flags(*gpl2e) & _PAGE_PRESENT)))
+ return 1;
+
+ if (error_code & ERROR_W) {
+ if (unlikely(!(guest_l2e_get_flags(*gpl2e) & _PAGE_RW)))
+ return 1;
+ }
+ if (error_code & ERROR_U) {
+ if (unlikely(!(guest_l2e_get_flags(*gpl2e) & _PAGE_USER)))
+ return 1;
+ }
+
+ if (guest_l2e_get_flags(*gpl2e) & _PAGE_PSE)
+ return 0;
+
+ __guest_get_l1e(v, va, gpl1e);
+
+ /* Then check the guest L1 page-table entry */
+ if (unlikely(!(guest_l1e_get_flags(*gpl1e) & _PAGE_PRESENT)))
+ return 1;
+
+ if (error_code & ERROR_W) {
+ if (unlikely(!(guest_l1e_get_flags(*gpl1e) & _PAGE_RW)))
+ return 1;
+ }
+ if (error_code & ERROR_U) {
+ if (unlikely(!(guest_l1e_get_flags(*gpl1e) & _PAGE_USER)))
+ return 1;
+ }
+
+ return 0;
+}
+#else
+static inline int guest_page_fault(struct vcpu *v,
+ unsigned long va, unsigned int error_code,
+ guest_l2_pgentry_t *gpl2e, guest_l1_pgentry_t *gpl1e)
+{
+ struct domain *d = v->domain;
+ pgentry_64_t gle, *lva;
+ unsigned long mfn;
+ int i;
+
+ __rw_entry(v, va, &gle, GUEST_ENTRY | GET_ENTRY | PAGING_L4);
+ if (unlikely(!(entry_get_flags(gle) & _PAGE_PRESENT)))
+ return 1;
+
+ if (error_code & ERROR_W) {
+ if (unlikely(!(entry_get_flags(gle) & _PAGE_RW)))
+ return 1;
+ }
+ if (error_code & ERROR_U) {
+ if (unlikely(!(entry_get_flags(gle) & _PAGE_USER)))
+ return 1;
+ }
+ for (i = PAGING_L3; i >= PAGING_L1; i--) {
+ /*
+ * If it's not external mode, then mfn should be machine physical.
+ */
+ mfn = __gpfn_to_mfn(d, (entry_get_value(gle) >> PAGE_SHIFT));
+
+ lva = (pgentry_64_t *) phys_to_virt(
+ mfn << PAGE_SHIFT);
+ gle = lva[table_offset_64(va, i)];
+
+ if (unlikely(!(entry_get_flags(gle) & _PAGE_PRESENT)))
+ return 1;
+
+ if (error_code & ERROR_W) {
+ if (unlikely(!(entry_get_flags(gle) & _PAGE_RW)))
+ return 1;
+ }
+ if (error_code & ERROR_U) {
+ if (unlikely(!(entry_get_flags(gle) & _PAGE_USER)))
+ return 1;
+ }
+
+ if (i == PAGING_L2) {
+ if (gpl2e)
+ gpl2e->l2 = gle.lo;
+
+ if (likely(entry_get_flags(gle) & _PAGE_PSE))
+ return 0;
+
+ }
+
+ if (i == PAGING_L1)
+ if (gpl1e)
+ gpl1e->l1 = gle.lo;
+ }
+ return 0;
+}
+#endif
static int shadow_fault_64(unsigned long va, struct cpu_user_regs *regs)
{
struct vcpu *v = current;
struct domain *d = v->domain;
- l2_pgentry_t gl2e;
- l1_pgentry_t sl1e, gl1e;
+ guest_l2_pgentry_t gl2e;
+ guest_l1_pgentry_t gl1e;
+ l1_pgentry_t sl1e;
perfc_incrc(shadow_fault_calls);
@@ -2853,12 +3129,11 @@
* STEP 2. Check if the fault belongs to guest
*/
if ( guest_page_fault(
- v, va, regs->error_code,
- (pgentry_64_t *)&gl2e, (pgentry_64_t *)&gl1e) ) {
+ v, va, regs->error_code, &gl2e, &gl1e) ) {
goto fail;
}
- if ( unlikely(!(l2e_get_flags(gl2e) & _PAGE_PSE)) ) {
+ if ( unlikely(!(guest_l2e_get_flags(gl2e) & _PAGE_PSE)) ) {
/*
* Handle 4K pages here
*/
@@ -2892,11 +3167,11 @@
*/
/* Write fault? */
if ( regs->error_code & 2 ) {
- if ( !l2e_rw_fault(v, &gl2e, va, WRITE_FAULT) ) {
+ if ( !l2e_rw_fault(v, (l2_pgentry_t *)&gl2e, va, WRITE_FAULT) ) {
goto fail;
}
} else {
- l2e_rw_fault(v, &gl2e, va, READ_FAULT);
+ l2e_rw_fault(v, (l2_pgentry_t *)&gl2e, va, READ_FAULT);
}
/*
@@ -2944,7 +3219,27 @@
shadow_unlock(d);
}
-#ifndef PGENTRY_32
+static unsigned long gva_to_gpa_64(unsigned long gva)
+{
+ struct vcpu *v = current;
+ guest_l1_pgentry_t gl1e = {0};
+ guest_l2_pgentry_t gl2e = {0};
+ unsigned long gpa;
+
+ if (guest_page_fault(v, gva, 0, &gl2e, &gl1e))
+ return 0;
+
+ if (guest_l2e_get_flags(gl2e) & _PAGE_PSE)
+ gpa = guest_l2e_get_paddr(gl2e) + (gva & ((1 <<
GUEST_L2_PAGETABLE_SHIFT) - 1));
+ else
+ gpa = guest_l1e_get_paddr(gl1e) + (gva & ~PAGE_MASK);
+
+ return gpa;
+
+}
+
+#ifndef GUEST_PGENTRY_32
+
struct shadow_ops MODE_F_HANDLER = {
.guest_paging_levels = 4,
.invlpg = shadow_invlpg_64,
@@ -2955,10 +3250,42 @@
.do_update_va_mapping = do_update_va_mapping,
.mark_mfn_out_of_sync = mark_mfn_out_of_sync,
.is_out_of_sync = is_out_of_sync,
+ .gva_to_gpa = gva_to_gpa_64,
};
#endif
#endif
+
+#if CONFIG_PAGING_LEVELS == 2
+struct shadow_ops MODE_A_HANDLER = {
+ .guest_paging_levels = 2,
+ .invlpg = shadow_invlpg_32,
+ .fault = shadow_fault_32,
+ .update_pagetables = shadow_update_pagetables,
+ .sync_all = sync_all,
+ .remove_all_write_access = remove_all_write_access,
+ .do_update_va_mapping = do_update_va_mapping,
+ .mark_mfn_out_of_sync = mark_mfn_out_of_sync,
+ .is_out_of_sync = is_out_of_sync,
+ .gva_to_gpa = gva_to_gpa_64,
+};
+
+#elif CONFIG_PAGING_LEVELS == 3
+struct shadow_ops MODE_B_HANDLER = {
+ .guest_paging_levels = 3,
+ .invlpg = shadow_invlpg_32,
+ .fault = shadow_fault_32,
+ .update_pagetables = shadow_update_pagetables,
+ .sync_all = sync_all,
+ .remove_all_write_access = remove_all_write_access,
+ .do_update_va_mapping = do_update_va_mapping,
+ .mark_mfn_out_of_sync = mark_mfn_out_of_sync,
+ .is_out_of_sync = is_out_of_sync,
+ .gva_to_gpa = gva_to_gpa_pae,
+};
+
+#endif
+
/*
* Local variables:
diff -r 95cfc001ddd1 -r 8b87d43412bf xen/arch/x86/shadow_public.c
--- a/xen/arch/x86/shadow_public.c Fri Sep 2 09:02:13 2005
+++ b/xen/arch/x86/shadow_public.c Fri Sep 2 09:43:32 2005
@@ -33,11 +33,15 @@
#if CONFIG_PAGING_LEVELS >= 3
#include <asm/shadow_64.h>
+#endif
+#if CONFIG_PAGING_LEVELS == 4
extern struct shadow_ops MODE_F_HANDLER;
+extern struct shadow_ops MODE_D_HANDLER;
#endif
extern struct shadow_ops MODE_A_HANDLER;
+#define SHADOW_MAX_GUEST32(_encoded) ((L1_PAGETABLE_ENTRIES_32 - 1) -
((_encoded) >> 16))
/****************************************************************************/
/************* export interface functions ***********************************/
/****************************************************************************/
@@ -48,7 +52,7 @@
shadow_lock(d);
switch(levels) {
-#if CONFIG_PAGING_LEVELS >= 4
+#if CONFIG_PAGING_LEVELS >= 4
case 4:
if ( d->arch.ops != &MODE_F_HANDLER )
d->arch.ops = &MODE_F_HANDLER;
@@ -56,9 +60,14 @@
return 1;
#endif
case 3:
- case 2:
+ case 2:
+#if CONFIG_PAGING_LEVELS == 2
if ( d->arch.ops != &MODE_A_HANDLER )
d->arch.ops = &MODE_A_HANDLER;
+#elif CONFIG_PAGING_LEVELS == 4
+ if ( d->arch.ops != &MODE_D_HANDLER )
+ d->arch.ops = &MODE_D_HANDLER;
+#endif
shadow_unlock(d);
return 1;
default:
@@ -122,13 +131,17 @@
return d->arch.ops->is_out_of_sync(v, va);
}
+unsigned long gva_to_gpa(unsigned long gva)
+{
+ struct domain *d = current->domain;
+ return d->arch.ops->gva_to_gpa(gva);
+}
/****************************************************************************/
/****************************************************************************/
#if CONFIG_PAGING_LEVELS >= 4
/*
* Convert PAE 3-level page-table to 4-level page-table
*/
-#define PDP_ENTRIES 4
static pagetable_t page_table_convert(struct domain *d)
{
struct pfn_info *l4page, *l3page;
@@ -203,19 +216,41 @@
/*
* Free l2, l3, l4 shadow tables
*/
+
+void free_fake_shadow_l2(struct domain *d,unsigned long smfn);
+
static void inline
free_shadow_tables(struct domain *d, unsigned long smfn, u32 level)
{
pgentry_64_t *ple = map_domain_page(smfn);
int i, external = shadow_mode_external(d);
-
- for ( i = 0; i < PAGETABLE_ENTRIES; i++ )
- if ( external || is_guest_l4_slot(i) )
- if ( entry_get_flags(ple[i]) & _PAGE_PRESENT )
- put_shadow_ref(entry_get_pfn(ple[i]));
-
- unmap_domain_page(ple);
-}
+ struct pfn_info *page = &frame_table[smfn];
+
+ if (d->arch.ops->guest_paging_levels == PAGING_L2)
+ {
+#if CONFIG_PAGING_LEVELS >=4
+ for ( i = 0; i < PDP_ENTRIES; i++ )
+ {
+ if (entry_get_flags(ple[i]) & _PAGE_PRESENT )
+ free_fake_shadow_l2(d,entry_get_pfn(ple[i]));
+ }
+
+ page = &frame_table[entry_get_pfn(ple[0])];
+ free_domheap_pages(page, SL2_ORDER);
+ unmap_domain_page(ple);
+#endif
+ }
+ else
+ {
+ for ( i = 0; i < PAGETABLE_ENTRIES; i++ )
+ if ( external || is_guest_l4_slot(i) )
+ if ( entry_get_flags(ple[i]) & _PAGE_PRESENT )
+ put_shadow_ref(entry_get_pfn(ple[i]));
+
+ unmap_domain_page(ple);
+ }
+}
+
void free_monitor_pagetable(struct vcpu *v)
{
@@ -453,7 +488,12 @@
struct pfn_info *spage = pfn_to_page(smfn);
u32 min_max = spage->tlbflush_timestamp;
int min = SHADOW_MIN(min_max);
- int max = SHADOW_MAX(min_max);
+ int max;
+
+ if (d->arch.ops->guest_paging_levels == PAGING_L2)
+ max = SHADOW_MAX_GUEST32(min_max);
+ else
+ max = SHADOW_MAX(min_max);
for ( i = min; i <= max; i++ )
{
@@ -512,9 +552,24 @@
unmap_domain_page(pl2e);
}
+void free_fake_shadow_l2(struct domain *d, unsigned long smfn)
+{
+ pgentry_64_t *ple = map_domain_page(smfn);
+ int i;
+
+ for ( i = 0; i < PAGETABLE_ENTRIES; i = i + 2 )
+ {
+ if ( entry_get_flags(ple[i]) & _PAGE_PRESENT )
+ put_shadow_ref(entry_get_pfn(ple[i]));
+ }
+
+ unmap_domain_page(ple);
+}
+
void free_shadow_page(unsigned long smfn)
{
struct pfn_info *page = &frame_table[smfn];
+
unsigned long gmfn = page->u.inuse.type_info & PGT_mfn_mask;
struct domain *d = page_get_owner(pfn_to_page(gmfn));
unsigned long gpfn = __mfn_to_gpfn(d, gmfn);
@@ -531,6 +586,7 @@
gpfn |= (1UL << 63);
}
#endif
+
delete_shadow_status(d, gpfn, gmfn, type);
switch ( type )
@@ -687,7 +743,7 @@
int i;
struct shadow_status *x;
struct vcpu *v;
-
+
/*
* WARNING! The shadow page table must not currently be in use!
* e.g., You are expected to have paused the domain and synchronized CR3.
@@ -794,7 +850,16 @@
perfc_decr(free_l1_pages);
struct pfn_info *page = list_entry(list_ent, struct pfn_info, list);
- free_domheap_page(page);
+ if (d->arch.ops->guest_paging_levels == PAGING_L2)
+ {
+#if CONFIG_PAGING_LEVELS >=4
+ free_domheap_pages(page, SL1_ORDER);
+#else
+ free_domheap_page(page);
+#endif
+ }
+ else
+ free_domheap_page(page);
}
shadow_audit(d, 0);
@@ -1191,7 +1256,7 @@
{
DPRINTK("Don't try to do a shadow op on yourself!\n");
return -EINVAL;
- }
+ }
domain_pause(d);
diff -r 95cfc001ddd1 -r 8b87d43412bf xen/arch/x86/vmx.c
--- a/xen/arch/x86/vmx.c Fri Sep 2 09:02:13 2005
+++ b/xen/arch/x86/vmx.c Fri Sep 2 09:43:32 2005
@@ -412,7 +412,7 @@
if ( !result )
{
__vmread(GUEST_RIP, &eip);
- printk("vmx pgfault to guest va=%p eip=%p\n", va, eip);
+ printk("vmx pgfault to guest va=%lx eip=%lx\n", va, eip);
}
#endif
@@ -456,7 +456,16 @@
clear_bit(X86_FEATURE_PSE, &edx);
clear_bit(X86_FEATURE_PAE, &edx);
clear_bit(X86_FEATURE_PSE36, &edx);
+#else
+ struct vcpu *d = current;
+ if (d->domain->arch.ops->guest_paging_levels == PAGING_L2)
+ {
+ clear_bit(X86_FEATURE_PSE, &edx);
+ clear_bit(X86_FEATURE_PAE, &edx);
+ clear_bit(X86_FEATURE_PSE36, &edx);
+ }
#endif
+
}
regs->eax = (unsigned long) eax;
@@ -650,7 +659,7 @@
p->df = (eflags & X86_EFLAGS_DF) ? 1 : 0;
if (test_bit(5, &exit_qualification)) /* "rep" prefix */
- p->count = vm86 ? regs->ecx & 0xFFFF : regs->ecx;
+ p->count = vm86 ? regs->ecx & 0xFFFF : regs->ecx;
/*
* Split up string I/O operations that cross page boundaries. Don't
@@ -1006,6 +1015,15 @@
#if CONFIG_PAGING_LEVELS >= 4
if(!shadow_set_guest_paging_levels(d->domain, 4)) {
+ printk("Unsupported guest paging levels\n");
+ domain_crash_synchronous(); /* need to take a clean path */
+ }
+#endif
+ }
+ else
+ {
+#if CONFIG_PAGING_LEVELS >= 4
+ if(!shadow_set_guest_paging_levels(d->domain, 2)) {
printk("Unsupported guest paging levels\n");
domain_crash_synchronous(); /* need to take a clean path */
}
diff -r 95cfc001ddd1 -r 8b87d43412bf xen/include/asm-x86/page-guest32.h
--- a/xen/include/asm-x86/page-guest32.h Fri Sep 2 09:02:13 2005
+++ b/xen/include/asm-x86/page-guest32.h Fri Sep 2 09:43:32 2005
@@ -32,6 +32,11 @@
/* Get pte access flags (unsigned int). */
#define l1e_get_flags_32(x) (get_pte_flags_32((x).l1))
#define l2e_get_flags_32(x) (get_pte_flags_32((x).l2))
+
+#define l1e_get_paddr_32(x) \
+ ((physaddr_t)(((x).l1 & (PADDR_MASK&PAGE_MASK))))
+#define l2e_get_paddr_32(x) \
+ ((physaddr_t)(((x).l2 & (PADDR_MASK&PAGE_MASK))))
/* Construct an empty pte. */
#define l1e_empty_32() ((l1_pgentry_32_t) { 0 })
diff -r 95cfc001ddd1 -r 8b87d43412bf xen/include/asm-x86/shadow.h
--- a/xen/include/asm-x86/shadow.h Fri Sep 2 09:02:13 2005
+++ b/xen/include/asm-x86/shadow.h Fri Sep 2 09:43:32 2005
@@ -34,6 +34,8 @@
#include <asm/vmx.h>
#include <public/dom0_ops.h>
#include <asm/shadow_public.h>
+#include <asm/page-guest32.h>
+#include <asm/shadow_ops.h>
/* Shadow PT operation mode : shadow-mode variable in arch_domain. */
@@ -104,9 +106,9 @@
} while (0)
#endif
-#define SHADOW_ENCODE_MIN_MAX(_min, _max) ((((L1_PAGETABLE_ENTRIES - 1) -
(_max)) << 16) | (_min))
+#define SHADOW_ENCODE_MIN_MAX(_min, _max) ((((GUEST_L1_PAGETABLE_ENTRIES - 1)
- (_max)) << 16) | (_min))
#define SHADOW_MIN(_encoded) ((_encoded) & ((1u<<16) - 1))
-#define SHADOW_MAX(_encoded) ((L1_PAGETABLE_ENTRIES - 1) - ((_encoded) >> 16))
+#define SHADOW_MAX(_encoded) ((GUEST_L1_PAGETABLE_ENTRIES - 1) - ((_encoded)
>> 16))
extern void shadow_mode_init(void);
extern int shadow_mode_control(struct domain *p, dom0_shadow_control_t *sc);
@@ -132,6 +134,7 @@
struct domain_mmap_cache *cache);
#if CONFIG_PAGING_LEVELS >= 3
#include <asm/page-guest32.h>
+extern unsigned long gva_to_gpa(unsigned long gva);
extern void shadow_l3_normal_pt_update(struct domain *d,
unsigned long pa, l3_pgentry_t l3e,
struct domain_mmap_cache *cache);
@@ -794,22 +797,22 @@
#endif
static inline void l1pte_propagate_from_guest(
- struct domain *d, l1_pgentry_t gpte, l1_pgentry_t *spte_p)
+ struct domain *d, guest_l1_pgentry_t gpte, l1_pgentry_t *spte_p)
{
unsigned long mfn;
l1_pgentry_t spte;
spte = l1e_empty();
- if ( ((l1e_get_flags(gpte) & (_PAGE_PRESENT|_PAGE_ACCESSED) ) ==
+ if ( ((guest_l1e_get_flags(gpte) & (_PAGE_PRESENT|_PAGE_ACCESSED) ) ==
(_PAGE_PRESENT|_PAGE_ACCESSED)) &&
VALID_MFN(mfn = __gpfn_to_mfn(d, l1e_get_pfn(gpte))) )
{
spte = l1e_from_pfn(
- mfn, l1e_get_flags(gpte) & ~(_PAGE_GLOBAL | _PAGE_AVAIL));
+ mfn, guest_l1e_get_flags(gpte) & ~(_PAGE_GLOBAL | _PAGE_AVAIL));
if ( shadow_mode_log_dirty(d) ||
- !(l1e_get_flags(gpte) & _PAGE_DIRTY) ||
+ !(guest_l1e_get_flags(gpte) & _PAGE_DIRTY) ||
mfn_is_page_table(mfn) )
{
l1e_remove_flags(spte, _PAGE_RW);
@@ -859,22 +862,22 @@
static inline void l2pde_general(
struct domain *d,
- l2_pgentry_t *gpde_p,
+ guest_l2_pgentry_t *gpde_p,
l2_pgentry_t *spde_p,
unsigned long sl1mfn)
{
- l2_pgentry_t gpde = *gpde_p;
+ guest_l2_pgentry_t gpde = *gpde_p;
l2_pgentry_t spde;
spde = l2e_empty();
- if ( (l2e_get_flags(gpde) & _PAGE_PRESENT) && (sl1mfn != 0) )
+ if ( (guest_l2e_get_flags(gpde) & _PAGE_PRESENT) && (sl1mfn != 0) )
{
spde = l2e_from_pfn(
- sl1mfn,
- (l2e_get_flags(gpde) | _PAGE_RW | _PAGE_ACCESSED) & ~_PAGE_AVAIL);
+ sl1mfn,
+ (guest_l2e_get_flags(gpde) | _PAGE_RW | _PAGE_ACCESSED) &
~_PAGE_AVAIL);
/* N.B. PDEs do not have a dirty bit. */
- l2e_add_flags(gpde, _PAGE_ACCESSED);
+ guest_l2e_add_flags(gpde, _PAGE_ACCESSED);
*gpde_p = gpde;
}
@@ -887,12 +890,12 @@
}
static inline void l2pde_propagate_from_guest(
- struct domain *d, l2_pgentry_t *gpde_p, l2_pgentry_t *spde_p)
-{
- l2_pgentry_t gpde = *gpde_p;
+ struct domain *d, guest_l2_pgentry_t *gpde_p, l2_pgentry_t *spde_p)
+{
+ guest_l2_pgentry_t gpde = *gpde_p;
unsigned long sl1mfn = 0;
- if ( l2e_get_flags(gpde) & _PAGE_PRESENT )
+ if ( guest_l2e_get_flags(gpde) & _PAGE_PRESENT )
sl1mfn = __shadow_status(d, l2e_get_pfn(gpde), PGT_l1_shadow);
l2pde_general(d, gpde_p, spde_p, sl1mfn);
}
@@ -904,7 +907,7 @@
static int inline
validate_pte_change(
struct domain *d,
- l1_pgentry_t new_pte,
+ guest_l1_pgentry_t new_pte,
l1_pgentry_t *shadow_pte_p)
{
l1_pgentry_t old_spte, new_spte;
@@ -1004,7 +1007,7 @@
static int inline
validate_pde_change(
struct domain *d,
- l2_pgentry_t new_gpde,
+ guest_l2_pgentry_t new_gpde,
l2_pgentry_t *shadow_pde_p)
{
l2_pgentry_t old_spde, new_spde;
diff -r 95cfc001ddd1 -r 8b87d43412bf xen/include/asm-x86/shadow_64.h
--- a/xen/include/asm-x86/shadow_64.h Fri Sep 2 09:02:13 2005
+++ b/xen/include/asm-x86/shadow_64.h Fri Sep 2 09:43:32 2005
@@ -27,6 +27,7 @@
#ifndef _XEN_SHADOW_64_H
#define _XEN_SHADOW_64_H
#include <asm/shadow.h>
+#include <asm/shadow_ops.h>
#define READ_FAULT 0
#define WRITE_FAULT 1
@@ -42,14 +43,14 @@
#define ESH_LOG(_f, _a...) ((void)0)
#endif
-#define L4 4UL
-#define L3 3UL
-#define L2 2UL
-#define L1 1UL
+#define PAGING_L4 4UL
+#define PAGING_L3 3UL
+#define PAGING_L2 2UL
+#define PAGING_L1 1UL
#define L_MASK 0xff
-#define ROOT_LEVEL_64 L4
-#define ROOT_LEVEL_32 L2
+#define ROOT_LEVEL_64 PAGING_L4
+#define ROOT_LEVEL_32 PAGING_L2
#define SHADOW_ENTRY (2UL << 16)
#define GUEST_ENTRY (1UL << 16)
@@ -58,6 +59,10 @@
#define SET_ENTRY (1UL << 8)
#define PAGETABLE_ENTRIES (1<<PAGETABLE_ORDER)
+
+/* For 32-bit VMX guest to allocate shadow L1 & L2*/
+#define SL1_ORDER 1
+#define SL2_ORDER 2
typedef struct { intpte_t lo; } pgentry_64_t;
#define shadow_level_to_type(l) (l << 29)
@@ -76,6 +81,10 @@
#define entry_remove_flags(x, flags) ((x).lo &= ~put_pte_flags(flags))
#define entry_has_changed(x,y,flags) \
( !!(((x).lo ^ (y).lo) &
((PADDR_MASK&PAGE_MASK)|put_pte_flags(flags))) )
+
+#define PAE_SHADOW_SELF_ENTRY 259
+#define PDP_ENTRIES 4
+
static inline int table_offset_64(unsigned long va, int level)
{
switch(level) {
@@ -86,8 +95,13 @@
case 3:
return (((va) >> L3_PAGETABLE_SHIFT) & (L3_PAGETABLE_ENTRIES -
1));
#if CONFIG_PAGING_LEVELS >= 4
+#ifndef GUEST_PGENTRY_32
case 4:
return (((va) >> L4_PAGETABLE_SHIFT) & (L4_PAGETABLE_ENTRIES -
1));
+#else
+ case 4:
+ return PAE_SHADOW_SELF_ENTRY;
+#endif
#endif
default:
//printk("<table_offset_64> level %d is too big\n", level);
@@ -165,30 +179,30 @@
return le_e;
}
#define __shadow_set_l4e(v, va, value) \
- __rw_entry(v, va, value, SHADOW_ENTRY | SET_ENTRY | L4)
+ __rw_entry(v, va, value, SHADOW_ENTRY | SET_ENTRY | PAGING_L4)
#define __shadow_get_l4e(v, va, sl4e) \
- __rw_entry(v, va, sl4e, SHADOW_ENTRY | GET_ENTRY | L4)
+ __rw_entry(v, va, sl4e, SHADOW_ENTRY | GET_ENTRY | PAGING_L4)
#define __shadow_set_l3e(v, va, value) \
- __rw_entry(v, va, value, SHADOW_ENTRY | SET_ENTRY | L3)
+ __rw_entry(v, va, value, SHADOW_ENTRY | SET_ENTRY | PAGING_L3)
#define __shadow_get_l3e(v, va, sl3e) \
- __rw_entry(v, va, sl3e, SHADOW_ENTRY | GET_ENTRY | L3)
+ __rw_entry(v, va, sl3e, SHADOW_ENTRY | GET_ENTRY | PAGING_L3)
#define __shadow_set_l2e(v, va, value) \
- __rw_entry(v, va, value, SHADOW_ENTRY | SET_ENTRY | L2)
+ __rw_entry(v, va, value, SHADOW_ENTRY | SET_ENTRY | PAGING_L2)
#define __shadow_get_l2e(v, va, sl2e) \
- __rw_entry(v, va, sl2e, SHADOW_ENTRY | GET_ENTRY | L2)
+ __rw_entry(v, va, sl2e, SHADOW_ENTRY | GET_ENTRY | PAGING_L2)
#define __shadow_set_l1e(v, va, value) \
- __rw_entry(v, va, value, SHADOW_ENTRY | SET_ENTRY | L1)
+ __rw_entry(v, va, value, SHADOW_ENTRY | SET_ENTRY | PAGING_L1)
#define __shadow_get_l1e(v, va, sl1e) \
- __rw_entry(v, va, sl1e, SHADOW_ENTRY | GET_ENTRY | L1)
+ __rw_entry(v, va, sl1e, SHADOW_ENTRY | GET_ENTRY | PAGING_L1)
#define __guest_set_l4e(v, va, value) \
- __rw_entry(v, va, value, GUEST_ENTRY | SET_ENTRY | L4)
+ __rw_entry(v, va, value, GUEST_ENTRY | SET_ENTRY | PAGING_L4)
#define __guest_get_l4e(v, va, gl4e) \
- __rw_entry(v, va, gl4e, GUEST_ENTRY | GET_ENTRY | L4)
+ __rw_entry(v, va, gl4e, GUEST_ENTRY | GET_ENTRY | PAGING_L4)
#define __guest_set_l3e(v, va, value) \
- __rw_entry(v, va, value, GUEST_ENTRY | SET_ENTRY | L3)
+ __rw_entry(v, va, value, GUEST_ENTRY | SET_ENTRY | PAGING_L3)
#define __guest_get_l3e(v, va, sl3e) \
- __rw_entry(v, va, gl3e, GUEST_ENTRY | GET_ENTRY | L3)
+ __rw_entry(v, va, gl3e, GUEST_ENTRY | GET_ENTRY | PAGING_L3)
static inline void * __guest_set_l2e(
struct vcpu *v, u64 va, void *value, int size)
@@ -205,7 +219,7 @@
return &l2va[l2_table_offset_32(va)];
}
case 8:
- return __rw_entry(v, va, value, GUEST_ENTRY | SET_ENTRY | L2);
+ return __rw_entry(v, va, value, GUEST_ENTRY | SET_ENTRY |
PAGING_L2);
default:
BUG();
return NULL;
@@ -230,7 +244,7 @@
return &l2va[l2_table_offset_32(va)];
}
case 8:
- return __rw_entry(v, va, gl2e, GUEST_ENTRY | GET_ENTRY | L2);
+ return __rw_entry(v, va, gl2e, GUEST_ENTRY | GET_ENTRY |
PAGING_L2);
default:
BUG();
return NULL;
@@ -269,7 +283,7 @@
}
case 8:
- return __rw_entry(v, va, value, GUEST_ENTRY | SET_ENTRY | L1);
+ return __rw_entry(v, va, value, GUEST_ENTRY | SET_ENTRY |
PAGING_L1);
default:
BUG();
return NULL;
@@ -310,7 +324,7 @@
}
case 8:
// 64-bit guest
- return __rw_entry(v, va, gl1e, GUEST_ENTRY | GET_ENTRY | L1);
+ return __rw_entry(v, va, gl1e, GUEST_ENTRY | GET_ENTRY |
PAGING_L1);
default:
BUG();
return NULL;
@@ -334,7 +348,7 @@
sle = entry_empty();
if ( (entry_get_flags(gle) & _PAGE_PRESENT) && (smfn != 0) )
{
- if ((entry_get_flags(gle) & _PAGE_PSE) && level == L2) {
+ if ((entry_get_flags(gle) & _PAGE_PSE) && level == PAGING_L2) {
sle = entry_from_pfn(smfn, entry_get_flags(gle));
entry_remove_flags(sle, _PAGE_PSE);
@@ -376,7 +390,7 @@
unsigned long smfn = 0;
if ( entry_get_flags(gle) & _PAGE_PRESENT ) {
- if ((entry_get_flags(gle) & _PAGE_PSE) && level == L2) {
+ if ((entry_get_flags(gle) & _PAGE_PSE) && level == PAGING_L2) {
smfn = __shadow_status(d, entry_get_value(gle) >> PAGE_SHIFT,
PGT_fl1_shadow);
} else {
smfn = __shadow_status(d, entry_get_pfn(gle),
@@ -421,88 +435,6 @@
return 1;
}
-/*
- * Check P, R/W, U/S bits in the guest page table.
- * If the fault belongs to guest return 1,
- * else return 0.
- */
-static inline int guest_page_fault(struct vcpu *v,
- unsigned long va, unsigned int error_code, pgentry_64_t *gpl2e, pgentry_64_t
*gpl1e)
-{
- struct domain *d = v->domain;
- pgentry_64_t gle, *lva;
- unsigned long mfn;
- int i;
-
- __rw_entry(v, va, &gle, GUEST_ENTRY | GET_ENTRY | L4);
- if (unlikely(!(entry_get_flags(gle) & _PAGE_PRESENT)))
- return 1;
-
- if (error_code & ERROR_W) {
- if (unlikely(!(entry_get_flags(gle) & _PAGE_RW)))
- return 1;
- }
- if (error_code & ERROR_U) {
- if (unlikely(!(entry_get_flags(gle) & _PAGE_USER)))
- return 1;
- }
- for (i = L3; i >= L1; i--) {
- /*
- * If it's not external mode, then mfn should be machine physical.
- */
- mfn = __gpfn_to_mfn(d, (entry_get_paddr(gle) >> PAGE_SHIFT));
- if (mfn == -1)
- return 1;
-
- lva = (pgentry_64_t *) phys_to_virt(
- mfn << PAGE_SHIFT);
- gle = lva[table_offset_64(va, i)];
-
- if (unlikely(!(entry_get_flags(gle) & _PAGE_PRESENT)))
- return 1;
-
- if (error_code & ERROR_W) {
- if (unlikely(!(entry_get_flags(gle) & _PAGE_RW)))
- return 1;
- }
- if (error_code & ERROR_U) {
- if (unlikely(!(entry_get_flags(gle) & _PAGE_USER)))
- return 1;
- }
-
- if (i == L2) {
- if (gpl2e)
- *gpl2e = gle;
-
- if (likely(entry_get_flags(gle) & _PAGE_PSE))
- return 0;
-
- }
-
- if (i == L1)
- if (gpl1e)
- *gpl1e = gle;
- }
- return 0;
-}
-
-static inline unsigned long gva_to_gpa(unsigned long gva)
-{
- struct vcpu *v = current;
- pgentry_64_t gl1e = {0};
- pgentry_64_t gl2e = {0};
- unsigned long gpa;
-
- if (guest_page_fault(v, gva, 0, &gl2e, &gl1e))
- return 0;
- if (entry_get_flags(gl2e) & _PAGE_PSE)
- gpa = entry_get_paddr(gl2e) + (gva & ((1 << L2_PAGETABLE_SHIFT) - 1));
- else
- gpa = entry_get_paddr(gl1e) + (gva & ~PAGE_MASK);
-
- return gpa;
-
-}
#endif
diff -r 95cfc001ddd1 -r 8b87d43412bf xen/include/asm-x86/shadow_public.h
--- a/xen/include/asm-x86/shadow_public.h Fri Sep 2 09:02:13 2005
+++ b/xen/include/asm-x86/shadow_public.h Fri Sep 2 09:43:32 2005
@@ -49,6 +49,7 @@
(*mark_mfn_out_of_sync)(struct vcpu *v, unsigned long gpfn,
unsigned long mfn);
int (*is_out_of_sync)(struct vcpu *v, unsigned long va);
+ unsigned long (*gva_to_gpa)(unsigned long gva);
};
#endif
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|