Skip to content

Commit 8e236ef

Browse files
Marc Zyngieroupton
authored andcommitted
KVM: arm64: nv: Handle TLB invalidation targeting L2 stage-1
While dealing with TLB invalidation targeting the guest hypervisor's own stage-1 was easy, doing the same thing for its own guests is a bit more involved. Since such an invalidation is scoped by VMID, it needs to apply to all s2_mmu contexts that have been tagged by that VMID, irrespective of the value of VTTBR_EL2.BADDR. So for each s2_mmu context matching that VMID, we invalidate the corresponding TLBs, each context having its own "physical" VMID. Co-developed-by: Jintack Lim <[email protected]> Co-developed-by: Christoffer Dall <[email protected]> Signed-off-by: Jintack Lim <[email protected]> Signed-off-by: Christoffer Dall <[email protected]> Signed-off-by: Marc Zyngier <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Oliver Upton <[email protected]>
1 parent 67fda56 commit 8e236ef

File tree

3 files changed

+122
-0
lines changed

3 files changed

+122
-0
lines changed

arch/arm64/include/asm/kvm_nested.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,13 @@ extern void kvm_init_nested(struct kvm *kvm);
6565
extern int kvm_vcpu_init_nested(struct kvm_vcpu *vcpu);
6666
extern void kvm_init_nested_s2_mmu(struct kvm_s2_mmu *mmu);
6767
extern struct kvm_s2_mmu *lookup_s2_mmu(struct kvm_vcpu *vcpu);
68+
69+
union tlbi_info;
70+
71+
extern void kvm_s2_mmu_iterate_by_vmid(struct kvm *kvm, u16 vmid,
72+
const union tlbi_info *info,
73+
void (*)(struct kvm_s2_mmu *,
74+
const union tlbi_info *));
6875
extern void kvm_vcpu_load_hw_mmu(struct kvm_vcpu *vcpu);
6976
extern void kvm_vcpu_put_hw_mmu(struct kvm_vcpu *vcpu);
7077

arch/arm64/kvm/nested.c

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,41 @@ int kvm_walk_nested_s2(struct kvm_vcpu *vcpu, phys_addr_t gipa,
364364
return ret;
365365
}
366366

