mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 18:50:05 +01:00
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:
1 parent
202784f2d2
commit
2a654d3129
1 file changed
+22
-10
+22
-10
@@ -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);
|
||||
|
||||
|
||||