ifeq ($(CONFIG_SHADOW_PAGING),y)
-obj-y += common.o guest_2.o guest_3.o guest_4.o
+obj-y += common.o guest_2.o guest_3.o guest_4.o set.o
obj-$(CONFIG_HVM) += hvm.o
obj-$(CONFIG_PV) += pv.o
else
ASSERT(!next->u.sh.head);
return page_to_mfn(next);
}
+#else
+# define sh_next_page NULL
#endif
+#define shadow_set_l2e(d, sl2e, new_sl2e, sl2mfn) \
+ shadow_set_l2e(d, sl2e, new_sl2e, sl2mfn, SH_type_fl1_shadow, sh_next_page)
+
static inline u32
guest_index(void *ptr)
{
}
-/**************************************************************************/
-/* These functions update shadow entries (and do bookkeeping on the shadow
- * tables they are in). It is intended that they are the only
- * functions which ever write (non-zero) data onto a shadow page.
- */
-
-static inline void
-shadow_write_entries(void *d, const void *s, unsigned int entries, mfn_t mfn)
-/*
- * This function does the actual writes to shadow pages.
- * It must not be called directly, since it doesn't do the bookkeeping
- * that shadow_set_l*e() functions do.
- *
- * Copy PTEs safely when processors might be running on the
- * destination pagetable. This does *not* give safety against
- * concurrent writes (that's what the paging lock is for), just
- * stops the hardware picking up partially written entries.
- */
-{
- shadow_l1e_t *dst = d;
- const shadow_l1e_t *src = s;
- void *map = NULL;
- unsigned int i = 0;
-
- /*
- * Because we mirror access rights at all levels in the shadow, an
- * l2 (or higher) entry with the RW bit cleared will leave us with
- * no write access through the linear map.
- * We detect that by writing to the shadow with put_unsafe() and
- * using map_domain_page() to get a writeable mapping if we need to.
- */
- if ( put_unsafe(*src, dst) )
- {
- perfc_incr(shadow_linear_map_failed);
- map = map_domain_page(mfn);
- dst = map + PAGE_OFFSET(dst);
- }
- else
- {
- ++src;
- ++dst;
- i = 1;
- }
-
- ASSERT(IS_ALIGNED((unsigned long)dst, sizeof(*dst)));
-
- for ( ; i < entries; i++ )
- write_atomic(&dst++->l1, src++->l1);
-
- unmap_domain_page(map);
-}
-
-/* type is only used to distinguish grant map pages from ordinary RAM
- * i.e. non-p2m_is_grant() pages are treated as p2m_ram_rw. */
-static int inline
-shadow_get_page_from_l1e(shadow_l1e_t sl1e, struct domain *d, p2m_type_t type)
-{
- int res;
- mfn_t mfn;
- struct domain *owner;
-
- ASSERT(!sh_l1e_is_magic(sl1e));
- ASSERT(shadow_mode_refcounts(d));
-
- res = get_page_from_l1e(sl1e, d, d);
-
- // If a privileged domain is attempting to install a map of a page it does
- // not own, we let it succeed anyway.
- //
- if ( unlikely(res < 0) &&
- !shadow_mode_translate(d) &&
- mfn_valid(mfn = shadow_l1e_get_mfn(sl1e)) &&
- (owner = page_get_owner(mfn_to_page(mfn))) &&
- (d != owner) )
- {
- res = xsm_priv_mapping(XSM_TARGET, d, owner);
- if ( !res ) {
- res = get_page_from_l1e(sl1e, d, owner);
- SHADOW_PRINTK("privileged domain %d installs map of mfn %"PRI_mfn" "
- "which is owned by d%d: %s\n",
- d->domain_id, mfn_x(mfn), owner->domain_id,
- res >= 0 ? "success" : "failed");
- }
- }
-
- /* Okay, it might still be a grant mapping PTE. Try it. */
- if ( unlikely(res < 0) &&
- (type == p2m_grant_map_rw ||
- (type == p2m_grant_map_ro &&
- !(shadow_l1e_get_flags(sl1e) & _PAGE_RW))) )
- {
- /* It's a grant mapping. The grant table implementation will
- already have checked that we're supposed to have access, so
- we can just grab a reference directly. */
- mfn = shadow_l1e_get_mfn(sl1e);
- if ( mfn_valid(mfn) )
- res = get_page_from_l1e(sl1e, d, page_get_owner(mfn_to_page(mfn)));
- }
-
- if ( unlikely(res < 0) )
- {
- perfc_incr(shadow_get_page_fail);
- SHADOW_PRINTK("failed: l1e=" SH_PRI_pte "\n");
- }
-
- return res;
-}
-
-static void inline
-shadow_put_page_from_l1e(shadow_l1e_t sl1e, struct domain *d)
-{
- if ( !shadow_mode_refcounts(d) )
- return;
-
- put_page_from_l1e(sl1e, d);
-}
-
-#if GUEST_PAGING_LEVELS >= 4
-static int shadow_set_l4e(struct domain *d,
- shadow_l4e_t *sl4e,
- shadow_l4e_t new_sl4e,
- mfn_t sl4mfn)
-{
- int flags = 0;
- shadow_l4e_t old_sl4e;
- paddr_t paddr;
- ASSERT(sl4e != NULL);
- old_sl4e = *sl4e;
-
- if ( old_sl4e.l4 == new_sl4e.l4 ) return 0; /* Nothing to do */
-
- paddr = ((((paddr_t)mfn_x(sl4mfn)) << PAGE_SHIFT)
- | (((unsigned long)sl4e) & ~PAGE_MASK));
-
- if ( shadow_l4e_get_flags(new_sl4e) & _PAGE_PRESENT )
- {
- /* About to install a new reference */
- mfn_t sl3mfn = shadow_l4e_get_mfn(new_sl4e);
-
- if ( !sh_get_ref(d, sl3mfn, paddr) )
- {
- domain_crash(d);
- return SHADOW_SET_ERROR;
- }
-
- /* Are we pinning l3 shadows to handle weird Linux behaviour? */
- if ( sh_type_is_pinnable(d, SH_type_l3_64_shadow) )
- sh_pin(d, sl3mfn);
- }
-
- /* Write the new entry */
- shadow_write_entries(sl4e, &new_sl4e, 1, sl4mfn);
- flush_root_pgtbl_domain(d);
-
- flags |= SHADOW_SET_CHANGED;
-
- if ( shadow_l4e_get_flags(old_sl4e) & _PAGE_PRESENT )
- {
- /* We lost a reference to an old mfn. */
- mfn_t osl3mfn = shadow_l4e_get_mfn(old_sl4e);
-
- if ( !mfn_eq(osl3mfn, shadow_l4e_get_mfn(new_sl4e))
- || !perms_strictly_increased(shadow_l4e_get_flags(old_sl4e),
- shadow_l4e_get_flags(new_sl4e)) )
- {
- flags |= SHADOW_SET_FLUSH;
- }
- sh_put_ref(d, osl3mfn, paddr);
- }
-
- return flags;
-}
-
-static int shadow_set_l3e(struct domain *d,
- shadow_l3e_t *sl3e,
- shadow_l3e_t new_sl3e,
- mfn_t sl3mfn)
-{
- int flags = 0;
- shadow_l3e_t old_sl3e;
- paddr_t paddr;
- ASSERT(sl3e != NULL);
- old_sl3e = *sl3e;
-
- if ( old_sl3e.l3 == new_sl3e.l3 ) return 0; /* Nothing to do */
-
- paddr = ((((paddr_t)mfn_x(sl3mfn)) << PAGE_SHIFT)
- | (((unsigned long)sl3e) & ~PAGE_MASK));
-
- if ( shadow_l3e_get_flags(new_sl3e) & _PAGE_PRESENT )
- {
- /* About to install a new reference */
- if ( !sh_get_ref(d, shadow_l3e_get_mfn(new_sl3e), paddr) )
- {
- domain_crash(d);
- return SHADOW_SET_ERROR;
- }
- }
-
- /* Write the new entry */
- shadow_write_entries(sl3e, &new_sl3e, 1, sl3mfn);
- flags |= SHADOW_SET_CHANGED;
-
- if ( shadow_l3e_get_flags(old_sl3e) & _PAGE_PRESENT )
- {
- /* We lost a reference to an old mfn. */
- mfn_t osl2mfn = shadow_l3e_get_mfn(old_sl3e);
-
- if ( !mfn_eq(osl2mfn, shadow_l3e_get_mfn(new_sl3e)) ||
- !perms_strictly_increased(shadow_l3e_get_flags(old_sl3e),
- shadow_l3e_get_flags(new_sl3e)) )
- {
- flags |= SHADOW_SET_FLUSH;
- }
- sh_put_ref(d, osl2mfn, paddr);
- }
- return flags;
-}
-#endif /* GUEST_PAGING_LEVELS >= 4 */
-
-static int shadow_set_l2e(struct domain *d,
- shadow_l2e_t *sl2e,
- shadow_l2e_t new_sl2e,
- mfn_t sl2mfn)
-{
- int flags = 0;
- shadow_l2e_t old_sl2e;
- paddr_t paddr;
-
-#if GUEST_PAGING_LEVELS == 2
- /* In 2-on-3 we work with pairs of l2es pointing at two-page
- * shadows. Reference counting and up-pointers track from the first
- * page of the shadow to the first l2e, so make sure that we're
- * working with those:
- * Start with a pair of identical entries */
- shadow_l2e_t pair[2] = { new_sl2e, new_sl2e };
- /* Align the pointer down so it's pointing at the first of the pair */
- sl2e = (shadow_l2e_t *)((unsigned long)sl2e & ~(sizeof(shadow_l2e_t)));
-#endif
-
- ASSERT(sl2e != NULL);
- old_sl2e = *sl2e;
-
- if ( old_sl2e.l2 == new_sl2e.l2 ) return 0; /* Nothing to do */
-
- paddr = ((((paddr_t)mfn_x(sl2mfn)) << PAGE_SHIFT)
- | (((unsigned long)sl2e) & ~PAGE_MASK));
-
- if ( shadow_l2e_get_flags(new_sl2e) & _PAGE_PRESENT )
- {
- mfn_t sl1mfn = shadow_l2e_get_mfn(new_sl2e);
- ASSERT(mfn_to_page(sl1mfn)->u.sh.head);
-
- /* About to install a new reference */
- if ( !sh_get_ref(d, sl1mfn, paddr) )
- {
- domain_crash(d);
- return SHADOW_SET_ERROR;
- }
-#if (SHADOW_OPTIMIZATIONS & SHOPT_OUT_OF_SYNC)
- {
- struct page_info *sp = mfn_to_page(sl1mfn);
- mfn_t gl1mfn;
-
- ASSERT(sp->u.sh.head);
- gl1mfn = backpointer(sp);
- /* If the shadow is a fl1 then the backpointer contains
- the GFN instead of the GMFN, and it's definitely not
- OOS. */
- if ( (sp->u.sh.type != SH_type_fl1_shadow) && mfn_valid(gl1mfn)
- && mfn_is_out_of_sync(gl1mfn) )
- sh_resync(d, gl1mfn);
- }
-#endif
-#if GUEST_PAGING_LEVELS == 2
- /* Update the second entry to point tio the second half of the l1 */
- sl1mfn = sh_next_page(sl1mfn);
- pair[1] = shadow_l2e_from_mfn(sl1mfn, shadow_l2e_get_flags(new_sl2e));
-#endif
- }
-
- /* Write the new entry */
-#if GUEST_PAGING_LEVELS == 2
- shadow_write_entries(sl2e, &pair, 2, sl2mfn);
-#else /* normal case */
- shadow_write_entries(sl2e, &new_sl2e, 1, sl2mfn);
-#endif
- flags |= SHADOW_SET_CHANGED;
-
- if ( shadow_l2e_get_flags(old_sl2e) & _PAGE_PRESENT )
- {
- /* We lost a reference to an old mfn. */
- mfn_t osl1mfn = shadow_l2e_get_mfn(old_sl2e);
-
- if ( !mfn_eq(osl1mfn, shadow_l2e_get_mfn(new_sl2e)) ||
- !perms_strictly_increased(shadow_l2e_get_flags(old_sl2e),
- shadow_l2e_get_flags(new_sl2e)) )
- {
- flags |= SHADOW_SET_FLUSH;
- }
- sh_put_ref(d, osl1mfn, paddr);
- }
- return flags;
-}
-
-static int shadow_set_l1e(struct domain *d,
- shadow_l1e_t *sl1e,
- shadow_l1e_t new_sl1e,
- p2m_type_t new_type,
- mfn_t sl1mfn)
-{
- int flags = 0;
- shadow_l1e_t old_sl1e;
- unsigned int old_sl1f;
-#if SHADOW_OPTIMIZATIONS & SHOPT_OUT_OF_SYNC
- mfn_t new_gmfn = shadow_l1e_get_mfn(new_sl1e);
-#endif
- ASSERT(sl1e != NULL);
-
-#if SHADOW_OPTIMIZATIONS & SHOPT_OUT_OF_SYNC
- if ( mfn_valid(new_gmfn) && mfn_oos_may_write(new_gmfn)
- && ((shadow_l1e_get_flags(new_sl1e) & (_PAGE_RW|_PAGE_PRESENT))
- == (_PAGE_RW|_PAGE_PRESENT)) )
- oos_fixup_add(d, new_gmfn, sl1mfn, pgentry_ptr_to_slot(sl1e));
-#endif
-
- old_sl1e = *sl1e;
-
- if ( old_sl1e.l1 == new_sl1e.l1 ) return 0; /* Nothing to do */
-
- if ( (shadow_l1e_get_flags(new_sl1e) & _PAGE_PRESENT)
- && !sh_l1e_is_magic(new_sl1e) )
- {
- /* About to install a new reference */
- if ( shadow_mode_refcounts(d) )
- {
-#define PAGE_FLIPPABLE (_PAGE_RW | _PAGE_PWT | _PAGE_PCD | _PAGE_PAT)
- int rc;
-
- TRACE_SHADOW_PATH_FLAG(TRCE_SFLAG_SHADOW_L1_GET_REF);
- switch ( rc = shadow_get_page_from_l1e(new_sl1e, d, new_type) )
- {
- default:
- /* Doesn't look like a pagetable. */
- flags |= SHADOW_SET_ERROR;
- new_sl1e = shadow_l1e_empty();
- break;
- case PAGE_FLIPPABLE & -PAGE_FLIPPABLE ... PAGE_FLIPPABLE:
- ASSERT(!(rc & ~PAGE_FLIPPABLE));
- new_sl1e = shadow_l1e_flip_flags(new_sl1e, rc);
- /* fall through */
- case 0:
- shadow_vram_get_mfn(shadow_l1e_get_mfn(new_sl1e),
- shadow_l1e_get_flags(new_sl1e),
- sl1mfn, sl1e, d);
- break;
- }
-#undef PAGE_FLIPPABLE
- }
- }
-
- /* Write the new entry */
- shadow_write_entries(sl1e, &new_sl1e, 1, sl1mfn);
- flags |= SHADOW_SET_CHANGED;
-
- old_sl1f = shadow_l1e_get_flags(old_sl1e);
- if ( (old_sl1f & _PAGE_PRESENT) && !sh_l1e_is_magic(old_sl1e) &&
- shadow_mode_refcounts(d) )
- {
- /* We lost a reference to an old mfn. */
- /* N.B. Unlike higher-level sets, never need an extra flush
- * when writing an l1e. Because it points to the same guest frame
- * as the guest l1e did, it's the guest's responsibility to
- * trigger a flush later. */
- shadow_vram_put_mfn(shadow_l1e_get_mfn(old_sl1e), old_sl1f,
- sl1mfn, sl1e, d);
- shadow_put_page_from_l1e(old_sl1e, d);
- TRACE_SHADOW_PATH_FLAG(TRCE_SFLAG_SHADOW_L1_PUT_REF);
- }
- return flags;
-}
-
-
/**************************************************************************/
/* Macros to walk pagetables. These take the shadow of a pagetable and
* walk every "interesting" entry. That is, they don't touch Xen mappings,
--- /dev/null
+/******************************************************************************
+ * arch/x86/mm/shadow/set.c
+ *
+ * Simple, mostly-synchronous shadow page tables.
+ * Parts of this code are Copyright (c) 2006 by XenSource Inc.
+ * Parts of this code are Copyright (c) 2006 by Michael A Fetterman
+ * Parts based on earlier work by Michael A Fetterman, Ian Pratt et al.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define GUEST_PAGING_LEVELS 0
+
+#include <xen/sched.h>
+#include <xsm/xsm.h>
+#include <asm/shadow.h>
+#include "private.h"
+#include "types.h"
+
+/*
+ * These functions update shadow entries (and do bookkeeping on the shadow
+ * tables they are in). It is intended that they are the only
+ * functions which ever write (non-zero) data onto a shadow page.
+ */
+
+static inline void
+shadow_write_entries(void *d, const void *s, unsigned int entries, mfn_t mfn)
+/*
+ * This function does the actual writes to shadow pages.
+ * It must not be called directly, since it doesn't do the bookkeeping
+ * that shadow_set_l*e() functions do.
+ *
+ * Copy PTEs safely when processors might be running on the
+ * destination pagetable. This does *not* give safety against
+ * concurrent writes (that's what the paging lock is for), just
+ * stops the hardware picking up partially written entries.
+ */
+{
+ shadow_l1e_t *dst = d;
+ const shadow_l1e_t *src = s;
+ void *map = NULL;
+ unsigned int i = 0;
+
+ /*
+ * Because we mirror access rights at all levels in the shadow, an
+ * l2 (or higher) entry with the RW bit cleared will leave us with
+ * no write access through the linear map.
+ * We detect that by writing to the shadow with put_unsafe() and
+ * using map_domain_page() to get a writeable mapping if we need to.
+ */
+ if ( put_unsafe(*src, dst) )
+ {
+ perfc_incr(shadow_linear_map_failed);
+ map = map_domain_page(mfn);
+ dst = map + PAGE_OFFSET(dst);
+ }
+ else
+ {
+ ++src;
+ ++dst;
+ i = 1;
+ }
+
+ ASSERT(IS_ALIGNED((unsigned long)dst, sizeof(*dst)));
+
+ for ( ; i < entries; i++ )
+ write_atomic(&dst++->l1, src++->l1);
+
+ unmap_domain_page(map);
+}
+
+/*
+ * "type" is only used to distinguish grant map pages from ordinary RAM
+ * i.e. non-p2m_is_grant() pages are treated as p2m_ram_rw.
+ */
+static int inline
+shadow_get_page_from_l1e(shadow_l1e_t sl1e, struct domain *d, p2m_type_t type)
+{
+ int res;
+ mfn_t mfn;
+ struct domain *owner;
+
+ ASSERT(!sh_l1e_is_magic(sl1e));
+ ASSERT(shadow_mode_refcounts(d));
+
+ res = get_page_from_l1e(sl1e, d, d);
+
+ /*
+ * If a privileged domain is attempting to install a map of a page it does
+ * not own, we let it succeed anyway.
+ */
+ if ( unlikely(res < 0) &&
+ !shadow_mode_translate(d) &&
+ mfn_valid(mfn = shadow_l1e_get_mfn(sl1e)) &&
+ (owner = page_get_owner(mfn_to_page(mfn))) &&
+ (d != owner) )
+ {
+ res = xsm_priv_mapping(XSM_TARGET, d, owner);
+ if ( !res )
+ {
+ res = get_page_from_l1e(sl1e, d, owner);
+ SHADOW_PRINTK("privileged %pd installs map of mfn %"PRI_mfn" owned by %pd: %s\n",
+ d, mfn_x(mfn), owner,
+ res >= 0 ? "success" : "failed");
+ }
+ }
+
+ /* Okay, it might still be a grant mapping PTE. Try it. */
+ if ( unlikely(res < 0) &&
+ (type == p2m_grant_map_rw ||
+ (type == p2m_grant_map_ro &&
+ !(shadow_l1e_get_flags(sl1e) & _PAGE_RW))) )
+ {
+ /*
+ * It's a grant mapping. The grant table implementation will
+ * already have checked that we're supposed to have access, so
+ * we can just grab a reference directly.
+ */
+ mfn = shadow_l1e_get_mfn(sl1e);
+ if ( mfn_valid(mfn) )
+ res = get_page_from_l1e(sl1e, d, page_get_owner(mfn_to_page(mfn)));
+ }
+
+ if ( unlikely(res < 0) )
+ {
+ perfc_incr(shadow_get_page_fail);
+ SHADOW_PRINTK("failed: l1e=" SH_PRI_pte "\n");
+ }
+
+ return res;
+}
+
+int shadow_set_l4e(struct domain *d, shadow_l4e_t *sl4e,
+ shadow_l4e_t new_sl4e, mfn_t sl4mfn)
+{
+ int flags = 0;
+ shadow_l4e_t old_sl4e;
+ paddr_t paddr;
+
+ ASSERT(sl4e != NULL);
+ old_sl4e = *sl4e;
+
+ if ( old_sl4e.l4 == new_sl4e.l4 ) return 0; /* Nothing to do */
+
+ paddr = mfn_to_maddr(sl4mfn) | PAGE_OFFSET(sl4e);
+
+ if ( shadow_l4e_get_flags(new_sl4e) & _PAGE_PRESENT )
+ {
+ /* About to install a new reference */
+ mfn_t sl3mfn = shadow_l4e_get_mfn(new_sl4e);
+
+ if ( !sh_get_ref(d, sl3mfn, paddr) )
+ {
+ domain_crash(d);
+ return SHADOW_SET_ERROR;
+ }
+
+ /* Are we pinning l3 shadows to handle weird Linux behaviour? */
+ if ( sh_type_is_pinnable(d, SH_type_l3_64_shadow) )
+ sh_pin(d, sl3mfn);
+ }
+
+ /* Write the new entry */
+ shadow_write_entries(sl4e, &new_sl4e, 1, sl4mfn);
+ flush_root_pgtbl_domain(d);
+
+ flags |= SHADOW_SET_CHANGED;
+
+ if ( shadow_l4e_get_flags(old_sl4e) & _PAGE_PRESENT )
+ {
+ /* We lost a reference to an old mfn. */
+ mfn_t osl3mfn = shadow_l4e_get_mfn(old_sl4e);
+
+ if ( !mfn_eq(osl3mfn, shadow_l4e_get_mfn(new_sl4e)) ||
+ !perms_strictly_increased(shadow_l4e_get_flags(old_sl4e),
+ shadow_l4e_get_flags(new_sl4e)) )
+ flags |= SHADOW_SET_FLUSH;
+
+ sh_put_ref(d, osl3mfn, paddr);
+ }
+
+ return flags;
+}
+
+int shadow_set_l3e(struct domain *d, shadow_l3e_t *sl3e,
+ shadow_l3e_t new_sl3e, mfn_t sl3mfn)
+{
+ int flags = 0;
+ shadow_l3e_t old_sl3e;
+ paddr_t paddr;
+
+ ASSERT(sl3e != NULL);
+ old_sl3e = *sl3e;
+
+ if ( old_sl3e.l3 == new_sl3e.l3 ) return 0; /* Nothing to do */
+
+ paddr = mfn_to_maddr(sl3mfn) | PAGE_OFFSET(sl3e);
+
+ if ( shadow_l3e_get_flags(new_sl3e) & _PAGE_PRESENT )
+ {
+ /* About to install a new reference */
+ if ( !sh_get_ref(d, shadow_l3e_get_mfn(new_sl3e), paddr) )
+ {
+ domain_crash(d);
+ return SHADOW_SET_ERROR;
+ }
+ }
+
+ /* Write the new entry */
+ shadow_write_entries(sl3e, &new_sl3e, 1, sl3mfn);
+ flags |= SHADOW_SET_CHANGED;
+
+ if ( shadow_l3e_get_flags(old_sl3e) & _PAGE_PRESENT )
+ {
+ /* We lost a reference to an old mfn. */
+ mfn_t osl2mfn = shadow_l3e_get_mfn(old_sl3e);
+
+ if ( !mfn_eq(osl2mfn, shadow_l3e_get_mfn(new_sl3e)) ||
+ !perms_strictly_increased(shadow_l3e_get_flags(old_sl3e),
+ shadow_l3e_get_flags(new_sl3e)) )
+ flags |= SHADOW_SET_FLUSH;
+
+ sh_put_ref(d, osl2mfn, paddr);
+ }
+
+ return flags;
+}
+
+int shadow_set_l2e(struct domain *d, shadow_l2e_t *sl2e,
+ shadow_l2e_t new_sl2e, mfn_t sl2mfn,
+ unsigned int type_fl1_shadow,
+ mfn_t (*next_page)(mfn_t smfn))
+{
+ int flags = 0;
+ shadow_l2e_t old_sl2e;
+ paddr_t paddr;
+ /*
+ * In 2-on-3 we work with pairs of l2es pointing at two-page
+ * shadows. Reference counting and up-pointers track from the first
+ * page of the shadow to the first l2e, so make sure that we're
+ * working with those:
+ * Start with a pair of identical entries.
+ */
+ shadow_l2e_t pair[2] = { new_sl2e, new_sl2e };
+
+ if ( next_page )
+ {
+ /* Align the pointer down so it's pointing at the first of the pair */
+ sl2e = (shadow_l2e_t *)((unsigned long)sl2e & ~sizeof(shadow_l2e_t));
+ }
+
+ ASSERT(sl2e != NULL);
+ old_sl2e = *sl2e;
+
+ if ( old_sl2e.l2 == new_sl2e.l2 ) return 0; /* Nothing to do */
+
+ paddr = mfn_to_maddr(sl2mfn) | PAGE_OFFSET(sl2e);
+
+ if ( shadow_l2e_get_flags(new_sl2e) & _PAGE_PRESENT )
+ {
+ mfn_t sl1mfn = shadow_l2e_get_mfn(new_sl2e);
+ ASSERT(mfn_to_page(sl1mfn)->u.sh.head);
+
+ /* About to install a new reference */
+ if ( !sh_get_ref(d, sl1mfn, paddr) )
+ {
+ domain_crash(d);
+ return SHADOW_SET_ERROR;
+ }
+
+#if (SHADOW_OPTIMIZATIONS & SHOPT_OUT_OF_SYNC)
+ {
+ struct page_info *sp = mfn_to_page(sl1mfn);
+ mfn_t gl1mfn;
+
+ ASSERT(sp->u.sh.head);
+ gl1mfn = backpointer(sp);
+ /*
+ * If the shadow is a fl1 then the backpointer contains the
+ * GFN instead of the GMFN, and it's definitely not OOS.
+ */
+ if ( (sp->u.sh.type != type_fl1_shadow) && mfn_valid(gl1mfn)
+ && mfn_is_out_of_sync(gl1mfn) )
+ sh_resync(d, gl1mfn);
+ }
+#endif
+
+ if ( next_page )
+ {
+ /* Update the second entry to point to the second half of the l1 */
+ sl1mfn = next_page(sl1mfn);
+ pair[1] = shadow_l2e_from_mfn(sl1mfn,
+ shadow_l2e_get_flags(new_sl2e));
+ }
+ }
+
+ /* Write the new entry / entries */
+ shadow_write_entries(sl2e, &pair, !next_page ? 1 : 2, sl2mfn);
+
+ flags |= SHADOW_SET_CHANGED;
+
+ if ( shadow_l2e_get_flags(old_sl2e) & _PAGE_PRESENT )
+ {
+ /* We lost a reference to an old mfn. */
+ mfn_t osl1mfn = shadow_l2e_get_mfn(old_sl2e);
+
+ if ( !mfn_eq(osl1mfn, shadow_l2e_get_mfn(new_sl2e)) ||
+ !perms_strictly_increased(shadow_l2e_get_flags(old_sl2e),
+ shadow_l2e_get_flags(new_sl2e)) )
+ flags |= SHADOW_SET_FLUSH;
+
+ sh_put_ref(d, osl1mfn, paddr);
+ }
+
+ return flags;
+}
+
+int shadow_set_l1e(struct domain *d, shadow_l1e_t *sl1e,
+ shadow_l1e_t new_sl1e, p2m_type_t new_type,
+ mfn_t sl1mfn)
+{
+ int flags = 0;
+ shadow_l1e_t old_sl1e;
+ unsigned int old_sl1f;
+#if SHADOW_OPTIMIZATIONS & SHOPT_OUT_OF_SYNC
+ mfn_t new_gmfn = shadow_l1e_get_mfn(new_sl1e);
+#endif
+
+ ASSERT(sl1e != NULL);
+
+#if SHADOW_OPTIMIZATIONS & SHOPT_OUT_OF_SYNC
+ if ( mfn_valid(new_gmfn) && mfn_oos_may_write(new_gmfn) &&
+ ((shadow_l1e_get_flags(new_sl1e) & (_PAGE_RW | _PAGE_PRESENT)) ==
+ (_PAGE_RW | _PAGE_PRESENT)) )
+ oos_fixup_add(d, new_gmfn, sl1mfn, pgentry_ptr_to_slot(sl1e));
+#endif
+
+ old_sl1e = *sl1e;
+
+ if ( old_sl1e.l1 == new_sl1e.l1 ) return 0; /* Nothing to do */
+
+ if ( (shadow_l1e_get_flags(new_sl1e) & _PAGE_PRESENT) &&
+ !sh_l1e_is_magic(new_sl1e) )
+ {
+ /* About to install a new reference */
+ if ( shadow_mode_refcounts(d) )
+ {
+#define PAGE_FLIPPABLE (_PAGE_RW | _PAGE_PWT | _PAGE_PCD | _PAGE_PAT)
+ int rc;
+
+ TRACE_SHADOW_PATH_FLAG(TRCE_SFLAG_SHADOW_L1_GET_REF);
+ switch ( rc = shadow_get_page_from_l1e(new_sl1e, d, new_type) )
+ {
+ default:
+ /* Doesn't look like a pagetable. */
+ flags |= SHADOW_SET_ERROR;
+ new_sl1e = shadow_l1e_empty();
+ break;
+ case PAGE_FLIPPABLE & -PAGE_FLIPPABLE ... PAGE_FLIPPABLE:
+ ASSERT(!(rc & ~PAGE_FLIPPABLE));
+ new_sl1e = shadow_l1e_flip_flags(new_sl1e, rc);
+ /* fall through */
+ case 0:
+ shadow_vram_get_mfn(shadow_l1e_get_mfn(new_sl1e),
+ shadow_l1e_get_flags(new_sl1e),
+ sl1mfn, sl1e, d);
+ break;
+ }
+#undef PAGE_FLIPPABLE
+ }
+ }
+
+ /* Write the new entry */
+ shadow_write_entries(sl1e, &new_sl1e, 1, sl1mfn);
+ flags |= SHADOW_SET_CHANGED;
+
+ old_sl1f = shadow_l1e_get_flags(old_sl1e);
+ if ( (old_sl1f & _PAGE_PRESENT) && !sh_l1e_is_magic(old_sl1e) &&
+ shadow_mode_refcounts(d) )
+ {
+ /*
+ * We lost a reference to an old mfn.
+ *
+ * N.B. Unlike higher-level sets, never need an extra flush when
+ * writing an l1e. Because it points to the same guest frame as the
+ * guest l1e did, it's the guest's responsibility to trigger a flush
+ * later.
+ */
+ shadow_vram_put_mfn(shadow_l1e_get_mfn(old_sl1e), old_sl1f,
+ sl1mfn, sl1e, d);
+ shadow_put_page_from_l1e(old_sl1e, d);
+ TRACE_SHADOW_PATH_FLAG(TRCE_SFLAG_SHADOW_L1_PUT_REF);
+ }
+
+ return flags;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
/* The number of levels in the shadow pagetable is entirely determined
* by the number of levels in the guest pagetable */
-#if GUEST_PAGING_LEVELS == 4
-#define SHADOW_PAGING_LEVELS 4
+#if GUEST_PAGING_LEVELS != 2
+#define SHADOW_PAGING_LEVELS GUEST_PAGING_LEVELS
#else
#define SHADOW_PAGING_LEVELS 3
#endif
#define SHADOW_L1_PAGETABLE_SHIFT 12
#define SHADOW_L2_PAGETABLE_SHIFT 21
#define SHADOW_L3_PAGETABLE_SHIFT 30
-#else /* SHADOW_PAGING_LEVELS == 4 */
+#elif SHADOW_PAGING_LEVELS == 4
#define SHADOW_L1_PAGETABLE_ENTRIES 512
#define SHADOW_L2_PAGETABLE_ENTRIES 512
#define SHADOW_L3_PAGETABLE_ENTRIES 512
typedef l1_pgentry_t shadow_l1e_t;
typedef l2_pgentry_t shadow_l2e_t;
typedef l3_pgentry_t shadow_l3e_t;
-#if SHADOW_PAGING_LEVELS >= 4
typedef l4_pgentry_t shadow_l4e_t;
-#endif
/* Access functions for them */
static inline paddr_t shadow_l1e_get_paddr(shadow_l1e_t sl1e)
{ return l2e_get_paddr(sl2e); }
static inline paddr_t shadow_l3e_get_paddr(shadow_l3e_t sl3e)
{ return l3e_get_paddr(sl3e); }
-#if SHADOW_PAGING_LEVELS >= 4
static inline paddr_t shadow_l4e_get_paddr(shadow_l4e_t sl4e)
{ return l4e_get_paddr(sl4e); }
-#endif
static inline mfn_t shadow_l1e_get_mfn(shadow_l1e_t sl1e)
{ return l1e_get_mfn(sl1e); }
{ return l2e_get_mfn(sl2e); }
static inline mfn_t shadow_l3e_get_mfn(shadow_l3e_t sl3e)
{ return l3e_get_mfn(sl3e); }
-#if SHADOW_PAGING_LEVELS >= 4
static inline mfn_t shadow_l4e_get_mfn(shadow_l4e_t sl4e)
{ return l4e_get_mfn(sl4e); }
-#endif
static inline u32 shadow_l1e_get_flags(shadow_l1e_t sl1e)
{ return l1e_get_flags(sl1e); }
{ return l2e_get_flags(sl2e); }
static inline u32 shadow_l3e_get_flags(shadow_l3e_t sl3e)
{ return l3e_get_flags(sl3e); }
-#if SHADOW_PAGING_LEVELS >= 4
static inline u32 shadow_l4e_get_flags(shadow_l4e_t sl4e)
{ return l4e_get_flags(sl4e); }
-#endif
static inline shadow_l1e_t
shadow_l1e_remove_flags(shadow_l1e_t sl1e, u32 flags)
{ return l2e_empty(); }
static inline shadow_l3e_t shadow_l3e_empty(void)
{ return l3e_empty(); }
-#if SHADOW_PAGING_LEVELS >= 4
static inline shadow_l4e_t shadow_l4e_empty(void)
{ return l4e_empty(); }
-#endif
static inline shadow_l1e_t shadow_l1e_from_mfn(mfn_t mfn, u32 flags)
{ return l1e_from_mfn(mfn, flags); }
{ return l2e_from_mfn(mfn, flags); }
static inline shadow_l3e_t shadow_l3e_from_mfn(mfn_t mfn, u32 flags)
{ return l3e_from_mfn(mfn, flags); }
-#if SHADOW_PAGING_LEVELS >= 4
static inline shadow_l4e_t shadow_l4e_from_mfn(mfn_t mfn, u32 flags)
{ return l4e_from_mfn(mfn, flags); }
-#endif
#define shadow_l1_table_offset(a) l1_table_offset(a)
#define shadow_l2_table_offset(a) l2_table_offset(a)
#define SH_type_fl1_shadow SH_type_fl1_pae_shadow
#define SH_type_l2_shadow SH_type_l2_pae_shadow
#define SH_type_l2h_shadow SH_type_l2h_pae_shadow
-#else
+#elif GUEST_PAGING_LEVELS == 4
#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_l4_shadow SH_type_l4_64_shadow
#endif
+#if GUEST_PAGING_LEVELS
+
/* macros for dealing with the naming of the internal function names of the
* shadow code's external entry points.
*/
#define sh_rm_write_access_from_sl1p INTERNAL_NAME(sh_rm_write_access_from_sl1p)
#endif
+#endif /* GUEST_PAGING_LEVELS */
+
#if SHADOW_PAGING_LEVELS == 3
#define MFN_FITS_IN_HVM_CR3(_MFN) !(mfn_x(_MFN) >> 20)
#endif
#define SH_PRI_gpte PRI_gpte
#define SH_PRI_gfn PRI_gfn
+int shadow_set_l1e(struct domain *d, shadow_l1e_t *sl1e,
+ shadow_l1e_t new_sl1e, p2m_type_t new_type,
+ mfn_t sl1mfn);
+int shadow_set_l2e(struct domain *d, shadow_l2e_t *sl2e,
+ shadow_l2e_t new_sl2e, mfn_t sl2mfn,
+ unsigned int type_fl1_shadow,
+ mfn_t (*next_page)(mfn_t smfn));
+int shadow_set_l3e(struct domain *d, shadow_l3e_t *sl3e,
+ shadow_l3e_t new_sl3e, mfn_t sl3mfn);
+int shadow_set_l4e(struct domain *d, shadow_l4e_t *sl4e,
+ shadow_l4e_t new_sl4e, mfn_t sl4mfn);
+
+static void inline
+shadow_put_page_from_l1e(shadow_l1e_t sl1e, struct domain *d)
+{
+ if ( !shadow_mode_refcounts(d) )
+ return;
+
+ put_page_from_l1e(sl1e, d);
+}
#if (SHADOW_OPTIMIZATIONS & SHOPT_FAST_FAULT_PATH)
/******************************************************************************