Skip to content

Commit 53ce49e

Browse files
committed
Merge branch kvm-arm64/mops into kvmarm/next
* kvm-arm64/mops: : KVM support for MOPS, courtesy of Kristina Martsenko : : MOPS adds new instructions for accelerating memcpy(), memset(), and : memmove() operations in hardware. This series brings virtualization : support for KVM guests, and allows VMs to run on asymmetrict systems : that may have different MOPS implementations. KVM: arm64: Expose MOPS instructions to guests KVM: arm64: Add handler for MOPS exceptions Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
2 parents a87a364 + e0bb80c commit 53ce49e

File tree

8 files changed

+78
-53
lines changed

8 files changed

+78
-53
lines changed

arch/arm64/include/asm/kvm_arm.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,9 @@
102102
#define HCR_HOST_NVHE_PROTECTED_FLAGS (HCR_HOST_NVHE_FLAGS | HCR_TSC)
103103
#define HCR_HOST_VHE_FLAGS (HCR_RW | HCR_TGE | HCR_E2H)
104104

105-
#define HCRX_GUEST_FLAGS (HCRX_EL2_SMPME | HCRX_EL2_TCR2En)
105+
#define HCRX_GUEST_FLAGS \
106+
(HCRX_EL2_SMPME | HCRX_EL2_TCR2En | \
107+
(cpus_have_final_cap(ARM64_HAS_MOPS) ? (HCRX_EL2_MSCEn | HCRX_EL2_MCE2) : 0))
106108
#define HCRX_HOST_FLAGS (HCRX_EL2_MSCEn | HCRX_EL2_TCR2En)
107109

108110
/* TCR_EL2 Registers bits */

arch/arm64/include/asm/traps.h

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,9 @@
99

1010
#include <linux/list.h>
1111
#include <asm/esr.h>
12+
#include <asm/ptrace.h>
1213
#include <asm/sections.h>
1314

14-
struct pt_regs;
15-
1615
#ifdef CONFIG_ARMV8_DEPRECATED
1716
bool try_emulate_armv8_deprecated(struct pt_regs *regs, u32 insn);
1817
#else
@@ -101,4 +100,55 @@ static inline unsigned long arm64_ras_serror_get_severity(unsigned long esr)
101100

102101
bool arm64_is_fatal_ras_serror(struct pt_regs *regs, unsigned long esr);
103102
void __noreturn arm64_serror_panic(struct pt_regs *regs, unsigned long esr);
103+
104+
static inline void arm64_mops_reset_regs(struct user_pt_regs *regs, unsigned long esr)
105+
{
106+
bool wrong_option = esr & ESR_ELx_MOPS_ISS_WRONG_OPTION;
107+
bool option_a = esr & ESR_ELx_MOPS_ISS_OPTION_A;
108+
int dstreg = ESR_ELx_MOPS_ISS_DESTREG(esr);
109+
int srcreg = ESR_ELx_MOPS_ISS_SRCREG(esr);
110+
int sizereg = ESR_ELx_MOPS_ISS_SIZEREG(esr);
111+
unsigned long dst, src, size;
112+
113+
dst = regs->regs[dstreg];
114+
src = regs->regs[srcreg];
115+
size = regs->regs[sizereg];
116+
117+
/*
118+
* Put the registers back in the original format suitable for a
119+
* prologue instruction, using the generic return routine from the
120+
* Arm ARM (DDI 0487I.a) rules CNTMJ and MWFQH.
121+
*/
122+
if (esr & ESR_ELx_MOPS_ISS_MEM_INST) {
123+
/* SET* instruction */
124+
if (option_a ^ wrong_option) {
125+
/* Format is from Option A; forward set */
126+
regs->regs[dstreg] = dst + size;
127+
regs->regs[sizereg] = -size;
128+
}
129+
} else {
130+
/* CPY* instruction */
131+
if (!(option_a ^ wrong_option)) {
132+
/* Format is from Option B */
133+
if (regs->pstate & PSR_N_BIT) {
134+
/* Backward copy */
135+
regs->regs[dstreg] = dst - size;
136+
regs->regs[srcreg] = src - size;
137+
}
138+
} else {
139+
/* Format is from Option A */
140+
if (size & BIT(63)) {
141+
/* Forward copy */
142+
regs->regs[dstreg] = dst + size;
143+
regs->regs[srcreg] = src + size;
144+
regs->regs[sizereg] = -size;
145+
}
146+
}
147+
}
148+
149+
if (esr & ESR_ELx_MOPS_ISS_FROM_EPILOGUE)
150+
regs->pc -= 8;
151+
else
152+
regs->pc -= 4;
153+
}
104154
#endif

