From 80f21b991b836b98684971824bba496f8794591c Mon Sep 17 00:00:00 2001 From: qinwei1 Date: Mon, 30 Oct 2023 22:58:48 +0800 Subject: [PATCH 1/5] arm64: refine the fatal handler Summary The original implement for exception handler is very simple and haven't framework for breakpoint/watchpoint routine or brk instruction. I refine the fatal handler and add framework for debug handler to register or unregister. this is a prepare for watchpoint/breakpoint implement Signed-off-by: qinwei1 --- arch/arm64/src/common/arm64_fatal.c | 682 +++++++++++++-------- arch/arm64/src/common/arm64_fatal.h | 158 ++++- arch/arm64/src/common/arm64_vector_table.S | 8 +- arch/arm64/src/common/arm64_vectors.S | 40 +- 4 files changed, 604 insertions(+), 284 deletions(-) diff --git a/arch/arm64/src/common/arm64_fatal.c b/arch/arm64/src/common/arm64_fatal.c index 3486fe1d5d18d..5c1b5241904c3 100644 --- a/arch/arm64/src/common/arm64_fatal.c +++ b/arch/arm64/src/common/arm64_fatal.c @@ -39,6 +39,7 @@ #include #include "sched/sched.h" #include "irq/irq.h" + #include "arm64_arch.h" #include "arm64_internal.h" #include "arm64_fatal.h" @@ -51,326 +52,527 @@ #endif /**************************************************************************** - * Private Functions + * Private Type Declarations ****************************************************************************/ +struct fatal_handle_info +{ + fatal_handle_func_t handle_fn; + const char *name; +}; + /**************************************************************************** - * Name: print_ec_cause + * Private Functions Declarations ****************************************************************************/ +/* Default callback handler for debug and fatal event + * Can be override by other handler + */ + +static int default_debug_handler(struct regs_context *regs, + uint64_t far, uint64_t esr); +static int default_fatal_handler(struct regs_context *regs, + uint64_t far, uint64_t esr); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const char *g_esr_class_str[] = +{ + [0 ... ESR_ELX_EC_MAX] = "UNRECOGNIZED EC", + [ESR_ELX_EC_UNKNOWN] = "Unknown/Uncategorized", + [ESR_ELX_EC_WFX] = "WFI/WFE", + [ESR_ELX_EC_CP15_32] = "CP15 MCR/MRC", + [ESR_ELX_EC_CP15_64] = "CP15 MCRR/MRRC", + [ESR_ELX_EC_CP14_MR] = "CP14 MCR/MRC", + [ESR_ELX_EC_CP14_LS] = "CP14 LDC/STC", + [ESR_ELX_EC_FP_ASIMD] = "ASIMD", + [ESR_ELX_EC_CP10_ID] = "CP10 MRC/VMRS", + [ESR_ELX_EC_PAC] = "PAC", + [ESR_ELX_EC_CP14_64] = "CP14 MCRR/MRRC", + [ESR_ELX_EC_BTI] = "BTI", + [ESR_ELX_EC_ILL] = "PSTATE.IL", + [ESR_ELX_EC_SVC32] = "SVC (AArch32)", + [ESR_ELX_EC_HVC32] = "HVC (AArch32)", + [ESR_ELX_EC_SMC32] = "SMC (AArch32)", + [ESR_ELX_EC_SVC64] = "SVC (AArch64)", + [ESR_ELX_EC_HVC64] = "HVC (AArch64)", + [ESR_ELX_EC_SMC64] = "SMC (AArch64)", + [ESR_ELX_EC_SYS64] = "MSR/MRS (AArch64)", + [ESR_ELX_EC_SVE] = "SVE", + [ESR_ELX_EC_ERET] = "ERET/ERETAA/ERETAB", + [ESR_ELX_EC_FPAC] = "FPAC", + [ESR_ELX_EC_SME] = "SME", + [ESR_ELX_EC_IMP_DEF] = "EL3 IMP DEF", + [ESR_ELX_EC_IABT_LOW] = "IABT (lower EL)", + [ESR_ELX_EC_IABT_CUR] = "IABT (current EL)", + [ESR_ELX_EC_PC_ALIGN] = "PC Alignment", + [ESR_ELX_EC_DABT_LOW] = "DABT (lower EL)", + [ESR_ELX_EC_DABT_CUR] = "DABT (current EL)", + [ESR_ELX_EC_SP_ALIGN] = "SP Alignment", + [ESR_ELX_EC_MOPS] = "MOPS", + [ESR_ELX_EC_FP_EXC32] = "FP (AArch32)", + [ESR_ELX_EC_FP_EXC64] = "FP (AArch64)", + [ESR_ELX_EC_SERROR] = "SError", + [ESR_ELX_EC_BREAKPT_LOW] = "Breakpoint (lower EL)", + [ESR_ELX_EC_BREAKPT_CUR] = "Breakpoint (current EL)", + [ESR_ELX_EC_SOFTSTP_LOW] = "Software Step (lower EL)", + [ESR_ELX_EC_SOFTSTP_CUR] = "Software Step (current EL)", + [ESR_ELX_EC_WATCHPT_LOW] = "Watchpoint (lower EL)", + [ESR_ELX_EC_WATCHPT_CUR] = "Watchpoint (current EL)", + [ESR_ELX_EC_BKPT32] = "BKPT (AArch32)", + [ESR_ELX_EC_VECTOR32] = "Vector catch (AArch32)", + [ESR_ELX_EC_BRK64] = "BRK (AArch64)", +}; + +static const char *g_esr_desc_str[] = +{ + [0 ... ESR_ELX_EC_MAX] = "UNRECOGNIZED EC", + [ESR_ELX_EC_UNKNOWN] = "Unknown/Uncategorized", + [ESR_ELX_EC_WFX] = "Trapped WFI or WFE instruction execution", + [ESR_ELX_EC_CP15_32] = "Trapped MCR or MRC access with" + "(coproc==0b1111) " + "that is not reported using EC 0b000000", + [ESR_ELX_EC_CP15_64] = "Trapped MCRR or MRRC access with" + "(coproc==0b1111) " + "that is not reported using EC 0b000000", + [ESR_ELX_EC_CP14_MR] = "Trapped MCR or MRC access with (coproc==0b1110)", + [ESR_ELX_EC_CP14_LS] = "Trapped LDC or STC access", + [ESR_ELX_EC_FP_ASIMD] = "Trapped access to SVE, Advanced SIMD, or " + "floating-point functionality", + [ESR_ELX_EC_CP10_ID] = "CP10 MRC/VMRS", + [ESR_ELX_EC_PAC] = "PAC", + [ESR_ELX_EC_CP14_64] = "Trapped MRRC access with (coproc==0b1110)", + [ESR_ELX_EC_BTI] = "Branch Target Exception", + [ESR_ELX_EC_ILL] = "Illegal Execution state", + [ESR_ELX_EC_SVC32] = "SVC instruction execution in AArch32 state", + [ESR_ELX_EC_HVC32] = "HVC (AArch32)", + [ESR_ELX_EC_SMC32] = "SMC (AArch32)", + [ESR_ELX_EC_SVC64] = "SVC (AArch64)", + [ESR_ELX_EC_HVC64] = "HVC (AArch64)", + [ESR_ELX_EC_SMC64] = "SMC (AArch64)", + [ESR_ELX_EC_SYS64] = "Trapped MSR, MRS or System instruction " + "execution in AArch64 state, that is not " + "reported using EC 0b000000, 0b000001 or 0b000111", + [ESR_ELX_EC_SVE] = "Trapped access to SVE functionality", + [ESR_ELX_EC_ERET] = "ERET/ERETAA/ERETAB", + [ESR_ELX_EC_FPAC] = "Exception from a Pointer Authentication " + "instruction authentication failure", + [ESR_ELX_EC_SME] = "SME", + [ESR_ELX_EC_IMP_DEF] = "EL3 IMP DEF", + [ESR_ELX_EC_IABT_LOW] = "Instruction Abort from a lower Exception level, " + "that might be using AArch32 or AArch64", + [ESR_ELX_EC_IABT_CUR] = "Instruction Abort taken without a change " + "in Exception level", + [ESR_ELX_EC_PC_ALIGN] = "PC alignment fault exception.", + [ESR_ELX_EC_DABT_LOW] = "Data Abort from a lower Exception level, " + "that might be using AArch32 or AArch64", + [ESR_ELX_EC_DABT_CUR] = "Data Abort taken without a change in " + "Exception level", + [ESR_ELX_EC_SP_ALIGN] = "SP alignment fault exception", + [ESR_ELX_EC_MOPS] = "MOPS", + [ESR_ELX_EC_FP_EXC32] = "Trapped floating-point exception taken from " + "AArch32 state", + [ESR_ELX_EC_FP_EXC64] = "Trapped floating-point exception taken from " + "AArch64 state", + [ESR_ELX_EC_SERROR] = "SError interrupt", + [ESR_ELX_EC_BREAKPT_LOW] = "Breakpoint exception from a lower " + "Exception level, " + "that might be using AArch32 or AArch64", + [ESR_ELX_EC_BREAKPT_CUR] = "Breakpoint exception taken without a change " + "in Exception level", + [ESR_ELX_EC_SOFTSTP_LOW] = "Software Step exception from a lower " + "Exception level," + "that might be using AArch32 or AArch64", + [ESR_ELX_EC_SOFTSTP_CUR] = "Software Step exception taken without a " + "change in Exception level", + [ESR_ELX_EC_WATCHPT_LOW] = "Watchpoint exception from a lower " + "Exception level, " + "that might be using AArch32 or AArch64", + [ESR_ELX_EC_WATCHPT_CUR] = "Watchpoint exception taken without " + "a change in Exception level.", + [ESR_ELX_EC_BKPT32] = "BKPT instruction execution in AArch32 state", + [ESR_ELX_EC_VECTOR32] = "Vector catch (AArch32)", + [ESR_ELX_EC_BRK64] = "BRK instruction execution in AArch64 state.", +}; + +static struct fatal_handle_info g_fatal_handler[] = +{ + { default_fatal_handler, "ttbr address size fault" }, + { default_fatal_handler, "level 1 address size fault" }, + { default_fatal_handler, "level 2 address size fault" }, + { default_fatal_handler, "level 3 address size fault" }, + { default_fatal_handler, "level 0 translation fault" }, + { default_fatal_handler, "level 1 translation fault" }, + { default_fatal_handler, "level 2 translation fault" }, + { default_fatal_handler, "level 3 translation fault" }, + { default_fatal_handler, "unknown 8" }, + { default_fatal_handler, "level 1 access flag fault" }, + { default_fatal_handler, "level 2 access flag fault" }, + { default_fatal_handler, "level 3 access flag fault" }, + { default_fatal_handler, "unknown 12" }, + { default_fatal_handler, "level 1 permission fault" }, + { default_fatal_handler, "level 2 permission fault" }, + { default_fatal_handler, "level 3 permission fault" }, + { default_fatal_handler, "synchronous external abort" }, + { default_fatal_handler, "synchronous tag check fault" }, + { default_fatal_handler, "unknown 18" }, + { default_fatal_handler, "unknown 19" }, + { default_fatal_handler, "level 0 (translation table walk)" }, + { default_fatal_handler, "level 1 (translation table walk)" }, + { default_fatal_handler, "level 2 (translation table walk)" }, + { default_fatal_handler, "level 3 (translation table walk)" }, + { default_fatal_handler, "synchronous parity or ECC error" }, + { default_fatal_handler, "unknown 25" }, + { default_fatal_handler, "unknown 26" }, + { default_fatal_handler, "unknown 27" }, + { default_fatal_handler, "level 0 synchronous parity " + "error (translation table walk)" }, + { default_fatal_handler, "level 1 synchronous parity " + "error (translation table walk)" }, + { default_fatal_handler, "level 2 synchronous parity " + "error (translation table walk)" }, + { default_fatal_handler, "level 3 synchronous parity " + "error (translation table walk)" }, + { default_fatal_handler, "unknown 32" }, + { default_fatal_handler, "alignment fault" }, + { default_fatal_handler, "unknown 34" }, + { default_fatal_handler, "unknown 35" }, + { default_fatal_handler, "unknown 36" }, + { default_fatal_handler, "unknown 37" }, + { default_fatal_handler, "unknown 38" }, + { default_fatal_handler, "unknown 39" }, + { default_fatal_handler, "unknown 40" }, + { default_fatal_handler, "unknown 41" }, + { default_fatal_handler, "unknown 42" }, + { default_fatal_handler, "unknown 43" }, + { default_fatal_handler, "unknown 44" }, + { default_fatal_handler, "unknown 45" }, + { default_fatal_handler, "unknown 46" }, + { default_fatal_handler, "unknown 47" }, + { default_fatal_handler, "TLB conflict abort" }, + { default_fatal_handler, "Unsupported atomic hardware update fault" }, + { default_fatal_handler, "unknown 50" }, + { default_fatal_handler, "unknown 51" }, + { default_fatal_handler, "implementation fault (lockdown abort)" }, + { default_fatal_handler, "implementation fault (unsupported exclusive)" }, + { default_fatal_handler, "unknown 54" }, + { default_fatal_handler, "unknown 55" }, + { default_fatal_handler, "unknown 56" }, + { default_fatal_handler, "unknown 57" }, + { default_fatal_handler, "unknown 58" }, + { default_fatal_handler, "unknown 59" }, + { default_fatal_handler, "unknown 60" }, + { default_fatal_handler, "section domain fault" }, + { default_fatal_handler, "page domain fault" }, + { default_fatal_handler, "unknown 63" }, +}; + +static struct fatal_handle_info g_debug_handler[] = +{ + { default_debug_handler, "hardware breakpoint" }, + { default_debug_handler, "hardware single-step" }, + { default_debug_handler, "hardware watchpoint" }, + { default_debug_handler, "unknown 3" }, + { default_debug_handler, "aarch32 BKPT" }, + { default_debug_handler, "aarch32 vector catch" }, + { default_debug_handler, "aarch64 BRK" }, + { default_debug_handler, "unknown 7" }, +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static const char *esr_get_class_string(uint64_t esr) +{ + uint32_t ec = ESR_ELX_EC(esr); + + return g_esr_class_str[ec]; +} + +static const char *esr_get_desc_string(uint64_t esr) +{ + uint32_t ec = ESR_ELX_EC(esr); + + return g_esr_desc_str[ec]; +} + static void print_ec_cause(uint64_t esr) { - uint32_t ec = (uint32_t)esr >> 26; + sinfo("%s\n", esr_get_class_string(esr)); + sinfo("%s\n", esr_get_desc_string(esr)); +} - switch (ec) - { - case 0b000000: - { - sinfo("Unknown reason\n"); - break; - } +static int default_fatal_handler(struct regs_context *regs, + uint64_t far, uint64_t esr) +{ + struct fatal_handle_info *inf = g_fatal_handler + (esr & ESR_ELX_FSC); - case 0b000001: - { - sinfo("Trapped WFI or WFE instruction execution\n"); - break; - } + /* Data Fault Status Code. */ - case 0b000011: - { - sinfo( - "Trapped MCR or MRC access with (coproc==0b1111) that " - "is not reported using EC 0b000000\n"); - break; - } + sinfo("(IFSC/DFSC) for Data/Instruction aborts: %s\n", inf->name); - case 0b000100: - { - sinfo( - "Trapped MCRR or MRRC access with (coproc==0b1111) " - "that is not reported using EC 0b000000\n"); - break; - } + return -EINVAL; /* "fault" */ +} - case 0b000101: - { - sinfo("Trapped MCR or MRC access with (coproc==0b1110)\n"); - break; - } +static int default_debug_handler(struct regs_context *regs, + uint64_t far, uint64_t esr) +{ + struct fatal_handle_info *inf = g_debug_handler + DBG_ESR_EVT(esr); - case 0b000110: - { - sinfo("Trapped LDC or STC access\n"); - break; - } + sinfo("Default Debug Handler: %s\n", inf->name); + return -1; /* "fault" */ +} - case 0b000111: - { - sinfo( - "Trapped access to SVE, Advanced SIMD, or " - "floating-point functionality\n"); - break; - } +static int arm64_el1_abort(struct regs_context *regs, uint64_t esr) +{ + uint64_t far = read_sysreg(far_el1); + struct fatal_handle_info *inf = g_fatal_handler + (esr & ESR_ELX_FSC); - case 0b001100: - { - sinfo("Trapped MRRC access with (coproc==0b1110)\n"); - break; - } + return inf->handle_fn(regs, far, esr); +} - case 0b001101: - { - sinfo("Branch Target Exception\n"); - break; - } +static int arm64_el1_pc(struct regs_context *regs, uint64_t esr) +{ + uint64_t far = read_sysreg(far_el1); - case 0b001110: - { - sinfo("Illegal Execution state\n"); - break; - } + sinfo("SP/PC alignment exception at 0x%" PRIx64 "\n", far); + return -EINVAL; /* "fault" */ +} - case 0b010001: - { - sinfo("SVC instruction execution in AArch32 state\n"); - break; - } +static int arm64_el1_bti(struct regs_context *regs, uint64_t esr) +{ + uint64_t far = read_sysreg(far_el1); - case 0b011000: - { - sinfo( - "Trapped MSR, MRS or System instruction execution in " - "AArch64 state, that is not reported using EC " - "0b000000, 0b000001 or 0b000111\n"); - break; - } + sinfo("BTI exception at 0x%" PRIx64 "\n", far); + return -EINVAL; /* "fault" */ +} - case 0b011001: - { - sinfo("Trapped access to SVE functionality\n"); - break; - } +static int arm64_el1_undef(struct regs_context *regs, uint64_t esr) +{ + uint32_t insn; + + sinfo("Undefined instruction at 0x%" PRIx64 ", dump:\n", regs->elr); + memcpy(&insn, (void *)(regs->elr - 8), 4); + sinfo("0x%" PRIx64 " : 0x%" PRIx32 "\n", regs->elr - 8, insn); + memcpy(&insn, (void *)(regs->elr - 4), 4); + sinfo("0x%" PRIx64 " : 0x%" PRIx32 "\n", regs->elr - 4, insn); + memcpy(&insn, (void *)(regs->elr), 4); + sinfo("0x%" PRIx64 " : 0x%" PRIx32 "\n", regs->elr, insn); + memcpy(&insn, (void *)(regs->elr + 4), 4); + sinfo("0x%" PRIx64 " : 0x%" PRIx32 "\n", regs->elr + 4, insn); + memcpy(&insn, (void *)(regs->elr + 8), 4); + sinfo("0x%" PRIx64 " : 0x%" PRIx32 "\n", regs->elr + 8, insn); + + return -1; +} - case 0b100000: - { - sinfo( - "Instruction Abort from a lower Exception level, that " - "might be using AArch32 or AArch64\n"); - break; - } +static int arm64_el1_fpac(struct regs_context *regs, uint64_t esr) +{ + uint64_t far = read_sysreg(far_el1); - case 0b100001: - { - sinfo( - "Instruction Abort taken without a change " - "in Exception level.\n"); - break; - } + /* Unexpected FPAC exception in the kernel. */ - case 0b100010: - { - sinfo("PC alignment fault exception.\n"); - break; - } + sinfo("Unexpected FPAC exception at 0x%" PRIx64 "\n", far); + return -EINVAL; +} - case 0b100100: - { - sinfo( - "Data Abort from a lower Exception level, that might " - "be using AArch32 or AArch64\n"); - break; - } +static int arm64_el1_dbg(struct regs_context *regs, uint64_t esr) +{ + uint64_t far = read_sysreg(far_el1); + struct fatal_handle_info *inf = g_debug_handler + DBG_ESR_EVT(esr); - case 0b100101: - { - sinfo("Data Abort taken without a change in Exception level\n"); - break; - } + return inf->handle_fn(regs, far, esr); +} - case 0b100110: - { - sinfo("SP alignment fault exception\n"); - break; - } +static int arm64_el1_exception_handler(uint64_t esr, + struct regs_context *regs) +{ + uint32_t ec = ESR_ELX_EC(esr); + int ret; - case 0b101000: - { - sinfo( - "Trapped floating-point exception " - "taken from AArch32 state\n"); - break; - } + switch (ec) + { + /* Data/Instruction Abort at EL1 */ - case 0b101100: + case ESR_ELX_EC_DABT_CUR: + case ESR_ELX_EC_IABT_CUR: { - sinfo( - "Trapped floating-point exception " - "taken from AArch64 state.\n"); + ret = arm64_el1_abort(regs, esr); break; } - case 0b101111: - { - sinfo("SError interrupt\n"); - break; - } + /* PC alignment fault exception. */ - case 0b110000: + case ESR_ELX_EC_PC_ALIGN: { - sinfo( - "Breakpoint exception from a lower Exception level, " - "that might be using AArch32 or AArch64\n"); + ret = arm64_el1_pc(regs, esr); break; } - case 0b110001: - { - sinfo( - "Breakpoint exception taken without a change in " - "Exception level\n"); - break; - } + /* Trapped MSR, MRS or System instruction execution + * in AArch64 state + */ - case 0b110010: + case ESR_ELX_EC_SYS64: + case ESR_ELX_EC_UNKNOWN: { - sinfo( - "Software Step exception from a lower Exception level, " - "that might be using AArch32 or AArch64\n"); + ret = arm64_el1_undef(regs, esr); break; } - case 0b110011: - { - sinfo( - "Software Step exception taken without a change in " - "Exception level\n"); - break; - } + /* Branch Target Exception */ - case 0b110100: + case ESR_ELX_EC_BTI: { - sinfo( - "Watchpoint exception from a lower Exception level, " - "that might be using AArch32 or AArch64\n"); + ret = arm64_el1_bti(regs, esr); break; } - case 0b110101: + case ESR_ELX_EC_BREAKPT_CUR: + + /* Breakpoint exception taken in current Exception level */ + + case ESR_ELX_EC_SOFTSTP_CUR: + + /* Software Step exception taken in current Exception level */ + + case ESR_ELX_EC_WATCHPT_CUR: + + /* Watchpoint exception taken in current Exception level */ + + case ESR_ELX_EC_BRK64: { - sinfo( - "Watchpoint exception taken without a change in " - "Exception level.\n"); + /* BRK instruction execution in AArch64 state */ + + ret = arm64_el1_dbg(regs, esr); break; } - case 0b111000: + case ESR_ELX_EC_FPAC: { - sinfo("BKPT instruction execution in AArch32 state\n"); + /* Exception from a Pointer Authentication + * instruction authentication failure + */ + + ret = arm64_el1_fpac(regs, esr); break; } - case 0b111100: + default: { - sinfo("BRK instruction execution in AArch64 state.\n"); - break; + sinfo("64-bit el1h sync, esr = 0x%x", ec); + ret = -EINVAL; } + } - default: - break; - } + return ret; } -/**************************************************************************** - * Public Functions - ****************************************************************************/ +static int arm64_exception_handler(struct regs_context *regs) +{ + uint64_t el; + uint64_t esr; + uint64_t elr; + uint64_t far; + const char *el_str; + int ret = -EINVAL; + + el = arm64_current_el(); + + switch (el) + { + case MODE_EL1: + { + el_str = "MODE_EL1"; + esr = read_sysreg(esr_el1); + far = read_sysreg(far_el1); + elr = read_sysreg(elr_el1); + ret = arm64_el1_exception_handler(esr, regs); + break; + } -/**************************************************************************** - * Name: up_mdelay - ****************************************************************************/ + case MODE_EL2: + { + el_str = "MODE_EL2"; + esr = read_sysreg(esr_el2); + far = read_sysreg(far_el2); + elr = read_sysreg(elr_el2); + break; + } -void up_mdelay(unsigned int milliseconds) -{ - volatile unsigned int i; - volatile unsigned int j; +#ifdef CONFIG_ARCH_HAVE_EL3 + case MODE_EL3: + { + el_str = "MODE_EL3"; + esr = read_sysreg(esr_el3); + far = read_sysreg(far_el3); + elr = read_sysreg(elr_el3); + break; + } - for (i = 0; i < milliseconds; i++) +#endif + default: { - for (j = 0; j < CONFIG_BOARD_LOOPSPERMSEC; j++) - { - } + el_str = "Unknown"; + + /* Just to keep the compiler happy */ + + esr = elr = far = 0; + break; + } + } + + if (ret != 0) + { + sinfo("CurrentEL: %s\n", el_str); + sinfo("ESR_ELn: 0x%" PRIx64 "\n", esr); + sinfo("FAR_ELn: 0x%" PRIx64 "\n", far); + sinfo("ELR_ELn: 0x%" PRIx64 "\n", elr); + + print_ec_cause(esr); } + + return ret; } /**************************************************************************** - * Name: arm64_fatal_error - * - * Description: - * + * Public Functions ****************************************************************************/ -void arm64_fatal_error(unsigned int reason, struct regs_context * reg) +void arm64_fatal_handler(struct regs_context *regs) { - uint64_t el, esr, elr, far; + int ret; - sinfo("reason = %d\n", reason); + /* Nested exception are not supported */ - up_set_current_regs((uint64_t *)reg); + DEBUGASSERT(up_current_regs() == NULL); - if (reason != K_ERR_SPURIOUS_IRQ) - { - __asm__ volatile ("mrs %0, CurrentEL" : "=r" (el)); + up_set_current_regs((uint64_t *)regs); - switch (GET_EL(el)) - { - case MODE_EL1: - { - sinfo("CurrentEL: MODE_EL1\n"); - __asm__ volatile ("mrs %0, esr_el1" : "=r" (esr)); - __asm__ volatile ("mrs %0, far_el1" : "=r" (far)); - __asm__ volatile ("mrs %0, elr_el1" : "=r" (elr)); - break; - } - - case MODE_EL2: - { - sinfo("CurrentEL: MODE_EL2\n"); - __asm__ volatile ("mrs %0, esr_el2" : "=r" (esr)); - __asm__ volatile ("mrs %0, far_el2" : "=r" (far)); - __asm__ volatile ("mrs %0, elr_el2" : "=r" (elr)); - break; - } + ret = arm64_exception_handler(regs); -#ifdef CONFIG_ARCH_HAVE_EL3 - case MODE_EL3: - { - sinfo("CurrentEL: MODE_EL3\n"); - __asm__ volatile ("mrs %0, esr_el3" : "=r" (esr)); - __asm__ volatile ("mrs %0, far_el3" : "=r" (far)); - __asm__ volatile ("mrs %0, elr_el3" : "=r" (elr)); - break; - } -#endif + if (ret != 0) + { + /* The fatal is not handled, print error and hung */ - default: - { - sinfo("CurrentEL: unknown\n"); + PANIC_WITH_REGS("panic", regs); + } - /* Just to keep the compiler happy */ + /* Set CURRENT_REGS to NULL to indicate that we are no longer in an + * Exception handler. + */ - esr = elr = far = 0; - break; - } - } + up_set_current_regs(NULL); +} - if (GET_EL(el) != MODE_EL0) - { - sinfo("ESR_ELn: 0x%"PRIx64"\n", esr); - sinfo("FAR_ELn: 0x%"PRIx64"\n", far); - sinfo("ELR_ELn: 0x%"PRIx64"\n", elr); +void arm64_register_debug_hook(int nr, fatal_handle_func_t fn) +{ + DEBUGVERIFY(nr > 0 && nr <= nitems(g_debug_handler)); - print_ec_cause(esr); - } - } + /* Override the default handler */ - PANIC_WITH_REGS("panic", reg); + g_debug_handler[nr].handle_fn = fn; } diff --git a/arch/arm64/src/common/arm64_fatal.h b/arch/arm64/src/common/arm64_fatal.h index 360a28e8fa975..301e158f00011 100644 --- a/arch/arm64/src/common/arm64_fatal.h +++ b/arch/arm64/src/common/arm64_fatal.h @@ -21,12 +21,6 @@ #ifndef __ARCH_ARM64_SRC_COMMON_ARM64_FATAL_H #define __ARCH_ARM64_SRC_COMMON_ARM64_FATAL_H -/* Fatal error APIs */ - -#define K_ERR_CPU_EXCEPTION (0) -#define K_ERR_CPU_MODE32 (1) -#define K_ERR_SPURIOUS_IRQ (2) - #ifndef __ASSEMBLY__ /**************************************************************************** @@ -43,6 +37,123 @@ * Pre-processor Definitions ****************************************************************************/ +#define ESR_ELX_EC_UNKNOWN (0x00) +#define ESR_ELX_EC_WFX (0x01) + +/* Unallocated EC: 0x02 */ + +#define ESR_ELX_EC_CP15_32 (0x03) +#define ESR_ELX_EC_CP15_64 (0x04) +#define ESR_ELX_EC_CP14_MR (0x05) +#define ESR_ELX_EC_CP14_LS (0x06) +#define ESR_ELX_EC_FP_ASIMD (0x07) +#define ESR_ELX_EC_CP10_ID (0x08) /* EL2 only */ +#define ESR_ELX_EC_PAC (0x09) /* EL2 and above */ + +/* Unallocated EC: 0x0A - 0x0B */ + +#define ESR_ELX_EC_CP14_64 (0x0C) +#define ESR_ELX_EC_BTI (0x0D) +#define ESR_ELX_EC_ILL (0x0E) + +/* Unallocated EC: 0x0F - 0x10 */ + +#define ESR_ELX_EC_SVC32 (0x11) +#define ESR_ELX_EC_HVC32 (0x12) /* EL2 only */ +#define ESR_ELX_EC_SMC32 (0x13) /* EL2 and above */ + +/* Unallocated EC: 0x14 */ + +#define ESR_ELX_EC_SVC64 (0x15) +#define ESR_ELX_EC_HVC64 (0x16) /* EL2 and above */ +#define ESR_ELX_EC_SMC64 (0x17) /* EL2 and above */ +#define ESR_ELX_EC_SYS64 (0x18) +#define ESR_ELX_EC_SVE (0x19) +#define ESR_ELX_EC_ERET (0x1a) /* EL2 only */ + +/* Unallocated EC: 0x1B */ + +#define ESR_ELX_EC_FPAC (0x1C) /* EL1 and above */ +#define ESR_ELX_EC_SME (0x1D) + +/* Unallocated EC: 0x1D - 0x1E */ + +#define ESR_ELX_EC_IMP_DEF (0x1f) /* EL3 only */ +#define ESR_ELX_EC_IABT_LOW (0x20) +#define ESR_ELX_EC_IABT_CUR (0x21) +#define ESR_ELX_EC_PC_ALIGN (0x22) + +/* Unallocated EC: 0x23 */ + +#define ESR_ELX_EC_DABT_LOW (0x24) +#define ESR_ELX_EC_DABT_CUR (0x25) +#define ESR_ELX_EC_SP_ALIGN (0x26) +#define ESR_ELX_EC_MOPS (0x27) +#define ESR_ELX_EC_FP_EXC32 (0x28) + +/* Unallocated EC: 0x29 - 0x2B */ + +#define ESR_ELX_EC_FP_EXC64 (0x2C) + +/* Unallocated EC: 0x2D - 0x2E */ + +#define ESR_ELX_EC_SERROR (0x2F) +#define ESR_ELX_EC_BREAKPT_LOW (0x30) +#define ESR_ELX_EC_BREAKPT_CUR (0x31) +#define ESR_ELX_EC_SOFTSTP_LOW (0x32) +#define ESR_ELX_EC_SOFTSTP_CUR (0x33) +#define ESR_ELX_EC_WATCHPT_LOW (0x34) +#define ESR_ELX_EC_WATCHPT_CUR (0x35) + +/* Unallocated EC: 0x36 - 0x37 */ + +#define ESR_ELX_EC_BKPT32 (0x38) + +/* Unallocated EC: 0x39 */ + +#define ESR_ELX_EC_VECTOR32 (0x3A) /* EL2 only */ + +/* Unallocated EC: 0x3B */ + +#define ESR_ELX_EC_BRK64 (0x3C) + +/* Unallocated EC: 0x3D - 0x3F */ + +#define ESR_ELX_EC_MAX (0x3F) + +#define ESR_ELX_EC_SHIFT (26) +#define ESR_ELX_EC_WIDTH (6) +#define ESR_ELX_EC_MASK (0x3F << ESR_ELX_EC_SHIFT) +#define ESR_ELX_EC(esr) (((esr) & ESR_ELX_EC_MASK) \ + >> ESR_ELX_EC_SHIFT) + +/* Shared ISS fault status code(IFSC/DFSC) for Data/Instruction aborts */ + +#define ESR_ELX_FSC (0x3F) +#define ESR_ELX_FSC_TYPE (0x3C) +#define ESR_ELX_FSC_LEVEL (0x03) +#define ESR_ELX_FSC_EXTABT (0x10) +#define ESR_ELX_FSC_MTE (0x11) +#define ESR_ELX_FSC_SERROR (0x11) +#define ESR_ELX_FSC_ACCESS (0x08) +#define ESR_ELX_FSC_FAULT (0x04) +#define ESR_ELX_FSC_PERM (0x0C) +#define ESR_ELX_FSC_SEA_TTW0 (0x14) +#define ESR_ELX_FSC_SEA_TTW1 (0x15) +#define ESR_ELX_FSC_SEA_TTW2 (0x16) +#define ESR_ELX_FSC_SEA_TTW3 (0x17) +#define ESR_ELX_FSC_SECC (0x18) +#define ESR_ELX_FSC_SECC_TTW0 (0x1c) +#define ESR_ELX_FSC_SECC_TTW1 (0x1d) +#define ESR_ELX_FSC_SECC_TTW2 (0x1e) +#define ESR_ELX_FSC_SECC_TTW3 (0x1f) + +#define DBG_ESR_EVT(x) (((x) >> 27) & 0x7) +#define DBG_ESR_EVT_HWBP (0x0) +#define DBG_ESR_EVT_HWSS (0x1) +#define DBG_ESR_EVT_HWWP (0x2) +#define DBG_ESR_EVT_BRK (0x6) + #define __builtin_unreachable() \ do \ { \ @@ -51,28 +162,49 @@ } while (true) /**************************************************************************** - * Public Data + * Public Type Declarations ****************************************************************************/ +typedef int (*fatal_handle_func_t)(struct regs_context *regs, + uint64_t far, uint64_t esr); + /**************************************************************************** * Public Function Prototypes ****************************************************************************/ /**************************************************************************** - * Name: arm64_fatal_error + * Name: arm64_fatal_handler * * Description: - * fatal error handle for arm64 + * Fatal handle for arm64 * Input Parameters: - * reason: error reason * reg: exception stack reg context * - * Returned Value: + * Returned Value: None + * If the function return, the exception has been handled + * + ****************************************************************************/ + +void arm64_fatal_handler(struct regs_context *reg); + +/**************************************************************************** + * Name: arm64_register_debug_hook + * + * Description: + * Register a hook function for DEBUG event + * Input Parameters: + * nr: DEBUG event + * DBG_ESR_EVT_HWBP : Hardware BreakPoint + * DBG_ESR_EVT_HWSS : Hardware SingleStep + * DBG_ESR_EVT_HWWP : Hardware WatchPoint + * DBG_ESR_EVT_BRK : Brk instruction trigger + * fn: hook function + * + * Returned Value: none * ****************************************************************************/ -void arm64_fatal_error(unsigned int reason, struct regs_context * reg); -void arm64_dump_fatal(struct regs_context * reg); +void arm64_register_debug_hook(int nr, fatal_handle_func_t fn); #endif /* __ASSEMBLY__ */ diff --git a/arch/arm64/src/common/arm64_vector_table.S b/arch/arm64/src/common/arm64_vector_table.S index fa81c4e888e7f..1c05814c8763b 100644 --- a/arch/arm64/src/common/arm64_vector_table.S +++ b/arch/arm64/src/common/arm64_vector_table.S @@ -216,25 +216,25 @@ SECTION_SUBSEC_FUNC(exc_vector_table,_vector_table_section,_vector_table) .align 7 arm64_enter_exception x0, x1 - b arm64_mode32_error + b arm64_mode32_handler /* Lower EL using AArch32 / IRQ */ .align 7 arm64_enter_exception x0, x1 - b arm64_mode32_error + b arm64_mode32_handler /* Lower EL using AArch32 / FIQ */ .align 7 arm64_enter_exception x0, x1 - b arm64_mode32_error + b arm64_mode32_handler /* Lower EL using AArch32 / SError */ .align 7 arm64_enter_exception x0, x1 - b arm64_mode32_error + b arm64_mode32_handler /* Restore Corruptible Registers and exception context * from the task stack. diff --git a/arch/arm64/src/common/arm64_vectors.S b/arch/arm64/src/common/arm64_vectors.S index d2d1e5c95a309..26aa2888b973f 100644 --- a/arch/arm64/src/common/arm64_vectors.S +++ b/arch/arm64/src/common/arm64_vectors.S @@ -355,16 +355,13 @@ save_context: b arm64_exit_exception exc_handle: - arm64_exception_context_save x0 x1 sp - mov x0, #K_ERR_CPU_EXCEPTION - mov x1, sp + mov x0, sp - /* void arm64_fatal_error(unsigned int reason, const uint64_t *regs) - * x0 = reason - * x1 = Exception stack frame + /* void arm64_fatal_handler(struct regs_context * reg); + * x0 = Exception stack frame */ - bl arm64_fatal_error + bl arm64_fatal_handler /* Return here only in case of recoverable error */ @@ -445,28 +442,20 @@ irq_context_switch: irq_exit: b arm64_exit_exception -/* TODO: if the arm64_fatal_error return success, maybe need context switch */ +/* TODO: if the arm64_fatal_handler return success, maybe need context switch */ GTEXT(arm64_serror_handler) SECTION_FUNC(text, arm64_serror_handler) - arm64_exception_context_save x0 x1 sp - - mov x0, #K_ERR_CPU_EXCEPTION - mov x1, sp - - bl arm64_fatal_error + mov x0, sp + bl arm64_fatal_handler /* Return here only in case of recoverable error */ b arm64_exit_exception -GTEXT(arm64_mode32_error) -SECTION_FUNC(text, arm64_mode32_error) - arm64_exception_context_save x0 x1 sp - - mov x1, sp - mov x0, #K_ERR_CPU_MODE32 - - bl arm64_fatal_error +GTEXT(arm64_mode32_handler) +SECTION_FUNC(text, arm64_mode32_handler) + mov x0, sp + bl arm64_fatal_handler /* Return here only in case of recoverable error */ b arm64_exit_exception @@ -474,12 +463,9 @@ SECTION_FUNC(text, arm64_mode32_error) GTEXT(arm64_fiq_handler) SECTION_FUNC(text, arm64_fiq_handler) #ifndef CONFIG_ARM64_DECODEFIQ - arm64_exception_context_save x0 x1 sp - - mov x1, sp - mov x0, #K_ERR_SPURIOUS_IRQ /* K_ERR_SPURIOUS_IRQ */ - bl arm64_fatal_error + mov x0, sp + bl arm64_fatal_handler /* Return here only in case of recoverable error */ From 43b49c27d0219618f79e04eab7c10cffc770bac6 Mon Sep 17 00:00:00 2001 From: ligd Date: Mon, 29 Jan 2024 18:22:38 +0800 Subject: [PATCH 2/5] arm64: save FPU regs every time Signed-off-by: ligd --- arch/arm64/src/common/arm64_arch.h | 3 + arch/arm64/src/common/arm64_exit.c | 6 - arch/arm64/src/common/arm64_fpu.c | 140 +----------------- arch/arm64/src/common/arm64_initialstate.c | 20 --- .../src/common/arm64_schedulesigaction.c | 29 ---- arch/arm64/src/common/arm64_sigdeliver.c | 9 -- arch/arm64/src/common/arm64_syscall.c | 1 - arch/arm64/src/common/arm64_vector_table.S | 75 +++++----- arch/arm64/src/common/arm64_vectors.S | 129 ++-------------- 9 files changed, 53 insertions(+), 359 deletions(-) diff --git a/arch/arm64/src/common/arm64_arch.h b/arch/arm64/src/common/arm64_arch.h index 06935472fb595..35c4cdc105c15 100644 --- a/arch/arm64/src/common/arm64_arch.h +++ b/arch/arm64/src/common/arm64_arch.h @@ -299,6 +299,9 @@ struct regs_context uint64_t spsr; uint64_t sp_el0; uint64_t exe_depth; +#ifdef CONFIG_ARCH_FPU + struct fpu_reg fpu_regs; +#endif }; /**************************************************************************** diff --git a/arch/arm64/src/common/arm64_exit.c b/arch/arm64/src/common/arm64_exit.c index 0052adac94a74..cb0d4bd24a2ff 100644 --- a/arch/arm64/src/common/arm64_exit.c +++ b/arch/arm64/src/common/arm64_exit.c @@ -65,12 +65,6 @@ void up_exit(int status) */ enter_critical_section(); - - /* Destroy the task at the head of the ready to run list. */ -#ifdef CONFIG_ARCH_FPU - arm64_destory_fpu(tcb); -#endif - nxtask_exit(); /* Now, perform the context switch to the new ready-to-run task at the diff --git a/arch/arm64/src/common/arm64_fpu.c b/arch/arm64/src/common/arm64_fpu.c index c1accb48ebfa5..e80e7240aee29 100644 --- a/arch/arm64/src/common/arm64_fpu.c +++ b/arch/arm64/src/common/arm64_fpu.c @@ -77,11 +77,10 @@ struct arm64_fpu_procfs_file_s * Private Data ***************************************************************************/ -static struct fpu_reg g_idle_thread_fpu[CONFIG_SMP_NCPUS]; -static struct arm64_cpu_fpu_context g_cpu_fpu_ctx[CONFIG_SMP_NCPUS]; - #ifdef CONFIG_FS_PROCFS_REGISTER +static struct arm64_cpu_fpu_context g_cpu_fpu_ctx[CONFIG_SMP_NCPUS]; + /* procfs methods */ static int arm64_fpu_procfs_open(struct file *filep, const char *relpath, @@ -262,141 +261,6 @@ static int arm64_fpu_procfs_stat(const char *relpath, struct stat *buf) } #endif -/*************************************************************************** - * Public Functions - ***************************************************************************/ - -void arm64_init_fpu(struct tcb_s *tcb) -{ - if (tcb->pid < CONFIG_SMP_NCPUS) - { -#ifdef CONFIG_SMP - int cpu = tcb->cpu; -#else - int cpu = 0; -#endif - memset(&g_cpu_fpu_ctx[cpu], 0, - sizeof(struct arm64_cpu_fpu_context)); - g_cpu_fpu_ctx[cpu].idle_thread = tcb; - - tcb->xcp.fpu_regs = (uint64_t *)&g_idle_thread_fpu[cpu]; - } - - memset(tcb->xcp.fpu_regs, 0, sizeof(struct fpu_reg)); -} - -void arm64_destory_fpu(struct tcb_s *tcb) -{ - struct tcb_s *owner; - - /* save current fpu owner's context */ - - owner = g_cpu_fpu_ctx[this_cpu()].fpu_owner; - - if (owner == tcb) - { - g_cpu_fpu_ctx[this_cpu()].fpu_owner = NULL; - } -} - -/*************************************************************************** - * Name: arm64_fpu_enter_exception - * - * Description: - * called at every time get into a exception - * - ***************************************************************************/ - -void arm64_fpu_enter_exception(void) -{ -} - -void arm64_fpu_exit_exception(void) -{ -} - -void arm64_fpu_trap(struct regs_context *regs) -{ - struct tcb_s *owner; - - UNUSED(regs); - - /* disable fpu trap access */ - - arm64_fpu_access_trap_disable(); - - /* save current fpu owner's context */ - - owner = g_cpu_fpu_ctx[this_cpu()].fpu_owner; - - if (owner != NULL) - { - arm64_fpu_save((struct fpu_reg *)owner->xcp.fpu_regs); - ARM64_DSB(); - g_cpu_fpu_ctx[this_cpu()].save_count++; - g_cpu_fpu_ctx[this_cpu()].fpu_owner = NULL; - } - - if (arch_get_exception_depth() > 1) - { - /* if get_exception_depth > 1 - * it means FPU access exception occurred in exception context - * switch FPU owner to idle thread - */ - - owner = g_cpu_fpu_ctx[this_cpu()].idle_thread; - } - else - { - owner = running_task(); - } - - /* restore our context */ - - arm64_fpu_restore((struct fpu_reg *)owner->xcp.fpu_regs); - g_cpu_fpu_ctx[this_cpu()].restore_count++; - - /* become new owner */ - - g_cpu_fpu_ctx[this_cpu()].fpu_owner = owner; -} - -void arm64_fpu_context_restore(void) -{ - struct tcb_s *new_tcb = running_task(); - - arm64_fpu_access_trap_disable(); - - /* FPU trap has happened at this task */ - - if (new_tcb == g_cpu_fpu_ctx[this_cpu()].fpu_owner) - { - arm64_fpu_access_trap_disable(); - } - else - { - arm64_fpu_access_trap_enable(); - } - - g_cpu_fpu_ctx[this_cpu()].switch_count++; -} - -#ifdef CONFIG_SMP -void arm64_fpu_context_save(void) -{ - struct tcb_s *tcb = running_task(); - - if (tcb == g_cpu_fpu_ctx[this_cpu()].fpu_owner) - { - arm64_fpu_access_trap_disable(); - arm64_fpu_save((struct fpu_reg *)tcb->xcp.fpu_regs); - ARM64_DSB(); - g_cpu_fpu_ctx[this_cpu()].save_count++; - g_cpu_fpu_ctx[this_cpu()].fpu_owner = NULL; - } -} -#endif - void arm64_fpu_enable(void) { irqstate_t flags = up_irq_save(); diff --git a/arch/arm64/src/common/arm64_initialstate.c b/arch/arm64/src/common/arm64_initialstate.c index 93aa822fff6ec..32058db4855d4 100644 --- a/arch/arm64/src/common/arm64_initialstate.c +++ b/arch/arm64/src/common/arm64_initialstate.c @@ -47,10 +47,6 @@ #include "chip.h" #include "arm64_fatal.h" -#ifdef CONFIG_ARCH_FPU -#include "arm64_fpu.h" -#endif - /**************************************************************************** * Public Functions ****************************************************************************/ @@ -70,17 +66,6 @@ void arm64_new_task(struct tcb_s * tcb) } #endif -#ifdef CONFIG_ARCH_FPU - struct fpu_reg *pfpuctx; - pfpuctx = STACK_PTR_TO_FRAME(struct fpu_reg, stack_ptr); - tcb->xcp.fpu_regs = (uint64_t *)pfpuctx; - - /* set fpu context */ - - arm64_init_fpu(tcb); - stack_ptr = (uintptr_t)pfpuctx; -#endif - pinitctx = STACK_PTR_TO_FRAME(struct regs_context, stack_ptr); memset(pinitctx, 0, sizeof(struct regs_context)); pinitctx->elr = (uint64_t)tcb->start; @@ -150,11 +135,6 @@ void up_initial_state(struct tcb_s *tcb) tcb->stack_base_ptr = tcb->stack_alloc_ptr; tcb->adj_stack_size = CONFIG_IDLETHREAD_STACKSIZE; -#ifdef CONFIG_ARCH_FPU - /* set fpu context */ - - arm64_init_fpu(tcb); -#endif /* set initialize idle thread tcb and exception depth * core 0, idle0 */ diff --git a/arch/arm64/src/common/arm64_schedulesigaction.c b/arch/arm64/src/common/arm64_schedulesigaction.c index 888c8106268dd..4f0534345a2ff 100644 --- a/arch/arm64/src/common/arm64_schedulesigaction.c +++ b/arch/arm64/src/common/arm64_schedulesigaction.c @@ -38,10 +38,6 @@ #include "irq/irq.h" #include "arm64_fatal.h" -#ifdef CONFIG_ARCH_FPU -#include "arm64_fpu.h" -#endif - /**************************************************************************** * Public Functions ****************************************************************************/ @@ -58,16 +54,6 @@ void arm64_init_signal_process(struct tcb_s *tcb, struct regs_context *regs) struct regs_context *psigctx; char *stack_ptr = (char *)pctx->sp_elx - sizeof(struct regs_context); -#ifdef CONFIG_ARCH_FPU - struct fpu_reg *pfpuctx; - pfpuctx = STACK_PTR_TO_FRAME(struct fpu_reg, stack_ptr); - tcb->xcp.fpu_regs = (uint64_t *)pfpuctx; - - /* set fpu context */ - - arm64_init_fpu(tcb); - stack_ptr = (char *)pfpuctx; -#endif psigctx = STACK_PTR_TO_FRAME(struct regs_context, stack_ptr); memset(psigctx, 0, sizeof(struct regs_context)); psigctx->elr = (uint64_t)arm64_sigdeliver; @@ -177,9 +163,6 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) /* create signal process context */ tcb->xcp.saved_reg = up_current_regs(); -#ifdef CONFIG_ARCH_FPU - tcb->xcp.saved_fpu_regs = tcb->xcp.fpu_regs; -#endif arm64_init_signal_process(tcb, (struct regs_context *)up_current_regs()); @@ -201,9 +184,6 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) * have been delivered. */ -#ifdef CONFIG_ARCH_FPU - tcb->xcp.saved_fpu_regs = tcb->xcp.fpu_regs; -#endif /* create signal process context */ tcb->xcp.saved_reg = tcb->xcp.regs; @@ -279,9 +259,6 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) * been delivered. */ -#ifdef CONFIG_ARCH_FPU - tcb->xcp.saved_fpu_regs = tcb->xcp.fpu_regs; -#endif /* create signal process context */ tcb->xcp.saved_reg = tcb->xcp.regs; @@ -300,9 +277,6 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) /* create signal process context */ tcb->xcp.saved_reg = up_current_regs(); -#ifdef CONFIG_ARCH_FPU - tcb->xcp.saved_fpu_regs = tcb->xcp.fpu_regs; -#endif arm64_init_signal_process(tcb, (struct regs_context *)up_current_regs()); @@ -339,9 +313,6 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) * have been delivered. */ -#ifdef CONFIG_ARCH_FPU - tcb->xcp.saved_fpu_regs = tcb->xcp.fpu_regs; -#endif tcb->xcp.saved_reg = tcb->xcp.regs; /* create signal process context */ diff --git a/arch/arm64/src/common/arm64_sigdeliver.c b/arch/arm64/src/common/arm64_sigdeliver.c index 15e7946c7c007..0d46a98410db9 100644 --- a/arch/arm64/src/common/arm64_sigdeliver.c +++ b/arch/arm64/src/common/arm64_sigdeliver.c @@ -38,10 +38,6 @@ #include "irq/irq.h" #include "arm64_fatal.h" -#ifdef CONFIG_ARCH_FPU -#include "arm64_fpu.h" -#endif - /**************************************************************************** * Public Functions ****************************************************************************/ @@ -157,11 +153,6 @@ void arm64_sigdeliver(void) rtcb->xcp.sigdeliver = NULL; /* Allows next handler to be scheduled */ rtcb->xcp.regs = rtcb->xcp.saved_reg; -#ifdef CONFIG_ARCH_FPU - arm64_destory_fpu(rtcb); - rtcb->xcp.fpu_regs = rtcb->xcp.saved_fpu_regs; -#endif - /* Then restore the correct state for this thread of execution. */ #ifdef CONFIG_SMP diff --git a/arch/arm64/src/common/arm64_syscall.c b/arch/arm64/src/common/arm64_syscall.c index 318e7e0cf60f3..c59aef35cbd0c 100644 --- a/arch/arm64/src/common/arm64_syscall.c +++ b/arch/arm64/src/common/arm64_syscall.c @@ -193,7 +193,6 @@ uint64_t *arm64_syscall_switch(uint64_t * regs) */ ret_regs = (uint64_t *)f_regs->regs[REG_X1]; - f_regs->regs[REG_X1] = 0; /* set the saveregs = 0 */ DEBUGASSERT(ret_regs); } diff --git a/arch/arm64/src/common/arm64_vector_table.S b/arch/arm64/src/common/arm64_vector_table.S index 1c05814c8763b..21b70d2575207 100644 --- a/arch/arm64/src/common/arm64_vector_table.S +++ b/arch/arm64/src/common/arm64_vector_table.S @@ -45,8 +45,8 @@ * but only save ARM64_ESF_REGS */ -.macro arm64_enter_exception xreg0, xreg1 - sub sp, sp, #8 * XCPTCONTEXT_GP_REGS +.macro arm64_enter_exception + sub sp, sp, #8 * XCPTCONTEXT_REGS stp x0, x1, [sp, #8 * REG_X0] stp x2, x3, [sp, #8 * REG_X2] @@ -65,30 +65,32 @@ stp x28, x29, [sp, #8 * REG_X28] /* Save the current task's SP_ELx and x30 */ - add \xreg0, sp, #8 * XCPTCONTEXT_GP_REGS - stp x30, \xreg0, [sp, #8 * REG_X30] + add x0, sp, #8 * XCPTCONTEXT_REGS + stp x30, x0, [sp, #8 * REG_X30] /* ELR and SPSR */ #if CONFIG_ARCH_ARM64_EXCEPTION_LEVEL == 3 - mrs \xreg0, elr_el3 - mrs \xreg1, spsr_el3 + mrs x0, elr_el3 + mrs x1, spsr_el3 #else - mrs \xreg0, elr_el1 - mrs \xreg1, spsr_el1 + mrs x0, elr_el1 + mrs x1, spsr_el1 #endif - stp \xreg0, \xreg1, [sp, #8 * REG_ELR] + stp x0, x1, [sp, #8 * REG_ELR] - /* increment exception depth */ + /* Increment exception depth */ - mrs \xreg0, tpidrro_el0 - mov \xreg1, #1 - add \xreg0, \xreg0, \xreg1 - msr tpidrro_el0, \xreg0 + mrs x0, tpidrro_el0 + mov x1, #1 + add x0, x0, x1 + msr tpidrro_el0, x0 + /* Save the FPU registers */ + + add x0, sp, #8 * XCPTCONTEXT_GP_REGS #ifdef CONFIG_ARCH_FPU - bl arm64_fpu_enter_exception + bl arm64_fpu_save #endif - .endm /**************************************************************************** @@ -143,97 +145,97 @@ SECTION_SUBSEC_FUNC(exc_vector_table,_vector_table_section,_vector_table) /* Current EL with SP0 / Synchronous */ .align 7 - arm64_enter_exception x9, x10 + arm64_enter_exception b arm64_sync_exc /* Current EL with SP0 / IRQ */ .align 7 - arm64_enter_exception x0, x1 + arm64_enter_exception b arm64_irq_handler /* Current EL with SP0 / FIQ */ .align 7 - arm64_enter_exception x0, x1 + arm64_enter_exception b arm64_fiq_handler /* Current EL with SP0 / SError */ .align 7 - arm64_enter_exception x0, x1 + arm64_enter_exception b arm64_serror_handler /* Current EL with SPx / Synchronous */ .align 7 - arm64_enter_exception x9, x10 + arm64_enter_exception b arm64_sync_exc /* Current EL with SPx / IRQ */ .align 7 - arm64_enter_exception x0, x1 + arm64_enter_exception b arm64_irq_handler /* Current EL with SPx / FIQ */ .align 7 - arm64_enter_exception x0, x1 + arm64_enter_exception b arm64_fiq_handler /* Current EL with SPx / SError */ .align 7 - arm64_enter_exception x0, x1 + arm64_enter_exception b arm64_serror_handler /* Lower EL using AArch64 / Synchronous */ .align 7 - arm64_enter_exception x9, x10 + arm64_enter_exception b arm64_sync_exc /* Lower EL using AArch64 / IRQ */ .align 7 - arm64_enter_exception x0, x1 + arm64_enter_exception b arm64_irq_handler /* Lower EL using AArch64 / FIQ */ .align 7 - arm64_enter_exception x0, x1 + arm64_enter_exception b arm64_fiq_handler /* Lower EL using AArch64 / SError */ .align 7 - arm64_enter_exception x0, x1 + arm64_enter_exception b arm64_serror_handler /* Lower EL using AArch32 / Synchronous */ .align 7 - arm64_enter_exception x0, x1 + arm64_enter_exception b arm64_mode32_handler /* Lower EL using AArch32 / IRQ */ .align 7 - arm64_enter_exception x0, x1 + arm64_enter_exception b arm64_mode32_handler /* Lower EL using AArch32 / FIQ */ .align 7 - arm64_enter_exception x0, x1 + arm64_enter_exception b arm64_mode32_handler /* Lower EL using AArch32 / SError */ .align 7 - arm64_enter_exception x0, x1 + arm64_enter_exception b arm64_mode32_handler /* Restore Corruptible Registers and exception context @@ -242,10 +244,11 @@ SECTION_SUBSEC_FUNC(exc_vector_table,_vector_table_section,_vector_table) GTEXT(arm64_exit_exception) SECTION_FUNC(text, arm64_exit_exception) + + mov sp, x0 + add x0, x0, #8 * XCPTCONTEXT_GP_REGS #ifdef CONFIG_ARCH_FPU - bl arm64_fpu_exit_exception -GTEXT(arm64_exit_exc_fpu_done) -arm64_exit_exc_fpu_done: + bl arm64_fpu_restore #endif /* restore spsr and elr at el1*/ @@ -283,6 +286,6 @@ arm64_exit_exc_fpu_done: ldp x28, x29, [sp, #8 * REG_X28] ldp x30, xzr, [sp, #8 * REG_X30] - add sp, sp, #8 * XCPTCONTEXT_GP_REGS + add sp, sp, #8 * XCPTCONTEXT_REGS eret diff --git a/arch/arm64/src/common/arm64_vectors.S b/arch/arm64/src/common/arm64_vectors.S index 26aa2888b973f..05e874262e40a 100644 --- a/arch/arm64/src/common/arm64_vectors.S +++ b/arch/arm64/src/common/arm64_vectors.S @@ -99,63 +99,6 @@ SECTION_FUNC(text, up_saveusercontext) ret -/**************************************************************************** - * Function: arm64_context_switch - * - * Description: - * Routine to handle context switch - * - * arm64_context_switch( x0, x1) - * x0: restore thread stack context - * x1: save thread stack context - * note: - * x1 = 0, only restore x0 - * - ****************************************************************************/ - -GTEXT(arm64_context_switch) -SECTION_FUNC(text, arm64_context_switch) - cmp x1, #0x0 - beq restore_new - -#if defined(CONFIG_ARCH_FPU) && defined(CONFIG_SMP) - stp x0, x1, [sp, #-16]! - stp xzr, x30, [sp, #-16]! - bl arm64_fpu_context_save - ldp xzr, x30, [sp], #16 - ldp x0, x1, [sp], #16 -#endif - - /* Save the current SP_ELx */ - add x4, sp, #8 * XCPTCONTEXT_GP_REGS - str x4, [x1, #8 * REG_SP_ELX] - - /* Save the current task's SP_EL0 and exception depth */ - mrs x4, sp_el0 - mrs x5, tpidrro_el0 - stp x4, x5, [x1, #8 * REG_SP_EL0] - -restore_new: - - /* Restore SP_EL0 and thread's exception dept */ - ldp x4, x5, [x0, #8 * REG_SP_EL0] - msr tpidrro_el0, x5 - msr sp_el0, x4 - - /* retrieve new thread's SP_ELx */ - ldr x4, [x0, #8 * REG_SP_ELX] - sub sp, x4, #8 * XCPTCONTEXT_GP_REGS - -#ifdef CONFIG_ARCH_FPU - stp xzr, x30, [sp, #-16]! - bl arm64_fpu_context_restore - ldp xzr, x30, [sp], #16 -#endif - - /* Return to arm64_sync_exc() or arm64_irq_handler() */ - - ret - /**************************************************************************** * Function: arm64_jump_to_user * @@ -199,28 +142,27 @@ SECTION_FUNC(text, arm64_sync_exc) /* checking the EC value to see which exception need to be handle */ #if CONFIG_ARCH_ARM64_EXCEPTION_LEVEL == 3 - mrs x9, esr_el3 + mrs x0, esr_el3 #else - mrs x9, esr_el1 + mrs x0, esr_el1 #endif - lsr x10, x9, #26 + lsr x1, x0, #26 #ifdef CONFIG_ARCH_FPU /* fpu trap */ - cmp x10, #0x07 /* Access to SIMD or floating-point */ + cmp x1, #0x07 /*Access to SIMD or floating-point */ bne 1f - mov x0, sp /* x0 = context */ - bl arm64_fpu_trap + mov x0, sp /* when the fpu trap is handled */ - b arm64_exit_exc_fpu_done + b arm64_exit_exception 1: #endif /* 0x15 = SVC system call */ - cmp x10, #0x15 + cmp x1, #0x15 /* if this is a svc call ?*/ @@ -308,17 +250,13 @@ context_switch: */ mov x0, sp + str x0, [sp, #-16]! bl arm64_syscall_switch /* get save task reg context pointer */ - ldr x1, [sp, #8 * REG_X1] - cmp x1, #0x0 - - beq do_switch - ldr x1, [x1] + ldr x1, [sp], #16 -do_switch: #ifdef CONFIG_SMP /* Notes: * Complete any pending TLB or cache maintenance on this CPU in case @@ -330,15 +268,7 @@ do_switch: dsb ish #endif - bl arm64_context_switch - -#ifdef CONFIG_ARCH_FPU - /* when the fpu trap is handled */ - - b arm64_exit_exc_fpu_done -#else b arm64_exit_exception -#endif save_context: arm64_exception_context_save x0 x1 sp @@ -408,14 +338,6 @@ SECTION_FUNC(text, arm64_irq_handler) ldr x1, [sp], #16 - /* retrieve the task's stack. */ - - mov sp, x1 - - cmp x0, x1 - beq irq_exit - -irq_context_switch: #ifdef CONFIG_SMP /* Notes: * Complete any pending TLB or cache maintenance on this CPU in case @@ -427,19 +349,6 @@ irq_context_switch: #endif - /* Switch thread - * - x0: restore task reg context, return by arm64_decodeirq, - * - x1: save task reg context, save before call arm64_decodeirq - * call arm64_context_switch(x0) to switch - */ - bl arm64_context_switch -#ifdef CONFIG_ARCH_FPU - /* when the fpu trap is handled */ - - b arm64_exit_exc_fpu_done -#endif - -irq_exit: b arm64_exit_exception /* TODO: if the arm64_fatal_handler return success, maybe need context switch */ @@ -502,14 +411,6 @@ SECTION_FUNC(text, arm64_fiq_handler) ldr x1, [sp], #16 - /* retrieve the task's stack. */ - - mov sp, x1 - - cmp x0, x1 - beq fiq_exit - - #ifdef CONFIG_SMP /* Notes: * Complete any pending TLB or cache maintenance on this CPU in case @@ -521,17 +422,5 @@ SECTION_FUNC(text, arm64_fiq_handler) #endif - /* Switch thread - * - x0: restore task reg context, return by arm64_decodefiq, - * - x1: save task reg context, save before call arm64_decodefiq - * call arm64_context_switch(x0) to switch - */ - bl arm64_context_switch -#ifdef CONFIG_ARCH_FPU - /* when the fpu trap is handled */ - - b arm64_exit_exc_fpu_done -#endif -fiq_exit: b arm64_exit_exception #endif From 37ff50324b614e091d193ac09bb7d88324052820 Mon Sep 17 00:00:00 2001 From: qinwei1 Date: Mon, 30 Oct 2023 17:44:57 +0800 Subject: [PATCH 3/5] arm64: add arm64_current_el to obtain current EL Summary Add a macro to obtain current execute level Signed-off-by: qinwei1 --- arch/arm64/src/common/arm64_arch.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/arch/arm64/src/common/arm64_arch.h b/arch/arm64/src/common/arm64_arch.h index 35c4cdc105c15..d2310128e8368 100644 --- a/arch/arm64/src/common/arm64_arch.h +++ b/arch/arm64/src/common/arm64_arch.h @@ -394,6 +394,26 @@ static inline void arch_nop(void) __asm__ volatile ("nop"); } +/**************************************************************************** + * Name: + * arm64_current_el() + * + * Description: + * + * Get current execution level + * + ****************************************************************************/ + +#define arm64_current_el() \ + ({ \ + uint64_t __el; \ + int __ret; \ + __asm__ volatile ("mrs %0, CurrentEL" \ + : "=r" (__el)); \ + __ret = GET_EL(__el); \ + __ret; \ + }) + /**************************************************************************** * Name: * read_/write_/zero_ sysreg From 671c1f9c1c688a1a59da49051e640dbcb9783516 Mon Sep 17 00:00:00 2001 From: ligd Date: Sun, 4 Feb 2024 21:37:50 +0800 Subject: [PATCH 4/5] arm64: simply the vectors Signed-off-by: ligd --- arch/arm64/src/common/arm64_internal.h | 3 +- arch/arm64/src/common/arm64_syscall.c | 162 +++++++-------- arch/arm64/src/common/arm64_vectors.S | 271 ++++++------------------- 3 files changed, 128 insertions(+), 308 deletions(-) diff --git a/arch/arm64/src/common/arm64_internal.h b/arch/arm64/src/common/arm64_internal.h index 19c8b9eb69f64..594a644ce0614 100644 --- a/arch/arm64/src/common/arm64_internal.h +++ b/arch/arm64/src/common/arm64_internal.h @@ -312,8 +312,7 @@ void arm64_pginitialize(void); # define arm64_pginitialize() #endif /* CONFIG_LEGACY_PAGING */ -uint64_t * arm64_syscall_switch(uint64_t *regs); -int arm64_syscall(uint64_t *regs); +uint64_t *arm64_syscall(uint64_t *regs); /* Low level serial output **************************************************/ diff --git a/arch/arm64/src/common/arm64_syscall.c b/arch/arm64/src/common/arm64_syscall.c index c59aef35cbd0c..d75a207ee92ea 100644 --- a/arch/arm64/src/common/arm64_syscall.c +++ b/arch/arm64/src/common/arm64_syscall.c @@ -53,18 +53,18 @@ typedef uintptr_t (*syscall_t)(unsigned int, ...); ****************************************************************************/ static void arm64_dump_syscall(const char *tag, uint64_t cmd, - const struct regs_context * f_regs) + const uint64_t *regs) { - svcinfo("SYSCALL %s: regs: %p cmd: %" PRId64 "\n", tag, f_regs, cmd); + svcinfo("SYSCALL %s: regs: %p cmd: %" PRId64 "\n", tag, regs, cmd); svcinfo("x0: 0x%-16lx x1: 0x%lx\n", - f_regs->regs[REG_X0], f_regs->regs[REG_X1]); + regs[REG_X0], regs[REG_X1]); svcinfo("x2: 0x%-16lx x3: 0x%lx\n", - f_regs->regs[REG_X2], f_regs->regs[REG_X3]); + regs[REG_X2], regs[REG_X3]); svcinfo("x4: 0x%-16lx x5: 0x%lx\n", - f_regs->regs[REG_X4], f_regs->regs[REG_X5]); + regs[REG_X4], regs[REG_X5]); svcinfo("x6: 0x%-16lx x7: 0x%lx\n", - f_regs->regs[REG_X6], f_regs->regs[REG_X7]); + regs[REG_X6], regs[REG_X7]); } #ifdef CONFIG_LIB_SYSCALL @@ -145,32 +145,32 @@ uintptr_t dispatch_syscall(unsigned int nbr, uintptr_t parm1, #endif /**************************************************************************** - * Name: arm64_syscall_switch + * Name: arm64_syscall * * Description: * task switch syscall * ****************************************************************************/ -uint64_t *arm64_syscall_switch(uint64_t * regs) +uint64_t *arm64_syscall(uint64_t *regs) { + uint64_t *ret_regs = regs; uint64_t cmd; - struct regs_context *f_regs; - uint64_t *ret_regs; struct tcb_s *tcb; int cpu; +#ifdef CONFIG_BUILD_KERNEL + uint64_t spsr; +#endif /* Nested interrupts are not supported */ DEBUGASSERT(regs); - f_regs = (struct regs_context *)regs; - /* The SYSCALL command is in x0 on entry. Parameters follow in x1..x7 */ - cmd = f_regs->regs[REG_X0]; + cmd = regs[REG_X0]; - arm64_dump_syscall(__func__, cmd, f_regs); + arm64_dump_syscall(__func__, cmd, regs); switch (cmd) { @@ -192,7 +192,7 @@ uint64_t *arm64_syscall_switch(uint64_t * regs) * set will determine the restored context. */ - ret_regs = (uint64_t *)f_regs->regs[REG_X1]; + ret_regs = (uint64_t *)regs[REG_X1]; DEBUGASSERT(ret_regs); } @@ -216,85 +216,13 @@ uint64_t *arm64_syscall_switch(uint64_t * regs) case SYS_switch_context: { - DEBUGASSERT(f_regs->regs[REG_X1] != 0 && - f_regs->regs[REG_X2] != 0); - *(uint64_t **)f_regs->regs[REG_X1] = regs; + DEBUGASSERT(regs[REG_X1] != 0 && regs[REG_X2] != 0); + *(uint64_t **)regs[REG_X1] = regs; - ret_regs = (uint64_t *) f_regs->regs[REG_X2]; + ret_regs = (uint64_t *)regs[REG_X2]; } break; - default: - { - svcerr("ERROR: Bad SYS call: 0x%" PRIx64 "\n", cmd); - ret_regs = 0; - return 0; - } - break; - } - - if ((uint64_t *)f_regs != ret_regs) - { -#ifdef CONFIG_ARCH_ADDRENV - /* Make sure that the address environment for the previously - * running task is closed down gracefully (data caches dump, - * MMU flushed) and set up the address environment for the new - * thread at the head of the ready-to-run list. - */ - - addrenv_switch(NULL); -#endif - - /* Record the new "running" task. g_running_tasks[] is only used by - * assertion logic for reporting crashes. - */ - - cpu = this_cpu(); - tcb = current_task(cpu); - g_running_tasks[cpu] = tcb; - - /* Restore the cpu lock */ - - restore_critical_section(tcb, cpu); - } - - return ret_regs; -} - -/**************************************************************************** - * Name: arm64_syscall - * - * Description: - * SVC interrupts will vector here with insn=the SVC instruction and - * xcp=the interrupt context - * - * The handler may get the SVC number be de-referencing the return - * address saved in the xcp and decoding the SVC instruction - * - ****************************************************************************/ - -int arm64_syscall(uint64_t *regs) -{ - uint64_t cmd; - struct regs_context *f_regs; -#ifdef CONFIG_BUILD_KERNEL - uint64_t spsr; -#endif - - /* Nested interrupts are not supported */ - - DEBUGASSERT(regs); - - f_regs = (struct regs_context *)regs; - - /* The SYSCALL command is in x0 on entry. Parameters follow in x1..x7 */ - - cmd = f_regs->regs[REG_X0]; - - arm64_dump_syscall(__func__, cmd, f_regs); - - switch (cmd) - { #ifdef CONFIG_BUILD_KERNEL /* R0=SYS_signal_handler: This a user signal handler callback * @@ -396,11 +324,59 @@ int arm64_syscall(uint64_t *regs) break; #endif + /* This is not an architecture-specific system call. If NuttX is built + * as a standalone kernel with a system call interface, then all of the + * additional system calls must be handled as in the default case. + */ + default: + { +#ifdef CONFIG_LIB_SYSCALL - DEBUGPANIC(); - break; + /* Verify that the SYS call number is within range */ + + DEBUGASSERT(cmd >= CONFIG_SYS_RESERVED && cmd < SYS_maxsyscall); + + /* Make sure that there is a no saved SYSCALL return address. We + * cannot yet handle nested system calls. + */ + + regs[REG_X0] = dispatch_syscall(regs[REG_X0], regs[REG_X1], + regs[REG_X2], regs[REG_X3], + regs[REG_X4], regs[REG_X5], + regs[REG_X6]); + +#else + svcerr("ERROR: Bad SYS call: 0x%" PRIx64 "\n", cmd); +#endif + } + break; } - return 0; + if (regs != ret_regs) + { +#ifdef CONFIG_ARCH_ADDRENV + /* Make sure that the address environment for the previously + * running task is closed down gracefully (data caches dump, + * MMU flushed) and set up the address environment for the new + * thread at the head of the ready-to-run list. + */ + + addrenv_switch(NULL); +#endif + + /* Record the new "running" task. g_running_tasks[] is only used by + * assertion logic for reporting crashes. + */ + + cpu = this_cpu(); + tcb = current_task(cpu); + g_running_tasks[cpu] = tcb; + + /* Restore the cpu lock */ + + restore_critical_section(tcb, cpu); + } + + return ret_regs; } diff --git a/arch/arm64/src/common/arm64_vectors.S b/arch/arm64/src/common/arm64_vectors.S index 05e874262e40a..5f65caa608a33 100644 --- a/arch/arm64/src/common/arm64_vectors.S +++ b/arch/arm64/src/common/arm64_vectors.S @@ -139,164 +139,33 @@ SECTION_FUNC(text, arm64_jump_to_user) GTEXT(arm64_sync_exc) SECTION_FUNC(text, arm64_sync_exc) - /* checking the EC value to see which exception need to be handle */ - -#if CONFIG_ARCH_ARM64_EXCEPTION_LEVEL == 3 - mrs x0, esr_el3 + /* Switch to IRQ stack and save current sp on it. */ +#ifdef CONFIG_SMP + get_cpu_id x0 + ldr x1, =(g_cpu_int_stacktop) + lsl x0, x0, #3 + ldr x1, [x1, x0] #else - mrs x0, esr_el1 + ldr x1, =(g_interrupt_stack + CONFIG_ARCH_INTERRUPTSTACK) #endif - lsr x1, x0, #26 -#ifdef CONFIG_ARCH_FPU - /* fpu trap */ - - cmp x1, #0x07 /*Access to SIMD or floating-point */ - bne 1f mov x0, sp + mov sp, x1 - /* when the fpu trap is handled */ - - b arm64_exit_exception -1: +#if CONFIG_ARCH_ARM64_EXCEPTION_LEVEL == 3 + mrs x4, esr_el3 +#else + mrs x4, esr_el1 #endif - /* 0x15 = SVC system call */ - - cmp x1, #0x15 - - /* if this is a svc call ?*/ - - bne exc_handle - -#ifdef CONFIG_LIB_SYSCALL - /* Handle user system calls separately */ - - cmp x0, #CONFIG_SYS_RESERVED - blt reserved_syscall - /* Call dispatch_syscall() on the kernel stack with interrupts enabled */ + lsr x5, x4, #26 + cmp x5, #0x15 + bne arm64_fatal_handler - mrs x10, spsr_el1 - and x10, x10, #IRQ_SPSR_MASK - cmp x10, xzr - bne 1f - msr daifclr, #IRQ_DAIF_MASK /* Re-enable interrupts */ - -1: - bl dispatch_syscall - msr daifset, #IRQ_DAIF_MASK /* Disable interrupts */ - - /* Save the return value into the user context */ - - str x0, [sp, #8 * REG_X0] - - /* Return from exception */ + bl arm64_syscall /* Call the handler */ b arm64_exit_exception -reserved_syscall: -#endif - - /* x0 = syscall_cmd - * if ( x0 <= SYS_switch_context ) { - * call context_switch - * it's a context switch syscall, so context need to be done - * } - * #define SYS_save_context (0) - * #define SYS_restore_context (1) - * #define SYS_switch_context (2) - */ - - ldr x0, [sp, #8 * REG_X0] - cmp x0, #SYS_save_context - beq save_context - - cmp x0, #SYS_switch_context - beq context_switch - - cmp x0, #SYS_restore_context - beq context_switch - - /* Normal syscall, thread context will not switch - * - * call the SVC handler with interrupts disabled. - * void arm64_syscall(uint64_t *regs) - * in: - * regs = pointer to struct reg_context allocating - * from stack, esf_reg has put on it - * regs[REG_X0]: syscall cmd - * regs[REG_X1] ~ regs[REG_X6]: syscall parameter - * out: - * x0: return by arm64_syscall - */ - - mov x0, sp /* x0 = reg frame */ - - /* Call arm64_syscall() on the user stack */ - - bl arm64_syscall /* Call the handler */ - - /* Return from exception */ - - b arm64_exit_exception - -context_switch: - /* Call arm64_syscall_switch() for context switch - * - * uint64_t * arm64_syscall_switch(uint64_t * regs) - * out: - * x0: return by arm64_syscall_switch, restore task context - * regs[REG_X1]: save task context, if x1 = 0, only restore x0 - */ - - mov x0, sp - str x0, [sp, #-16]! - bl arm64_syscall_switch - - /* get save task reg context pointer */ - - ldr x1, [sp], #16 - -#ifdef CONFIG_SMP - /* Notes: - * Complete any pending TLB or cache maintenance on this CPU in case - * the thread migrates to a different CPU. - * This full barrier is also required by the membarrier system - * call. - */ - - dsb ish -#endif - - b arm64_exit_exception - -save_context: - arm64_exception_context_save x0 x1 sp - - mov x0, sp - bl arm64_syscall_save_context - - /* Save the return value into the ESF */ - - str x0, [sp, #8 * REG_X0] - - /* Return from exception */ - - b arm64_exit_exception - -exc_handle: - mov x0, sp - - /* void arm64_fatal_handler(struct regs_context * reg); - * x0 = Exception stack frame - */ - - bl arm64_fatal_handler - - /* Return here only in case of recoverable error */ - - b arm64_exit_exception - /**************************************************************************** * Name: arm64_irq_handler * @@ -309,20 +178,16 @@ GTEXT(arm64_irq_handler) SECTION_FUNC(text, arm64_irq_handler) /* Switch to IRQ stack and save current sp on it. */ #ifdef CONFIG_SMP - get_cpu_id x1 - ldr x0, =(g_cpu_int_stacktop) - lsl x1, x1, #3 - ldr x0, [x0, x1] + get_cpu_id x0 + ldr x1, =(g_cpu_int_stacktop) + lsl x0, x0, #3 + ldr x1, [x1, x0] #else - ldr x0, =(g_interrupt_stack + CONFIG_ARCH_INTERRUPTSTACK) + ldr x1, =(g_interrupt_stack + CONFIG_ARCH_INTERRUPTSTACK) #endif - /* Save the task's stack and switch irq stack */ - mov x1, sp - mov sp, x0 - str x1, [sp, #-16]! - - mov x0, x1 /* x0 = reg frame */ + mov x0, sp + mov sp, x1 /* Call arm64_decodeirq() on the interrupt stack * with interrupts disabled @@ -330,28 +195,15 @@ SECTION_FUNC(text, arm64_irq_handler) bl arm64_decodeirq - /* Upon return from arm64_decodeirq, x0 holds the pointer to the - * call reg context area, which can be use to restore context. - * This may or may not be the same value that was passed to arm64_decodeirq: - * It will differ if a context switch is required. - */ - - ldr x1, [sp], #16 - -#ifdef CONFIG_SMP - /* Notes: - * Complete any pending TLB or cache maintenance on this CPU in case - * the thread migrates to a different CPU. - * This full barrier is also required by the membarrier system - * call. - */ - dsb ish - -#endif - - b arm64_exit_exception + b arm64_exit_exception -/* TODO: if the arm64_fatal_handler return success, maybe need context switch */ +/**************************************************************************** + * Name: arm64_serror_handler + * + * Description: + * SError exception handler + * + ****************************************************************************/ GTEXT(arm64_serror_handler) SECTION_FUNC(text, arm64_serror_handler) @@ -359,7 +211,15 @@ SECTION_FUNC(text, arm64_serror_handler) bl arm64_fatal_handler /* Return here only in case of recoverable error */ - b arm64_exit_exception + b arm64_exit_exception + +/**************************************************************************** + * Name: arm64_mode32_handler + * + * Description: + * Mode32 exception handler + * + ****************************************************************************/ GTEXT(arm64_mode32_handler) SECTION_FUNC(text, arm64_mode32_handler) @@ -369,6 +229,14 @@ SECTION_FUNC(text, arm64_mode32_handler) b arm64_exit_exception +/**************************************************************************** + * Name: arm64_frq_handler + * + * Description: + * Interrupt exception handler + * + ****************************************************************************/ + GTEXT(arm64_fiq_handler) SECTION_FUNC(text, arm64_fiq_handler) #ifndef CONFIG_ARM64_DECODEFIQ @@ -382,45 +250,22 @@ SECTION_FUNC(text, arm64_fiq_handler) #else /* Switch to FIQ stack and save current sp on it. */ #ifdef CONFIG_SMP - get_cpu_id x1 - ldr x0, =(g_cpu_int_fiq_stacktop) - lsl x1, x1, #3 - ldr x0, [x0, x1] + get_cpu_id x0 + ldr x1, =(g_cpu_int_fiq_stacktop) + lsl x0, x0, #3 + ldr x1, [x1, x0] #else - ldr x0, =(g_interrupt_fiq_stack + CONFIG_ARCH_INTERRUPTSTACK) + ldr x1, =(g_interrupt_fiq_stack + CONFIG_ARCH_INTERRUPTSTACK) #endif - /* Save the task's stack and switch fiq stack */ - - mov x1, sp - mov sp, x0 - str x1, [sp, #-16]! - mov x0, x1 /* x0 = reg frame */ + mov x0, sp + mov sp, x1 - /* Call arm64_decodefiq() on the interrupt stack + /* Call arm64_decodeirq() on the interrupt stack * with interrupts disabled */ - bl arm64_decodefiq - - /* Upon return from arm64_decodefiq, x0 holds the pointer to the - * call reg context area, which can be use to restore context. - * This may or may not be the same value that was passed to arm64_decodefiq: - * It will differ if a context switch is required. - */ - - ldr x1, [sp], #16 - -#ifdef CONFIG_SMP - /* Notes: - * Complete any pending TLB or cache maintenance on this CPU in case - * the thread migrates to a different CPU. - * This full barrier is also required by the membarrier system - * call. - */ - dsb ish - -#endif + bl arm64_decodeirq - b arm64_exit_exception + b arm64_exit_exception #endif From 848afc2b60e8e3308d9ed3995f3ac7316bd8bdc2 Mon Sep 17 00:00:00 2001 From: lipengfei28 Date: Thu, 12 Sep 2024 17:51:32 +0800 Subject: [PATCH 5/5] Kernel build: enter exception save sp_sl0,exit exception restroe sp_el0 Signed-off-by: lipengfei28 --- arch/arm64/src/common/arm64_vector_table.S | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm64/src/common/arm64_vector_table.S b/arch/arm64/src/common/arm64_vector_table.S index 21b70d2575207..34d77f787dc92 100644 --- a/arch/arm64/src/common/arm64_vector_table.S +++ b/arch/arm64/src/common/arm64_vector_table.S @@ -78,6 +78,10 @@ #endif stp x0, x1, [sp, #8 * REG_ELR] + mrs x0, sp_el0 + mrs x1, tpidrro_el0 + stp x0, x1, [sp, #8 * REG_SP_EL0] + /* Increment exception depth */ mrs x0, tpidrro_el0 @@ -262,6 +266,10 @@ SECTION_FUNC(text, arm64_exit_exception) msr spsr_el1, x1 #endif + ldp x0, x1, [sp, #8 * REG_SP_EL0] + msr sp_el0, x0 + msr tpidrro_el0, x1 + /* decrement exception depth */ mrs x0, tpidrro_el0