1/*# 2 *# Copyright 2017, Data61 3 *# Commonwealth Scientific and Industrial Research Organisation (CSIRO) 4 *# ABN 41 687 119 230. 5 *# 6 *# This software may be distributed and modified according to the terms of 7 *# the BSD 2-Clause license. Note that NO WARRANTY is provided. 8 *# See "LICENSE_BSD2.txt" for details. 9 *# 10 *# @TAG(DATA61_BSD) 11 #*/ 12 13#include <assert.h> 14#include <limits.h> 15#include <stddef.h> 16#include <stdint.h> 17#include <stdlib.h> 18#include <string.h> 19#include <sel4/sel4.h> 20#include <sel4debug/debug.h> 21#include <utils/util.h> 22#include <camkes.h> 23#include <stdarg.h> 24#include <camkes/gdb/serial.h> 25#include <camkes/gdb/gdb.h> 26 27/*? macros.show_includes(me.instance.type.includes) ?*/ 28/*? macros.show_includes(me.interface.type.includes, '../static/components/%s/' % me.instance.type.name) ?*/ 29 30/*- set methods_len = len(me.interface.type.methods) -*/ 31/*- set instance = me.instance.name -*/ 32/*- set interface = me.interface.name -*/ 33/*- set size = 'seL4_MsgMaxLength * sizeof(seL4_Word)' -*/ 34/*- set allow_trailing_data = False -*/ 35/*- set ep = alloc("ep_fault", seL4_EndpointObject, read=True, write=True, grantreply=True) -*/ 36/*- set cnode = alloc_cap('cnode', my_cnode) -*/ 37 /*- if options.realtime -*/ 38 /*- set reply_cap_slot = alloc('reply_cap_slot', seL4_RTReplyObject) -*/ 39 /*- else -*/ 40 /*- set reply_cap_slot = alloc_cap('reply_cap_slot', None) -*/ 41 /*- endif -*/ 42/*- set info = c_symbol('info') -*/ 43 44static gdb_state_t gdb_state; 45 46static stop_reason_t find_stop_reason(seL4_Word fault_type, seL4_Word *args) { 47 if (fault_type == seL4_Fault_DebugException) { 48 seL4_Word exception_reason = args[1]; 49 ZF_LOGD("MR 0: %zX", args[0]); 50 ZF_LOGD("MR 1: %zX", args[1]); 51 ZF_LOGD("MR 2: %zX", args[2]); 52 ZF_LOGD("MR 3: %zX", args[3]); 53 ZF_LOGD("Breakpoint number %zu", args[1]); 54 if (exception_reason == seL4_DataBreakpoint) { 55 ZF_LOGD("Data breakpoint"); 56 gdb_state.stop_watch_addr = args[2]; 57 return stop_watch; 58 } else if (exception_reason == seL4_InstructionBreakpoint) { 59 ZF_LOGD("Hardware breakpoint"); 60 return stop_hw_break; 61 } else if (exception_reason == seL4_SingleStep && gdb_state.current_thread_step_mode) { 62 return stop_step; 63 } else if (exception_reason == seL4_SoftwareBreakRequest) { 64 ZF_LOGD("Decrementing fault ep because of seL4 kernel behavior"); 65 /* TODO This is a special case where the seL4 kernel gives us a fault instruction 66 pointer that is no the faulting instruction. We decrement the pc to correct for 67 this. In the future the kernel may end up changing the fault ip behavior and this 68 decrement will then need to be removed to account for it. 69 */ 70 gdb_state.current_pc--; 71 delegate_write_register(gdb_state.current_thread_tcb, gdb_state.current_pc, 0); 72 73 return stop_sw_break; 74 } else { 75 return stop_none; 76 } 77 } else { 78 ZF_LOGE("Unknown fault type: %zd", fault_type); 79 ZF_LOGE("MR 0: %zX", args[0]); 80 ZF_LOGE("MR 1: %zX", args[1]); 81 ZF_LOGE("MR 2: %zX", args[2]); 82 ZF_LOGE("MR 3: %zX", args[3]); 83 84 return stop_none; 85 } 86} 87 88void /*? me.interface.name ?*/__init(void) { 89 gdb_state.sem_post = b_post; 90 gdb_state.current_thread_tcb = 1; 91 serial_init(&gdb_state); 92} 93 94int /*? me.interface.name ?*/__run(void) { 95 seL4_Word fault_type; 96 seL4_Word length; 97 seL4_MessageInfo_t info; 98 seL4_Word args[4]; 99 seL4_Word reply_cap = /*? reply_cap_slot ?*/; 100 while (1) { 101 /* Wait for fault */ 102 info = seL4_Recv(/*? ep ?*/, &gdb_state.current_thread_tcb); 103 /* Get the relevant registers */ 104 fault_type = seL4_MessageInfo_get_label(info); 105 length = seL4_MessageInfo_get_length(info); 106 for (int i = 0; i < length; i++) { 107 args[i] = seL4_GetMR(i); 108 } 109 gdb_state.current_pc = args[0]; 110 ZF_LOGD("------------------------------"); 111 ZF_LOGD("Received fault for tcb %zu", gdb_state.current_thread_tcb); 112 ZF_LOGD("Stopped at %zx", gdb_state.current_pc); 113 ZF_LOGD("Length: %zu", length); 114 // Save the reply cap 115 seL4_CNode_SaveCaller(/*? cnode ?*/, reply_cap, 32); 116 117 gdb_state.stop_reason = find_stop_reason(fault_type, args); 118 gdb_state.current_thread_step_mode = false; 119 120 /* Send fault message to gdb client */ 121 gdb_handle_fault(&gdb_state); 122 123 /* Wait for gdb client to deal with fault */ 124 int UNUSED error = b_wait(); 125 126 /* Reply to the fault ep to restart the thread. 127 We look inside the gdb_state struct to interpret how to restart the thread. 128 */ 129 if (gdb_state.stop_reason == stop_step && gdb_state.current_thread_step_mode==false) { 130 /* If this was a Debug Exception, then we respond with 131 a bp_num and the number of instruction to step 132 Since we're going to continue, we set MR0 to 0 133 */ 134 info = seL4_MessageInfo_new(0, 0, 0, 1); 135 seL4_SetMR(0, 0); 136 seL4_Send(reply_cap, info); 137 } else if (gdb_state.stop_reason == stop_none) { 138 /* If this was a fault, set the instruction pointer to 139 what we expect it to be 140 */ 141 info = seL4_MessageInfo_new(0, 0, 0, 1); 142 seL4_SetMR(0, gdb_state.current_pc); 143 seL4_Send(reply_cap, info); 144 } else { 145 ZF_LOGD("Responding to some other debug exception %d", gdb_state.stop_reason); 146 seL4_Signal(reply_cap); 147 } 148 149 } 150 UNREACHABLE(); 151} 152 153