x86/shadow: refactor shadow_vram_{get,put}_l1e()

By passing the functions an MFN and flags, only a single instance of
each is needed; they were pretty large for being inline functions
anyway.

While moving the code, also adjust coding style and add const where
sensible / possible.

Signed-off-by: Jan Beulich <jbeulich@suse.com>
Acked-by: Roger Pau Monné <roger.pau@citrix.com>
Acked-by: Tim Deegan <tim@xen.org>
This commit is contained in:
Jan Beulich committed 2020-10-30 14:25:42 +01:00
1 parent 6e2ee3dfd6
commit 8ac7e452a6
3 files changed
+123 -113

No files matched your search

+98
View File
@@ -903,6 +903,104 @@ int shadow_track_dirty_vram(struct domain *d,
return rc;
}
void shadow_vram_get_mfn(mfn_t mfn, unsigned int l1f,
mfn_t sl1mfn, const void *sl1e,
const struct domain *d)
{
unsigned long gfn;
struct sh_dirty_vram *dirty_vram = d->arch.hvm.dirty_vram;
ASSERT(is_hvm_domain(d));
if ( !dirty_vram /* tracking disabled? */ ||
!(l1f & _PAGE_RW) /* read-only mapping? */ ||
!mfn_valid(mfn) /* mfn can be invalid in mmio_direct */)
return;
gfn = gfn_x(mfn_to_gfn(d, mfn));
/* Page sharing not supported on shadow PTs */
BUG_ON(SHARED_M2P(gfn));
if ( (gfn >= dirty_vram->begin_pfn) && (gfn < dirty_vram->end_pfn) )
{
unsigned long i = gfn - dirty_vram->begin_pfn;
const struct page_info *page = mfn_to_page(mfn);
if ( (page->u.inuse.type_info & PGT_count_mask) == 1 )
/* Initial guest reference, record it */
dirty_vram->sl1ma[i] = mfn_to_maddr(sl1mfn) |
PAGE_OFFSET(sl1e);
}
}
void shadow_vram_put_mfn(mfn_t mfn, unsigned int l1f,
mfn_t sl1mfn, const void *sl1e,
const struct domain *d)
{
unsigned long gfn;
struct sh_dirty_vram *dirty_vram = d->arch.hvm.dirty_vram;
ASSERT(is_hvm_domain(d));
if ( !dirty_vram /* tracking disabled? */ ||
!(l1f & _PAGE_RW) /* read-only mapping? */ ||
!mfn_valid(mfn) /* mfn can be invalid in mmio_direct */)
return;
gfn = gfn_x(mfn_to_gfn(d, mfn));
/* Page sharing not supported on shadow PTs */
BUG_ON(SHARED_M2P(gfn));
if ( (gfn >= dirty_vram->begin_pfn) && (gfn < dirty_vram->end_pfn) )
{
unsigned long i = gfn - dirty_vram->begin_pfn;
const struct page_info *page = mfn_to_page(mfn);
bool dirty = false;
paddr_t sl1ma = mfn_to_maddr(sl1mfn) | PAGE_OFFSET(sl1e);
if ( (page->u.inuse.type_info & PGT_count_mask) == 1 )
{
/* Last reference */
if ( dirty_vram->sl1ma[i] == INVALID_PADDR )
{
/* We didn't know it was that one, let's say it is dirty */
dirty = true;
}
else
{
ASSERT(dirty_vram->sl1ma[i] == sl1ma);
dirty_vram->sl1ma[i] = INVALID_PADDR;
if ( l1f & _PAGE_DIRTY )
dirty = true;
}
}
else
{
/* We had more than one reference, just consider the page dirty. */
dirty = true;
/* Check that it's not the one we recorded. */
if ( dirty_vram->sl1ma[i] == sl1ma )
{
/* Too bad, we remembered the wrong one... */
dirty_vram->sl1ma[i] = INVALID_PADDR;
}
else
{
/*
* Ok, our recorded sl1e is still pointing to this page, let's
* just hope it will remain.
*/
}
}
if ( dirty )
{
dirty_vram->dirty_bitmap[i / 8] |= 1 << (i % 8);
dirty_vram->last_dirty = NOW();
}
}
}
/*
* Local variables:
* mode: C
+17 -113
View File
@@ -1047,107 +1047,6 @@ static int shadow_set_l2e(struct domain *d,
return flags;
}
static inline void shadow_vram_get_l1e(shadow_l1e_t new_sl1e,
shadow_l1e_t *sl1e,
mfn_t sl1mfn,
struct domain *d)
{
#ifdef CONFIG_HVM
mfn_t mfn = shadow_l1e_get_mfn(new_sl1e);
int flags = shadow_l1e_get_flags(new_sl1e);
unsigned long gfn;
struct sh_dirty_vram *dirty_vram = d->arch.hvm.dirty_vram;
if ( !is_hvm_domain(d) || !dirty_vram /* tracking disabled? */
|| !(flags & _PAGE_RW) /* read-only mapping? */
|| !mfn_valid(mfn) ) /* mfn can be invalid in mmio_direct */
return;
gfn = gfn_x(mfn_to_gfn(d, mfn));
/* Page sharing not supported on shadow PTs */
BUG_ON(SHARED_M2P(gfn));
if ( (gfn >= dirty_vram->begin_pfn) && (gfn < dirty_vram->end_pfn) )
{
unsigned long i = gfn - dirty_vram->begin_pfn;
struct page_info *page = mfn_to_page(mfn);
if ( (page->u.inuse.type_info & PGT_count_mask) == 1 )
/* Initial guest reference, record it */
dirty_vram->sl1ma[i] = mfn_to_maddr(sl1mfn)
| ((unsigned long)sl1e & ~PAGE_MASK);
}
#endif
}
static inline void shadow_vram_put_l1e(shadow_l1e_t old_sl1e,
shadow_l1e_t *sl1e,
mfn_t sl1mfn,
struct domain *d)
{
#ifdef CONFIG_HVM
mfn_t mfn = shadow_l1e_get_mfn(old_sl1e);
int flags = shadow_l1e_get_flags(old_sl1e);
unsigned long gfn;
struct sh_dirty_vram *dirty_vram = d->arch.hvm.dirty_vram;
if ( !is_hvm_domain(d) || !dirty_vram /* tracking disabled? */
|| !(flags & _PAGE_RW) /* read-only mapping? */
|| !mfn_valid(mfn) ) /* mfn can be invalid in mmio_direct */
return;
gfn = gfn_x(mfn_to_gfn(d, mfn));
/* Page sharing not supported on shadow PTs */
BUG_ON(SHARED_M2P(gfn));
if ( (gfn >= dirty_vram->begin_pfn) && (gfn < dirty_vram->end_pfn) )
{
unsigned long i = gfn - dirty_vram->begin_pfn;
struct page_info *page = mfn_to_page(mfn);
int dirty = 0;
paddr_t sl1ma = mfn_to_maddr(sl1mfn)
| ((unsigned long)sl1e & ~PAGE_MASK);
if ( (page->u.inuse.type_info & PGT_count_mask) == 1 )
{
/* Last reference */
if ( dirty_vram->sl1ma[i] == INVALID_PADDR ) {
/* We didn't know it was that one, let's say it is dirty */
dirty = 1;
}
else
{
ASSERT(dirty_vram->sl1ma[i] == sl1ma);
dirty_vram->sl1ma[i] = INVALID_PADDR;
if ( flags & _PAGE_DIRTY )
dirty = 1;
}
}
else
{
/* We had more than one reference, just consider the page dirty. */
dirty = 1;
/* Check that it's not the one we recorded. */
if ( dirty_vram->sl1ma[i] == sl1ma )
{
/* Too bad, we remembered the wrong one... */
dirty_vram->sl1ma[i] = INVALID_PADDR;
}
else
{
/* Ok, our recorded sl1e is still pointing to this page, let's
* just hope it will remain. */
}
}
if ( dirty )
{
dirty_vram->dirty_bitmap[i / 8] |= 1 << (i % 8);
dirty_vram->last_dirty = NOW();
}
}
#endif
}
static int shadow_set_l1e(struct domain *d,
shadow_l1e_t *sl1e,
shadow_l1e_t new_sl1e,
@@ -1156,6 +1055,7 @@ static int shadow_set_l1e(struct domain *d,
{
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
@@ -1194,7 +1094,9 @@ static int shadow_set_l1e(struct domain *d,
new_sl1e = shadow_l1e_flip_flags(new_sl1e, rc);
/* fall through */
case 0:
shadow_vram_get_l1e(new_sl1e, sl1e, sl1mfn, d);
shadow_vram_get_mfn(shadow_l1e_get_mfn(new_sl1e),
shadow_l1e_get_flags(new_sl1e),
sl1mfn, sl1e, d);
break;
}
#undef PAGE_FLIPPABLE
@@ -1205,20 +1107,19 @@ static int shadow_set_l1e(struct domain *d,
shadow_write_entries(sl1e, &new_sl1e, 1, sl1mfn);
flags |= SHADOW_SET_CHANGED;
if ( (shadow_l1e_get_flags(old_sl1e) & _PAGE_PRESENT)
&& !sh_l1e_is_magic(old_sl1e) )
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. */
if ( shadow_mode_refcounts(d) )
{
shadow_vram_put_l1e(old_sl1e, sl1e, sl1mfn, d);
shadow_put_page_from_l1e(old_sl1e, d);
TRACE_SHADOW_PATH_FLAG(TRCE_SFLAG_SHADOW_L1_PUT_REF);
}
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;
}
@@ -1944,9 +1845,12 @@ void sh_destroy_l1_shadow(struct domain *d, mfn_t smfn)
/* Decrement refcounts of all the old entries */
mfn_t sl1mfn = smfn;
SHADOW_FOREACH_L1E(sl1mfn, sl1e, 0, 0, {
if ( (shadow_l1e_get_flags(*sl1e) & _PAGE_PRESENT)
&& !sh_l1e_is_magic(*sl1e) ) {
shadow_vram_put_l1e(*sl1e, sl1e, sl1mfn, d);
unsigned int sl1f = shadow_l1e_get_flags(*sl1e);
if ( (sl1f & _PAGE_PRESENT) && !sh_l1e_is_magic(*sl1e) )
{
shadow_vram_put_mfn(shadow_l1e_get_mfn(*sl1e), sl1f,
sl1mfn, sl1e, d);
shadow_put_page_from_l1e(*sl1e, d);
}
});
+8
View File
@@ -410,6 +410,14 @@ void shadow_update_paging_modes(struct vcpu *v);
* With user_only == 1, unhooks only the user-mode mappings. */
void shadow_unhook_mappings(struct domain *d, mfn_t smfn, int user_only);
/* VRAM dirty tracking helpers. */
void shadow_vram_get_mfn(mfn_t mfn, unsigned int l1f,
mfn_t sl1mfn, const void *sl1e,
const struct domain *d);
void shadow_vram_put_mfn(mfn_t mfn, unsigned int l1f,
mfn_t sl1mfn, const void *sl1e,
const struct domain *d);
#if (SHADOW_OPTIMIZATIONS & SHOPT_OUT_OF_SYNC)
/* Allow a shadowed page to go out of sync */
int sh_unsync(struct vcpu *v, mfn_t gmfn);
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.