arch/arm64/kernel/traps.c

Lines changed: 1 addition & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -516,53 +516,7 @@ void do_el1_fpac(struct pt_regs *regs, unsigned long esr)
516516

517517
void do_el0_mops(struct pt_regs *regs, unsigned long esr)
518518
{
519-
bool wrong_option = esr & ESR_ELx_MOPS_ISS_WRONG_OPTION;
520-
bool option_a = esr & ESR_ELx_MOPS_ISS_OPTION_A;
521-
int dstreg = ESR_ELx_MOPS_ISS_DESTREG(esr);
522-
int srcreg = ESR_ELx_MOPS_ISS_SRCREG(esr);
523-
int sizereg = ESR_ELx_MOPS_ISS_SIZEREG(esr);
524-
unsigned long dst, src, size;
525-
526-
dst = pt_regs_read_reg(regs, dstreg);
527-
src = pt_regs_read_reg(regs, srcreg);
528-
size = pt_regs_read_reg(regs, sizereg);
529-
530-
/*
531-
* Put the registers back in the original format suitable for a
532-
* prologue instruction, using the generic return routine from the
533-
* Arm ARM (DDI 0487I.a) rules CNTMJ and MWFQH.
534-
*/
535-
if (esr & ESR_ELx_MOPS_ISS_MEM_INST) {
536-
/* SET* instruction */
537-
if (option_a ^ wrong_option) {
538-
/* Format is from Option A; forward set */
539-
pt_regs_write_reg(regs, dstreg, dst + size);
540-
pt_regs_write_reg(regs, sizereg, -size);
541-
}
542-
} else {
543-
/* CPY* instruction */
544-
if (!(option_a ^ wrong_option)) {
545-
/* Format is from Option B */
546-
if (regs->pstate & PSR_N_BIT) {
547-
/* Backward copy */
548-
pt_regs_write_reg(regs, dstreg, dst - size);
549-
pt_regs_write_reg(regs, srcreg, src - size);
550-
}
551-
} else {
552-
/* Format is from Option A */
553-
if (size & BIT(63)) {
554-
/* Forward copy */
555-
pt_regs_write_reg(regs, dstreg, dst + size);
556-
pt_regs_write_reg(regs, srcreg, src + size);
557-
pt_regs_write_reg(regs, sizereg, -size);
558-
}
559-
}
560-
}
561-
562-
if (esr & ESR_ELx_MOPS_ISS_FROM_EPILOGUE)
563-
regs->pc -= 8;
564-
else
565-
regs->pc -= 4;
519+
arm64_mops_reset_regs(&regs->user_regs, esr);
566520

567521
/*
568522
* If single stepping then finish the step before executing the

arch/arm64/kvm/hyp/include/hyp/switch.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include <asm/fpsimd.h>
3131
#include <asm/debug-monitors.h>
3232
#include <asm/processor.h>
33+
#include <asm/traps.h>
3334

3435
struct kvm_exception_table_entry {
3536
int insn, fixup;
@@ -265,6 +266,22 @@ static inline bool __populate_fault_info(struct kvm_vcpu *vcpu)
265266
return __get_fault_info(vcpu->arch.fault.esr_el2, &vcpu->arch.fault);
266267
}
267268

269+
static bool kvm_hyp_handle_mops(struct kvm_vcpu *vcpu, u64 *exit_code)
270+
{
271+
*vcpu_pc(vcpu) = read_sysreg_el2(SYS_ELR);
272+
arm64_mops_reset_regs(vcpu_gp_regs(vcpu), vcpu->arch.fault.esr_el2);
273+
write_sysreg_el2(*vcpu_pc(vcpu), SYS_ELR);
274+
275+
/*
276+
* Finish potential single step before executing the prologue
277+
* instruction.
278+
*/
279+
*vcpu_cpsr(vcpu) &= ~DBG_SPSR_SS;
280+
write_sysreg_el2(*vcpu_cpsr(vcpu), SYS_SPSR);
281+
282+
return true;
283+
}
284+
268285
static inline void __hyp_sve_restore_guest(struct kvm_vcpu *vcpu)
269286
{
270287
sve_cond_update_zcr_vq(vcpu_sve_max_vq(vcpu) - 1, SYS_ZCR_EL2);

arch/arm64/kvm/hyp/include/nvhe/fixed_config.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,8 @@
197197

198198
#define PVM_ID_AA64ISAR2_ALLOW (\
199199
ARM64_FEATURE_MASK(ID_AA64ISAR2_EL1_GPA3) | \
200-
ARM64_FEATURE_MASK(ID_AA64ISAR2_EL1_APA3) \
200+
ARM64_FEATURE_MASK(ID_AA64ISAR2_EL1_APA3) | \
201+
ARM64_FEATURE_MASK(ID_AA64ISAR2_EL1_MOPS) \
201202
)
202203

