Skip to content

Commit 7f3225f

Browse files
author
Marc Zyngier
committed
Merge branch kvm-arm64/nv-nv into kvmarm-master/next
* kvm-arm64/nv-nv: : . : Flick the switch on the NV support by adding the missing piece : in the form of the VNCR page management. From the cover letter: : : "This is probably the most interesting bit of the whole NV adventure. : So far, everything else has been a walk in the park, but this one is : where the real fun takes place. : : With FEAT_NV2, most of the NV support revolves around tricking a guest : into accessing memory while it tries to access system registers. The : hypervisor's job is to handle the context switch of the actual : registers with the state in memory as needed." : . KVM: arm64: nv: Release faulted-in VNCR page from mmu_lock critical section KVM: arm64: nv: Handle TLBI S1E2 for VNCR invalidation with mmu_lock held KVM: arm64: nv: Hold mmu_lock when invalidating VNCR SW-TLB before translating KVM: arm64: Document NV caps and vcpu flags KVM: arm64: Allow userspace to request KVM_ARM_VCPU_EL2* KVM: arm64: nv: Remove dead code from ERET handling KVM: arm64: nv: Plumb TLBI S1E2 into system instruction dispatch KVM: arm64: nv: Add S1 TLB invalidation primitive for VNCR_EL2 KVM: arm64: nv: Program host's VNCR_EL2 to the fixmap address KVM: arm64: nv: Handle VNCR_EL2 invalidation from MMU notifiers KVM: arm64: nv: Handle mapping of VNCR_EL2 at EL2 KVM: arm64: nv: Handle VNCR_EL2-triggered faults KVM: arm64: nv: Add userspace and guest handling of VNCR_EL2 KVM: arm64: nv: Add pseudo-TLB backing VNCR_EL2 KVM: arm64: nv: Don't adjust PSTATE.M when L2 is nesting KVM: arm64: nv: Move TLBI range decoding to a helper KVM: arm64: nv: Snapshot S1 ASID tagging information during walk KVM: arm64: nv: Extract translation helper from the AT code KVM: arm64: nv: Allocate VNCR page when required arm64: sysreg: Add layout for VNCR_EL2 Signed-off-by: Marc Zyngier <maz@kernel.org>
2 parents 35e4d7f + 538fbac commit 7f3225f

File tree

16 files changed

+956
-138
lines changed

16 files changed

+956
-138
lines changed

Documentation/virt/kvm/api.rst

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3460,7 +3460,8 @@ The initial values are defined as:
34603460
- FPSIMD/NEON registers: set to 0
34613461
- SVE registers: set to 0
34623462
- System registers: Reset to their architecturally defined
3463-
values as for a warm reset to EL1 (resp. SVC)
3463+
values as for a warm reset to EL1 (resp. SVC) or EL2 (in the
3464+
case of EL2 being enabled).
34643465

34653466
Note that because some registers reflect machine topology, all vcpus
34663467
should be created before this ioctl is invoked.
@@ -3527,6 +3528,17 @@ Possible features:
35273528
- the KVM_REG_ARM64_SVE_VLS pseudo-register is immutable, and can
35283529
no longer be written using KVM_SET_ONE_REG.
35293530

3531+
- KVM_ARM_VCPU_HAS_EL2: Enable Nested Virtualisation support,
3532+
booting the guest from EL2 instead of EL1.
3533+
Depends on KVM_CAP_ARM_EL2.
3534+
The VM is running with HCR_EL2.E2H being RES1 (VHE) unless
3535+
KVM_ARM_VCPU_HAS_EL2_E2H0 is also set.
3536+
3537+
- KVM_ARM_VCPU_HAS_EL2_E2H0: Restrict Nested Virtualisation
3538+
support to HCR_EL2.E2H being RES0 (non-VHE).
3539+
Depends on KVM_CAP_ARM_EL2_E2H0.
3540+
KVM_ARM_VCPU_HAS_EL2 must also be set.
3541+
35303542
4.83 KVM_ARM_PREFERRED_TARGET
35313543
-----------------------------
35323544

arch/arm64/include/asm/esr.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@
100100
#define ESR_ELx_AET_CE (UL(6) << ESR_ELx_AET_SHIFT)
101101

102102
/* Shared ISS field definitions for Data/Instruction aborts */
103+
#define ESR_ELx_VNCR_SHIFT (13)
104+
#define ESR_ELx_VNCR (UL(1) << ESR_ELx_VNCR_SHIFT)
103105
#define ESR_ELx_SET_SHIFT (11)
104106
#define ESR_ELx_SET_MASK (UL(3) << ESR_ELx_SET_SHIFT)
105107
#define ESR_ELx_FnV_SHIFT (10)

