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 <camkes.h> 14 15#include <string.h> 16 17typedef struct breakpoint_state { 18 seL4_Word vaddr; 19 seL4_Word type; 20 seL4_Word size; 21 seL4_Word rw; 22 seL4_Bool is_enabled; 23} breakpoint_state_t; 24 25 26static int check_read_memory(seL4_Word addr) { 27 // TODO This doesn't deal with page boundaries 28 uint32_t result = 0; 29 asm volatile ( 30 "movl $0, %%eax;" 31 "movl %[addr], %%ebx;" 32 "movl (%%ebx), %%ecx;" 33 // The code above will cause a fault to the mem handler if 34 // the memory is not readable. The mem handler will set eax 35 // appropriately 36 "movl %%eax, %0;" 37 : "=r" (result) 38 : [addr] "r" (addr) 39 : "eax", "ebx", "ecx" 40 ); 41 return result; 42} 43 44static int check_write_memory(seL4_Word addr) { 45 // TODO This doesn't deal with page boundaries 46 uint32_t result = 0; 47 asm volatile ( 48 "movl $0, %%eax;" 49 "movl %[addr], %%ebx;" 50 "movl (%%ebx), %%ecx;" 51 "movl %%ecx, (%%ebx);" 52 // The code above will cause a fault to the mem handler if 53 // the memory is not readable. The mem handler will set eax 54 // appropriately 55 "movl %%eax, %0;" 56 : "=r" (result) 57 : [addr] "r" (addr) 58 : "eax", "ebx", "ecx" 59 ); 60 return result; 61} 62 63#ifdef CONFIG_HARDWARE_DEBUG_API 64breakpoint_state_t breakpoints[seL4_NumDualFunctionMonitors]; 65#endif 66 67 68static void breakpoint_init(void) { 69#ifdef CONFIG_HARDWARE_DEBUG_API 70 for (int i = 0; i < seL4_NumDualFunctionMonitors; i++) { 71 breakpoints[i].vaddr = 0; 72 breakpoints[i].type = 0; 73 breakpoints[i].size = 0; 74 breakpoints[i].rw = 0; 75 breakpoints[i].is_enabled = false; 76 } 77#endif 78} 79 80static int find_free_breakpoint(void) { 81#ifdef CONFIG_HARDWARE_DEBUG_API 82 int bp = -1; 83 for (int i = 0; i < seL4_NumDualFunctionMonitors; i++) { 84 if (!breakpoints[i].is_enabled) { 85 bp = i; 86 break; 87 } 88 } 89 return bp; 90#else 91 return -1; 92#endif 93} 94 95static int get_breakpoint_num(seL4_Word vaddr UNUSED, seL4_Word type UNUSED, 96 seL4_Word size UNUSED, seL4_Word rw UNUSED) { 97#ifdef CONFIG_HARDWARE_DEBUG_API 98 int bp = -1; 99 for (int i = 0; i < seL4_NumDualFunctionMonitors; i++) { 100 if (breakpoints[i].is_enabled && breakpoints[i].vaddr == vaddr && 101 breakpoints[i].type == type && breakpoints[i].size == size && 102 breakpoints[i].rw == rw) { 103 bp = i; 104 break; 105 } 106 } 107 return bp; 108#else 109 return -1; 110#endif 111} 112 113static void set_breakpoint_state(seL4_Word vaddr UNUSED, seL4_Word type UNUSED, 114 seL4_Word size UNUSED, seL4_Word rw UNUSED, int bp UNUSED) { 115#ifdef CONFIG_HARDWARE_DEBUG_API 116 breakpoints[bp].vaddr = vaddr; 117 breakpoints[bp].type = type; 118 breakpoints[bp].size = size; 119 breakpoints[bp].rw = rw; 120 breakpoints[bp].is_enabled = true; 121#endif 122} 123 124static void clear_breakpoint_state(int bp UNUSED) { 125#ifdef CONFIG_HARDWARE_DEBUG_API 126 breakpoints[bp].vaddr = 0; 127 breakpoints[bp].type = 0; 128 breakpoints[bp].size = 0; 129 breakpoints[bp].rw = 0; 130 breakpoints[bp].is_enabled = false; 131#endif 132} 133 134 135void delegate__init() { 136 breakpoint_init(); 137} 138 139int delegate_read_memory(seL4_Word addr, seL4_Word length, delegate_mem_range_t *data) { 140 if (length == 0 || length > MAX_MEM_RANGE) { 141 ZF_LOGE("Invalid length %d", length); 142 return 1; 143 } 144 if (check_read_memory(addr)) { 145 return 1; 146 } else { 147 memcpy(data->data, (void *)addr, length); 148 return 0; 149 } 150} 151 152int delegate_write_memory(seL4_Word addr, seL4_Word length, delegate_mem_range_t data) { 153 if (length == 0 || length > MAX_MEM_RANGE) { 154 ZF_LOGE("Invalid length %d", length); 155 return 1; 156 } 157 // If invalid memory, return with error 158 if (check_write_memory(addr)) { 159 return 1; 160 } else { 161 memcpy((void *) addr, (void *) data.data, length); 162 return 0; 163 } 164} 165 166void delegate_read_registers(seL4_Word tcb_cap, seL4_UserContext *registers) { 167 int num_regs = sizeof(seL4_UserContext) / sizeof(seL4_Word); 168 seL4_TCB_ReadRegisters(tcb_cap, false, 0, num_regs, registers); 169 170 return; 171} 172 173void delegate_read_register(seL4_Word tcb_cap, seL4_Word *reg, seL4_Word reg_num) { 174 int num_regs = sizeof(seL4_UserContext) / sizeof(seL4_Word); 175 if (reg_num >= num_regs) { 176 ZF_LOGE("Invalid register num: %zd", reg_num); 177 return; 178 } 179 seL4_UserContext regs = {0}; 180 seL4_TCB_ReadRegisters(tcb_cap, false, 0, num_regs, ®s); 181 seL4_Word *reg_word = (seL4_Word *) (& regs); 182 *reg = reg_word[reg_num]; 183} 184 185 int delegate_write_registers(seL4_Word tcb_cap, seL4_UserContext registers, int len) { 186 // Get register values from IPC 187 seL4_UserContext regs = {0}; 188 int num_regs = sizeof(seL4_UserContext) / sizeof(seL4_Word); 189 seL4_TCB_ReadRegisters(tcb_cap, false, 0, num_regs, ®s); 190 seL4_Word *reg_word = (seL4_Word *) (®s); 191 for (int i = 0; i < len; i++) { 192 reg_word[i] = ((seL4_Word *)®s)[i]; 193 } 194 // Write registers 195 int err = seL4_TCB_WriteRegisters(tcb_cap, false, 0, num_regs, ®s); 196 if (err) { 197 return 1; 198 } else { 199 return 0; 200 } 201} 202 203int delegate_write_register(seL4_Word tcb_cap, seL4_Word data, seL4_Word reg_num) { 204 int num_regs = sizeof(seL4_UserContext) / sizeof(seL4_Word); 205 seL4_UserContext regs = {0}; 206 seL4_Word *reg_word = (seL4_Word *) (®s); 207 seL4_TCB_ReadRegisters(tcb_cap, false, 0, num_regs, ®s); 208 // Change relevant register 209 reg_word[reg_num] = data; 210 int err = seL4_TCB_WriteRegisters(tcb_cap, false, 0, num_regs, ®s); 211 if (err) { 212 return 1; 213 } else { 214 return 0; 215 } 216 217} 218 219int delegate_insert_break(seL4_Word tcb_cap, seL4_Word type, seL4_Word addr, seL4_Word size, seL4_Word rw) { 220 int err = 0; 221#ifdef CONFIG_HARDWARE_DEBUG_API 222 // Insert the breakpoint 223 int bp_num = find_free_breakpoint(); 224 if (bp_num == -1) { 225 err = 1; 226 } else { 227 // Set the breakpoint 228 err = seL4_TCB_SetBreakpoint(tcb_cap, (seL4_Uint16) bp_num, addr, 229 type, size, rw); 230 if (!err) { 231 set_breakpoint_state(addr, type, size, rw, bp_num); 232 } 233 seL4_TCB_GetBreakpoint(tcb_cap, bp_num); 234 } 235#else 236 err = -1; 237#endif 238 if (err) { 239 return 1; 240 } else { 241 return 0; 242 } 243} 244 245int delegate_remove_break(seL4_Word tcb_cap, seL4_Word type, seL4_Word addr, seL4_Word size, seL4_Word rw) { 246 int err = 0; 247#ifdef CONFIG_HARDWARE_DEBUG_API 248 // Find the breakpoint 249 int bp_num = get_breakpoint_num(addr, type, size, rw); 250 if (bp_num == -1) { 251 err = 1; 252 } 253 // Unset the breakpoint 254 err = seL4_TCB_UnsetBreakpoint(tcb_cap, (seL4_Uint16) bp_num); 255 if (!err) { 256 clear_breakpoint_state(bp_num); 257 } 258#else 259 err = -1; 260#endif 261 if (err) { 262 return 1; 263 } else { 264 return 0; 265 } 266} 267 268 269int delegate_resume(seL4_Word tcb_cap) { 270#ifdef CONFIG_HARDWARE_DEBUG_API 271 seL4_TCB_ConfigureSingleStepping_t result = 272 seL4_TCB_ConfigureSingleStepping(tcb_cap, 0, 0); 273 274 if (result.error) { 275 return 1; 276 } else { 277 return 0; 278 } 279#endif 280 return 1; 281} 282 283int delegate_step(seL4_Word tcb_cap) { 284#ifdef CONFIG_HARDWARE_DEBUG_API 285 seL4_TCB_ConfigureSingleStepping_t result = 286 seL4_TCB_ConfigureSingleStepping(tcb_cap, 0, 1); 287 288 if (result.error) { 289 return 1; 290 } else { 291 return 0; 292 } 293#endif 294 return 1; 295 296} 297 298