Skip to content

Commit 3bb7dce

Browse files
committed
Merge tag 'kvmarm-fixes-6.14-2' of git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm into HEAD
KVM/arm64 fixes for 6.14, take #2 - Large set of fixes for vector handling, specially in the interactions between host and guest state. This fixes a number of bugs affecting actual deployments, and greatly simplifies the FP/SIMD/SVE handling. Thanks to Mark Rutland for dealing with this thankless task. - Fix an ugly race between vcpu and vgic creation/init, resulting in unexpected behaviours. - Fix use of kernel VAs at EL2 when emulating timers with nVHE. - Small set of pKVM improvements and cleanups.
2 parents 43fb96a + b3aa928 commit 3bb7dce

File tree

13 files changed

+287
-375
lines changed

13 files changed

+287
-375
lines changed

arch/arm64/include/asm/kvm_emulate.h

-42
Original file line numberDiff line numberDiff line change
@@ -605,48 +605,6 @@ static __always_inline void kvm_incr_pc(struct kvm_vcpu *vcpu)
605605
__cpacr_to_cptr_set(clr, set));\
606606
} while (0)
607607

608-
static __always_inline void kvm_write_cptr_el2(u64 val)
609-
{
610-
if (has_vhe() || has_hvhe())
611-
write_sysreg(val, cpacr_el1);
612-
else
613-
write_sysreg(val, cptr_el2);
614-
}
615-
616-
/* Resets the value of cptr_el2 when returning to the host. */
617-
static __always_inline void __kvm_reset_cptr_el2(struct kvm *kvm)
618-
{
619-
u64 val;
620-
621-
if (has_vhe()) {
622-
val = (CPACR_EL1_FPEN | CPACR_EL1_ZEN_EL1EN);
623-
if (cpus_have_final_cap(ARM64_SME))
624-
val |= CPACR_EL1_SMEN_EL1EN;
625-
} else if (has_hvhe()) {
626-
val = CPACR_EL1_FPEN;
627-
628-
if (!kvm_has_sve(kvm) || !guest_owns_fp_regs())
629-
val |= CPACR_EL1_ZEN;
630-
if (cpus_have_final_cap(ARM64_SME))
631-
val |= CPACR_EL1_SMEN;
632-
} else {
633-
val = CPTR_NVHE_EL2_RES1;
634-
635-
if (kvm_has_sve(kvm) && guest_owns_fp_regs())
636-
val |= CPTR_EL2_TZ;
637-
if (!cpus_have_final_cap(ARM64_SME))
638-
val |= CPTR_EL2_TSM;
639-
}
640-
641-
kvm_write_cptr_el2(val);
642-
}
643-
644-
#ifdef __KVM_NVHE_HYPERVISOR__
645-
#define kvm_reset_cptr_el2(v) __kvm_reset_cptr_el2(kern_hyp_va((v)->kvm))
646-
#else
647-
#define kvm_reset_cptr_el2(v) __kvm_reset_cptr_el2((v)->kvm)
648-
#endif
649-
650608
/*
651609
* Returns a 'sanitised' view of CPTR_EL2, translating from nVHE to the VHE
652610
* format if E2H isn't set.

arch/arm64/include/asm/kvm_host.h

+6-18
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ static inline void push_hyp_memcache(struct kvm_hyp_memcache *mc,
100100
static inline void *pop_hyp_memcache(struct kvm_hyp_memcache *mc,
101101
void *(*to_va)(phys_addr_t phys))
102102
{
103-
phys_addr_t *p = to_va(mc->head);
103+
phys_addr_t *p = to_va(mc->head & PAGE_MASK);
104104

105105
if (!mc->nr_pages)
106106
return NULL;
@@ -615,32 +615,20 @@ struct cpu_sve_state {
615615
struct kvm_host_data {
616616
#define KVM_HOST_DATA_FLAG_HAS_SPE 0
617617
#define KVM_HOST_DATA_FLAG_HAS_TRBE 1
618-
#define KVM_HOST_DATA_FLAG_HOST_SVE_ENABLED 2
619-
#define KVM_HOST_DATA_FLAG_HOST_SME_ENABLED 3
620618
#define KVM_HOST_DATA_FLAG_TRBE_ENABLED 4
621619
#define KVM_HOST_DATA_FLAG_EL1_TRACING_CONFIGURED 5
622620
unsigned long flags;
623621

624622
struct kvm_cpu_context host_ctxt;
625623

626624
/*
627-
* All pointers in this union are hyp VA.
625+
* Hyp VA.
628626
* sve_state is only used in pKVM and if system_supports_sve().
629627
*/
630-
union {
631-
struct user_fpsimd_state *fpsimd_state;
632-
struct cpu_sve_state *sve_state;
633-
};
634-
635-
union {
636-
/* HYP VA pointer to the host storage for FPMR */
637-
u64 *fpmr_ptr;
638-
/*
639-
* Used by pKVM only, as it needs to provide storage
640-
* for the host
641-
*/
642-
u64 fpmr;
643-
};
628+
struct cpu_sve_state *sve_state;
629+
630+
/* Used by pKVM only. */
631+
u64 fpmr;
644632

