xen/arm: p2m: Introduce p2m_is_valid and use it

The LPAE format allows to store information in an entry even with the
valid bit unset. In a follow-up patch, we will take advantage of this
feature to re-purpose the valid bit for generating a translation fault
even if an entry contains valid information.

So we need a different way to know whether an entry contains valid
information. It is possible to use the information hold in the p2m_type
to know for that purpose. Indeed all entries containing valid
information will have a valid p2m type (i.e p2m_type != p2m_invalid).

This patch introduces a new helper p2m_is_valid, which implements that
idea, and replace most of lpae_is_valid call with the new helper. The ones
remaining are for TLBs handling and entries accounting.

With the renaming there are 2 others changes required:
    - Generate table entry with a valid p2m type
    - Detect new mapping for proper stats accounting

Signed-off-by: Julien Grall <julien.grall@arm.com>
Reviewed-by: Stefano Stabellini <sstabellini@kernel.org>
This commit is contained in:
Julien Grall committed 2018-12-12 15:49:47 +00:00
1 parent 202784f2d2
commit 2a654d3129
1 file changed
+22 -10
+22 -10
View File
@@ -211,18 +211,27 @@ static p2m_access_t p2m_mem_access_radix_get(struct p2m_domain *p2m, gfn_t gfn)
return radix_tree_ptr_to_int(ptr);
}
/*
* In the case of the P2M, the valid bit is used for other purpose. Use
* the type to check whether an entry is valid.
*/
static inline bool p2m_is_valid(lpae_t pte)
{
return pte.p2m.type != p2m_invalid;
}
/*
* lpae_is_* helpers don't check whether the valid bit is set in the
* PTE. Provide our own overlay to check the valid bit.
*/
static inline bool p2m_is_mapping(lpae_t pte, unsigned int level)
{
return lpae_is_valid(pte) && lpae_is_mapping(pte, level);
return p2m_is_valid(pte) && lpae_is_mapping(pte, level);
}
static inline bool p2m_is_superpage(lpae_t pte, unsigned int level)
{
return lpae_is_valid(pte) && lpae_is_superpage(pte, level);
return p2m_is_valid(pte) && lpae_is_superpage(pte, level);
}
#define GUEST_TABLE_MAP_FAILED 0
@@ -256,7 +265,7 @@ static int p2m_next_level(struct p2m_domain *p2m, bool read_only,
entry = *table + offset;
if ( !lpae_is_valid(*entry) )
if ( !p2m_is_valid(*entry) )
{
if ( read_only )
return GUEST_TABLE_MAP_FAILED;
@@ -348,7 +357,7 @@ mfn_t p2m_get_entry(struct p2m_domain *p2m, gfn_t gfn,
entry = table[offsets[level]];
if ( lpae_is_valid(entry) )
if ( p2m_is_valid(entry) )
{
*t = entry.p2m.type;
@@ -536,8 +545,11 @@ static lpae_t page_to_p2m_table(struct page_info *page)
/*
* The access value does not matter because the hardware will ignore
* the permission fields for table entry.
*
* We use p2m_ram_rw so the entry has a valid type. This is important
* for p2m_is_valid() to return valid on table entries.
*/
return mfn_to_p2m_entry(page_to_mfn(page), p2m_invalid, p2m_access_rwx);
return mfn_to_p2m_entry(page_to_mfn(page), p2m_ram_rw, p2m_access_rwx);
}
static inline void p2m_write_pte(lpae_t *p, lpae_t pte, bool clean_pte)
@@ -561,7 +573,7 @@ static int p2m_create_table(struct p2m_domain *p2m, lpae_t *entry)
struct page_info *page;
lpae_t *p;
ASSERT(!lpae_is_valid(*entry));
ASSERT(!p2m_is_valid(*entry));
page = alloc_domheap_page(NULL, 0);
if ( page == NULL )
@@ -618,7 +630,7 @@ static int p2m_mem_access_radix_set(struct p2m_domain *p2m, gfn_t gfn,
*/
static void p2m_put_l3_page(const lpae_t pte)
{
ASSERT(lpae_is_valid(pte));
ASSERT(p2m_is_valid(pte));
/*
* TODO: Handle other p2m types
@@ -646,7 +658,7 @@ static void p2m_free_entry(struct p2m_domain *p2m,
struct page_info *pg;
/* Nothing to do if the entry is invalid. */
if ( !lpae_is_valid(entry) )
if ( !p2m_is_valid(entry) )
return;
/* Nothing to do but updating the stats if the entry is a super-page. */
@@ -943,7 +955,7 @@ static int __p2m_set_entry(struct p2m_domain *p2m,
else
p2m->need_flush = true;
}
else /* new mapping */
else if ( !p2m_is_valid(orig_pte) ) /* new mapping */
p2m->stats.mappings[level]++;
p2m_write_pte(entry, pte, p2m->clean_pte);
@@ -957,7 +969,7 @@ static int __p2m_set_entry(struct p2m_domain *p2m,
* Free the entry only if the original pte was valid and the base
* is different (to avoid freeing when permission is changed).
*/
if ( lpae_is_valid(orig_pte) &&
if ( p2m_is_valid(orig_pte) &&
!mfn_eq(lpae_get_mfn(*entry), lpae_get_mfn(orig_pte)) )
p2m_free_entry(p2m, orig_pte, level);
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.