Skip to content
This repository was archived by the owner on Nov 8, 2023. It is now read-only.

Commit 45ce031

Browse files
committed
Merge tag 'kvmarm-fixes-6.10-1' of git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm into HEAD
KVM/arm64 fixes for 6.10, take #1 - Large set of FP/SVE fixes for pKVM, addressing the fallout from the per-CPU data rework and making sure that the host is not involved in the FP/SVE switching any more - Allow FEAT_BTI to be enabled with NV now that FEAT_PAUTH is copletely supported - Fix for the respective priorities of Failed PAC, Illegal Execution state and Instruction Abort exceptions - Fix the handling of AArch32 instruction traps failing their condition code, which was broken by the introduction of ESR_EL2.ISS2 - Allow vpcus running in AArch32 state to be restored in System mode - Fix AArch32 GPR restore that would lose the 64 bit state under some conditions
2 parents b50788f + afb91f5 commit 45ce031

File tree

21 files changed

+391
-73
lines changed

21 files changed

+391
-73
lines changed

arch/arm64/include/asm/el2_setup.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@
146146
/* Coprocessor traps */
147147
.macro __init_el2_cptr
148148
__check_hvhe .LnVHE_\@, x1
149-
mov x0, #(CPACR_EL1_FPEN_EL1EN | CPACR_EL1_FPEN_EL0EN)
149+
mov x0, #CPACR_ELx_FPEN
150150
msr cpacr_el1, x0
151151
b .Lskip_set_cptr_\@
152152
.LnVHE_\@:
@@ -277,7 +277,7 @@
277277

278278
// (h)VHE case
279279
mrs x0, cpacr_el1 // Disable SVE traps
280-
orr x0, x0, #(CPACR_EL1_ZEN_EL1EN | CPACR_EL1_ZEN_EL0EN)
280+
orr x0, x0, #CPACR_ELx_ZEN
281281
msr cpacr_el1, x0
282282
b .Lskip_set_cptr_\@
283283

@@ -298,7 +298,7 @@
298298

299299
// (h)VHE case
300300
mrs x0, cpacr_el1 // Disable SME traps
301-
orr x0, x0, #(CPACR_EL1_SMEN_EL0EN | CPACR_EL1_SMEN_EL1EN)
301+
orr x0, x0, #CPACR_ELx_SMEN
302302
msr cpacr_el1, x0
303303
b .Lskip_set_cptr_sme_\@
304304

arch/arm64/include/asm/kvm_arm.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,12 @@
305305
GENMASK(19, 14) | \
306306
BIT(11))
307307

308+
#define CPTR_VHE_EL2_RES0 (GENMASK(63, 32) | \
309+
GENMASK(27, 26) | \
310+
GENMASK(23, 22) | \
311+
GENMASK(19, 18) | \
312+
GENMASK(15, 0))
313+
308314
/* Hyp Debug Configuration Register bits */
309315
#define MDCR_EL2_E2TB_MASK (UL(0x3))
310316
#define MDCR_EL2_E2TB_SHIFT (UL(24))

arch/arm64/include/asm/kvm_emulate.h

Lines changed: 66 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,68 @@ static __always_inline void kvm_incr_pc(struct kvm_vcpu *vcpu)
557557
vcpu_set_flag((v), e); \
558558
} while (0)
559559