arch/arm64/include/asm/fixmap.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,12 @@ enum fixed_addresses {
4848
FIX_EARLYCON_MEM_BASE,
4949
FIX_TEXT_POKE0,
5050

51+
#ifdef CONFIG_KVM
52+
/* One slot per CPU, mapping the guest's VNCR page at EL2. */
53+
FIX_VNCR_END,
54+
FIX_VNCR = FIX_VNCR_END + NR_CPUS,
55+
#endif
56+
5157
#ifdef CONFIG_ACPI_APEI_GHES
5258
/* Used for GHES mapping from assorted contexts */
5359
FIX_APEI_GHES_IRQ,

arch/arm64/include/asm/kvm_host.h

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939

4040
#define KVM_MAX_VCPUS VGIC_V3_MAX_CPUS
4141

42-
#define KVM_VCPU_MAX_FEATURES 7
42+
#define KVM_VCPU_MAX_FEATURES 9
4343
#define KVM_VCPU_VALID_FEATURES (BIT(KVM_VCPU_MAX_FEATURES) - 1)
4444

4545
#define KVM_REQ_SLEEP \
@@ -53,6 +53,7 @@
5353
#define KVM_REQ_RESYNC_PMU_EL0 KVM_ARCH_REQ(7)
5454
#define KVM_REQ_NESTED_S2_UNMAP KVM_ARCH_REQ(8)
5555
#define KVM_REQ_GUEST_HYP_IRQ_PENDING KVM_ARCH_REQ(9)
56+
#define KVM_REQ_MAP_L1_VNCR_EL2 KVM_ARCH_REQ(10)
5657

5758
#define KVM_DIRTY_LOG_MANUAL_CAPS (KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE | \
5859
KVM_DIRTY_LOG_INITIALLY_SET)
@@ -395,6 +396,9 @@ struct kvm_arch {
395396
/* Masks for VNCR-backed and general EL2 sysregs */
396397
struct kvm_sysreg_masks *sysreg_masks;
397398

399+
/* Count the number of VNCR_EL2 currently mapped */
400+
atomic_t vncr_map_count;
401+
398402
/*
399403
* For an untrusted host VM, 'pkvm.handle' is used to lookup
400404
* the associated pKVM instance in the hypervisor.
@@ -573,6 +577,8 @@ enum vcpu_sysreg {
573577
VNCR(HDFGRTR2_EL2),
574578
VNCR(HDFGWTR2_EL2),
575579

580+
VNCR(VNCR_EL2),
581+
576582
VNCR(CNTVOFF_EL2),
577583
VNCR(CNTV_CVAL_EL0),
578584
VNCR(CNTV_CTL_EL0),
@@ -696,6 +702,8 @@ struct kvm_host_data {
696702
#define KVM_HOST_DATA_FLAG_HAS_TRBE 1
697703
#define KVM_HOST_DATA_FLAG_TRBE_ENABLED 4
698704
#define KVM_HOST_DATA_FLAG_EL1_TRACING_CONFIGURED 5
705+
#define KVM_HOST_DATA_FLAG_VCPU_IN_HYP_CONTEXT 6
706+
#define KVM_HOST_DATA_FLAG_L1_VNCR_MAPPED 7
699707
unsigned long flags;
700708

701709
struct kvm_cpu_context host_ctxt;
@@ -772,6 +780,8 @@ struct vcpu_reset_state {
772780
bool reset;
773781
};
774782

783+
struct vncr_tlb;
784+
775785
struct kvm_vcpu_arch {
776786
struct kvm_cpu_context ctxt;
777787

@@ -866,6 +876,9 @@ struct kvm_vcpu_arch {
866876

867877
/* Per-vcpu CCSIDR override or NULL */
868878
u32 *ccsidr;
879+
880+
/* Per-vcpu TLB for VNCR_EL2 -- NULL when !NV */
881+
struct vncr_tlb *vncr_tlb;
869882
};
870883

871884
/*

arch/arm64/include/asm/kvm_nested.h

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,38 @@ static inline u64 kvm_encode_nested_level(struct kvm_s2_trans *trans)
231231
shift; \
232232
})
233233

234+
static inline u64 decode_range_tlbi(u64 val, u64 *range, u16 *asid)
235+
{
236+
u64 base, tg, num, scale;
237+
int shift;
238+
239+
tg = FIELD_GET(GENMASK(47, 46), val);
240+
241+
switch(tg) {
242+
case 1:
243+
shift = 12;
244+
break;
245+
case 2:
246+
shift = 14;
247+
break;
248+
case 3:
249+
default: /* IMPDEF: handle tg==0 as 64k */
250+
shift = 16;
251+
break;
252+
}
253+
254+
base = (val & GENMASK(36, 0)) << shift;
255+
256+
if (asid)
257+
*asid = FIELD_GET(TLBIR_ASID_MASK, val);
258+
259+
scale = FIELD_GET(GENMASK(45, 44), val);
260+
num = FIELD_GET(GENMASK(43, 39), val);
261+
*range = __TLBI_RANGE_PAGES(num, scale) << shift;
262+
263+
return base;
264+
}
265+
234266
static inline unsigned int ps_to_output_size(unsigned int ps)
235267
{
236268
switch (ps) {
@@ -245,4 +277,72 @@ static inline unsigned int ps_to_output_size(unsigned int ps)
245277
}
246278
}
247279

