From 53e73854d09889ace5b6fe3efd42618b59414bbf Mon Sep 17 00:00:00 2001 From: Alwin Joshy Date: Fri, 16 Feb 2024 13:10:12 +1100 Subject: [PATCH] hw debug api: aarch64 port Signed-off-by: Alwin Joshy --- include/api/syscall.h | 1 + .../arm/arch/32/mode/object/structures.bf | 25 +- .../arch/arm/arch/64/mode/fastpath/fastpath.h | 4 + include/arch/arm/arch/64/mode/machine/debug.h | 133 ++++++++++ .../arm/arch/64/mode/machine/registerset.h | 38 +++ .../arm/arch/64/mode/object/structures.bf | 34 +++ include/arch/arm/arch/machine/debug.h | 21 +- include/arch/arm/armv/armv7-a/armv/debug.h | 3 +- include/arch/arm/armv/armv8-a/64/armv/debug.h | 31 +++ include/arch/arm/armv/armv8-a/64/armv/vcpu.h | 26 ++ libsel4/include/interfaces/sel4.xml | 3 +- .../aarch64/sel4/sel4_arch/constants.h | 4 + src/api/syscall.c | 19 ++ src/arch/arm/32/machine/debug.c | 69 ++++- src/arch/arm/64/c_traps.c | 4 + src/arch/arm/64/config.cmake | 1 + src/arch/arm/64/machine/debug.c | 240 ++++++++++++++++++ src/arch/arm/64/model/statedata.c | 5 + src/arch/arm/c_traps.c | 19 +- src/arch/arm/config.cmake | 4 - src/arch/arm/kernel/boot.c | 1 - src/arch/arm/machine/debug.c | 94 ++----- src/object/tcb.c | 4 + 23 files changed, 681 insertions(+), 102 deletions(-) create mode 100644 src/arch/arm/64/machine/debug.c diff --git a/include/api/syscall.h b/include/api/syscall.h index 42cb8fb5e85..b40cec8cba2 100644 --- a/include/api/syscall.h +++ b/include/api/syscall.h @@ -34,6 +34,7 @@ exception_t handleInterruptEntry(void); exception_t handleUnknownSyscall(word_t w); exception_t handleUserLevelFault(word_t w_a, word_t w_b); exception_t handleVMFaultEvent(vm_fault_type_t vm_faultType); +exception_t handleDebugFaultEvent(word_t esr); static inline word_t PURE getSyscallArg(word_t i, word_t *ipc_buffer) { diff --git a/include/arch/arm/arch/32/mode/object/structures.bf b/include/arch/arm/arch/32/mode/object/structures.bf index 6683f2aaa53..0e54bf0839c 100644 --- a/include/arch/arm/arch/32/mode/object/structures.bf +++ b/include/arch/arm/arch/32/mode/object/structures.bf @@ -549,13 +549,13 @@ block dbg_bcr { padding 3 field addressMask 5 field breakpointType 4 - field linkedBrp 4 - field secureStateControl 2 - field hypeModeControl 1 + field lbn 4 + field ssc 2 + field hmc 1 padding 4 - field byteAddressSelect 4 + field bas 4 padding 2 - field supervisorAccess 2 + field pmc 2 field enabled 1 } @@ -564,15 +564,16 @@ block dbg_wcr { padding 3 field addressMask 5 padding 3 - field enableLinking 1 - field linkedBrp 4 - field secureStateControl 2 - field hypeModeControl 1 - field byteAddressSelect 8 - field loadStore 2 - field supervisorAccess 2 + field watchpointType 1 + field lbn 4 + field ssc 2 + field hmc 1 + field bas 8 + field lsc 2 + field pac 2 field enabled 1 } + #endif /* CONFIG_HARDWARE_DEBUG_API */ #include diff --git a/include/arch/arm/arch/64/mode/fastpath/fastpath.h b/include/arch/arm/arch/64/mode/fastpath/fastpath.h index 313328263af..c7d4ee99664 100644 --- a/include/arch/arm/arch/64/mode/fastpath/fastpath.h +++ b/include/arch/arm/arch/64/mode/fastpath/fastpath.h @@ -139,6 +139,10 @@ static inline void NORETURN FORCE_INLINE fastpath_restore(word_t badge, word_t m c_exit_hook(); +#ifdef ARM_CP14_SAVE_AND_RESTORE_NATIVE_THREADS + restore_user_debug_context(cur_thread); +#endif + #ifdef CONFIG_HAVE_FPU lazyFPURestore(cur_thread); #endif /* CONFIG_HAVE_FPU */ diff --git a/include/arch/arm/arch/64/mode/machine/debug.h b/include/arch/arm/arch/64/mode/machine/debug.h index 1a2b4b6dc19..0bdc0730b0d 100644 --- a/include/arch/arm/arch/64/mode/machine/debug.h +++ b/include/arch/arm/arch/64/mode/machine/debug.h @@ -6,4 +6,137 @@ #pragma once +#ifdef ARM_BASE_CP14_SAVE_AND_RESTORE +void arch_restore_user_debug_context(tcb_t *target_thread); + +/** Determines and carries out what needs to be done for a debug exception. + * + * This could be handling a single-stepping exception, or a breakpoint or + * watchpoint. + */ +seL4_Fault_t handleUserLevelDebugException(word_t esr, word_t fault_vaddr); +bool_t isDebugFault(word_t esr); + +#define MAKE_DBGBVR(num) "DBGBVR" #num "_EL1" +#define MAKE_DBGBCR(num) "DBGBCR" #num "_EL1" +#define MAKE_DBGWVR(num) "DBGWVR" #num "_EL1" +#define MAKE_DBGWCR(num) "DBGWCR" #num "_EL1" + +/** Generates read functions for the CP14 control and value registers. + */ +#define DEBUG_GENERATE_READ_FN(_name, _reg) \ + static inline word_t _name(uint16_t bp_num) { \ + word_t ret; \ + \ + switch (bp_num) { \ + case 1: \ + MRS(MAKE_##_reg(1), ret); \ + return ret; \ + case 2: \ + MRS(MAKE_##_reg(2), ret); \ + return ret; \ + case 3: \ + MRS(MAKE_##_reg(3), ret); \ + return ret; \ + case 4: \ + MRS(MAKE_##_reg(4), ret); \ + return ret; \ + case 5: \ + MRS(MAKE_##_reg(5), ret); \ + return ret; \ + case 6: \ + MRS(MAKE_##_reg(6), ret); \ + return ret; \ + case 7: \ + MRS(MAKE_##_reg(7), ret); \ + return ret; \ + case 8: \ + MRS(MAKE_##_reg(8), ret); \ + return ret; \ + case 9: \ + MRS(MAKE_##_reg(9), ret); \ + return ret; \ + case 10: \ + MRS(MAKE_##_reg(10), ret); \ + return ret; \ + case 11: \ + MRS(MAKE_##_reg(11), ret); \ + return ret; \ + case 12: \ + MRS(MAKE_##_reg(12), ret); \ + return ret; \ + case 13: \ + MRS(MAKE_##_reg(13), ret); \ + return ret; \ + case 14: \ + MRS(MAKE_##_reg(14), ret); \ + return ret; \ + case 15: \ + MRS(MAKE_##_reg(15), ret); \ + return ret; \ + default: \ + assert(bp_num == 0); \ + MRS(MAKE_##_reg(0), ret); \ + return ret; \ + } \ + } + +/** Generates write functions for the CP14 control and value registers. + */ +#define DEBUG_GENERATE_WRITE_FN(_name, _reg) \ + static inline void _name(uint16_t bp_num, word_t val) { \ + switch (bp_num) { \ + case 1: \ + MSR(MAKE_##_reg(1), val); \ + return; \ + case 2: \ + MSR(MAKE_##_reg(2), val); \ + return; \ + case 3: \ + MSR(MAKE_##_reg(3), val); \ + return; \ + case 4: \ + MSR(MAKE_##_reg(4), val); \ + return; \ + case 5: \ + MSR(MAKE_##_reg(5), val); \ + return; \ + case 6: \ + MSR(MAKE_##_reg(6), val); \ + return; \ + case 7: \ + MSR(MAKE_##_reg(7), val); \ + return; \ + case 8: \ + MSR(MAKE_##_reg(8), val); \ + return; \ + case 9: \ + MSR(MAKE_##_reg(9), val); \ + return; \ + case 10: \ + MSR(MAKE_##_reg(10), val); \ + return; \ + case 11: \ + MSR(MAKE_##_reg(11), val); \ + return; \ + case 12: \ + MSR(MAKE_##_reg(12), val); \ + return; \ + case 13: \ + MSR(MAKE_##_reg(13), val); \ + return; \ + case 14: \ + MSR(MAKE_##_reg(14), val); \ + return; \ + case 15: \ + MSR(MAKE_##_reg(15), val); \ + return; \ + default: \ + assert(bp_num == 0); \ + MSR(MAKE_##_reg(0), val); \ + return; \ + } \ + } + +#endif /* ARM_BASE_CP14_SAVE_AND_RESTORE */ \ No newline at end of file diff --git a/include/arch/arm/arch/64/mode/machine/registerset.h b/include/arch/arm/arch/64/mode/machine/registerset.h index ca04077066d..dcf545931c2 100644 --- a/include/arch/arm/arch/64/mode/machine/registerset.h +++ b/include/arch/arm/arch/64/mode/machine/registerset.h @@ -7,6 +7,7 @@ #pragma once #include +#include /* CurrentEL register */ #define PEXPL1 (1 << 2) @@ -232,6 +233,33 @@ extern const register_t msgRegisters[]; extern const register_t frameRegisters[]; extern const register_t gpRegisters[]; +#ifdef ARM_BASE_CP14_SAVE_AND_RESTORE +typedef struct debug_register_pair { + word_t cr, vr; +} debug_register_pair_t; + +// @alwin: Copied from armv7, necessary? +/* + * This padding ensures that there is reasonable leeway when determining + * the size of the untyped needed for a TCB when watchpoint handling is + * involved. + */ +#define EXCLUSIVE_WATCHPOINT_PADDING 6 +#define EXCLUSIVE_WATCHPOINT_PADDED \ + (seL4_NumExclusiveWatchpoints > EXCLUSIVE_WATCHPOINT_PADDING) \ + ? seL4_NumExclusiveWatchpoints \ + : EXCLUSIVE_WATCHPOINT_PADDING + +typedef struct user_breakpoint_state { + /* We don't use context comparisons */ + debug_register_pair_t breakpoint[seL4_NumExclusiveBreakpoints], + watchpoint[EXCLUSIVE_WATCHPOINT_PADDED]; + uint32_t used_breakpoints_bf; + word_t n_instructions; + bool_t single_step_enabled; +} user_breakpoint_state_t; +#endif /* ARM_BASE_CP14_SAVE_AND_RESTORE */ + #ifdef CONFIG_HAVE_FPU typedef struct user_fpu_state { uint64_t vregs[64]; @@ -250,6 +278,9 @@ typedef struct user_fpu_state { */ struct user_context { word_t registers[n_contextRegisters]; +#ifdef ARM_BASE_CP14_SAVE_AND_RESTORE + user_breakpoint_state_t breakpointState; +#endif /* ARM_BASE_CP14_SAVE_AND_RESTORE */ #ifdef CONFIG_HAVE_FPU user_fpu_state_t fpuState; #endif /* CONFIG_HAVE_FPU */ @@ -260,9 +291,16 @@ unverified_compile_assert(registers_are_first_member_of_user_context, OFFSETOF(user_context_t, registers) == 0) +#ifdef ARM_BASE_CP14_SAVE_AND_RESTORE +void Arch_initBreakpointContext(user_context_t *context); +#endif + static inline void Arch_initContext(user_context_t *context) { context->registers[SPSR_EL1] = PSTATE_USER; +#ifdef ARM_BASE_CP14_SAVE_AND_RESTORE + Arch_initBreakpointContext(context); +#endif } #endif /* !__ASSEMBLER__ */ diff --git a/include/arch/arm/arch/64/mode/object/structures.bf b/include/arch/arm/arch/64/mode/object/structures.bf index 290bffdd8a4..519cf657ad6 100644 --- a/include/arch/arm/arch/64/mode/object/structures.bf +++ b/include/arch/arm/arch/64/mode/object/structures.bf @@ -412,4 +412,38 @@ tagged_union virq virqType { } #endif /* CONFIG_ARM_HYPERVISOR_SUPPORT */ +#ifdef CONFIG_HARDWARE_DEBUG_API + +block dbg_bcr { + padding 34 + padding 1 + padding 5 + field breakpointType 4 + field lbn 4 + field ssc 2 + field hmc 1 + padding 4 + field bas 4 + padding 2 + field pmc 2 + field enabled 1 +} + +block dbg_wcr { + padding 34 + padding 1 + field addressMask 5 + padding 3 + field watchpointType 1 + field lbn 4 + field ssc 2 + field hmc 1 + field bas 8 + field lsc 2 + field pac 2 + field enabled 1 +} + +#endif /* CONFIG_HARDWARE_DEBUG_API */ + #include diff --git a/include/arch/arm/arch/machine/debug.h b/include/arch/arm/arch/machine/debug.h index b85cedff146..68f2ee8b9d4 100644 --- a/include/arch/arm/arch/machine/debug.h +++ b/include/arch/arm/arch/machine/debug.h @@ -10,7 +10,7 @@ #include #include #include -#include +#include #ifdef ARM_BASE_CP14_SAVE_AND_RESTORE void restore_user_debug_context(tcb_t *target_thread); @@ -97,12 +97,22 @@ static inline void setHDCRTrapDebugExceptionState(bool_t enable_trapping) | BIT(HDCR_DEBUG_TDA_SHIFT) | BIT(HDCR_DEBUG_TDRA_SHIFT) | BIT(HDCR_DEBUG_TDOSA_SHIFT)); +#ifdef CONFIG_ARCH_AARCH64 + // @alwin: I think only this is necessary on aarch64 actually + // hcr |= (HCR_TGE); +#endif + } else { /* Let the PL1 Guest VM handle debug events on its own */ hdcr &= ~(BIT(HDCR_DEBUG_TDE_SHIFT) | BIT(HDCR_DEBUG_TDA_SHIFT) | BIT(HDCR_DEBUG_TDRA_SHIFT) | BIT(HDCR_DEBUG_TDOSA_SHIFT)); +#ifdef CONFIG_ARCH_AARCH64 + // @alwin: I think only this is necessary on aarch64 actually + // hcr |= (HCR_TGE); +#endif + } #ifdef CONFIG_ARCH_AARCH64 MSR("mdcr_el2", hdcr); @@ -172,6 +182,7 @@ static inline syscall_error_t Arch_decodeConfigureSingleStepping(tcb_t *t, bool_t is_reply) { word_t type; + (void) type; syscall_error_t ret = { .type = seL4_NoError }; @@ -188,6 +199,7 @@ static inline syscall_error_t Arch_decodeConfigureSingleStepping(tcb_t *t, return ret; } +#ifdef CONFIG_ARCH_AARCH32 type = seL4_InstructionBreakpoint; bp_num = t->tcbArch.tcbContext.breakpointState.single_step_hw_bp_num; } else { @@ -212,6 +224,7 @@ static inline syscall_error_t Arch_decodeConfigureSingleStepping(tcb_t *t, ret.invalidArgumentNumber = 0; return ret; } +#endif /* CONFIG_ARCH_AARCH32*/ } return ret; @@ -247,12 +260,15 @@ static inline syscall_error_t Arch_decodeSetBreakpoint(tcb_t *t, } } +#ifdef CONFIG_ARCH_AARCH32 if (size == 8 && !byte8WatchpointsSupported()) { userError("Debug: 8-byte watchpoints not supported on this CPU."); ret.type = seL4_InvalidArgument; ret.invalidArgumentNumber = 3; return ret; } +#endif /* CONFIG_ARCH_AARCH32 */ + if (size == 8 && type != seL4_DataBreakpoint) { userError("Debug: 8-byte sizes can only be used with watchpoints."); ret.type = seL4_InvalidArgument; @@ -291,18 +307,21 @@ static inline syscall_error_t Arch_decodeUnsetBreakpoint(tcb_t *t, uint16_t bp_n word_t type; dbg_bcr_t bcr; + (void) bcr; type = getTypeFromBpNum(bp_num); bp_num = convertBpNumToArch(bp_num); bcr.words[0] = t->tcbArch.tcbContext.breakpointState.breakpoint[bp_num].cr; if (type == seL4_InstructionBreakpoint) { +#ifdef CONFIG_ARCH_AARCH32 if (Arch_breakpointIsMismatch(bcr) == true && dbg_bcr_get_enabled(bcr)) { userError("Rejecting call to unsetBreakpoint on breakpoint configured " "for single-stepping (hwid %u).", bp_num); ret.type = seL4_IllegalOperation; return ret; } +#endif /* CONFIG_ARCH_AARCH32 */ } return ret; diff --git a/include/arch/arm/armv/armv7-a/armv/debug.h b/include/arch/arm/armv/armv7-a/armv/debug.h index 4a546a8006f..0b272a75373 100644 --- a/include/arch/arm/armv/armv7-a/armv/debug.h +++ b/include/arch/arm/armv/armv7-a/armv/debug.h @@ -141,8 +141,7 @@ static inline dbg_bcr_t Arch_setupBcr(dbg_bcr_t in_val, bool_t is_match) dbg_bcr_t bcr; bcr = dbg_bcr_set_addressMask(in_val, 0); - bcr = dbg_bcr_set_hypeModeControl(bcr, 0); - bcr = dbg_bcr_set_secureStateControl(bcr, 0); + bcr = dbg_bcr_set_bas(bcr, convertSizeToArch(4)); if (is_match) { bcr = dbg_bcr_set_breakpointType(bcr, DBGBCR_TYPE_UNLINKED_INSTRUCTION_MATCH); } else { diff --git a/include/arch/arm/armv/armv8-a/64/armv/debug.h b/include/arch/arm/armv/armv8-a/64/armv/debug.h index 207ab6f9472..acf59b3be3f 100644 --- a/include/arch/arm/armv/armv8-a/64/armv/debug.h +++ b/include/arch/arm/armv/armv8-a/64/armv/debug.h @@ -6,3 +6,34 @@ #pragma once +#define DBGBCR_BAS_A64 0xF + +enum v8_breakpoint_type { + DBGBCR_TYPE_UNLINKED_INSTRUCTION_MATCH = 0u, + DBGBCR_TYPE_LINKED_INSTRUCTION_MATCH = 0x1u, + + DBGBCR_TYPE_UNLINKED_CONTEXT_ID_MATCH = 0x2u, + DBGBCR_TYPE_LINKED_CONTEXT_ID_MATCH = 0x3u, + + DBGBCR_TYPE_UNLINKED_CONTEXTIDR_EL1_MATCH = 0x6u, + DBGBCR_TYPE_LINKED_CONTEXTIDR_EL1_MATCH = 0x7u, + + DBGBCR_TYPE_UNLINKED_VMID_MATCH = 0x8u, + DBGBCR_TYPE_LINKED_VMID_MATCH = 0x9u, + + DBGBCR_TYPE_UNLINKED_CONTEXT_ID_AND_VMID_MATCH = 0xAu, + DBGBCR_TYPE_LINKED_CONTEXT_ID_AND_VMID_MATCH = 0xBu, + + DBGBCR_TYPE_UNLINKED_CONTEXTIDR_EL2_MATCH = 0xCu, + DBGBCR_TYPE_LINKED_CONTEXTIDR_EL2_MATCH = 0xDu, + + DBGBCR_TYPE_UNLINKED_FULL_CONTEXT_ID_MATCH = 0xEu, + DBGBCR_TYPE_LINKED_FULL_CONTEXT_ID_MATCH = 0xFu, +}; + +static inline dbg_bcr_t Arch_setupBcr(dbg_bcr_t bcr, UNUSED bool_t is_match) +{ + bcr = dbg_bcr_set_bas(bcr, DBGBCR_BAS_A64); + bcr = dbg_bcr_set_breakpointType(bcr, DBGBCR_TYPE_UNLINKED_INSTRUCTION_MATCH); + return bcr; +} \ No newline at end of file diff --git a/include/arch/arm/armv/armv8-a/64/armv/vcpu.h b/include/arch/arm/armv/armv8-a/64/armv/vcpu.h index 64c1f9e8351..621d628da21 100644 --- a/include/arch/arm/armv/armv8-a/64/armv/vcpu.h +++ b/include/arch/arm/armv/armv8-a/64/armv/vcpu.h @@ -627,11 +627,23 @@ static inline void armv_vcpu_boot_init(void) /* set the SCTLR_EL1 for running native seL4 threads */ MSR(REG_SCTLR_EL1, SCTLR_EL1_NATIVE); isb(); + +#if defined(ARM_HYP_TRAP_CP14_IN_VCPU_THREADS) || defined(ARM_HYP_TRAP_CP14_IN_NATIVE_USER_THREADS) + initHDCR(); +#endif } static inline void armv_vcpu_save(vcpu_t *vcpu, UNUSED bool_t active) { vcpu_save_reg_range(vcpu, seL4_VCPUReg_TTBR0, seL4_VCPUReg_SPSR_EL1); + +#ifdef ARM_HYP_CP14_SAVE_AND_RESTORE_VCPU_THREADS + /* This is done when we are asked to save and restore the CP14 debug context + * of VCPU threads; the register context is saved into the underlying TCB. + */ + saveAllBreakpointState(vcpu->vcpuTCB); +#endif + isb(); } static inline void vcpu_enable(vcpu_t *vcpu) @@ -641,6 +653,13 @@ static inline void vcpu_enable(vcpu_t *vcpu) isb(); set_gic_vcpu_ctrl_hcr(vcpu->vgic.hcr); +#if !defined(ARM_CP14_SAVE_AND_RESTORE_NATIVE_THREADS) && defined(ARM_HYP_CP14_SAVE_AND_RESTORE_VCPU_THREADS) + restore_user_debug_context(vcpu->vcpuTCB); +#endif +#if defined(ARM_HYP_TRAP_CP14_IN_NATIVE_USER_THREADS) + setHDCRTrapDebugExceptionState(false); +#endif + #ifdef CONFIG_HAVE_FPU vcpu_restore_reg(vcpu, seL4_VCPUReg_CPACR); #endif @@ -672,6 +691,13 @@ static inline void vcpu_disable(vcpu_t *vcpu) setHCR(HCR_NATIVE); isb(); +#if defined(ARM_HYP_CP14_SAVE_AND_RESTORE_VCPU_THREADS) + loadAllDisabledBreakpointState(); +#endif +#if defined(ARM_HYP_TRAP_CP14_IN_NATIVE_USER_THREADS) + setHDCRTrapDebugExceptionState(true); +#endif + #ifdef CONFIG_HAVE_FPU /* Allow FPU instructions in EL0 and EL1 for native * threads by setting the CPACR_EL1. The CPTR_EL2 is diff --git a/libsel4/include/interfaces/sel4.xml b/libsel4/include/interfaces/sel4.xml index bfec5ddc842..09721cc42e9 100644 --- a/libsel4/include/interfaces/sel4.xml +++ b/libsel4/include/interfaces/sel4.xml @@ -782,7 +782,8 @@ seL4_TCB_ConfigureSingleStepping with an argument of 0. + description="The API-ID of a target breakpoint. This ID will be a positive integer, with values ranging from 0 to seL4_NumHWBreakpoints - 1. + This value is unused on AARCH64."/> diff --git a/libsel4/sel4_arch_include/aarch64/sel4/sel4_arch/constants.h b/libsel4/sel4_arch_include/aarch64/sel4/sel4_arch/constants.h index 4575c236a47..7aa89e90b0b 100644 --- a/libsel4/sel4_arch_include/aarch64/sel4/sel4_arch/constants.h +++ b/libsel4/sel4_arch_include/aarch64/sel4/sel4_arch/constants.h @@ -174,7 +174,11 @@ typedef enum { #define seL4_LargePageBits 21 #define seL4_HugePageBits 30 #define seL4_SlotBits 5 +#if defined(CONFIG_HARDWARE_DEBUG_API) || (defined(CONFIG_ARM_HYPERVISOR_SUPPORT) && defined(CONFIG_ARM_HYP_ENABLE_VCPU_CP14_SAVE_AND_RESTORE)) +#define seL4_TCBBits 12 +#else #define seL4_TCBBits 11 +#endif #define seL4_EndpointBits 4 #ifdef CONFIG_KERNEL_MCS #define seL4_NotificationBits 6 diff --git a/src/api/syscall.c b/src/api/syscall.c index 305f712b3d1..227ae3220e7 100644 --- a/src/api/syscall.c +++ b/src/api/syscall.c @@ -30,6 +30,9 @@ #ifdef CONFIG_DEBUG_BUILD #include #endif +#ifdef CONFIG_HARDWARE_DEBUG_API +#include +#endif /* The haskell function 'handleEvent' is split into 'handleXXX' variants * for each event causing a kernel entry */ @@ -256,6 +259,22 @@ exception_t handleVMFaultEvent(vm_fault_type_t vm_faultType) return EXCEPTION_NONE; } +#if defined(CONFIG_ARCH_AARCH64) && defined(CONFIG_HARDWARE_DEBUG_API) +exception_t handleDebugFaultEvent(word_t esr) +{ + MCS_DO_IF_BUDGET({ + current_fault = handleUserLevelDebugException(esr, getRestartPC(NODE_STATE(ksCurThread))); + if (seL4_Fault_get_seL4_FaultType(current_fault) != seL4_Fault_NullFault) { + handleFault(NODE_STATE(ksCurThread)); + } + }) + schedule(); + activateThread(); + + return EXCEPTION_NONE; +} +#endif /* defined(CONFIG_ARCH_AARCH64) && defined(CONFIG_HARDWARE_DEBUG_API) */ + #ifdef CONFIG_KERNEL_MCS static exception_t handleInvocation(bool_t isCall, bool_t isBlocking, bool_t canDonate, bool_t firstPhase, cptr_t cptr) #else diff --git a/src/arch/arm/32/machine/debug.c b/src/arch/arm/32/machine/debug.c index 83ac5c818f2..6168149be8a 100644 --- a/src/arch/arm/32/machine/debug.c +++ b/src/arch/arm/32/machine/debug.c @@ -49,19 +49,6 @@ #define DBGSDER_ENABLE_SECURE_USER_INVASIVE_DEBUG (BIT(0)) -/* ARMv7 Manuals, c3.3.1: - * "Breakpoint debug events are synchronous. That is, the debug event acts - * like an exception that cancels the breakpointed instruction." - * - * ARMv7 Manuals, c3.4.1: - * "Watchpoint debug events are precise and can be synchronous or asynchronous: - * a synchronous Watchpoint debug event acts like a synchronous abort - * exception on the memory access instruction itself. An asynchronous - * Watchpoint debug event acts like a precise asynchronous abort exception that - * cancels a later instruction." - */ - - /** Describes the availability and level of support for the debug features on * a particular CPU. Currently a static local singleton instance, but for * multiprocessor adaptation, just make it per-CPU. @@ -142,6 +129,62 @@ static inline word_t getMethodOfEntry(void) return dbg_dscr_get_methodOfEntry(dscr); } +/** Initiates or halts single-stepping on the target process. + * + * @param at arch_tcb_t for the target process to be configured. + * @param bp_num The hardware ID of the breakpoint register to be used. + * @param n_instr The number of instructions to step over. + */ +bool_t configureSingleStepping(tcb_t *t, + uint16_t bp_num, + word_t n_instr, + bool_t is_reply) +{ + + if (is_reply) { + bp_num = t->tcbArch.tcbContext.breakpointState.single_step_hw_bp_num; + } else { + bp_num = convertBpNumToArch(bp_num); + } + + /* On ARM single-stepping is emulated using breakpoint mismatches. So you + * would basically set the breakpoint to mismatch everything, and this will + * cause an exception to be triggered on every instruction. + * + * We use NULL as the mismatch address since no code should be trying to + * execute NULL, so it's a perfect address to use as the mismatch + * criterion. An alternative might be to use an address in the kernel's + * high vaddrspace, since that's an address that it's impossible for + * userspace to be executing at. + */ + dbg_bcr_t bcr; + + bcr.words[0] = readBcrContext(t, bp_num); + + /* If the user calls us with n_instr == 0, allow them to configure, but + * leave it disabled. + */ + if (n_instr > 0) { + bcr = dbg_bcr_set_enabled(bcr, 1); + t->tcbArch.tcbContext.breakpointState.single_step_enabled = true; + } else { + bcr = dbg_bcr_set_enabled(bcr, 0); + t->tcbArch.tcbContext.breakpointState.single_step_enabled = false; + } + + bcr = dbg_bcr_set_linkedBrp(bcr, 0); + bcr = dbg_bcr_set_supervisorAccess(bcr, DBGBCR_PRIV_USER); + bcr = dbg_bcr_set_byteAddressSelect(bcr, convertSizeToArch(1)); + bcr = Arch_setupBcr(bcr, false); + + writeBvrContext(t, bp_num, 0); + writeBcrContext(t, bp_num, bcr.words[0]); + + t->tcbArch.tcbContext.breakpointState.n_instructions = n_instr; + t->tcbArch.tcbContext.breakpointState.single_step_hw_bp_num = bp_num; + return true; +} + /** Using the DBGDIDR register, detects the debug architecture version, and * does a preliminary check for the level of support for our debug API. * diff --git a/src/arch/arm/64/c_traps.c b/src/arch/arm/64/c_traps.c index b8f1a2786b0..f3fe920674f 100644 --- a/src/arch/arm/64/c_traps.c +++ b/src/arch/arm/64/c_traps.c @@ -22,6 +22,10 @@ void VISIBLE NORETURN restore_user_context(void) c_exit_hook(); +#ifdef ARM_CP14_SAVE_AND_RESTORE_NATIVE_THREADS + restore_user_debug_context(NODE_STATE(ksCurThread)); +#endif + #ifdef CONFIG_HAVE_FPU lazyFPURestore(NODE_STATE(ksCurThread)); #endif /* CONFIG_HAVE_FPU */ diff --git a/src/arch/arm/64/config.cmake b/src/arch/arm/64/config.cmake index 0784d593f46..93a1158fe6e 100644 --- a/src/arch/arm/64/config.cmake +++ b/src/arch/arm/64/config.cmake @@ -14,6 +14,7 @@ add_sources( machine/capdl.c machine/registerset.c machine/fpu.c + machine/debug.c model/statedata.c c_traps.c idle.c diff --git a/src/arch/arm/64/machine/debug.c b/src/arch/arm/64/machine/debug.c new file mode 100644 index 00000000000..bb446e1aeaf --- /dev/null +++ b/src/arch/arm/64/machine/debug.c @@ -0,0 +1,240 @@ +/* + * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) + * + * SPDX-License-Identifier: GPL-2.0-only + */ + +#include +#ifdef CONFIG_HARDWARE_DEBUG_API + +#include +#include +#include +#include +#include +#include +#include +#include +#include /* seL4_NumExclusiveBreakpoints/Watchpoints */ +#include +#include + +#define MDSCR_MDE (BIT(15)) +#define MDSCR_SS (BIT(0)) +#define SPSR_SS (BIT(21)) + +#define ESR_EXCEPTION_CLASS_MASK 0xFC000000 +#define ESR_EXCEPTION_CLASS_OFF 26 + +#define DEBUG_ENTRY_BREAKPOINT 0x30 +#define DEBUG_ENTRY_SINGLE_STEP 0x32 +#define DEBUG_ENTRY_WATCHPOINT 0x34 +#define DEBUG_ENTRY_EXPLICIT_BKPT 0x3C + +#define OSDLR_LOCK (BIT(0)) +#define OSLAR_LOCK (BIT(0)) + + +/** Initiates or halts single-stepping on the target process. + * + * @param at arch_tcb_t for the target process to be configured. + * @param bp_num The hardware ID of the breakpoint register to be used. + * @param n_instr The number of instructions to step over. + */ +bool_t configureSingleStepping(tcb_t *t, uint16_t bp_num, word_t n_instr, + bool_t is_reply) { + if (n_instr > 0) { + /* Enable single stepping */ + t->tcbArch.tcbContext.breakpointState.single_step_enabled = true; + } else { + /* Disable single stepping */ + t->tcbArch.tcbContext.breakpointState.single_step_enabled = false; + } + + t->tcbArch.tcbContext.breakpointState.n_instructions = n_instr; + return true; +} + +/* Guides the debug hardware initialization sequence. */ +BOOT_CODE bool_t Arch_initHardwareBreakpoints(void) { + /* + * ARMv8 Architecture Reference Manual for A-profile Architecture + * D2.2: The Enable controls for each debug exception are: + * ... MDSCR_EL1.MDE + */ + + word_t mdscr = 0; + MRS("MDSCR_EL1", mdscr); + mdscr |= MDSCR_MDE; + MSR("MDSCR_EL1", mdscr); + + /* + * ARMv8 Architecture Reference Manual for A-profile Architecture + * D2.4: A debug exception can be taken only if all the following are true: + * - The OS Lock is unlocked + * - DoubleLockStatus() = False + * - The debug exception is enabled from the current exception level + * - The debug exception is enabled from the current security state + */ + + /* Ensure that the OS double lock is unset */ + word_t osdlr = 0; + MRS("osdlr_el1", osdlr); + osdlr &= ~OSDLR_LOCK; + MSR("osdlr_el1", osdlr); + + /* Ensure that the OS lock is unset */ + word_t oslar = 0; + MSR("oslar_el1", oslar); + + // @alwin: why does the below not work? if anything the top one should not + // work + // word_t oslar = 0; + // MRS("oslar_el1", oslar); + // oslar &= ~OSLAR_LOCK; + // MSR("oslar_el1", oslar); + // + + /* Ensure that all the breakpoint and watchpoint registers are initially disabled */ + disableAllBpsAndWps(); + + /* Ensure that single stepping is initally disabled */ + MRS("MDSCR_EL1", mdscr); + mdscr &= ~MDSCR_SS; + MSR("MDSCR_EL1", mdscr); + + /* Finally, also pre-load some initial register state that can be used + * for all new threads so that their initial saved debug register state + * is valid when it's first loaded onto the CPU. + */ + for (int i = 0; i < seL4_NumExclusiveBreakpoints; i++) { + armKSNullBreakpointState.breakpoint[i].cr = readBcrCp(i) & ~DBGBCR_ENABLE; + } + for (int i = 0; i < seL4_NumExclusiveWatchpoints; i++) { + armKSNullBreakpointState.watchpoint[i].cr = readWcrCp(i) & ~DBGWCR_ENABLE; + } + + return true; +} + +/* Abstract wrapper around the ESR fault status value */ + +static word_t getFaultStatus(word_t esr) { + return (esr & ESR_EXCEPTION_CLASS_MASK) >> ESR_EXCEPTION_CLASS_OFF; +} + +/** Called to determine if an abort was a debug exception. + * + * The ARM debug exceptions look like Prefetch Aborts or Data Aborts, and you + * have to examine some extra register state to determine whether or not the + * abort you currently have on your hands is actually a debug exception. + * + * This routine takes care of the checks. + * @param fs An abstraction of the DFSR/IFSR values, meant to make it irrelevant + * whether we're using the long/short descriptors. Bit positions and + * values change. This also makes the debug code forward compatible + * aarch64. + */ +bool_t isDebugFault(word_t esr) { + word_t exception_class = getFaultStatus(esr); + return (exception_class == DEBUG_ENTRY_BREAKPOINT || + exception_class == DEBUG_ENTRY_SINGLE_STEP || + exception_class == DEBUG_ENTRY_WATCHPOINT || + exception_class == DEBUG_ENTRY_EXPLICIT_BKPT); +} + +/** Called to process a debug exception. + * + * On x86, you're told which breakpoint register triggered the exception. On + * ARM, you're told the virtual address that triggered the exception and what + * type of access (data access vs instruction execution) triggered the exception + * and you have to figure out which register triggered it. + * + * For watchpoints, it's not very complicated: just check to see which + * register matches the virtual address. + * + * For breakpoints, it's a bit more complex: since both breakpoints and single- + * stepping are configured using the same registers, we need to first detect + * whether single-stepping is enabled. If not, then we check for a breakpoint. + * @param fault_vaddr The instruction vaddr which triggered the exception, as + * extracted by the kernel. + */ +seL4_Fault_t handleUserLevelDebugException(word_t esr, word_t fault_vaddr) { + int active_bp; + word_t bp_reason, bp_vaddr; + word_t exception_class = getFaultStatus(esr); + +#ifdef TRACK_KERNEL_ENTRIES + ksKernelEntry.path = Entry_DebugFault; + ksKernelEntry.word = exception_class; +#endif + + switch (exception_class) { + case DEBUG_ENTRY_BREAKPOINT: + bp_reason = seL4_InstructionBreakpoint; + bp_vaddr = fault_vaddr; + break; + case DEBUG_ENTRY_WATCHPOINT: + bp_reason = seL4_DataBreakpoint; + // @alwin: aarch32 does something else in hypervisor mode + bp_vaddr = getFAR(); + break; + case DEBUG_ENTRY_SINGLE_STEP: + bp_reason = seL4_SingleStep; + bp_vaddr = fault_vaddr; + active_bp = 0; + break; + // case DEBUG_ENTRY_ASYNC_WATCHPOINT: + // @alwin: necessary? + default: /* EXPLICIT_BKPT: BKPT instruction */ + assert(exception_class == DEBUG_ENTRY_EXPLICIT_BKPT); + bp_reason = seL4_SoftwareBreakRequest; + bp_vaddr = fault_vaddr; + active_bp = 0; + } + + /* There is no hardware register associated with BKPT instruction + * triggers or single stepping. + */ + if (bp_reason != seL4_SoftwareBreakRequest && bp_reason != seL4_SingleStep) { + active_bp = getAndResetActiveBreakpoint(bp_vaddr, bp_reason); + active_bp = getBpNumFromType(active_bp, bp_reason); + assert(active_bp >= 0); + } + + if (bp_reason == seL4_SingleStep && !singleStepFaultCounterReady(NODE_STATE(ksCurThread))) { + return seL4_Fault_NullFault_new(); +} + + return seL4_Fault_DebugException_new(bp_vaddr, active_bp, bp_reason); +} + +#endif /* CONFIG_HARDWARE_DEBUG_API */ + +#ifdef ARM_BASE_CP14_SAVE_AND_RESTORE + +/** Pops debug register context for a thread into the CPU. + * + * Mirrors the idea of restore_user_context. + */ +void arch_restore_user_debug_context(tcb_t *target_thread) { + assert(target_thread != NULL); + + /* Set/unset single stepping if applicable */ + word_t mdscr = 0, spsr = 0; + MRS("MDSCR_EL1", mdscr); + spsr = getRegister(target_thread, SPSR_EL1); + if (target_thread->tcbArch.tcbContext.breakpointState.single_step_enabled) { + /* Enable single stepping */ + mdscr |= MDSCR_SS; + spsr |= SPSR_SS; + } else { + /* Disable single stepping */ + mdscr &= ~MDSCR_SS; + spsr &= ~SPSR_SS; + } + MSR("MDSCR_EL1", mdscr); + setRegister(target_thread, SPSR_EL1, spsr); +} + +#endif /* ARM_BASE_CP14_SAVE_AND_RESTORE */ diff --git a/src/arch/arm/64/model/statedata.c b/src/arch/arm/64/model/statedata.c index 4bb135f3659..956ba7644b8 100644 --- a/src/arch/arm/64/model/statedata.c +++ b/src/arch/arm/64/model/statedata.c @@ -124,3 +124,8 @@ compile_assert(smmuStateCBCNodeSize, sizeof(smmuStateCBNode) >= ((SMMU_MAX_CB) * /*recording the context bank to ASID relationship*/ asid_t smmuStateCBAsidTable[SMMU_MAX_CB]; #endif + +#ifdef ARM_BASE_CP14_SAVE_AND_RESTORE +/* Null state for the Debug coprocessor's break/watchpoint registers */ +user_breakpoint_state_t armKSNullBreakpointState; +#endif /* ARM_BASE_CP14_SAVE_AND_RESTORE */ diff --git a/src/arch/arm/c_traps.c b/src/arch/arm/c_traps.c index 10b87464ad1..bc3db9cd28c 100644 --- a/src/arch/arm/c_traps.c +++ b/src/arch/arm/c_traps.c @@ -45,7 +45,15 @@ void VISIBLE NORETURN c_handle_undefined_instruction(void) #ifdef CONFIG_ARCH_AARCH32 handleUserLevelFault(0, 0); #else - handleUserLevelFault(getESR(), 0); + word_t esr = getESR(); +#ifdef CONFIG_HARDWARE_DEBUG_API + if (isDebugFault(esr)) { + handleDebugFaultEvent(esr); + restore_user_context(); + UNREACHABLE(); + } +#endif + handleUserLevelFault(esr, 0); #endif restore_user_context(); UNREACHABLE(); @@ -218,6 +226,15 @@ VISIBLE NORETURN void c_handle_vcpu_fault(word_t hsr) c_entry_hook(); +#ifdef CONFIG_HARDWARE_DEBUG_API + word_t esr = getESR(); + if (isDebugFault(esr)) { + handleDebugFaultEvent(esr); + restore_user_context(); + UNREACHABLE(); + } +#endif + #ifdef TRACK_KERNEL_ENTRIES ksKernelEntry.path = Entry_VCPUFault; ksKernelEntry.word = hsr; diff --git a/src/arch/arm/config.cmake b/src/arch/arm/config.cmake index 03bff4def41..238a78290db 100644 --- a/src/arch/arm/config.cmake +++ b/src/arch/arm/config.cmake @@ -222,10 +222,6 @@ if(KernelAArch32FPUEnableContextSwitch OR KernelSel4ArchAarch64) set(KernelHaveFPU ON) endif() -if(KernelSel4ArchAarch64) - set(KernelHardwareDebugAPIUnsupported ON CACHE INTERNAL "") -endif() - if( KernelArmCortexA7 OR KernelArmCortexA8 diff --git a/src/arch/arm/kernel/boot.c b/src/arch/arm/kernel/boot.c index 1c8decc70c9..b8826ee8de5 100644 --- a/src/arch/arm/kernel/boot.c +++ b/src/arch/arm/kernel/boot.c @@ -193,7 +193,6 @@ BOOT_CODE static bool_t init_cpu(void) if (config_set(CONFIG_ARM_HYPERVISOR_SUPPORT)) { vcpu_boot_init(); } - #ifdef CONFIG_HARDWARE_DEBUG_API if (!Arch_initHardwareBreakpoints()) { printf("Kernel built with CONFIG_HARDWARE_DEBUG_API, but this board doesn't " diff --git a/src/arch/arm/machine/debug.c b/src/arch/arm/machine/debug.c index 56a3d62e4e0..b024a21ef63 100644 --- a/src/arch/arm/machine/debug.c +++ b/src/arch/arm/machine/debug.c @@ -309,9 +309,10 @@ void setBreakpoint(tcb_t *t, /* Preserve reserved bits. */ bcr.words[0] = readBcrContext(t, bp_num); bcr = dbg_bcr_set_enabled(bcr, 1); - bcr = dbg_bcr_set_linkedBrp(bcr, 0); - bcr = dbg_bcr_set_supervisorAccess(bcr, DBGBCR_PRIV_USER); - bcr = dbg_bcr_set_byteAddressSelect(bcr, convertSizeToArch(4)); + bcr = dbg_bcr_set_lbn(bcr, 0); + bcr = dbg_bcr_set_pmc(bcr, DBGBCR_PRIV_USER); + bcr = dbg_bcr_set_hmc(bcr, 0); + bcr = dbg_bcr_set_ssc(bcr, 0); bcr = Arch_setupBcr(bcr, true); writeBcrContext(t, bp_num, bcr.words[0]); } else { @@ -322,12 +323,14 @@ void setBreakpoint(tcb_t *t, /* Preserve reserved bits */ wcr.words[0] = readWcrContext(t, bp_num); wcr = dbg_wcr_set_enabled(wcr, 1); - wcr = dbg_wcr_set_supervisorAccess(wcr, DBGWCR_PRIV_USER); - wcr = dbg_wcr_set_byteAddressSelect(wcr, convertSizeToArch(size)); - wcr = dbg_wcr_set_loadStore(wcr, convertAccessToArch(rw)); - wcr = dbg_wcr_set_enableLinking(wcr, 0); - wcr = dbg_wcr_set_linkedBrp(wcr, 0); - wcr = Arch_setupWcr(wcr); + wcr = dbg_wcr_set_pac(wcr, DBGWCR_PRIV_USER); + wcr = dbg_wcr_set_bas(wcr, convertSizeToArch(size)); + wcr = dbg_wcr_set_lsc(wcr, convertAccessToArch(rw)); + wcr = dbg_wcr_set_watchpointType(wcr, 0); + wcr = dbg_wcr_set_lbn(wcr, 0); + wcr = dbg_wcr_set_addressMask(wcr, 0); + wcr = dbg_wcr_set_hmc(wcr, 0); + wcr = dbg_wcr_set_ssc(wcr, 0); writeWcrContext(t, bp_num, wcr.words[0]); } } @@ -354,9 +357,11 @@ getBreakpoint_t getBreakpoint(tcb_t *t, uint16_t bp_num) dbg_bcr_t bcr; bcr.words[0] = readBcrContext(t, bp_num); +#ifdef CONFIG_ARCH_AARCH32 if (Arch_breakpointIsMismatch(bcr) == true) { ret.type = seL4_SingleStep; }; +#endif ret.size = 0; ret.rw = seL4_BreakOnRead; ret.vaddr = readBvrContext(t, bp_num); @@ -365,8 +370,8 @@ getBreakpoint_t getBreakpoint(tcb_t *t, uint16_t bp_num) dbg_wcr_t wcr; wcr.words[0] = readWcrContext(t, bp_num); - ret.size = convertArchToSize(dbg_wcr_get_byteAddressSelect(wcr)); - ret.rw = convertArchToAccess(dbg_wcr_get_loadStore(wcr)); + ret.size = convertArchToSize(dbg_wcr_get_bas(wcr)); + ret.rw = convertArchToAccess(dbg_wcr_get_lsc(wcr)); ret.vaddr = readWvrContext(t, bp_num); ret.is_enabled = dbg_wcr_get_enabled(wcr); } @@ -402,60 +407,6 @@ void unsetBreakpoint(tcb_t *t, uint16_t bp_num) } } -/** Initiates or halts single-stepping on the target process. - * - * @param at arch_tcb_t for the target process to be configured. - * @param bp_num The hardware ID of the breakpoint register to be used. - * @param n_instr The number of instructions to step over. - */ -bool_t configureSingleStepping(tcb_t *t, - uint16_t bp_num, - word_t n_instr, - bool_t is_reply) -{ - - if (is_reply) { - bp_num = t->tcbArch.tcbContext.breakpointState.single_step_hw_bp_num; - } else { - bp_num = convertBpNumToArch(bp_num); - } - - /* On ARM single-stepping is emulated using breakpoint mismatches. The aim - * of single stepping is to execute a single instruction. By setting an - * instruction mismatch breakpoint to the current LR of the target thread, - * the thread will be able to execute this instruction, but attempting to - * execute any other instruction will result in the generation of a debug - * exception that will be delivered to the kernel, allowing us to simulate - * single stepping. - */ - dbg_bcr_t bcr; - - bcr.words[0] = readBcrContext(t, bp_num); - - /* If the user calls us with n_instr == 0, allow them to configure, but - * leave it disabled. - */ - if (n_instr > 0) { - bcr = dbg_bcr_set_enabled(bcr, 1); - t->tcbArch.tcbContext.breakpointState.single_step_enabled = true; - } else { - bcr = dbg_bcr_set_enabled(bcr, 0); - t->tcbArch.tcbContext.breakpointState.single_step_enabled = false; - } - - bcr = dbg_bcr_set_linkedBrp(bcr, 0); - bcr = dbg_bcr_set_supervisorAccess(bcr, DBGBCR_PRIV_USER); - bcr = dbg_bcr_set_byteAddressSelect(bcr, convertSizeToArch(1)); - bcr = Arch_setupBcr(bcr, false); - - writeBvrContext(t, bp_num, t->tcbArch.tcbContext.registers[FaultIP]); - writeBcrContext(t, bp_num, bcr.words[0]); - - t->tcbArch.tcbContext.breakpointState.n_instructions = n_instr; - t->tcbArch.tcbContext.breakpointState.single_step_hw_bp_num = bp_num; - return true; -} - /** Load an initial, all-disabled setup state for the registers. */ BOOT_CODE void disableAllBpsAndWps(void) @@ -497,7 +448,7 @@ BOOT_CODE void disableAllBpsAndWps(void) */ int getAndResetActiveBreakpoint(word_t vaddr, word_t reason) { - word_t align_mask; + word_t align_mask = (word_t) -1; int i, ret = -1; if (reason == seL4_InstructionBreakpoint) { @@ -510,8 +461,11 @@ int getAndResetActiveBreakpoint(word_t vaddr, word_t reason) * range, which means it's not guaranteed to match the aligned value * that was programmed into the address register. */ +// @alwin: check if this is okay +#ifdef CONFIG_ARCH_AARCH32 align_mask = convertArchToSize(dbg_bcr_get_byteAddressSelect(bcr)); align_mask = ~(align_mask - 1); +#endif /* CONFIG_ARCH_AARCH32 */ if (bvr != (vaddr & align_mask) || !dbg_bcr_get_enabled(bcr)) { continue; @@ -528,7 +482,7 @@ int getAndResetActiveBreakpoint(word_t vaddr, word_t reason) word_t wvr = readWvrCp(i); wcr.words[0] = readWcrCp(i); - align_mask = convertArchToSize(dbg_wcr_get_byteAddressSelect(wcr)); + align_mask = convertArchToSize(dbg_wcr_get_bas(wcr)); align_mask = ~(align_mask - 1); if (wvr != (vaddr & align_mask) || !dbg_wcr_get_enabled(wcr)) { @@ -685,6 +639,12 @@ void restore_user_debug_context(tcb_t *target_thread) * * So we don't need to execute ISB here because we're about to RFE. */ + +#ifdef CONFIG_ARCH_AARCH64 + arch_restore_user_debug_context(target_thread); +#endif /* CONFIG_ARCH_ARCH64 */ + + } #endif /* ARM_BASE_CP14_SAVE_AND_RESTORE */ diff --git a/src/object/tcb.c b/src/object/tcb.c index 32d0a1e2db2..9059ff080e5 100644 --- a/src/object/tcb.c +++ b/src/object/tcb.c @@ -529,10 +529,14 @@ static exception_t invokeConfigureSingleStepping(bool_t call, word_t *buffer, tc bp_was_consumed = configureSingleStepping(t, bp_num, n_instrs, false); if (n_instrs == 0) { + #ifndef CONFIG_ARCH_AARCH64 unsetBreakpointUsedFlag(t, bp_num); + #endif /* CONFIG_ARCH_AARCH64 */ value = false; } else { + #ifndef CONFIG_ARCH_AARCH64 setBreakpointUsedFlag(t, bp_num); + #endif /* CONFIG_ARCH_AARCH64 */ value = bp_was_consumed; }