367+
/*
368+
* We can have multiple *different* MMU contexts with the same VMID:
369+
*
370+
* - S2 being enabled or not, hence differing by the HCR_EL2.VM bit
371+
*
372+
* - Multiple vcpus using private S2s (huh huh...), hence differing by the
373+
* VBBTR_EL2.BADDR address
374+
*
375+
* - A combination of the above...
376+
*
377+
* We can always identify which MMU context to pick at run-time. However,
378+
* TLB invalidation involving a VMID must take action on all the TLBs using
379+
* this particular VMID. This translates into applying the same invalidation
380+
* operation to all the contexts that are using this VMID. Moar phun!
381+
*/
382+
void kvm_s2_mmu_iterate_by_vmid(struct kvm *kvm, u16 vmid,
383+
const union tlbi_info *info,
384+
void (*tlbi_callback)(struct kvm_s2_mmu *,
385+
const union tlbi_info *))
386+
{
387+
write_lock(&kvm->mmu_lock);
388+
389+
for (int i = 0; i < kvm->arch.nested_mmus_size; i++) {
390+
struct kvm_s2_mmu *mmu = &kvm->arch.nested_mmus[i];
391+
392+
if (!kvm_s2_mmu_valid(mmu))
393+
continue;
394+
395+
if (vmid == get_vmid(mmu->tlb_vttbr))
396+
tlbi_callback(mmu, info);
397+
}
398+
399+
write_unlock(&kvm->mmu_lock);
400+
}
401+
367402
struct kvm_s2_mmu *lookup_s2_mmu(struct kvm_vcpu *vcpu)
368403
{
369404
struct kvm *kvm = vcpu->kvm;

arch/arm64/kvm/sys_regs.c

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2741,6 +2741,73 @@ static const struct sys_reg_desc sys_reg_descs[] = {
27412741
EL2_REG(SP_EL2, NULL, reset_unknown, 0),
27422742
};
27432743

2744+
/* Only defined here as this is an internal "abstraction" */
2745+
union tlbi_info {
2746+
struct {
2747+
u64 start;
2748+
u64 size;
2749+
} range;
2750+
2751+
struct {
2752+
u64 addr;
2753+
} ipa;
2754+
2755+
struct {
2756+
u64 addr;
2757+
u32 encoding;
2758+
} va;
2759+
};
2760+
2761+
static void s2_mmu_tlbi_s1e1(struct kvm_s2_mmu *mmu,
2762+
const union tlbi_info *info)
2763+
{
2764+
WARN_ON(__kvm_tlbi_s1e2(mmu, info->va.addr, info->va.encoding));
2765+
}
2766+
2767+
static bool handle_tlbi_el1(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
2768+
const struct sys_reg_desc *r)
2769+
{
2770+
u32 sys_encoding = sys_insn(p->Op0, p->Op1, p->CRn, p->CRm, p->Op2);
2771+
u64 vttbr = vcpu_read_sys_reg(vcpu, VTTBR_EL2);
2772+
2773+
/*
2774+
* If we're here, this is because we've trapped on a EL1 TLBI
2775+
* instruction that affects the EL1 translation regime while
2776+
* we're running in a context that doesn't allow us to let the
2777+
* HW do its thing (aka vEL2):
2778+
*
2779+
* - HCR_EL2.E2H == 0 : a non-VHE guest
2780+
* - HCR_EL2.{E2H,TGE} == { 1, 0 } : a VHE guest in guest mode
2781+
*
2782+
* We don't expect these helpers to ever be called when running
2783+
* in a vEL1 context.
2784+
*/
2785+
2786+
WARN_ON(!vcpu_is_el2(vcpu));
2787+
2788+
if (!kvm_supported_tlbi_s1e1_op(vcpu, sys_encoding)) {
2789+
kvm_inject_undefined(vcpu);
2790+
return false;
2791+
}
2792+
2793+
kvm_s2_mmu_iterate_by_vmid(vcpu->kvm, get_vmid(vttbr),
2794+
&(union tlbi_info) {
2795+
.va = {
2796+
.addr = p->regval,
2797+
.encoding = sys_encoding,
2798+
},
2799+
},
2800+
s2_mmu_tlbi_s1e1);
2801+
2802+
return true;
2803+
}
2804+
2805+
#define SYS_INSN(insn, access_fn) \
2806+
{ \
2807+
SYS_DESC(OP_##insn), \
2808+
.access = (access_fn), \
2809+
}
2810+
27442811
static struct sys_reg_desc sys_insn_descs[] = {
27452812
{ SYS_DESC(SYS_DC_ISW), access_dcsw },
27462813
{ SYS_DESC(SYS_DC_IGSW), access_dcgsw },
@@ -2751,6 +2818,19 @@ static struct sys_reg_desc sys_insn_descs[] = {
27512818
{ SYS_DESC(SYS_DC_CISW), access_dcsw },
27522819
{ SYS_DESC(SYS_DC_CIGSW), access_dcgsw },
27532820
{ SYS_DESC(SYS_DC_CIGDSW), access_dcgsw },
2821+
2822+
SYS_INSN(TLBI_VMALLE1IS, handle_tlbi_el1),
2823+
SYS_INSN(TLBI_VAE1IS, handle_tlbi_el1),
2824+
SYS_INSN(TLBI_ASIDE1IS, handle_tlbi_el1),
2825+
SYS_INSN(TLBI_VAAE1IS, handle_tlbi_el1),
2826+
SYS_INSN(TLBI_VALE1IS, handle_tlbi_el1),
2827+
SYS_INSN(TLBI_VAALE1IS, handle_tlbi_el1),
2828+
SYS_INSN(TLBI_VMALLE1, handle_tlbi_el1),
2829+
SYS_INSN(TLBI_VAE1, handle_tlbi_el1),
2830+
SYS_INSN(TLBI_ASIDE1, handle_tlbi_el1),
2831+
SYS_INSN(TLBI_VAAE1, handle_tlbi_el1),
2832+
SYS_INSN(TLBI_VALE1, handle_tlbi_el1),
2833+
SYS_INSN(TLBI_VAALE1, handle_tlbi_el1),
27542834
};
27552835

27562836
static const struct sys_reg_desc *first_idreg;

0 commit comments

Comments
 (0)