203204
u64 pvm_read_id_reg(const struct kvm_vcpu *vcpu, u32 id);

arch/arm64/kvm/hyp/nvhe/switch.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ static const exit_handler_fn hyp_exit_handlers[] = {
192192
[ESR_ELx_EC_DABT_LOW] = kvm_hyp_handle_dabt_low,
193193
[ESR_ELx_EC_WATCHPT_LOW] = kvm_hyp_handle_watchpt_low,
194194
[ESR_ELx_EC_PAC] = kvm_hyp_handle_ptrauth,
195+
[ESR_ELx_EC_MOPS] = kvm_hyp_handle_mops,
195196
};
196197

197198
static const exit_handler_fn pvm_exit_handlers[] = {
@@ -203,6 +204,7 @@ static const exit_handler_fn pvm_exit_handlers[] = {
203204
[ESR_ELx_EC_DABT_LOW] = kvm_hyp_handle_dabt_low,
204205
[ESR_ELx_EC_WATCHPT_LOW] = kvm_hyp_handle_watchpt_low,
205206
[ESR_ELx_EC_PAC] = kvm_hyp_handle_ptrauth,
207+
[ESR_ELx_EC_MOPS] = kvm_hyp_handle_mops,
206208
};
207209

208210
static const exit_handler_fn *kvm_get_exit_handler_array(struct kvm_vcpu *vcpu)

arch/arm64/kvm/hyp/vhe/switch.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ static const exit_handler_fn hyp_exit_handlers[] = {
139139
[ESR_ELx_EC_DABT_LOW] = kvm_hyp_handle_dabt_low,
140140
[ESR_ELx_EC_WATCHPT_LOW] = kvm_hyp_handle_watchpt_low,
141141
[ESR_ELx_EC_PAC] = kvm_hyp_handle_ptrauth,
142+
[ESR_ELx_EC_MOPS] = kvm_hyp_handle_mops,
142143
};
143144

144145
static const exit_handler_fn *kvm_get_exit_handler_array(struct kvm_vcpu *vcpu)

arch/arm64/kvm/sys_regs.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1348,7 +1348,6 @@ static u64 __kvm_read_sanitised_id_reg(const struct kvm_vcpu *vcpu,
13481348
ARM64_FEATURE_MASK(ID_AA64ISAR2_EL1_GPA3));
13491349
if (!cpus_have_final_cap(ARM64_HAS_WFXT))
13501350
val &= ~ARM64_FEATURE_MASK(ID_AA64ISAR2_EL1_WFxT);
1351-
val &= ~ARM64_FEATURE_MASK(ID_AA64ISAR2_EL1_MOPS);
13521351
break;
13531352
case SYS_ID_AA64MMFR2_EL1:
13541353
val &= ~ID_AA64MMFR2_EL1_CCIDX_MASK;
@@ -2099,7 +2098,6 @@ static const struct sys_reg_desc sys_reg_descs[] = {
20992098
ID_AA64ISAR1_EL1_API |
21002099
ID_AA64ISAR1_EL1_APA)),
21012100
ID_WRITABLE(ID_AA64ISAR2_EL1, ~(ID_AA64ISAR2_EL1_RES0 |
2102-
ID_AA64ISAR2_EL1_MOPS |
21032101
ID_AA64ISAR2_EL1_APA3 |
21042102
ID_AA64ISAR2_EL1_GPA3)),
21052103
ID_UNALLOCATED(6,3),

0 commit comments

Comments
 (0)