560+
#define __build_check_all_or_none(r, bits) \
561+
BUILD_BUG_ON(((r) & (bits)) && ((r) & (bits)) != (bits))
562+
563+
#define __cpacr_to_cptr_clr(clr, set) \
564+
({ \
565+
u64 cptr = 0; \
566+
\
567+
if ((set) & CPACR_ELx_FPEN) \
568+
cptr |= CPTR_EL2_TFP; \
569+
if ((set) & CPACR_ELx_ZEN) \
570+
cptr |= CPTR_EL2_TZ; \
571+
if ((set) & CPACR_ELx_SMEN) \
572+
cptr |= CPTR_EL2_TSM; \
573+
if ((clr) & CPACR_ELx_TTA) \
574+
cptr |= CPTR_EL2_TTA; \
575+
if ((clr) & CPTR_EL2_TAM) \
576+
cptr |= CPTR_EL2_TAM; \
577+
if ((clr) & CPTR_EL2_TCPAC) \
578+
cptr |= CPTR_EL2_TCPAC; \
579+
\
580+
cptr; \
581+
})
582+
583+
#define __cpacr_to_cptr_set(clr, set) \
584+
({ \
585+
u64 cptr = 0; \
586+
\
587+
if ((clr) & CPACR_ELx_FPEN) \
588+
cptr |= CPTR_EL2_TFP; \
589+
if ((clr) & CPACR_ELx_ZEN) \
590+
cptr |= CPTR_EL2_TZ; \
591+
if ((clr) & CPACR_ELx_SMEN) \
592+
cptr |= CPTR_EL2_TSM; \
593+
if ((set) & CPACR_ELx_TTA) \
594+
cptr |= CPTR_EL2_TTA; \
595+
if ((set) & CPTR_EL2_TAM) \
596+
cptr |= CPTR_EL2_TAM; \
597+
if ((set) & CPTR_EL2_TCPAC) \
598+
cptr |= CPTR_EL2_TCPAC; \
599+
\
600+
cptr; \
601+
})
602+
603+
#define cpacr_clear_set(clr, set) \
604+
do { \
605+
BUILD_BUG_ON((set) & CPTR_VHE_EL2_RES0); \
606+
BUILD_BUG_ON((clr) & CPACR_ELx_E0POE); \
607+
__build_check_all_or_none((clr), CPACR_ELx_FPEN); \
608+
__build_check_all_or_none((set), CPACR_ELx_FPEN); \
609+
__build_check_all_or_none((clr), CPACR_ELx_ZEN); \
610+
__build_check_all_or_none((set), CPACR_ELx_ZEN); \
611+
__build_check_all_or_none((clr), CPACR_ELx_SMEN); \
612+
__build_check_all_or_none((set), CPACR_ELx_SMEN); \
613+
\
614+
if (has_vhe() || has_hvhe()) \
615+
sysreg_clear_set(cpacr_el1, clr, set); \
616+
else \
617+
sysreg_clear_set(cptr_el2, \
618+
__cpacr_to_cptr_clr(clr, set), \
619+
__cpacr_to_cptr_set(clr, set));\
620+
} while (0)
621+
560622
static __always_inline void kvm_write_cptr_el2(u64 val)
561623
{
562624
if (has_vhe() || has_hvhe())
@@ -570,17 +632,16 @@ static __always_inline u64 kvm_get_reset_cptr_el2(struct kvm_vcpu *vcpu)
570632
u64 val;
571633

572634
if (has_vhe()) {
573-
val = (CPACR_EL1_FPEN_EL0EN | CPACR_EL1_FPEN_EL1EN |
574-
CPACR_EL1_ZEN_EL1EN);
635+
val = (CPACR_ELx_FPEN | CPACR_EL1_ZEN_EL1EN);
575636
if (cpus_have_final_cap(ARM64_SME))
576637
val |= CPACR_EL1_SMEN_EL1EN;
577638
} else if (has_hvhe()) {
578-
val = (CPACR_EL1_FPEN_EL0EN | CPACR_EL1_FPEN_EL1EN);
639+
val = CPACR_ELx_FPEN;
579640

580641
if (!vcpu_has_sve(vcpu) || !guest_owns_fp_regs())
581-
val |= CPACR_EL1_ZEN_EL1EN | CPACR_EL1_ZEN_EL0EN;
642+
val |= CPACR_ELx_ZEN;
582643
if (cpus_have_final_cap(ARM64_SME))
583-
val |= CPACR_EL1_SMEN_EL1EN | CPACR_EL1_SMEN_EL0EN;
644+
val |= CPACR_ELx_SMEN;
584645
} else {
585646
val = CPTR_NVHE_EL2_RES1;
586647

arch/arm64/include/asm/kvm_host.h

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ static inline enum kvm_mode kvm_get_mode(void) { return KVM_MODE_NONE; };
7676
DECLARE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
7777

7878
extern unsigned int __ro_after_init kvm_sve_max_vl;
79+
extern unsigned int __ro_after_init kvm_host_sve_max_vl;
7980
int __init kvm_arm_init_sve(void);
8081

8182
u32 __attribute_const__ kvm_target_cpu(void);
@@ -521,6 +522,20 @@ struct kvm_cpu_context {
521522
u64 *vncr_array;
522523
};
523524

525+
struct cpu_sve_state {
526+
__u64 zcr_el1;
527+
528+
/*
529+
* Ordering is important since __sve_save_state/__sve_restore_state
530+
* relies on it.
531+
*/
532+
__u32 fpsr;
533+
__u32 fpcr;
534+
535+
/* Must be SVE_VQ_BYTES (128 bit) aligned. */
536+
__u8 sve_regs[];
537+
};
538+
524539
/*
525540
* This structure is instantiated on a per-CPU basis, and contains
526541
* data that is:
@@ -534,7 +549,15 @@ struct kvm_cpu_context {
534549
*/
535550
struct kvm_host_data {
536551
struct kvm_cpu_context host_ctxt;
537-
struct user_fpsimd_state *fpsimd_state; /* hyp VA */
552+
553+
/*
554+
* All pointers in this union are hyp VA.
555+
* sve_state is only used in pKVM and if system_supports_sve().
556+
*/
557+
union {
558+
struct user_fpsimd_state *fpsimd_state;
559+
struct cpu_sve_state *sve_state;
560+
};
538561

539562
/* Ownership of the FP regs */
540563
enum {

arch/arm64/include/asm/kvm_hyp.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,8 @@ void __debug_restore_host_buffers_nvhe(struct kvm_vcpu *vcpu);
111111

112112
void __fpsimd_save_state(struct user_fpsimd_state *fp_regs);
113113
void __fpsimd_restore_state(struct user_fpsimd_state *fp_regs);
114-
void __sve_restore_state(void *sve_pffr, u32 *fpsr);
114+
void __sve_save_state(void *sve_pffr, u32 *fpsr, int save_ffr);
115+
void __sve_restore_state(void *sve_pffr, u32 *fpsr, int restore_ffr);
115116

116117
u64 __guest_enter(struct kvm_vcpu *vcpu);
117118

@@ -142,5 +143,6 @@ extern u64 kvm_nvhe_sym(id_aa64smfr0_el1_sys_val);
142143

143144
extern unsigned long kvm_nvhe_sym(__icache_flags);
144145
extern unsigned int kvm_nvhe_sym(kvm_arm_vmid_bits);
146+
extern unsigned int kvm_nvhe_sym(kvm_host_sve_max_vl);
145147

146148
#endif /* __ARM64_KVM_HYP_H__ */

arch/arm64/include/asm/kvm_pkvm.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,4 +128,13 @@ static inline unsigned long hyp_ffa_proxy_pages(void)
128128
return (2 * KVM_FFA_MBOX_NR_PAGES) + DIV_ROUND_UP(desc_max, PAGE_SIZE);
129129
}
130130

131+
static inline size_t pkvm_host_sve_state_size(void)
132+
{
133+
if (!system_supports_sve())
134+
return 0;
135+
136+
return size_add(sizeof(struct cpu_sve_state),
137+
SVE_SIG_REGS_SIZE(sve_vq_from_vl(kvm_host_sve_max_vl)));
138+
}
139+
131140
#endif /* __ARM64_KVM_PKVM_H__ */

arch/arm64/kvm/arm.c

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1931,6 +1931,11 @@ static unsigned long nvhe_percpu_order(void)
19311931
return size ? get_order(size) : 0;
19321932
}
19331933

1934+
static size_t pkvm_host_sve_state_order(void)
1935+
{
1936+
return get_order(pkvm_host_sve_state_size());
1937+
}
1938+
19341939
/* A lookup table holding the hypervisor VA for each vector slot */
19351940
static void *hyp_spectre_vector_selector[BP_HARDEN_EL2_SLOTS];
19361941

@@ -2310,12 +2315,20 @@ static void __init teardown_subsystems(void)
23102315

23112316
static void __init teardown_hyp_mode(void)
23122317
{
2318+
bool free_sve = system_supports_sve() && is_protected_kvm_enabled();
23132319
int cpu;
23142320

23152321
free_hyp_pgds();
23162322
for_each_possible_cpu(cpu) {
23172323
free_page(per_cpu(kvm_arm_hyp_stack_page, cpu));
23182324
free_pages(kvm_nvhe_sym(kvm_arm_hyp_percpu_base)[cpu], nvhe_percpu_order());
2325+
2326+
if (free_sve) {
2327+
struct cpu_sve_state *sve_state;
2328+
2329+
sve_state = per_cpu_ptr_nvhe_sym(kvm_host_data, cpu)->sve_state;
2330+
free_pages((unsigned long) sve_state, pkvm_host_sve_state_order());
2331+
}
23192332
}
23202333
}
23212334

@@ -2398,6 +2411,58 @@ static int __init kvm_hyp_init_protection(u32 hyp_va_bits)
23982411
return 0;
23992412
}
24002413

2414+
static int init_pkvm_host_sve_state(void)
2415+
{
2416+
int cpu;
2417+
2418+
if (!system_supports_sve())
2419+
return 0;
2420+
2421+
/* Allocate pages for host sve state in protected mode. */
2422+
for_each_possible_cpu(cpu) {
2423+
struct page *page = alloc_pages(GFP_KERNEL, pkvm_host_sve_state_order());
2424+
2425+
if (!page)
2426+
return -ENOMEM;
2427+
2428+
per_cpu_ptr_nvhe_sym(kvm_host_data, cpu)->sve_state = page_address(page);
2429+
}
2430+
2431+
/*
2432+
* Don't map the pages in hyp since these are only used in protected
2433+
* mode, which will (re)create its own mapping when initialized.
2434+
*/
2435+
2436+
return 0;
2437+
}
2438+
2439+
/*
2440+
* Finalizes the initialization of hyp mode, once everything else is initialized
2441+
* and the initialziation process cannot fail.
2442+
*/
2443+
static void finalize_init_hyp_mode(void)
2444+
{
2445+
int cpu;
2446+
2447+
if (system_supports_sve() && is_protected_kvm_enabled()) {
2448+
for_each_possible_cpu(cpu) {
2449+
struct cpu_sve_state *sve_state;
2450+
2451+
sve_state = per_cpu_ptr_nvhe_sym(kvm_host_data, cpu)->sve_state;
2452+
per_cpu_ptr_nvhe_sym(kvm_host_data, cpu)->sve_state =
2453+
kern_hyp_va(sve_state);
2454+
}
2455+
} else {
2456+
for_each_possible_cpu(cpu) {
2457+
struct user_fpsimd_state *fpsimd_state;
2458+
2459+
fpsimd_state = &per_cpu_ptr_nvhe_sym(kvm_host_data, cpu)->host_ctxt.fp_regs;
2460+
per_cpu_ptr_nvhe_sym(kvm_host_data, cpu)->fpsimd_state =
2461+
kern_hyp_va(fpsimd_state);
2462+
}
2463+
}
2464+
}
2465+
24012466
static void pkvm_hyp_init_ptrauth(void)
24022467
{
24032468
struct kvm_cpu_context *hyp_ctxt;
@@ -2566,6 +2631,10 @@ static int __init init_hyp_mode(void)
25662631
goto out_err;
25672632
}
25682633

2634+
err = init_pkvm_host_sve_state();
2635+
if (err)
2636+
goto out_err;
2637+
25692638
err = kvm_hyp_init_protection(hyp_va_bits);
25702639
if (err) {
25712640
kvm_err("Failed to init hyp memory protection\n");
@@ -2730,6 +2799,13 @@ static __init int kvm_arm_init(void)
27302799
if (err)
27312800
goto out_subs;
27322801

2802+
/*
2803+
* This should be called after initialization is done and failure isn't
2804+
* possible anymore.
2805+
*/
2806+
if (!in_hyp_mode)
2807+
finalize_init_hyp_mode();
2808+
27332809
kvm_arm_initialised = true;
27342810

27352811
return 0;

arch/arm64/kvm/emulate-nested.c

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2181,16 +2181,23 @@ void kvm_emulate_nested_eret(struct kvm_vcpu *vcpu)
21812181
if (forward_traps(vcpu, HCR_NV))
21822182
return;
21832183

2184+
spsr = vcpu_read_sys_reg(vcpu, SPSR_EL2);
2185+
spsr = kvm_check_illegal_exception_return(vcpu, spsr);
2186+
21842187
/* Check for an ERETAx */
21852188
esr = kvm_vcpu_get_esr(vcpu);
21862189
if (esr_iss_is_eretax(esr) && !kvm_auth_eretax(vcpu, &elr)) {
21872190
/*
2188-
* Oh no, ERETAx failed to authenticate. If we have
2189-
* FPACCOMBINE, deliver an exception right away. If we
2190-
* don't, then let the mangled ELR value trickle down the
2191+
* Oh no, ERETAx failed to authenticate.
2192+
*
2193+
* If we have FPACCOMBINE and we don't have a pending
2194+
* Illegal Execution State exception (which has priority
2195+
* over FPAC), deliver an exception right away.
2196+
*
2197+
* Otherwise, let the mangled ELR value trickle down the
21912198
* ERET handling, and the guest will have a little surprise.
21922199
*/
2193-
if (kvm_has_pauth(vcpu->kvm, FPACCOMBINE)) {
2200+
if (kvm_has_pauth(vcpu->kvm, FPACCOMBINE) && !(spsr & PSR_IL_BIT)) {
21942201
esr &= ESR_ELx_ERET_ISS_ERETA;
21952202
esr |= FIELD_PREP(ESR_ELx_EC_MASK, ESR_ELx_EC_FPAC);
21962203
kvm_inject_nested_sync(vcpu, esr);
@@ -2201,17 +2208,11 @@ void kvm_emulate_nested_eret(struct kvm_vcpu *vcpu)
22012208
preempt_disable();
22022209
kvm_arch_vcpu_put(vcpu);
22032210

2204-
spsr = __vcpu_sys_reg(vcpu, SPSR_EL2);
2205-
spsr = kvm_check_illegal_exception_return(vcpu, spsr);
22062211
if (!esr_iss_is_eretax(esr))
22072212
elr = __vcpu_sys_reg(vcpu, ELR_EL2);
22082213

22092214
trace_kvm_nested_eret(vcpu, elr, spsr);
22102215

2211-
/*
2212-
* Note that the current exception level is always the virtual EL2,
2213-
* since we set HCR_EL2.NV bit only when entering the virtual EL2.
2214-
*/
22152216
*vcpu_pc(vcpu) = elr;
22162217
*vcpu_cpsr(vcpu) = spsr;
22172218

arch/arm64/kvm/fpsimd.c

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,13 @@ void kvm_arch_vcpu_load_fp(struct kvm_vcpu *vcpu)
9090
fpsimd_save_and_flush_cpu_state();
9191
}
9292
}
93+
94+
/*
95+
* If normal guests gain SME support, maintain this behavior for pKVM
96+
* guests, which don't support SME.
97+
*/
98+
WARN_ON(is_protected_kvm_enabled() && system_supports_sme() &&
99+
read_sysreg_s(SYS_SVCR));
93100
}
94101

95102
/*
@@ -161,9 +168,7 @@ void kvm_arch_vcpu_put_fp(struct kvm_vcpu *vcpu)
161168
if (has_vhe() && system_supports_sme()) {
162169
/* Also restore EL0 state seen on entry */
163170
if (vcpu_get_flag(vcpu, HOST_SME_ENABLED))
164-
sysreg_clear_set(CPACR_EL1, 0,
165-
CPACR_EL1_SMEN_EL0EN |
166-
CPACR_EL1_SMEN_EL1EN);
171+
sysreg_clear_set(CPACR_EL1, 0, CPACR_ELx_SMEN);
167172
else
168173
sysreg_clear_set(CPACR_EL1,
169174
CPACR_EL1_SMEN_EL0EN,

0 commit comments

Comments
 (0)