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