|
16 | 16 |
|
17 | 17 | #include "sys_regs.h"
|
18 | 18 |
|
| 19 | +struct vncr_tlb { |
| 20 | + /* The guest's VNCR_EL2 */ |
| 21 | + u64 gva; |
| 22 | + struct s1_walk_info wi; |
| 23 | + struct s1_walk_result wr; |
| 24 | + |
| 25 | + u64 hpa; |
| 26 | + |
| 27 | + /* -1 when not mapped on a CPU */ |
| 28 | + int cpu; |
| 29 | + |
| 30 | + /* |
| 31 | + * true if the TLB is valid. Can only be changed with the |
| 32 | + * mmu_lock held. |
| 33 | + */ |
| 34 | + bool valid; |
| 35 | +}; |
| 36 | + |
19 | 37 | /*
|
20 | 38 | * Ratio of live shadow S2 MMU per vcpu. This is a trade-off between
|
21 | 39 | * memory usage and potential number of different sets of S2 PTs in
|
@@ -811,6 +829,60 @@ void kvm_arch_flush_shadow_all(struct kvm *kvm)
|
811 | 829 | kvm_uninit_stage2_mmu(kvm);
|
812 | 830 | }
|
813 | 831 |
|
| 832 | +/* |
| 833 | + * Dealing with VNCR_EL2 exposed by the *guest* is a complicated matter: |
| 834 | + * |
| 835 | + * - We introduce an internal representation of a vcpu-private TLB, |
| 836 | + * representing the mapping between the guest VA contained in VNCR_EL2, |
| 837 | + * the IPA the guest's EL2 PTs point to, and the actual PA this lives at. |
| 838 | + * |
| 839 | + * - On translation fault from a nested VNCR access, we create such a TLB. |
| 840 | + * If there is no mapping to describe, the guest inherits the fault. |
| 841 | + * Crucially, no actual mapping is done at this stage. |
| 842 | + * |
| 843 | + * - On vcpu_load() in a non-HYP context with HCR_EL2.NV==1, if the above |
| 844 | + * TLB exists, we map it in the fixmap for this CPU, and run with it. We |
| 845 | + * have to respect the permissions dictated by the guest, but not the |
| 846 | + * memory type (FWB is a must). |
| 847 | + * |
| 848 | + * - Note that we usually don't do a vcpu_load() on the back of a fault |
| 849 | + * (unless we are preempted), so the resolution of a translation fault |
| 850 | + * must go via a request that will map the VNCR page in the fixmap. |
| 851 | + * vcpu_load() might as well use the same mechanism. |
| 852 | + * |
| 853 | + * - On vcpu_put() in a non-HYP context with HCR_EL2.NV==1, if the TLB was |
| 854 | + * mapped, we unmap it. Yes it is that simple. The TLB still exists |
| 855 | + * though, and may be reused at a later load. |
| 856 | + * |
| 857 | + * - On permission fault, we simply forward the fault to the guest's EL2. |
| 858 | + * Get out of my way. |
| 859 | + * |
| 860 | + * - On any TLBI for the EL2&0 translation regime, we must find any TLB that |
| 861 | + * intersects with the TLBI request, invalidate it, and unmap the page |
| 862 | + * from the fixmap. Because we need to look at all the vcpu-private TLBs, |
| 863 | + * this requires some wide-ranging locking to ensure that nothing races |
| 864 | + * against it. This may require some refcounting to avoid the search when |
| 865 | + * no such TLB is present. |
| 866 | + * |
| 867 | + * - On MMU notifiers, we must invalidate our TLB in a similar way, but |
| 868 | + * looking at the IPA instead. The funny part is that there may not be a |
| 869 | + * stage-2 mapping for this page if L1 hasn't accessed it using LD/ST |
| 870 | + * instructions. |
| 871 | + */ |
| 872 | + |
| 873 | +int kvm_vcpu_allocate_vncr_tlb(struct kvm_vcpu *vcpu) |
| 874 | +{ |
| 875 | + if (!kvm_has_feat(vcpu->kvm, ID_AA64MMFR4_EL1, NV_frac, NV2_ONLY)) |
| 876 | + return 0; |
| 877 | + |
| 878 | + vcpu->arch.vncr_tlb = kzalloc(sizeof(*vcpu->arch.vncr_tlb), |
| 879 | + GFP_KERNEL_ACCOUNT); |
| 880 | + if (!vcpu->arch.vncr_tlb) |
| 881 | + return -ENOMEM; |
| 882 | + |
| 883 | + return 0; |
| 884 | +} |
| 885 | + |
814 | 886 | /*
|
815 | 887 | * Our emulated CPU doesn't support all the possible features. For the
|
816 | 888 | * sake of simplicity (and probably mental sanity), wipe out a number
|
|
0 commit comments