645633
/* Ownership of the FP regs */
646634
enum {

arch/arm64/kernel/fpsimd.c

-25
Original file line numberDiff line numberDiff line change
@@ -1694,31 +1694,6 @@ void fpsimd_signal_preserve_current_state(void)
16941694
sve_to_fpsimd(current);
16951695
}
16961696

1697-
/*
1698-
* Called by KVM when entering the guest.
1699-
*/
1700-
void fpsimd_kvm_prepare(void)
1701-
{
1702-
if (!system_supports_sve())
1703-
return;
1704-
1705-
/*
1706-
* KVM does not save host SVE state since we can only enter
1707-
* the guest from a syscall so the ABI means that only the
1708-
* non-saved SVE state needs to be saved. If we have left
1709-
* SVE enabled for performance reasons then update the task
1710-
* state to be FPSIMD only.
1711-
*/
1712-
get_cpu_fpsimd_context();
1713-
1714-
if (test_and_clear_thread_flag(TIF_SVE)) {
1715-
sve_to_fpsimd(current);
1716-
current->thread.fp_type = FP_STATE_FPSIMD;
1717-
}
1718-
1719-
put_cpu_fpsimd_context();
1720-
}
1721-
17221697
/*
17231698
* Associate current's FPSIMD context with this cpu
17241699
* The caller must have ownership of the cpu FPSIMD context before calling

arch/arm64/kvm/arch_timer.c

+7-9
Original file line numberDiff line numberDiff line change
@@ -447,21 +447,19 @@ static void kvm_timer_update_status(struct arch_timer_context *ctx, bool level)
447447
static void kvm_timer_update_irq(struct kvm_vcpu *vcpu, bool new_level,
448448
struct arch_timer_context *timer_ctx)
449449
{
450-
int ret;
451-
452450
kvm_timer_update_status(timer_ctx, new_level);
453451

454452
timer_ctx->irq.level = new_level;
455453
trace_kvm_timer_update_irq(vcpu->vcpu_id, timer_irq(timer_ctx),
456454
timer_ctx->irq.level);
457455

458-
if (!userspace_irqchip(vcpu->kvm)) {
459-
ret = kvm_vgic_inject_irq(vcpu->kvm, vcpu,
460-
timer_irq(timer_ctx),
461-
timer_ctx->irq.level,
462-
timer_ctx);
463-
WARN_ON(ret);
464-
}
456+
if (userspace_irqchip(vcpu->kvm))
457+
return;
458+
459+
kvm_vgic_inject_irq(vcpu->kvm, vcpu,
460+
timer_irq(timer_ctx),
461+
timer_ctx->irq.level,
462+
timer_ctx);
465463
}
466464

467465
/* Only called for a fully emulated timer */

arch/arm64/kvm/arm.c

