1c9180b72SBen Gardon // SPDX-License-Identifier: GPL-2.0 2c9180b72SBen Gardon 3c9180b72SBen Gardon #ifndef __KVM_X86_MMU_TDP_ITER_H 4c9180b72SBen Gardon #define __KVM_X86_MMU_TDP_ITER_H 5c9180b72SBen Gardon 6c9180b72SBen Gardon #include <linux/kvm_host.h> 7c9180b72SBen Gardon 8c9180b72SBen Gardon #include "mmu.h" 9ba3a6120SSean Christopherson #include "spte.h" 10c9180b72SBen Gardon 11c9180b72SBen Gardon /* 120e587aa7SSean Christopherson * TDP MMU SPTEs are RCU protected to allow paging structures (non-leaf SPTEs) 13bb95dfb9SSean Christopherson * to be zapped while holding mmu_lock for read, and to allow TLB flushes to be 14bb95dfb9SSean Christopherson * batched without having to collect the list of zapped SPs. Flows that can 15bb95dfb9SSean Christopherson * remove SPs must service pending TLB flushes prior to dropping RCU protection. 160e587aa7SSean Christopherson */ 170e587aa7SSean Christopherson static inline u64 kvm_tdp_mmu_read_spte(tdp_ptep_t sptep) 180e587aa7SSean Christopherson { 190e587aa7SSean Christopherson return READ_ONCE(*rcu_dereference(sptep)); 200e587aa7SSean Christopherson } 21ba3a6120SSean Christopherson 22ba3a6120SSean Christopherson static inline u64 kvm_tdp_mmu_write_spte_atomic(tdp_ptep_t sptep, u64 new_spte) 230e587aa7SSean Christopherson { 24837d557aSSean Christopherson KVM_MMU_WARN_ON(is_ept_ve_possible(new_spte)); 25ba3a6120SSean Christopherson return xchg(rcu_dereference(sptep), new_spte); 26ba3a6120SSean Christopherson } 27ba3a6120SSean Christopherson 28e29b7492SJames Houghton static inline u64 tdp_mmu_clear_spte_bits_atomic(tdp_ptep_t sptep, u64 mask) 29e29b7492SJames Houghton { 30e29b7492SJames Houghton atomic64_t *sptep_atomic = (atomic64_t *)rcu_dereference(sptep); 31e29b7492SJames Houghton 32e29b7492SJames Houghton return (u64)atomic64_fetch_and(~mask, sptep_atomic); 33e29b7492SJames Houghton } 34e29b7492SJames Houghton 35ba3a6120SSean Christopherson static inline void __kvm_tdp_mmu_write_spte(tdp_ptep_t sptep, u64 new_spte) 36ba3a6120SSean Christopherson { 37837d557aSSean Christopherson KVM_MMU_WARN_ON(is_ept_ve_possible(new_spte)); 38ba3a6120SSean Christopherson WRITE_ONCE(*rcu_dereference(sptep), new_spte); 39ba3a6120SSean Christopherson } 40ba3a6120SSean Christopherson 41ba3a6120SSean Christopherson /* 42*61d65f2dSJames Houghton * SPTEs must be modified atomically if they are shadow-present, leaf SPTEs, 43*61d65f2dSJames Houghton * and have volatile bits (bits that can be set outside of mmu_lock) that 44*61d65f2dSJames Houghton * must not be clobbered. 45ba3a6120SSean Christopherson */ 46*61d65f2dSJames Houghton static inline bool kvm_tdp_mmu_spte_need_atomic_update(u64 old_spte, int level) 4741e07665SVipin Sharma { 4841e07665SVipin Sharma return is_shadow_present_pte(old_spte) && 4941e07665SVipin Sharma is_last_spte(old_spte, level) && 50*61d65f2dSJames Houghton spte_needs_atomic_update(old_spte); 5141e07665SVipin Sharma } 5241e07665SVipin Sharma 5341e07665SVipin Sharma static inline u64 kvm_tdp_mmu_write_spte(tdp_ptep_t sptep, u64 old_spte, 5441e07665SVipin Sharma u64 new_spte, int level) 5541e07665SVipin Sharma { 56*61d65f2dSJames Houghton if (kvm_tdp_mmu_spte_need_atomic_update(old_spte, level)) 57ba3a6120SSean Christopherson return kvm_tdp_mmu_write_spte_atomic(sptep, new_spte); 58ba3a6120SSean Christopherson 59ba3a6120SSean Christopherson __kvm_tdp_mmu_write_spte(sptep, new_spte); 60ba3a6120SSean Christopherson return old_spte; 610e587aa7SSean Christopherson } 620e587aa7SSean Christopherson 6389c313f2SVipin Sharma static inline u64 tdp_mmu_clear_spte_bits(tdp_ptep_t sptep, u64 old_spte, 6489c313f2SVipin Sharma u64 mask, int level) 6589c313f2SVipin Sharma { 66*61d65f2dSJames Houghton if (kvm_tdp_mmu_spte_need_atomic_update(old_spte, level)) 67e29b7492SJames Houghton return tdp_mmu_clear_spte_bits_atomic(sptep, mask); 6889c313f2SVipin Sharma 6989c313f2SVipin Sharma __kvm_tdp_mmu_write_spte(sptep, old_spte & ~mask); 7089c313f2SVipin Sharma return old_spte; 7189c313f2SVipin Sharma } 7289c313f2SVipin Sharma 730e587aa7SSean Christopherson /* 74c9180b72SBen Gardon * A TDP iterator performs a pre-order walk over a TDP paging structure. 75c9180b72SBen Gardon */ 76c9180b72SBen Gardon struct tdp_iter { 77c9180b72SBen Gardon /* 78c9180b72SBen Gardon * The iterator will traverse the paging structure towards the mapping 79c9180b72SBen Gardon * for this GFN. 80c9180b72SBen Gardon */ 8174953d35SBen Gardon gfn_t next_last_level_gfn; 82ed5e484bSBen Gardon /* 83ed5e484bSBen Gardon * The next_last_level_gfn at the time when the thread last 84ed5e484bSBen Gardon * yielded. Only yielding when the next_last_level_gfn != 85ed5e484bSBen Gardon * yielded_gfn helps ensure forward progress. 86ed5e484bSBen Gardon */ 87ed5e484bSBen Gardon gfn_t yielded_gfn; 88c9180b72SBen Gardon /* Pointers to the page tables traversed to reach the current SPTE */ 897cca2d0bSBen Gardon tdp_ptep_t pt_path[PT64_ROOT_MAX_LEVEL]; 90c9180b72SBen Gardon /* A pointer to the current SPTE */ 917cca2d0bSBen Gardon tdp_ptep_t sptep; 923fc3f718SIsaku Yamahata /* The lowest GFN (mask bits excluded) mapped by the current SPTE */ 93c9180b72SBen Gardon gfn_t gfn; 943fc3f718SIsaku Yamahata /* Mask applied to convert the GFN to the mapping GPA */ 953fc3f718SIsaku Yamahata gfn_t gfn_bits; 96c9180b72SBen Gardon /* The level of the root page given to the iterator */ 97c9180b72SBen Gardon int root_level; 98c9180b72SBen Gardon /* The lowest level the iterator should traverse to */ 99c9180b72SBen Gardon int min_level; 100c9180b72SBen Gardon /* The iterator's current level within the paging structure */ 101c9180b72SBen Gardon int level; 10208889894SSean Christopherson /* The address space ID, i.e. SMM vs. regular. */ 10308889894SSean Christopherson int as_id; 104c9180b72SBen Gardon /* A snapshot of the value at sptep */ 105c9180b72SBen Gardon u64 old_spte; 106c9180b72SBen Gardon /* 107c9180b72SBen Gardon * Whether the iterator has a valid state. This will be false if the 108c9180b72SBen Gardon * iterator walks off the end of the paging structure. 109c9180b72SBen Gardon */ 110c9180b72SBen Gardon bool valid; 1113a0f64deSSean Christopherson /* 1123a0f64deSSean Christopherson * True if KVM dropped mmu_lock and yielded in the middle of a walk, in 1133a0f64deSSean Christopherson * which case tdp_iter_next() needs to restart the walk at the root 1143a0f64deSSean Christopherson * level instead of advancing to the next entry. 1153a0f64deSSean Christopherson */ 1163a0f64deSSean Christopherson bool yielded; 117c9180b72SBen Gardon }; 118c9180b72SBen Gardon 119c9180b72SBen Gardon /* 120c9180b72SBen Gardon * Iterates over every SPTE mapping the GFN range [start, end) in a 121c9180b72SBen Gardon * preorder traversal. 122c9180b72SBen Gardon */ 123e23186daSIsaku Yamahata #define for_each_tdp_pte_min_level(iter, kvm, root, min_level, start, end) \ 1243fc3f718SIsaku Yamahata for (tdp_iter_start(&iter, root, min_level, start, kvm_gfn_root_bits(kvm, root)); \ 125c9180b72SBen Gardon iter.valid && iter.gfn < end; \ 126c9180b72SBen Gardon tdp_iter_next(&iter)) 127c9180b72SBen Gardon 1283fc3f718SIsaku Yamahata #define for_each_tdp_pte_min_level_all(iter, root, min_level) \ 1293fc3f718SIsaku Yamahata for (tdp_iter_start(&iter, root, min_level, 0, 0); \ 1303fc3f718SIsaku Yamahata iter.valid && iter.gfn < tdp_mmu_max_gfn_exclusive(); \ 1313fc3f718SIsaku Yamahata tdp_iter_next(&iter)) 1323fc3f718SIsaku Yamahata 133e23186daSIsaku Yamahata #define for_each_tdp_pte(iter, kvm, root, start, end) \ 134e23186daSIsaku Yamahata for_each_tdp_pte_min_level(iter, kvm, root, PG_LEVEL_4K, start, end) 135a6a0b05dSBen Gardon 1367cca2d0bSBen Gardon tdp_ptep_t spte_to_child_pt(u64 pte, int level); 137c9180b72SBen Gardon 13877aa6075SDavid Matlack void tdp_iter_start(struct tdp_iter *iter, struct kvm_mmu_page *root, 1393fc3f718SIsaku Yamahata int min_level, gfn_t next_last_level_gfn, gfn_t gfn_bits); 140c9180b72SBen Gardon void tdp_iter_next(struct tdp_iter *iter); 141b601c3bcSBen Gardon void tdp_iter_restart(struct tdp_iter *iter); 142c9180b72SBen Gardon 143c9180b72SBen Gardon #endif /* __KVM_X86_MMU_TDP_ITER_H */ 144