Skip to content

Commit 8536cea

Browse files
kristina-martsenkoctmarinas
authored andcommitted
arm64: mops: handle MOPS exceptions
The memory copy/set instructions added as part of FEAT_MOPS can take an exception (e.g. page fault) part-way through their execution and resume execution afterwards. If however the task is re-scheduled and execution resumes on a different CPU, then the CPU may take a new type of exception to indicate this. This is because the architecture allows two options (Option A and Option B) to implement the instructions and a heterogeneous system can have different implementations between CPUs. In this case the OS has to reset the registers and restart execution from the prologue instruction. The algorithm for doing this is provided as part of the Arm ARM. Add an exception handler for the new exception and wire it up for userspace tasks. Reviewed-by: Catalin Marinas <[email protected]> Signed-off-by: Kristina Martsenko <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Catalin Marinas <[email protected]>
1 parent 3172613 commit 8536cea

File tree

4 files changed

+74
-1
lines changed

4 files changed

+74
-1
lines changed

arch/arm64/include/asm/esr.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
#define ESR_ELx_EC_DABT_LOW (0x24)
4848
#define ESR_ELx_EC_DABT_CUR (0x25)
4949
#define ESR_ELx_EC_SP_ALIGN (0x26)
50-
/* Unallocated EC: 0x27 */
50+
#define ESR_ELx_EC_MOPS (0x27)
5151
#define ESR_ELx_EC_FP_EXC32 (0x28)
5252
/* Unallocated EC: 0x29 - 0x2B */
5353
#define ESR_ELx_EC_FP_EXC64 (0x2C)
@@ -356,6 +356,15 @@
356356
#define ESR_ELx_SME_ISS_ZA_DISABLED 3
357357
#define ESR_ELx_SME_ISS_ZT_DISABLED 4
358358

359+
/* ISS field definitions for MOPS exceptions */
360+
#define ESR_ELx_MOPS_ISS_MEM_INST (UL(1) << 24)
361+
#define ESR_ELx_MOPS_ISS_FROM_EPILOGUE (UL(1) << 18)
362+
#define ESR_ELx_MOPS_ISS_WRONG_OPTION (UL(1) << 17)
363+
#define ESR_ELx_MOPS_ISS_OPTION_A (UL(1) << 16)
364+
#define ESR_ELx_MOPS_ISS_DESTREG(esr) (((esr) & (UL(0x1f) << 10)) >> 10)
365+
#define ESR_ELx_MOPS_ISS_SRCREG(esr) (((esr) & (UL(0x1f) << 5)) >> 5)
366+
#define ESR_ELx_MOPS_ISS_SIZEREG(esr) (((esr) & (UL(0x1f) << 0)) >> 0)
367+
359368
#ifndef __ASSEMBLY__
360369
#include <asm/types.h>
361370

arch/arm64/include/asm/exception.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ void do_el0_svc(struct pt_regs *regs);
7777
void do_el0_svc_compat(struct pt_regs *regs);
7878
void do_el0_fpac(struct pt_regs *regs, unsigned long esr);
7979
void do_el1_fpac(struct pt_regs *regs, unsigned long esr);
80+
void do_el0_mops(struct pt_regs *regs, unsigned long esr);
8081
void do_serror(struct pt_regs *regs, unsigned long esr);
8182
void do_notify_resume(struct pt_regs *regs, unsigned long thread_flags);
8283

arch/arm64/kernel/entry-common.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,14 @@ static void noinstr el0_bti(struct pt_regs *regs)
611611
exit_to_user_mode(regs);
612612
}
613613

614+
static void noinstr el0_mops(struct pt_regs *regs, unsigned long esr)
615+
{
616+
enter_from_user_mode(regs);
617+
local_daif_restore(DAIF_PROCCTX);
618+
do_el0_mops(regs, esr);
619+
exit_to_user_mode(regs);
620+
}
621+
614622
static void noinstr el0_inv(struct pt_regs *regs, unsigned long esr)
615623
{
616624
enter_from_user_mode(regs);
@@ -688,6 +696,9 @@ asmlinkage void noinstr el0t_64_sync_handler(struct pt_regs *regs)
688696
case ESR_ELx_EC_BTI:
689697
el0_bti(regs);
690698
break;
699+
case ESR_ELx_EC_MOPS:
700+
el0_mops(regs, esr);
701+
break;
691702
case ESR_ELx_EC_BREAKPT_LOW:
692703
case ESR_ELx_EC_SOFTSTP_LOW:
693704
case ESR_ELx_EC_WATCHPT_LOW:

arch/arm64/kernel/traps.c

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,57 @@ void do_el1_fpac(struct pt_regs *regs, unsigned long esr)
514514
die("Oops - FPAC", regs, esr);
515515
}
516516

517+
void do_el0_mops(struct pt_regs *regs, unsigned long esr)
518+
{
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;
566+
}
567+
517568
#define __user_cache_maint(insn, address, res) \
518569
if (address >= TASK_SIZE_MAX) { \
519570
res = -EFAULT; \
@@ -824,6 +875,7 @@ static const char *esr_class_str[] = {
824875
[ESR_ELx_EC_DABT_LOW] = "DABT (lower EL)",
825876
[ESR_ELx_EC_DABT_CUR] = "DABT (current EL)",
826877
[ESR_ELx_EC_SP_ALIGN] = "SP Alignment",
878+
[ESR_ELx_EC_MOPS] = "MOPS",
827879
[ESR_ELx_EC_FP_EXC32] = "FP (AArch32)",
828880
[ESR_ELx_EC_FP_EXC64] = "FP (AArch64)",
829881
[ESR_ELx_EC_SERROR] = "SError",

0 commit comments

Comments
 (0)