-8
Original file line numberDiff line numberDiff line change
@@ -2481,14 +2481,6 @@ static void finalize_init_hyp_mode(void)
24812481
per_cpu_ptr_nvhe_sym(kvm_host_data, cpu)->sve_state =
24822482
kern_hyp_va(sve_state);
24832483
}
2484-
} else {
2485-
for_each_possible_cpu(cpu) {
2486-
struct user_fpsimd_state *fpsimd_state;
2487-
2488-
fpsimd_state = &per_cpu_ptr_nvhe_sym(kvm_host_data, cpu)->host_ctxt.fp_regs;
2489-
per_cpu_ptr_nvhe_sym(kvm_host_data, cpu)->fpsimd_state =
2490-
kern_hyp_va(fpsimd_state);
2491-
}
24922484
}
24932485
}
24942486

arch/arm64/kvm/fpsimd.c

+9-98
Original file line numberDiff line numberDiff line change
@@ -54,50 +54,18 @@ void kvm_arch_vcpu_load_fp(struct kvm_vcpu *vcpu)
5454
if (!system_supports_fpsimd())
5555
return;
5656

57-
fpsimd_kvm_prepare();
58-
5957
/*
60-
* We will check TIF_FOREIGN_FPSTATE just before entering the
61-
* guest in kvm_arch_vcpu_ctxflush_fp() and override this to
62-
* FP_STATE_FREE if the flag set.
58+
* Ensure that any host FPSIMD/SVE/SME state is saved and unbound such
59+
* that the host kernel is responsible for restoring this state upon
60+
* return to userspace, and the hyp code doesn't need to save anything.
61+
*
62+
* When the host may use SME, fpsimd_save_and_flush_cpu_state() ensures
63+
* that PSTATE.{SM,ZA} == {0,0}.
6364
*/
64-
*host_data_ptr(fp_owner) = FP_STATE_HOST_OWNED;
65-
*host_data_ptr(fpsimd_state) = kern_hyp_va(&current->thread.uw.fpsimd_state);
66-
*host_data_ptr(fpmr_ptr) = kern_hyp_va(&current->thread.uw.fpmr);
67-
68-
host_data_clear_flag(HOST_SVE_ENABLED);
69-
if (read_sysreg(cpacr_el1) & CPACR_EL1_ZEN_EL0EN)
70-
host_data_set_flag(HOST_SVE_ENABLED);
71-
72-
if (system_supports_sme()) {
73-
host_data_clear_flag(HOST_SME_ENABLED);
74-
if (read_sysreg(cpacr_el1) & CPACR_EL1_SMEN_EL0EN)
75-
host_data_set_flag(HOST_SME_ENABLED);
76-
77-
/*
78-
* If PSTATE.SM is enabled then save any pending FP
79-
* state and disable PSTATE.SM. If we leave PSTATE.SM
80-
* enabled and the guest does not enable SME via
81-
* CPACR_EL1.SMEN then operations that should be valid
82-
* may generate SME traps from EL1 to EL1 which we
83-
* can't intercept and which would confuse the guest.
84-
*
85-
* Do the same for PSTATE.ZA in the case where there
86-
* is state in the registers which has not already
87-
* been saved, this is very unlikely to happen.
88-
*/
89-
if (read_sysreg_s(SYS_SVCR) & (SVCR_SM_MASK | SVCR_ZA_MASK)) {
90-
*host_data_ptr(fp_owner) = FP_STATE_FREE;
91-
fpsimd_save_and_flush_cpu_state();
92-
}
93-
}
65+
fpsimd_save_and_flush_cpu_state();
66+
*host_data_ptr(fp_owner) = FP_STATE_FREE;
9467

95-
/*
96-
* If normal guests gain SME support, maintain this behavior for pKVM
97-
* guests, which don't support SME.
98-
*/
99-
WARN_ON(is_protected_kvm_enabled() && system_supports_sme() &&
100-
read_sysreg_s(SYS_SVCR));
68+
WARN_ON_ONCE(system_supports_sme() && read_sysreg_s(SYS_SVCR));
10169
}
10270

