Skip to content

Commit

Permalink
hw debug api: aarch64 port
Browse files Browse the repository at this point in the history
Adding support for the hardware debug API to
aarch64.

Signed-off-by: Alwin Joshy <joshyalwin@gmail.com>
  • Loading branch information
alwin-joshy committed Feb 26, 2024
1 parent d5851b0 commit f94b530
Show file tree
Hide file tree
Showing 21 changed files with 672 additions and 96 deletions.
1 change: 1 addition & 0 deletions include/api/syscall.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
4 changes: 4 additions & 0 deletions include/arch/arm/arch/64/mode/fastpath/fastpath.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
137 changes: 137 additions & 0 deletions include/arch/arm/arch/64/mode/machine/debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,141 @@

#pragma once

#ifdef ARM_BASE_CP14_SAVE_AND_RESTORE

void aarch64_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 */

#ifdef CONFIG_HARDWARE_DEBUG_API
exception_t handleDebugFaultEvent(word_t esr);
#endif /* CONFIG_HARDWARE_DEBUG_API */
38 changes: 38 additions & 0 deletions include/arch/arm/arch/64/mode/machine/registerset.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#pragma once

#include <config.h>
#include <arch/machine/debug_conf.h>

/* CurrentEL register */
#define PEXPL1 (1 << 2)
Expand Down Expand Up @@ -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];
Expand All @@ -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 */
Expand All @@ -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__ */
Expand Down
34 changes: 34 additions & 0 deletions include/arch/arm/arch/64/mode/object/structures.bf
Original file line number Diff line number Diff line change
Expand Up @@ -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 <sel4/arch/shared_types.bf>
27 changes: 27 additions & 0 deletions include/arch/arm/arch/machine/debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <api/types.h>
#include <arch/machine/debug_conf.h>
#include <sel4/plat/api/constants.h>
#include <mode/machine/debug.h>
#include <armv/debug.h>

#ifdef ARM_BASE_CP14_SAVE_AND_RESTORE
Expand Down Expand Up @@ -144,6 +145,23 @@ static inline void initHDCR(void)

#ifdef CONFIG_HARDWARE_DEBUG_API

/** Convert a watchpoint size (0, 1, 2, 4 or 8 bytes) into the arch specific
* register encoding.
*/
static inline word_t convertSizeToArch(word_t size) {
switch (size) {
case 1:
return 0x1;
case 2:
return 0x3;
case 8:
return 0xFF;
default:
assert(size == 4);
return 0xF;
}
}

/** These next two functions are part of some state flags.
*
* A bitfield of all currently enabled breakpoints for a thread is kept in that
Expand Down Expand Up @@ -184,7 +202,9 @@ static inline syscall_error_t Arch_decodeConfigureSingleStepping(tcb_t *t,
word_t n_instr,
bool_t is_reply)
{
#ifdef CONFIG_ARCH_AARCH32
word_t type;
#endif
syscall_error_t ret = {
.type = seL4_NoError
};
Expand All @@ -201,6 +221,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 {
Expand All @@ -225,6 +246,7 @@ static inline syscall_error_t Arch_decodeConfigureSingleStepping(tcb_t *t,
ret.invalidArgumentNumber = 0;
return ret;
}
#endif /* CONFIG_ARCH_AARCH32*/
}

return ret;
Expand Down Expand Up @@ -260,12 +282,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;
Expand Down Expand Up @@ -302,6 +327,7 @@ static inline syscall_error_t Arch_decodeUnsetBreakpoint(tcb_t *t, uint16_t bp_n
return ret;
}

#ifdef CONFIG_ARCH_AARCH32
word_t type;

type = getTypeFromBpNum(bp_num);
Expand All @@ -315,6 +341,7 @@ static inline syscall_error_t Arch_decodeUnsetBreakpoint(tcb_t *t, uint16_t bp_n
return ret;
}
}
#endif /* CONFIG_ARCH_AARCH32 */

return ret;
}
Expand Down
12 changes: 0 additions & 12 deletions include/arch/arm/armv/armv7-a/armv/debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,6 @@ 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_hmc(bcr, 0);
bcr = dbg_bcr_set_ssc(bcr, 0);
if (is_match) {
bcr = dbg_bcr_set_breakpointType(bcr, DBGBCR_TYPE_UNLINKED_INSTRUCTION_MATCH);
} else {
Expand All @@ -151,16 +149,6 @@ static inline dbg_bcr_t Arch_setupBcr(dbg_bcr_t in_val, bool_t is_match)
return bcr;
}

static inline dbg_wcr_t Arch_setupWcr(dbg_wcr_t in_val)
{
dbg_wcr_t wcr;

wcr = dbg_wcr_set_addressMask(in_val, 0);
wcr = dbg_wcr_set_hmc(wcr, 0);
wcr = dbg_wcr_set_ssc(wcr, 0);
return wcr;
}

static inline bool_t Arch_breakpointIsSingleStepping(tcb_t *t, uint16_t bp_num) {
/* Detect if the bp is set up for single stepping */

Expand Down

0 comments on commit f94b530

Please sign in to comment.