hv: nested: Introduce shadow EPT release function

When a shadow EPT is not used anymore, its resources need to be
released.

free_sept_table() is introduced to walk the whole shadow EPT table and
free the pagetable pages.

Please note, the PML4E page of shadow EPT is not freed by
free_sept_table() as it still be used to present a shadow EPT pointer.

Tracked-On: #5923
Signed-off-by: Shuo A Liu <shuo.a.liu@intel.com>
Reviewed-by: Jason Chen CJ <jason.cj.chen@intel.com>
Acked-by: Eddie Dong <eddie.dong@intel.com>
This commit is contained in:
Shuo A Liu 2021-05-28 18:58:13 +08:00 committed by wenlingz
parent 8c2eea94b8
commit bc4dca179a

View File

@ -59,6 +59,42 @@ static bool is_leaf_ept_entry(uint64_t ept_entry, enum _page_table_level pt_leve
return (((ept_entry & PAGE_PSE) != 0U) || (pt_level == IA32E_PT));
}
/*
* @brief Release all pages except the PML4E page of a shadow EPT
*/
static void free_sept_table(uint64_t *shadow_eptp)
{
uint64_t *shadow_pml4e, *shadow_pdpte, *shadow_pde;
uint64_t i, j, k;
if (shadow_eptp) {
for (i = 0UL; i < PTRS_PER_PML4E; i++) {
shadow_pml4e = pml4e_offset(shadow_eptp, i << PML4E_SHIFT);
if (!is_present_ept_entry(*shadow_pml4e)) {
continue;
}
for (j = 0UL; j < PTRS_PER_PDPTE; j++) {
shadow_pdpte = pdpte_offset(shadow_pml4e, j << PDPTE_SHIFT);
if (!is_present_ept_entry(*shadow_pdpte) ||
is_leaf_ept_entry(*shadow_pdpte, IA32E_PDPT)) {
continue;
}
for (k = 0UL; k < PTRS_PER_PDE; k++) {
shadow_pde = pde_offset(shadow_pdpte, k << PDE_SHIFT);
if (!is_present_ept_entry(*shadow_pde) ||
is_leaf_ept_entry(*shadow_pde, IA32E_PD)) {
continue;
}
free_page(&sept_page_pool, (struct page *)((*shadow_pde) & EPT_ENTRY_PFN_MASK));
}
free_page(&sept_page_pool, (struct page *)((*shadow_pdpte) & EPT_ENTRY_PFN_MASK));
}
free_page(&sept_page_pool, (struct page *)((*shadow_pml4e) & EPT_ENTRY_PFN_MASK));
*shadow_pml4e = 0UL;
}
}
}
/*
* @brief Convert a guest EPTP to the associated nept_desc.
* @return struct nept_desc * if existed.
@ -159,6 +195,7 @@ void put_nept_desc(uint64_t guest_eptp)
if (desc->ref_count == 0UL) {
dev_dbg(VETP_LOG_LEVEL, "[%s], nept_desc[%llx] ref[%d] shadow_eptp[%llx] guest_eptp[%llx]",
__func__, desc, desc->ref_count, desc->shadow_eptp, desc->guest_eptp);
free_sept_table((void *)(desc->shadow_eptp & PAGE_MASK));
free_page(&sept_page_pool, (struct page *)(desc->shadow_eptp & PAGE_MASK));
/* Flush the hardware TLB */
invept((void *)(desc->shadow_eptp & PAGE_MASK));