Skip to content

Commit

Permalink
hardware debug API: aarch64 and single stepping
Browse files Browse the repository at this point in the history
Signed-off-by: Alwin Joshy <[email protected]>
  • Loading branch information
alwin-joshy committed Jan 15, 2024
1 parent b383b19 commit e5f009a
Show file tree
Hide file tree
Showing 2 changed files with 130 additions and 1 deletion.
22 changes: 21 additions & 1 deletion apps/sel4test-tests/arch/arm/arch/debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,36 @@
*/
#pragma once

#ifdef CONFIG_ARCH_AARCH32
#define TEST_SOFTWARE_BREAK_ASM() \
asm volatile( \
".global sbreak, post_sbreak\n\t" \
".type post_sbreak, function\n\t" \
"sbreak:\n\t" \
"bkpt\n\t")
#else
#define TEST_SOFTWARE_BREAK_ASM() \
asm volatile( \
".global sbreak, post_sbreak\n\t" \
".type post_sbreak, function\n\t" \
"sbreak:\n\t" \
"brk #0\n\t")
#endif

#define TEST_SINGLE_STEP_ASM() \
asm volatile( \
".global label_one, label_two\n\t" \
"label_one: \n\t" \
"nop \n\t" \
"label_two: \n\t" \
"nop \n\t" \
)

/* Tell C about the symbols exported by the ASM above. */
extern char sbreak;
extern char sbreak, label_one, label_two;
#define TEST_SOFTWARE_BREAK_EXPECTED_FAULT_LABEL sbreak
#define TEST_SS_LABEL_ONE label_one
#define TEST_SS_LABEL_TWO label_two
#define SINGLESTEP_EXPECTED_BP_CONSUMPTION_VALUE (true)
#define TEST_NUM_DATA_WPS seL4_NumExclusiveWatchpoints
#define TEST_NUM_INSTR_BPS seL4_NumExclusiveBreakpoints
Expand Down
109 changes: 109 additions & 0 deletions apps/sel4test-tests/src/arch/arm/tests/breakpoints.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/*
* Copyright 2024, UNSW Sydney
*
* SPDX-License-Identifier: BSD-2-Clause
*/

#include <autoconf.h>

#ifdef CONFIG_HARDWARE_DEBUG_API

#include <sel4/sel4.h>
#include <utils/attribute.h>

#include <arch/debug.h>
#include "../../../helpers.h"
#include "../../../test.h"
#include "../../../tests/breakpoints.h"

static int faulter_main(seL4_Word arg0, seL4_Word arg1, seL4_Word arg2, seL4_Word arg3)
{
TEST_SINGLE_STEP_ASM();
/* NOTHING BELOW SHOULD EVER BE REACHED */
int *ptr = NULL;
*ptr = 0xBEEF;
return 0;
}

static int handler_main(seL4_Word faulter_tcb, seL4_Word a1, seL4_Word a2, seL4_Word a3)
{
seL4_Word sender_badge;
seL4_MessageInfo_t tag;
seL4_Word label;

/* Wait for the faulter to trigger an event. */
tag = api_wait(fault_ep_cspath.capPtr, &sender_badge);
ZF_LOGV("Handler got a fault on the ep.\n");
label = seL4_MessageInfo_get_label(tag);

/* Check that it is a breakpoint exception */
if (label != seL4_Fault_DebugException ||
seL4_GetMR(seL4_DebugException_ExceptionReason) != seL4_InstructionBreakpoint) {
ZF_LOGV("Received exception other than instruction breakpoint exception.\n");
return -1;
}

/* Disable the breakpoint and enable single stepping */
int error = seL4_TCB_UnsetBreakpoint(faulter_tcb, 0);
test_eq(error, 0);

seL4_TCB_ConfigureSingleStepping_t res = seL4_TCB_ConfigureSingleStepping(faulter_tcb, 0, 1);
test_eq(res.error, 0);

/* Reply to the thread to resume it */
tag = api_reply_recv(fault_ep_cspath.capPtr, seL4_MessageInfo_new(0, 0, 0, 0), &sender_badge, 0);
label = seL4_MessageInfo_get_label(tag);

/* Wait for the single step exception */
fault_data.vaddr = seL4_GetMR(seL4_DebugException_FaultIP);
fault_data.reason = seL4_GetMR(seL4_DebugException_ExceptionReason);
fault_data.vaddr2 = seL4_GetMR(seL4_DebugException_TriggerAddress);
fault_data.bp_num = seL4_GetMR(seL4_DebugException_BreakpointNumber);

if (label == seL4_Fault_DebugException &&
fault_data.reason == seL4_SingleStep &&
fault_data.vaddr == (seL4_Word) &TEST_SS_LABEL_TWO) {

return 0;
} else {
ZF_LOGE("Fault of type %zd received. Vaddr 0x%zx\n", label, fault_data.vaddr);
fault_data.bp_num = 0;
return -1;
}
}

static int test_single_step_one(struct env *env)
{
int error, result;
helper_thread_t faulter_thread, handler_thread;
test_eq(setup_caps_for_test(env), 0);

create_helper_thread(env, &handler_thread);
set_helper_priority(env, &handler_thread, BREAKPOINT_TEST_HANDLER_PRIO);

error = setup_faulter_thread_for_test(env, &faulter_thread);
test_eq(error, seL4_NoError);

/* We want it to run until the first label */
error = seL4_TCB_SetBreakpoint(get_helper_tcb(&faulter_thread), 0, (seL4_Word) &TEST_SS_LABEL_ONE,
seL4_InstructionBreakpoint, 0, seL4_BreakOnRead);
test_eq(error, seL4_NoError);

start_helper(env, &handler_thread, &handler_main, get_helper_tcb(&faulter_thread), 0, 0, 0);
start_helper(env, &faulter_thread, &faulter_main, 0, 0, 0, 0);

result = wait_for_helper(&handler_thread);

cleanup_helper(env, &faulter_thread);
cleanup_helper(env, &handler_thread);

/* Ensure the test was a success */
test_eq(result, 0);

return sel4test_get_result();
}

DEFINE_TEST(SINGLESTEP_001, "Test that single stepping 1 instruction works",
test_single_step_one, config_set(CONFIG_HARDWARE_DEBUG_API))

#endif /* CONFIG_HARDWARE_DEBUG_API */

0 comments on commit e5f009a

Please sign in to comment.