18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci
38c2ecf20Sopenharmony_ci#include "mmu_internal.h"
48c2ecf20Sopenharmony_ci#include "tdp_iter.h"
58c2ecf20Sopenharmony_ci#include "spte.h"
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci/*
88c2ecf20Sopenharmony_ci * Recalculates the pointer to the SPTE for the current GFN and level and
98c2ecf20Sopenharmony_ci * reread the SPTE.
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_cistatic void tdp_iter_refresh_sptep(struct tdp_iter *iter)
128c2ecf20Sopenharmony_ci{
138c2ecf20Sopenharmony_ci	iter->sptep = iter->pt_path[iter->level - 1] +
148c2ecf20Sopenharmony_ci		SHADOW_PT_INDEX(iter->gfn << PAGE_SHIFT, iter->level);
158c2ecf20Sopenharmony_ci	iter->old_spte = READ_ONCE(*iter->sptep);
168c2ecf20Sopenharmony_ci}
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_cistatic gfn_t round_gfn_for_level(gfn_t gfn, int level)
198c2ecf20Sopenharmony_ci{
208c2ecf20Sopenharmony_ci	return gfn & -KVM_PAGES_PER_HPAGE(level);
218c2ecf20Sopenharmony_ci}
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci/*
248c2ecf20Sopenharmony_ci * Sets a TDP iterator to walk a pre-order traversal of the paging structure
258c2ecf20Sopenharmony_ci * rooted at root_pt, starting with the walk to translate next_last_level_gfn.
268c2ecf20Sopenharmony_ci */
278c2ecf20Sopenharmony_civoid tdp_iter_start(struct tdp_iter *iter, u64 *root_pt, int root_level,
288c2ecf20Sopenharmony_ci		    int min_level, gfn_t next_last_level_gfn)
298c2ecf20Sopenharmony_ci{
308c2ecf20Sopenharmony_ci	WARN_ON(root_level < 1);
318c2ecf20Sopenharmony_ci	WARN_ON(root_level > PT64_ROOT_MAX_LEVEL);
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci	iter->next_last_level_gfn = next_last_level_gfn;
348c2ecf20Sopenharmony_ci	iter->yielded_gfn = iter->next_last_level_gfn;
358c2ecf20Sopenharmony_ci	iter->root_level = root_level;
368c2ecf20Sopenharmony_ci	iter->min_level = min_level;
378c2ecf20Sopenharmony_ci	iter->level = root_level;
388c2ecf20Sopenharmony_ci	iter->pt_path[iter->level - 1] = root_pt;
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	iter->gfn = round_gfn_for_level(iter->next_last_level_gfn, iter->level);
418c2ecf20Sopenharmony_ci	tdp_iter_refresh_sptep(iter);
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	iter->valid = true;
448c2ecf20Sopenharmony_ci}
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci/*
478c2ecf20Sopenharmony_ci * Given an SPTE and its level, returns a pointer containing the host virtual
488c2ecf20Sopenharmony_ci * address of the child page table referenced by the SPTE. Returns null if
498c2ecf20Sopenharmony_ci * there is no such entry.
508c2ecf20Sopenharmony_ci */
518c2ecf20Sopenharmony_ciu64 *spte_to_child_pt(u64 spte, int level)
528c2ecf20Sopenharmony_ci{
538c2ecf20Sopenharmony_ci	/*
548c2ecf20Sopenharmony_ci	 * There's no child entry if this entry isn't present or is a
558c2ecf20Sopenharmony_ci	 * last-level entry.
568c2ecf20Sopenharmony_ci	 */
578c2ecf20Sopenharmony_ci	if (!is_shadow_present_pte(spte) || is_last_spte(spte, level))
588c2ecf20Sopenharmony_ci		return NULL;
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	return __va(spte_to_pfn(spte) << PAGE_SHIFT);
618c2ecf20Sopenharmony_ci}
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci/*
648c2ecf20Sopenharmony_ci * Steps down one level in the paging structure towards the goal GFN. Returns
658c2ecf20Sopenharmony_ci * true if the iterator was able to step down a level, false otherwise.
668c2ecf20Sopenharmony_ci */
678c2ecf20Sopenharmony_cistatic bool try_step_down(struct tdp_iter *iter)
688c2ecf20Sopenharmony_ci{
698c2ecf20Sopenharmony_ci	u64 *child_pt;
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	if (iter->level == iter->min_level)
728c2ecf20Sopenharmony_ci		return false;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	/*
758c2ecf20Sopenharmony_ci	 * Reread the SPTE before stepping down to avoid traversing into page
768c2ecf20Sopenharmony_ci	 * tables that are no longer linked from this entry.
778c2ecf20Sopenharmony_ci	 */
788c2ecf20Sopenharmony_ci	iter->old_spte = READ_ONCE(*iter->sptep);
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	child_pt = spte_to_child_pt(iter->old_spte, iter->level);
818c2ecf20Sopenharmony_ci	if (!child_pt)
828c2ecf20Sopenharmony_ci		return false;
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	iter->level--;
858c2ecf20Sopenharmony_ci	iter->pt_path[iter->level - 1] = child_pt;
868c2ecf20Sopenharmony_ci	iter->gfn = round_gfn_for_level(iter->next_last_level_gfn, iter->level);
878c2ecf20Sopenharmony_ci	tdp_iter_refresh_sptep(iter);
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	return true;
908c2ecf20Sopenharmony_ci}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci/*
938c2ecf20Sopenharmony_ci * Steps to the next entry in the current page table, at the current page table
948c2ecf20Sopenharmony_ci * level. The next entry could point to a page backing guest memory or another
958c2ecf20Sopenharmony_ci * page table, or it could be non-present. Returns true if the iterator was
968c2ecf20Sopenharmony_ci * able to step to the next entry in the page table, false if the iterator was
978c2ecf20Sopenharmony_ci * already at the end of the current page table.
988c2ecf20Sopenharmony_ci */
998c2ecf20Sopenharmony_cistatic bool try_step_side(struct tdp_iter *iter)
1008c2ecf20Sopenharmony_ci{
1018c2ecf20Sopenharmony_ci	/*
1028c2ecf20Sopenharmony_ci	 * Check if the iterator is already at the end of the current page
1038c2ecf20Sopenharmony_ci	 * table.
1048c2ecf20Sopenharmony_ci	 */
1058c2ecf20Sopenharmony_ci	if (SHADOW_PT_INDEX(iter->gfn << PAGE_SHIFT, iter->level) ==
1068c2ecf20Sopenharmony_ci            (PT64_ENT_PER_PAGE - 1))
1078c2ecf20Sopenharmony_ci		return false;
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	iter->gfn += KVM_PAGES_PER_HPAGE(iter->level);
1108c2ecf20Sopenharmony_ci	iter->next_last_level_gfn = iter->gfn;
1118c2ecf20Sopenharmony_ci	iter->sptep++;
1128c2ecf20Sopenharmony_ci	iter->old_spte = READ_ONCE(*iter->sptep);
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	return true;
1158c2ecf20Sopenharmony_ci}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci/*
1188c2ecf20Sopenharmony_ci * Tries to traverse back up a level in the paging structure so that the walk
1198c2ecf20Sopenharmony_ci * can continue from the next entry in the parent page table. Returns true on a
1208c2ecf20Sopenharmony_ci * successful step up, false if already in the root page.
1218c2ecf20Sopenharmony_ci */
1228c2ecf20Sopenharmony_cistatic bool try_step_up(struct tdp_iter *iter)
1238c2ecf20Sopenharmony_ci{
1248c2ecf20Sopenharmony_ci	if (iter->level == iter->root_level)
1258c2ecf20Sopenharmony_ci		return false;
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	iter->level++;
1288c2ecf20Sopenharmony_ci	iter->gfn = round_gfn_for_level(iter->gfn, iter->level);
1298c2ecf20Sopenharmony_ci	tdp_iter_refresh_sptep(iter);
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	return true;
1328c2ecf20Sopenharmony_ci}
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci/*
1358c2ecf20Sopenharmony_ci * Step to the next SPTE in a pre-order traversal of the paging structure.
1368c2ecf20Sopenharmony_ci * To get to the next SPTE, the iterator either steps down towards the goal
1378c2ecf20Sopenharmony_ci * GFN, if at a present, non-last-level SPTE, or over to a SPTE mapping a
1388c2ecf20Sopenharmony_ci * highter GFN.
1398c2ecf20Sopenharmony_ci *
1408c2ecf20Sopenharmony_ci * The basic algorithm is as follows:
1418c2ecf20Sopenharmony_ci * 1. If the current SPTE is a non-last-level SPTE, step down into the page
1428c2ecf20Sopenharmony_ci *    table it points to.
1438c2ecf20Sopenharmony_ci * 2. If the iterator cannot step down, it will try to step to the next SPTE
1448c2ecf20Sopenharmony_ci *    in the current page of the paging structure.
1458c2ecf20Sopenharmony_ci * 3. If the iterator cannot step to the next entry in the current page, it will
1468c2ecf20Sopenharmony_ci *    try to step up to the parent paging structure page. In this case, that
1478c2ecf20Sopenharmony_ci *    SPTE will have already been visited, and so the iterator must also step
1488c2ecf20Sopenharmony_ci *    to the side again.
1498c2ecf20Sopenharmony_ci */
1508c2ecf20Sopenharmony_civoid tdp_iter_next(struct tdp_iter *iter)
1518c2ecf20Sopenharmony_ci{
1528c2ecf20Sopenharmony_ci	if (try_step_down(iter))
1538c2ecf20Sopenharmony_ci		return;
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	do {
1568c2ecf20Sopenharmony_ci		if (try_step_side(iter))
1578c2ecf20Sopenharmony_ci			return;
1588c2ecf20Sopenharmony_ci	} while (try_step_up(iter));
1598c2ecf20Sopenharmony_ci	iter->valid = false;
1608c2ecf20Sopenharmony_ci}
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ciu64 *tdp_iter_root_pt(struct tdp_iter *iter)
1638c2ecf20Sopenharmony_ci{
1648c2ecf20Sopenharmony_ci	return iter->pt_path[iter->root_level - 1];
1658c2ecf20Sopenharmony_ci}
1668c2ecf20Sopenharmony_ci
167