162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include "mmu_internal.h" 562306a36Sopenharmony_ci#include "tdp_iter.h" 662306a36Sopenharmony_ci#include "spte.h" 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci/* 962306a36Sopenharmony_ci * Recalculates the pointer to the SPTE for the current GFN and level and 1062306a36Sopenharmony_ci * reread the SPTE. 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_cistatic void tdp_iter_refresh_sptep(struct tdp_iter *iter) 1362306a36Sopenharmony_ci{ 1462306a36Sopenharmony_ci iter->sptep = iter->pt_path[iter->level - 1] + 1562306a36Sopenharmony_ci SPTE_INDEX(iter->gfn << PAGE_SHIFT, iter->level); 1662306a36Sopenharmony_ci iter->old_spte = kvm_tdp_mmu_read_spte(iter->sptep); 1762306a36Sopenharmony_ci} 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci/* 2062306a36Sopenharmony_ci * Return the TDP iterator to the root PT and allow it to continue its 2162306a36Sopenharmony_ci * traversal over the paging structure from there. 2262306a36Sopenharmony_ci */ 2362306a36Sopenharmony_civoid tdp_iter_restart(struct tdp_iter *iter) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci iter->yielded = false; 2662306a36Sopenharmony_ci iter->yielded_gfn = iter->next_last_level_gfn; 2762306a36Sopenharmony_ci iter->level = iter->root_level; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci iter->gfn = gfn_round_for_level(iter->next_last_level_gfn, iter->level); 3062306a36Sopenharmony_ci tdp_iter_refresh_sptep(iter); 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci iter->valid = true; 3362306a36Sopenharmony_ci} 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci/* 3662306a36Sopenharmony_ci * Sets a TDP iterator to walk a pre-order traversal of the paging structure 3762306a36Sopenharmony_ci * rooted at root_pt, starting with the walk to translate next_last_level_gfn. 3862306a36Sopenharmony_ci */ 3962306a36Sopenharmony_civoid tdp_iter_start(struct tdp_iter *iter, struct kvm_mmu_page *root, 4062306a36Sopenharmony_ci int min_level, gfn_t next_last_level_gfn) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci if (WARN_ON_ONCE(!root || (root->role.level < 1) || 4362306a36Sopenharmony_ci (root->role.level > PT64_ROOT_MAX_LEVEL))) { 4462306a36Sopenharmony_ci iter->valid = false; 4562306a36Sopenharmony_ci return; 4662306a36Sopenharmony_ci } 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci iter->next_last_level_gfn = next_last_level_gfn; 4962306a36Sopenharmony_ci iter->root_level = root->role.level; 5062306a36Sopenharmony_ci iter->min_level = min_level; 5162306a36Sopenharmony_ci iter->pt_path[iter->root_level - 1] = (tdp_ptep_t)root->spt; 5262306a36Sopenharmony_ci iter->as_id = kvm_mmu_page_as_id(root); 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci tdp_iter_restart(iter); 5562306a36Sopenharmony_ci} 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci/* 5862306a36Sopenharmony_ci * Given an SPTE and its level, returns a pointer containing the host virtual 5962306a36Sopenharmony_ci * address of the child page table referenced by the SPTE. Returns null if 6062306a36Sopenharmony_ci * there is no such entry. 6162306a36Sopenharmony_ci */ 6262306a36Sopenharmony_citdp_ptep_t spte_to_child_pt(u64 spte, int level) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci /* 6562306a36Sopenharmony_ci * There's no child entry if this entry isn't present or is a 6662306a36Sopenharmony_ci * last-level entry. 6762306a36Sopenharmony_ci */ 6862306a36Sopenharmony_ci if (!is_shadow_present_pte(spte) || is_last_spte(spte, level)) 6962306a36Sopenharmony_ci return NULL; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci return (tdp_ptep_t)__va(spte_to_pfn(spte) << PAGE_SHIFT); 7262306a36Sopenharmony_ci} 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci/* 7562306a36Sopenharmony_ci * Steps down one level in the paging structure towards the goal GFN. Returns 7662306a36Sopenharmony_ci * true if the iterator was able to step down a level, false otherwise. 7762306a36Sopenharmony_ci */ 7862306a36Sopenharmony_cistatic bool try_step_down(struct tdp_iter *iter) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci tdp_ptep_t child_pt; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci if (iter->level == iter->min_level) 8362306a36Sopenharmony_ci return false; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci /* 8662306a36Sopenharmony_ci * Reread the SPTE before stepping down to avoid traversing into page 8762306a36Sopenharmony_ci * tables that are no longer linked from this entry. 8862306a36Sopenharmony_ci */ 8962306a36Sopenharmony_ci iter->old_spte = kvm_tdp_mmu_read_spte(iter->sptep); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci child_pt = spte_to_child_pt(iter->old_spte, iter->level); 9262306a36Sopenharmony_ci if (!child_pt) 9362306a36Sopenharmony_ci return false; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci iter->level--; 9662306a36Sopenharmony_ci iter->pt_path[iter->level - 1] = child_pt; 9762306a36Sopenharmony_ci iter->gfn = gfn_round_for_level(iter->next_last_level_gfn, iter->level); 9862306a36Sopenharmony_ci tdp_iter_refresh_sptep(iter); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci return true; 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci/* 10462306a36Sopenharmony_ci * Steps to the next entry in the current page table, at the current page table 10562306a36Sopenharmony_ci * level. The next entry could point to a page backing guest memory or another 10662306a36Sopenharmony_ci * page table, or it could be non-present. Returns true if the iterator was 10762306a36Sopenharmony_ci * able to step to the next entry in the page table, false if the iterator was 10862306a36Sopenharmony_ci * already at the end of the current page table. 10962306a36Sopenharmony_ci */ 11062306a36Sopenharmony_cistatic bool try_step_side(struct tdp_iter *iter) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci /* 11362306a36Sopenharmony_ci * Check if the iterator is already at the end of the current page 11462306a36Sopenharmony_ci * table. 11562306a36Sopenharmony_ci */ 11662306a36Sopenharmony_ci if (SPTE_INDEX(iter->gfn << PAGE_SHIFT, iter->level) == 11762306a36Sopenharmony_ci (SPTE_ENT_PER_PAGE - 1)) 11862306a36Sopenharmony_ci return false; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci iter->gfn += KVM_PAGES_PER_HPAGE(iter->level); 12162306a36Sopenharmony_ci iter->next_last_level_gfn = iter->gfn; 12262306a36Sopenharmony_ci iter->sptep++; 12362306a36Sopenharmony_ci iter->old_spte = kvm_tdp_mmu_read_spte(iter->sptep); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci return true; 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci/* 12962306a36Sopenharmony_ci * Tries to traverse back up a level in the paging structure so that the walk 13062306a36Sopenharmony_ci * can continue from the next entry in the parent page table. Returns true on a 13162306a36Sopenharmony_ci * successful step up, false if already in the root page. 13262306a36Sopenharmony_ci */ 13362306a36Sopenharmony_cistatic bool try_step_up(struct tdp_iter *iter) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci if (iter->level == iter->root_level) 13662306a36Sopenharmony_ci return false; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci iter->level++; 13962306a36Sopenharmony_ci iter->gfn = gfn_round_for_level(iter->gfn, iter->level); 14062306a36Sopenharmony_ci tdp_iter_refresh_sptep(iter); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci return true; 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci/* 14662306a36Sopenharmony_ci * Step to the next SPTE in a pre-order traversal of the paging structure. 14762306a36Sopenharmony_ci * To get to the next SPTE, the iterator either steps down towards the goal 14862306a36Sopenharmony_ci * GFN, if at a present, non-last-level SPTE, or over to a SPTE mapping a 14962306a36Sopenharmony_ci * highter GFN. 15062306a36Sopenharmony_ci * 15162306a36Sopenharmony_ci * The basic algorithm is as follows: 15262306a36Sopenharmony_ci * 1. If the current SPTE is a non-last-level SPTE, step down into the page 15362306a36Sopenharmony_ci * table it points to. 15462306a36Sopenharmony_ci * 2. If the iterator cannot step down, it will try to step to the next SPTE 15562306a36Sopenharmony_ci * in the current page of the paging structure. 15662306a36Sopenharmony_ci * 3. If the iterator cannot step to the next entry in the current page, it will 15762306a36Sopenharmony_ci * try to step up to the parent paging structure page. In this case, that 15862306a36Sopenharmony_ci * SPTE will have already been visited, and so the iterator must also step 15962306a36Sopenharmony_ci * to the side again. 16062306a36Sopenharmony_ci */ 16162306a36Sopenharmony_civoid tdp_iter_next(struct tdp_iter *iter) 16262306a36Sopenharmony_ci{ 16362306a36Sopenharmony_ci if (iter->yielded) { 16462306a36Sopenharmony_ci tdp_iter_restart(iter); 16562306a36Sopenharmony_ci return; 16662306a36Sopenharmony_ci } 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci if (try_step_down(iter)) 16962306a36Sopenharmony_ci return; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci do { 17262306a36Sopenharmony_ci if (try_step_side(iter)) 17362306a36Sopenharmony_ci return; 17462306a36Sopenharmony_ci } while (try_step_up(iter)); 17562306a36Sopenharmony_ci iter->valid = false; 17662306a36Sopenharmony_ci} 17762306a36Sopenharmony_ci 178