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