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 <[email protected]>
  • Loading branch information
alwin-joshy authored and lsf37 committed Jul 18, 2024
1 parent b397473 commit 1253115
Show file tree
Hide file tree
Showing 20 changed files with 661 additions and 94 deletions.
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 */
26 changes: 26 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,21 @@ 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;

typedef struct user_breakpoint_state {
/* We don't use context comparisons */
debug_register_pair_t breakpoint[seL4_NumExclusiveBreakpoints],
watchpoint[seL4_NumExclusiveWatchpoints];
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 +266,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 +279,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,24 @@ 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 +203,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 +222,10 @@ static inline syscall_error_t Arch_decodeConfigureSingleStepping(tcb_t *t,
return ret;
}

/* The following code relates to checking that the specified breakpoint is suitable to
for being used for conguring single stepping. AARCH64 does not need to use breakpoints
to simulate single stepping, so these checks can be ommited. */
#ifdef CONFIG_ARCH_AARCH32
type = seL4_InstructionBreakpoint;
bp_num = t->tcbArch.tcbContext.breakpointState.single_step_hw_bp_num;
} else {
Expand All @@ -225,6 +250,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 @@ -266,6 +292,7 @@ static inline syscall_error_t Arch_decodeSetBreakpoint(tcb_t *t,
ret.invalidArgumentNumber = 3;
return ret;
}

if (size == 8 && type != seL4_DataBreakpoint) {
userError("Debug: 8-byte sizes can only be used with watchpoints.");
ret.type = seL4_InvalidArgument;
Expand Down
13 changes: 1 addition & 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,17 +149,8 @@ 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)
static inline bool_t Arch_breakpointIsSingleStepping(tcb_t *t, uint16_t bp_num)
{
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 */

return (t->tcbArch.tcbContext.breakpointState.single_step_enabled &&
Expand Down
45 changes: 45 additions & 0 deletions include/arch/arm/armv/armv8-a/64/armv/debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,48 @@

#pragma once

#if defined(CONFIG_HARDWARE_DEBUG_API)

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_INSTRUCTION_MISMATCH = 0x4u,
DBGBCR_TYPE_LINKED_INSTRUCTION_MISMATCH = 0x5u,

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, bool_t is_match)
{
if (is_match) {
bcr = dbg_bcr_set_breakpointType(bcr, DBGBCR_TYPE_UNLINKED_INSTRUCTION_MATCH);
} else {
bcr = dbg_bcr_set_breakpointType(bcr, DBGBCR_TYPE_UNLINKED_INSTRUCTION_MISMATCH);
}
return bcr;
}

static inline bool_t Arch_breakpointIsSingleStepping(tcb_t *t, uint16_t bp_num)
{
/* AARCH64 does not use breakpoints for single-stepping */
return false;
}

#endif
Loading

0 comments on commit 1253115

Please sign in to comment.