280+
enum trans_regime {
281+
TR_EL10,
282+
TR_EL20,
283+
TR_EL2,
284+
};
285+
286+
struct s1_walk_info {
287+
u64 baddr;
288+
enum trans_regime regime;
289+
unsigned int max_oa_bits;
290+
unsigned int pgshift;
291+
unsigned int txsz;
292+
int sl;
293+
bool as_el0;
294+
bool hpd;
295+
bool e0poe;
296+
bool poe;
297+
bool pan;
298+
bool be;
299+
bool s2;
300+
};
301+
302+
struct s1_walk_result {
303+
union {
304+
struct {
305+
u64 desc;
306+
u64 pa;
307+
s8 level;
308+
u8 APTable;
309+
bool nG;
310+
u16 asid;
311+
bool UXNTable;
312+
bool PXNTable;
313+
bool uwxn;
314+
bool uov;
315+
bool ur;
316+
bool uw;
317+
bool ux;
318+
bool pwxn;
319+
bool pov;
320+
bool pr;
321+
bool pw;
322+
bool px;
323+
};
324+
struct {
325+
u8 fst;
326+
bool ptw;
327+
bool s2;
328+
};
329+
};
330+
bool failed;
331+
};
332+
333+
int __kvm_translate_va(struct kvm_vcpu *vcpu, struct s1_walk_info *wi,
334+
struct s1_walk_result *wr, u64 va);
335+
336+
/* VNCR management */
337+
int kvm_vcpu_allocate_vncr_tlb(struct kvm_vcpu *vcpu);
338+
int kvm_handle_vncr_abort(struct kvm_vcpu *vcpu);
339+
void kvm_handle_s1e2_tlbi(struct kvm_vcpu *vcpu, u32 inst, u64 val);
340+
341+
#define vncr_fixmap(c) \
342+
({ \
343+
u32 __c = (c); \
344+
BUG_ON(__c >= NR_CPUS); \
345+
(FIX_VNCR - __c); \
346+
})
347+
248348
#endif /* __ARM64_KVM_NESTED_H */

arch/arm64/include/asm/sysreg.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -534,7 +534,7 @@
534534
#define SYS_VTTBR_EL2 sys_reg(3, 4, 2, 1, 0)
535535
#define SYS_VTCR_EL2 sys_reg(3, 4, 2, 1, 2)
536536

537-
#define SYS_VNCR_EL2 sys_reg(3, 4, 2, 2, 0)
537+
#define SYS_HAFGRTR_EL2 sys_reg(3, 4, 3, 1, 6)
538538
#define SYS_SPSR_EL2 sys_reg(3, 4, 4, 0, 0)
539539
#define SYS_ELR_EL2 sys_reg(3, 4, 4, 0, 1)
540540
#define SYS_SP_EL1 sys_reg(3, 4, 4, 1, 0)

arch/arm64/kvm/arm.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,12 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
368368
case KVM_CAP_ARM_EL1_32BIT:
369369
r = cpus_have_final_cap(ARM64_HAS_32BIT_EL1);
370370
break;
371+
case KVM_CAP_ARM_EL2:
372+
r = cpus_have_final_cap(ARM64_HAS_NESTED_VIRT);
373+
break;
374+
case KVM_CAP_ARM_EL2_E2H0:
375+
r = cpus_have_final_cap(ARM64_HAS_HCR_NV1);
376+
break;
371377
case KVM_CAP_GUEST_DEBUG_HW_BPS:
372378
r = get_num_brps();
373379
break;
@@ -843,6 +849,10 @@ int kvm_arch_vcpu_run_pid_change(struct kvm_vcpu *vcpu)
843849
return ret;
844850

845851
if (vcpu_has_nv(vcpu)) {
852+
ret = kvm_vcpu_allocate_vncr_tlb(vcpu);
853+
if (ret)
854+
return ret;
855+
846856
ret = kvm_vgic_vcpu_nv_init(vcpu);
847857
if (ret)
848858
return ret;

0 commit comments

Comments
 (0)