10371
/*
@@ -162,52 +130,7 @@ void kvm_arch_vcpu_put_fp(struct kvm_vcpu *vcpu)
162130

163131
local_irq_save(flags);
164132

165-
/*
166-
* If we have VHE then the Hyp code will reset CPACR_EL1 to
167-
* the default value and we need to reenable SME.
168-
*/
169-
if (has_vhe() && system_supports_sme()) {
170-
/* Also restore EL0 state seen on entry */
171-
if (host_data_test_flag(HOST_SME_ENABLED))
172-
sysreg_clear_set(CPACR_EL1, 0, CPACR_EL1_SMEN);
173-
else
174-
sysreg_clear_set(CPACR_EL1,
175-
CPACR_EL1_SMEN_EL0EN,
176-
CPACR_EL1_SMEN_EL1EN);
177-
isb();
178-
}
179-
180133
if (guest_owns_fp_regs()) {
181-
if (vcpu_has_sve(vcpu)) {
182-
u64 zcr = read_sysreg_el1(SYS_ZCR);
183-
184-
/*
185-
* If the vCPU is in the hyp context then ZCR_EL1 is
186-
* loaded with its vEL2 counterpart.
187-
*/
188-
__vcpu_sys_reg(vcpu, vcpu_sve_zcr_elx(vcpu)) = zcr;
189-
190-
/*
191-
* Restore the VL that was saved when bound to the CPU,
192-
* which is the maximum VL for the guest. Because the
193-
* layout of the data when saving the sve state depends
194-
* on the VL, we need to use a consistent (i.e., the
195-
* maximum) VL.
196-
* Note that this means that at guest exit ZCR_EL1 is
197-
* not necessarily the same as on guest entry.
198-
*
199-
* ZCR_EL2 holds the guest hypervisor's VL when running
200-
* a nested guest, which could be smaller than the
201-
* max for the vCPU. Similar to above, we first need to
202-
* switch to a VL consistent with the layout of the
203-
* vCPU's SVE state. KVM support for NV implies VHE, so
204-
* using the ZCR_EL1 alias is safe.
205-
*/
206-
if (!has_vhe() || (vcpu_has_nv(vcpu) && !is_hyp_ctxt(vcpu)))
207-
sve_cond_update_zcr_vq(vcpu_sve_max_vq(vcpu) - 1,
208-
SYS_ZCR_EL1);
209-
}
210-
211134
/*
212135
* Flush (save and invalidate) the fpsimd/sve state so that if
213136
* the host tries to use fpsimd/sve, it's not using stale data
@@ -219,18 +142,6 @@ void kvm_arch_vcpu_put_fp(struct kvm_vcpu *vcpu)
219142
* when needed.
220143
*/
221144
fpsimd_save_and_flush_cpu_state();
222-
} else if (has_vhe() && system_supports_sve()) {
223-
/*
224-
* The FPSIMD/SVE state in the CPU has not been touched, and we
225-
* have SVE (and VHE): CPACR_EL1 (alias CPTR_EL2) has been
226-
* reset by kvm_reset_cptr_el2() in the Hyp code, disabling SVE
227-
* for EL0. To avoid spurious traps, restore the trap state
228-
* seen by kvm_arch_vcpu_load_fp():
229-
*/
230-
if (host_data_test_flag(HOST_SVE_ENABLED))
231-
sysreg_clear_set(CPACR_EL1, 0, CPACR_EL1_ZEN_EL0EN);
232-
else
233-
sysreg_clear_set(CPACR_EL1, CPACR_EL1_ZEN_EL0EN, 0);
234145
}
235146

236147
local_irq_restore(flags);

arch/arm64/kvm/hyp/entry.S

+5
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@ alternative_if ARM64_HAS_RAS_EXTN
4444
alternative_else_nop_endif
4545
mrs x1, isr_el1
4646
cbz x1, 1f
47+
48+
// Ensure that __guest_enter() always provides a context
49+
// synchronization event so that callers don't need ISBs for anything
50+
// that would usually be synchonized by the ERET.
51+
isb
4752
mov x0, #ARM_EXCEPTION_IRQ
4853
ret
4954

0 commit comments

Comments
 (0)