Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 
0003 #include "mmu_internal.h"
0004 #include "tdp_iter.h"
0005 #include "spte.h"
0006 
0007 /*
0008  * Recalculates the pointer to the SPTE for the current GFN and level and
0009  * reread the SPTE.
0010  */
0011 static void tdp_iter_refresh_sptep(struct tdp_iter *iter)
0012 {
0013     iter->sptep = iter->pt_path[iter->level - 1] +
0014         SPTE_INDEX(iter->gfn << PAGE_SHIFT, iter->level);
0015     iter->old_spte = kvm_tdp_mmu_read_spte(iter->sptep);
0016 }
0017 
0018 static gfn_t round_gfn_for_level(gfn_t gfn, int level)
0019 {
0020     return gfn & -KVM_PAGES_PER_HPAGE(level);
0021 }
0022 
0023 /*
0024  * Return the TDP iterator to the root PT and allow it to continue its
0025  * traversal over the paging structure from there.
0026  */
0027 void tdp_iter_restart(struct tdp_iter *iter)
0028 {
0029     iter->yielded = false;
0030     iter->yielded_gfn = iter->next_last_level_gfn;
0031     iter->level = iter->root_level;
0032 
0033     iter->gfn = round_gfn_for_level(iter->next_last_level_gfn, iter->level);
0034     tdp_iter_refresh_sptep(iter);
0035 
0036     iter->valid = true;
0037 }
0038 
0039 /*
0040  * Sets a TDP iterator to walk a pre-order traversal of the paging structure
0041  * rooted at root_pt, starting with the walk to translate next_last_level_gfn.
0042  */
0043 void tdp_iter_start(struct tdp_iter *iter, struct kvm_mmu_page *root,
0044             int min_level, gfn_t next_last_level_gfn)
0045 {
0046     int root_level = root->role.level;
0047 
0048     WARN_ON(root_level < 1);
0049     WARN_ON(root_level > PT64_ROOT_MAX_LEVEL);
0050 
0051     iter->next_last_level_gfn = next_last_level_gfn;
0052     iter->root_level = root_level;
0053     iter->min_level = min_level;
0054     iter->pt_path[iter->root_level - 1] = (tdp_ptep_t)root->spt;
0055     iter->as_id = kvm_mmu_page_as_id(root);
0056 
0057     tdp_iter_restart(iter);
0058 }
0059 
0060 /*
0061  * Given an SPTE and its level, returns a pointer containing the host virtual
0062  * address of the child page table referenced by the SPTE. Returns null if
0063  * there is no such entry.
0064  */
0065 tdp_ptep_t spte_to_child_pt(u64 spte, int level)
0066 {
0067     /*
0068      * There's no child entry if this entry isn't present or is a
0069      * last-level entry.
0070      */
0071     if (!is_shadow_present_pte(spte) || is_last_spte(spte, level))
0072         return NULL;
0073 
0074     return (tdp_ptep_t)__va(spte_to_pfn(spte) << PAGE_SHIFT);
0075 }
0076 
0077 /*
0078  * Steps down one level in the paging structure towards the goal GFN. Returns
0079  * true if the iterator was able to step down a level, false otherwise.
0080  */
0081 static bool try_step_down(struct tdp_iter *iter)
0082 {
0083     tdp_ptep_t child_pt;
0084 
0085     if (iter->level == iter->min_level)
0086         return false;
0087 
0088     /*
0089      * Reread the SPTE before stepping down to avoid traversing into page
0090      * tables that are no longer linked from this entry.
0091      */
0092     iter->old_spte = kvm_tdp_mmu_read_spte(iter->sptep);
0093 
0094     child_pt = spte_to_child_pt(iter->old_spte, iter->level);
0095     if (!child_pt)
0096         return false;
0097 
0098     iter->level--;
0099     iter->pt_path[iter->level - 1] = child_pt;
0100     iter->gfn = round_gfn_for_level(iter->next_last_level_gfn, iter->level);
0101     tdp_iter_refresh_sptep(iter);
0102 
0103     return true;
0104 }
0105 
0106 /*
0107  * Steps to the next entry in the current page table, at the current page table
0108  * level. The next entry could point to a page backing guest memory or another
0109  * page table, or it could be non-present. Returns true if the iterator was
0110  * able to step to the next entry in the page table, false if the iterator was
0111  * already at the end of the current page table.
0112  */
0113 static bool try_step_side(struct tdp_iter *iter)
0114 {
0115     /*
0116      * Check if the iterator is already at the end of the current page
0117      * table.
0118      */
0119     if (SPTE_INDEX(iter->gfn << PAGE_SHIFT, iter->level) ==
0120         (SPTE_ENT_PER_PAGE - 1))
0121         return false;
0122 
0123     iter->gfn += KVM_PAGES_PER_HPAGE(iter->level);
0124     iter->next_last_level_gfn = iter->gfn;
0125     iter->sptep++;
0126     iter->old_spte = kvm_tdp_mmu_read_spte(iter->sptep);
0127 
0128     return true;
0129 }
0130 
0131 /*
0132  * Tries to traverse back up a level in the paging structure so that the walk
0133  * can continue from the next entry in the parent page table. Returns true on a
0134  * successful step up, false if already in the root page.
0135  */
0136 static bool try_step_up(struct tdp_iter *iter)
0137 {
0138     if (iter->level == iter->root_level)
0139         return false;
0140 
0141     iter->level++;
0142     iter->gfn = round_gfn_for_level(iter->gfn, iter->level);
0143     tdp_iter_refresh_sptep(iter);
0144 
0145     return true;
0146 }
0147 
0148 /*
0149  * Step to the next SPTE in a pre-order traversal of the paging structure.
0150  * To get to the next SPTE, the iterator either steps down towards the goal
0151  * GFN, if at a present, non-last-level SPTE, or over to a SPTE mapping a
0152  * highter GFN.
0153  *
0154  * The basic algorithm is as follows:
0155  * 1. If the current SPTE is a non-last-level SPTE, step down into the page
0156  *    table it points to.
0157  * 2. If the iterator cannot step down, it will try to step to the next SPTE
0158  *    in the current page of the paging structure.
0159  * 3. If the iterator cannot step to the next entry in the current page, it will
0160  *    try to step up to the parent paging structure page. In this case, that
0161  *    SPTE will have already been visited, and so the iterator must also step
0162  *    to the side again.
0163  */
0164 void tdp_iter_next(struct tdp_iter *iter)
0165 {
0166     if (iter->yielded) {
0167         tdp_iter_restart(iter);
0168         return;
0169     }
0170 
0171     if (try_step_down(iter))
0172         return;
0173 
0174     do {
0175         if (try_step_side(iter))
0176             return;
0177     } while (try_step_up(iter));
0178     iter->valid = false;
0179 }
0180