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 GNU General Public License version 2. Note that NO WARRANTY is provided. 8 * See "LICENSE_GPLv2.txt" for details. 9 * 10 * @TAG(DATA61_GPL) 11 */ 12 13#include <config.h> 14 15#ifdef CONFIG_HARDWARE_DEBUG_API 16 17#include <arch/machine/debug.h> 18#include <mode/machine/debug.h> 19#include <arch/machine.h> 20#include <machine/registerset.h> 21#include <plat/api/constants.h> /* seL4_NumHWBReakpoints */ 22 23/* Intel manual Vol3, 17.2.4 */ 24#define X86_DEBUG_BP_SIZE_1B (0x0u) 25#define X86_DEBUG_BP_SIZE_2B (0x1u) 26#define X86_DEBUG_BP_SIZE_4B (0x3u) 27#define X86_DEBUG_BP_SIZE_8B (0x2u) 28 29#define X86_DEBUG_BP0_SIZE_SHIFT (18) 30#define X86_DEBUG_BP1_SIZE_SHIFT (22) 31#define X86_DEBUG_BP2_SIZE_SHIFT (26) 32#define X86_DEBUG_BP3_SIZE_SHIFT (30) 33 34/* NOTE: Intel manual 17.2.4: 35 * I/O breakpoints are supported by every processor later than i486, but only 36 * when CR4.DE=1. 37 * When CR4.DE=0, or if processor is earlier than i586, this bit is "Undefined", 38 * which is not the same as "Reserved", so it won't trigger an exception - it 39 * will just cause an undefined reaction from the CPU. 40 */ 41#define X86_DEBUG_BP_TYPE_IO (0x2u) 42#define X86_DEBUG_BP_TYPE_INSTR (0x0u) 43#define X86_DEBUG_BP_TYPE_DATA_WRITE (0x1u) 44#define X86_DEBUG_BP_TYPE_DATA_READWRITE (0x3u) 45 46#define X86_DEBUG_BP0_TYPE_SHIFT (16) 47#define X86_DEBUG_BP1_TYPE_SHIFT (20) 48#define X86_DEBUG_BP2_TYPE_SHIFT (24) 49#define X86_DEBUG_BP3_TYPE_SHIFT (28) 50 51#define X86_DEBUG_EFLAGS_TRAP_FLAG ((word_t)BIT(8)) 52#define X86_DEBUG_EFLAGS_RESUME_FLAG ((word_t)BIT(16)) 53#define X86_DEBUG_DR6_SINGLE_STEP_FLAG ((word_t)BIT(14)) 54 55#define X86_DEBUG_DR6_BP_MASK (0xFu) 56 57static bool_t byte8_bps_supported = false; 58 59bool_t 60byte8BreakpointsSupported(void) 61{ 62 return byte8_bps_supported; 63} 64 65static inline void 66bitwiseAndDr6Reg(word_t mask) 67{ 68 word_t tmp; 69 70 tmp = readDr6Reg() & mask; 71 writeDr6Reg(tmp); 72} 73 74static inline word_t 75readDr7Context(tcb_t *t) 76{ 77 return t->tcbArch.tcbContext.breakpointState.dr[5]; 78} 79 80static inline void 81bitwiseOrDr7Context(tcb_t *t, word_t val) 82{ 83 t->tcbArch.tcbContext.breakpointState.dr[5] |= val; 84} 85 86static inline void 87bitwiseAndDr7Context(tcb_t *t, word_t mask) 88{ 89 t->tcbArch.tcbContext.breakpointState.dr[5] &= mask; 90} 91 92static void 93unsetDr7BitsFor(tcb_t *t, uint16_t bp_num) 94{ 95 word_t mask; 96 97 switch (bp_num) { 98 case 0: 99 mask = (0x3u << X86_DEBUG_BP0_SIZE_SHIFT) | (0x3u << X86_DEBUG_BP0_TYPE_SHIFT); 100 break; 101 case 1: 102 mask = (0x3u << X86_DEBUG_BP1_SIZE_SHIFT) | (0x3u << X86_DEBUG_BP1_TYPE_SHIFT); 103 break; 104 case 2: 105 mask = (0x3u << X86_DEBUG_BP2_SIZE_SHIFT) | (0x3u << X86_DEBUG_BP2_TYPE_SHIFT); 106 break; 107 default: /* 3 */ 108 assert(bp_num == 3); 109 mask = (0x3u << X86_DEBUG_BP3_SIZE_SHIFT) | (0x3u << X86_DEBUG_BP3_TYPE_SHIFT); 110 break; 111 } 112 113 mask = ~mask; 114 bitwiseAndDr7Context(t, mask); 115} 116 117/** Converts an seL4_BreakpointType value into the underlying hardware 118 * equivalent. 119 * @param bp_num Breakpoint number. 120 * @param type One of the values of seL4_BreakpointType. 121 * @param rw Access trigger condition (read/write). 122 * @return Hardware specific register value representing the inputs. 123 */ 124PURE static inline word_t 125convertTypeAndAccessToArch(uint16_t bp_num, word_t type, word_t rw) 126{ 127 switch (type) { 128 case seL4_InstructionBreakpoint: 129 type = X86_DEBUG_BP_TYPE_INSTR; 130 break; 131 default: /* seL4_DataBreakpoint */ 132 assert(type == seL4_DataBreakpoint); 133 type = (rw == seL4_BreakOnWrite) 134 ? X86_DEBUG_BP_TYPE_DATA_WRITE 135 : X86_DEBUG_BP_TYPE_DATA_READWRITE; 136 } 137 138 switch (bp_num) { 139 case 0: 140 return type << X86_DEBUG_BP0_TYPE_SHIFT; 141 case 1: 142 return type << X86_DEBUG_BP1_TYPE_SHIFT; 143 case 2: 144 return type << X86_DEBUG_BP2_TYPE_SHIFT; 145 default: /* 3 */ 146 assert(bp_num == 3); 147 return type << X86_DEBUG_BP3_TYPE_SHIFT; 148 } 149} 150 151/** Reverse of convertTypeAndAccessToArch(): converts hardware values into 152 * seL4 API values. 153 * @param dr7 Hardware register value as input for conversion. 154 * @param bp_num Breakpoint number. 155 * @param type[out] Converted type value. 156 * @param rw[out] Converted output access trigger value. 157 */ 158typedef struct { 159 word_t type, rw; 160} convertedTypeAndAccess_t; 161 162PURE static inline convertedTypeAndAccess_t 163convertArchToTypeAndAccess(word_t dr7, uint16_t bp_num) 164{ 165 convertedTypeAndAccess_t ret; 166 167 switch (bp_num) { 168 case 0: 169 dr7 &= 0x3u << X86_DEBUG_BP0_TYPE_SHIFT; 170 dr7 >>= X86_DEBUG_BP0_TYPE_SHIFT; 171 break; 172 case 1: 173 dr7 &= 0x3u << X86_DEBUG_BP1_TYPE_SHIFT; 174 dr7 >>= X86_DEBUG_BP1_TYPE_SHIFT; 175 break; 176 case 2: 177 dr7 &= 0x3u << X86_DEBUG_BP2_TYPE_SHIFT; 178 dr7 >>= X86_DEBUG_BP2_TYPE_SHIFT; 179 break; 180 default: /* 3 */ 181 assert(bp_num == 3); 182 dr7 &= 0x3u << X86_DEBUG_BP3_TYPE_SHIFT; 183 dr7 >>= X86_DEBUG_BP3_TYPE_SHIFT; 184 } 185 186 switch (dr7) { 187 case X86_DEBUG_BP_TYPE_INSTR: 188 ret.type = seL4_InstructionBreakpoint; 189 ret.rw = seL4_BreakOnRead; 190 break; 191 case X86_DEBUG_BP_TYPE_DATA_WRITE: 192 ret.type = seL4_DataBreakpoint; 193 ret.rw = seL4_BreakOnWrite; 194 break; 195 default: /* Read-write */ 196 assert(dr7 == X86_DEBUG_BP_TYPE_DATA_READWRITE); 197 ret.type = seL4_DataBreakpoint; 198 ret.rw = seL4_BreakOnReadWrite; 199 break; 200 } 201 return ret; 202} 203 204/** Converts an integer size number into an equivalent hardware register value. 205 * @param n Breakpoint number. 206 * @param type One value from seL4_BreakpointType. 207 * @param size An integer for the operand size of the breakpoint. 208 * @return Converted, hardware-specific value. 209 */ 210PURE static inline word_t 211convertSizeToArch(uint16_t bp_num, word_t type, word_t size) 212{ 213 if (type == seL4_InstructionBreakpoint) { 214 /* Intel manual vol3 17.2.4: 215 * "If the corresponding RWn field in register DR7 is 00 (instruction 216 * execution), then the LENn field should also be 00" 217 */ 218 size = 0; 219 } else { 220 switch (size) { 221 case 1: 222 size = X86_DEBUG_BP_SIZE_1B; 223 break; 224 case 2: 225 size = X86_DEBUG_BP_SIZE_2B; 226 break; 227 case 8: 228 size = X86_DEBUG_BP_SIZE_8B; 229 break; 230 default: /* 4B */ 231 assert(size == 4); 232 size = X86_DEBUG_BP_SIZE_4B; 233 } 234 } 235 236 switch (bp_num) { 237 case 0: 238 return size << X86_DEBUG_BP0_SIZE_SHIFT; 239 case 1: 240 return size << X86_DEBUG_BP1_SIZE_SHIFT; 241 case 2: 242 return size << X86_DEBUG_BP2_SIZE_SHIFT; 243 default: /* 3 */ 244 assert(bp_num == 3); 245 return size << X86_DEBUG_BP3_SIZE_SHIFT; 246 } 247} 248 249/** Reverse of convertSizeToArch(): converts a hardware-specific size value 250 * into an integer representation. 251 * @param dr7 Hardware register value as input. 252 * @param n Breakpoint number. 253 * @return Converted size value. 254 */ 255PURE static inline word_t 256convertArchToSize(word_t dr7, uint16_t bp_num) 257{ 258 word_t type; 259 260 switch (bp_num) { 261 case 0: 262 type = dr7 & (0x3u << X86_DEBUG_BP0_TYPE_SHIFT); 263 type >>= X86_DEBUG_BP0_TYPE_SHIFT; 264 dr7 &= 0x3u << X86_DEBUG_BP0_SIZE_SHIFT; 265 dr7 >>= X86_DEBUG_BP0_SIZE_SHIFT; 266 break; 267 case 1: 268 type = dr7 & (0x3u << X86_DEBUG_BP1_TYPE_SHIFT); 269 type >>= X86_DEBUG_BP1_TYPE_SHIFT; 270 dr7 &= 0x3u << X86_DEBUG_BP1_SIZE_SHIFT; 271 dr7 >>= X86_DEBUG_BP1_SIZE_SHIFT; 272 break; 273 case 2: 274 type = dr7 & (0x3u << X86_DEBUG_BP2_TYPE_SHIFT); 275 type >>= X86_DEBUG_BP2_TYPE_SHIFT; 276 dr7 &= 0x3u << X86_DEBUG_BP2_SIZE_SHIFT; 277 dr7 >>= X86_DEBUG_BP2_SIZE_SHIFT; 278 break; 279 default: /* 3 */ 280 assert(bp_num == 3); 281 type = dr7 & (0x3u << X86_DEBUG_BP3_TYPE_SHIFT); 282 type >>= X86_DEBUG_BP3_TYPE_SHIFT; 283 dr7 &= 0x3u << X86_DEBUG_BP3_SIZE_SHIFT; 284 dr7 >>= X86_DEBUG_BP3_SIZE_SHIFT; 285 } 286 287 /* Force size to 0 if type is instruction breakpoint. */ 288 if (type == X86_DEBUG_BP_TYPE_INSTR) { 289 return 0; 290 } 291 292 switch (dr7) { 293 case X86_DEBUG_BP_SIZE_1B: 294 return 1; 295 case X86_DEBUG_BP_SIZE_2B: 296 return 2; 297 case X86_DEBUG_BP_SIZE_8B: 298 return 8; 299 default: /* 4B */ 300 assert(dr7 == X86_DEBUG_BP_SIZE_4B); 301 return 4; 302 } 303} 304 305/** Enables a breakpoint. 306 * @param bp_num Hardware breakpoint ID. Usually an integer from 0..N. 307 */ 308static void 309enableBreakpoint(tcb_t *t, uint16_t bp_num) 310{ 311 word_t enable_bit; 312 313 assert(t != NULL); 314 assert(bp_num < X86_DEBUG_BP_N_REGS); 315 316 switch (bp_num) { 317 case 0: 318 enable_bit = X86_DEBUG_BP0_ENABLE_BIT; 319 break; 320 case 1: 321 enable_bit = X86_DEBUG_BP1_ENABLE_BIT; 322 break; 323 case 2: 324 enable_bit = X86_DEBUG_BP2_ENABLE_BIT; 325 break; 326 default: 327 enable_bit = X86_DEBUG_BP3_ENABLE_BIT; 328 break; 329 } 330 331 bitwiseOrDr7Context(t, enable_bit); 332} 333 334/** Disables a breakpoint without clearing its configuration. 335 * @param bp_num Hardware breakpoint ID. Usually an integer from 0..N. 336 */ 337static void 338disableBreakpoint(tcb_t *t, uint16_t bp_num) 339{ 340 word_t disable_mask; 341 342 assert(t != NULL); 343 assert(bp_num < X86_DEBUG_BP_N_REGS); 344 345 switch (bp_num) { 346 case 0: 347 disable_mask = ~X86_DEBUG_BP0_ENABLE_BIT; 348 break; 349 case 1: 350 disable_mask = ~X86_DEBUG_BP1_ENABLE_BIT; 351 break; 352 case 2: 353 disable_mask = ~X86_DEBUG_BP2_ENABLE_BIT; 354 break; 355 default: 356 disable_mask = ~X86_DEBUG_BP3_ENABLE_BIT; 357 break; 358 } 359 360 bitwiseAndDr7Context(t, disable_mask); 361} 362 363/** Returns a boolean for whether or not a breakpoint is enabled. 364 * @param bp_num Hardware breakpoint ID. Usually an integer from 0..N. 365 */ 366static bool_t 367breakpointIsEnabled(tcb_t *t, uint16_t bp_num) 368{ 369 word_t dr7; 370 371 assert(t != NULL); 372 assert(bp_num < X86_DEBUG_BP_N_REGS); 373 374 dr7 = readDr7Context(t); 375 switch (bp_num) { 376 case 0: 377 return !!(dr7 & X86_DEBUG_BP0_ENABLE_BIT); 378 case 1: 379 return !!(dr7 & X86_DEBUG_BP1_ENABLE_BIT); 380 case 2: 381 return !!(dr7 & X86_DEBUG_BP2_ENABLE_BIT); 382 default: 383 return !!(dr7 & X86_DEBUG_BP3_ENABLE_BIT); 384 } 385} 386 387static void 388setBpVaddrContext(tcb_t *t, uint16_t bp_num, word_t vaddr) 389{ 390 assert(t != NULL); 391 user_breakpoint_state_t *ubs = &t->tcbArch.tcbContext.breakpointState; 392 393 switch (bp_num) { 394 case 0: 395 ubs->dr[0] = vaddr; 396 break; 397 case 1: 398 ubs->dr[1] = vaddr; 399 break; 400 case 2: 401 ubs->dr[2] = vaddr; 402 break; 403 default: 404 assert(bp_num == 3); 405 ubs->dr[3] = vaddr; 406 break; 407 } 408 return; 409} 410 411/** Backend for the seL4_TCB_SetBreakpoint invocation. 412 * 413 * @param uds Arch TCB register context structure. 414 * @param bp_num Hardware breakpoint ID. 415 * @param vaddr USerspace virtual address on which you'd like this breakpoing 416 * to trigger. 417 * @param types One of the seL4_BreakpointType values. 418 * @param size positive integer indicating the byte-range size that should 419 * trigger the breakpoint. 0 is valid for Instruction breakpoints. 420 * @param rw Access type that should trigger the BP (read/write). 421 */ 422void 423setBreakpoint(tcb_t *t, 424 uint16_t bp_num, word_t vaddr, word_t types, word_t size, word_t rw) 425{ 426 word_t dr7val; 427 428 assert(t != NULL); 429 430 dr7val = convertTypeAndAccessToArch(bp_num, types, rw); 431 dr7val |= convertSizeToArch(bp_num, types, size); 432 433 setBpVaddrContext(t, bp_num, vaddr); 434 unsetDr7BitsFor(t, bp_num); 435 bitwiseOrDr7Context(t, dr7val); 436 enableBreakpoint(t, bp_num); 437} 438 439static word_t 440getBpVaddrContext(tcb_t *t, uint16_t bp_num) 441{ 442 assert(t != NULL); 443 user_breakpoint_state_t *ubs = &t->tcbArch.tcbContext.breakpointState; 444 445 switch (bp_num) { 446 case 0: 447 return ubs->dr[0]; 448 case 1: 449 return ubs->dr[1]; 450 case 2: 451 return ubs->dr[2]; 452 default: 453 assert(bp_num == 3); 454 return ubs->dr[3]; 455 } 456} 457 458/** Backend for the x86 seL4_TCB_GetBreakpoint invocation. 459 * 460 * Returns information about a particular breakpoint ID, including whether or 461 * not it's enabled. 462 * 463 * @param uds Arch TCB register context pointer. 464 * @param bp_num Hardware breakpoint ID of the BP you'd like to query. 465 * @return Structure containing information about the status of the breakpoint. 466 */ 467getBreakpoint_t 468getBreakpoint(tcb_t *t, uint16_t bp_num) 469{ 470 word_t dr7val; 471 getBreakpoint_t ret; 472 convertedTypeAndAccess_t res; 473 474 dr7val = readDr7Context(t); 475 ret.vaddr = getBpVaddrContext(t, bp_num); 476 ret.size = convertArchToSize(dr7val, bp_num); 477 res = convertArchToTypeAndAccess(dr7val, bp_num); 478 ret.type = res.type; 479 ret.rw = res.rw; 480 ret.is_enabled = breakpointIsEnabled(t, bp_num); 481 return ret; 482} 483 484/** Backend for the x86 seL4_TCB_UnsetBreakpoint invocation. 485 * 486 * Unsets and *clears* a hardware breakpoint. 487 * @param uds Arch TCB register context pointer. 488 * @param bp_num The hardware breakpoint ID you'd like to clear. 489 */ 490void 491unsetBreakpoint(tcb_t *t, uint16_t bp_num) 492{ 493 disableBreakpoint(t, bp_num); 494 unsetDr7BitsFor(t, bp_num); 495 setBpVaddrContext(t, bp_num, 0); 496} 497 498/** Used in the exception path to determine if an exception was caused by 499 * single-stepping being active. 500 * 501 * @param uc Arch TCB register context structure. 502 * @return a structure stating whether or not the exception was caused by 503 * hardware single-stepping, and what the instruction vaddr was. 504 */ 505typedef struct { 506 bool_t ret; 507 word_t instr_vaddr; 508} testAndResetSingleStepException_t; 509 510static testAndResetSingleStepException_t 511testAndResetSingleStepException(tcb_t *t) 512{ 513 testAndResetSingleStepException_t ret; 514 word_t dr6; 515 516 dr6 = readDr6Reg(); 517 if (!(dr6 & X86_DEBUG_DR6_SINGLE_STEP_FLAG)) { 518 ret.ret = false; 519 return ret; 520 } 521 522 ret.ret = true; 523 ret.instr_vaddr = t->tcbArch.tcbContext.registers[FaultIP]; 524 bitwiseAndDr6Reg(~X86_DEBUG_DR6_SINGLE_STEP_FLAG); 525 526 /* And that's not all: if the breakpoint is an instruction breakpoint, we 527 * also need to set EFLAGS.RF. The processor raises the #DB exception BEFORE 528 * the instruction executes. This means that when we IRET to userspace, the 529 * SAME breakpoint will trigger again, and so on ad infinitum. EFLAGS.RF 530 * solves this problem: 531 * 532 * When EFLAGS.RF is set, the processor will ignore instruction breakpoints 533 * that should be raised, for one instruction. After that instruction 534 * executes, the processor will also automatically unset EFLAGS.RF. See 535 * Intel manuals, vol3, section 17.3.1.1. 536 */ 537 /* This will automatically be popped by restore_user_context() */ 538 t->tcbArch.tcbContext.registers[FLAGS] |= X86_DEBUG_EFLAGS_RESUME_FLAG; 539 return ret; 540} 541 542bool_t 543configureSingleStepping(tcb_t *t, uint16_t bp_num, word_t n_instr, 544 UNUSED bool_t is_reply) 545{ 546 /* On x86 no hardware breakpoints are needed for single stepping. */ 547 if (n_instr == 0) { 548 /* If n_instr (number of instructions to single-step) is 0, that is the 549 * same as requesting that single-stepping be disabled. 550 */ 551 t->tcbArch.tcbContext.breakpointState.single_step_enabled = false; 552 t->tcbArch.tcbContext.registers[FLAGS] &= ~X86_DEBUG_EFLAGS_TRAP_FLAG; 553 } else { 554 t->tcbArch.tcbContext.breakpointState.single_step_enabled = true; 555 } 556 557 t->tcbArch.tcbContext.breakpointState.n_instructions = n_instr; 558 return false; 559} 560 561/** Used in the exception path to determine which breakpoint triggered the 562 * exception. 563 * 564 * First, checks to see which hardware breakpoint was triggered, and saves 565 * the ID of that breakpoint. Secondly, resets that breakpoint such that its 566 * "triggered" bit is no longer in the asserted state -- whatever that means 567 * for the arch. So on x86, that means clearing the indicator bit in DR6. 568 * 569 * Aside from the ID of the breakpoint that was raised, also returns 570 * information about the breakpoint (vaddr, access, type, etc). 571 * 572 * @param uc Arch TCB register context pointer. 573 * @return Structure with a "bp_num" member that states which hardware 574 * breakpoint was triggered, and gives information describing the 575 * breakpoint. 576 */ 577typedef struct { 578 int bp_num; 579 word_t vaddr, reason; 580} getAndResetActiveBreakpoint_t; 581 582static getAndResetActiveBreakpoint_t 583getAndResetActiveBreakpoint(tcb_t *t) 584{ 585 convertedTypeAndAccess_t tmp; 586 getAndResetActiveBreakpoint_t ret; 587 588 /* Read from the hardware regs, not user context */ 589 word_t dr6 = readDr6Reg(); 590 if (dr6 & BIT(0)) { 591 ret.bp_num = 0; 592 } else if (dr6 & BIT(1)) { 593 ret.bp_num = 1; 594 } else if (dr6 & BIT(2)) { 595 ret.bp_num = 2; 596 } else if (dr6 & BIT(3)) { 597 ret.bp_num = 3; 598 } else { 599 ret.bp_num = -1; 600 return ret; 601 } 602 603 tmp = convertArchToTypeAndAccess(readDr7Context(t), ret.bp_num); 604 ret.vaddr = getBpVaddrContext(t, ret.bp_num); 605 ret.reason = tmp.type; 606 607 bitwiseAndDr6Reg(~BIT(ret.bp_num)); 608 return ret; 609} 610 611exception_t 612handleUserLevelDebugException(int int_vector) 613{ 614 tcb_t *ct; 615 getAndResetActiveBreakpoint_t active_bp; 616 testAndResetSingleStepException_t single_step_info; 617 618#if defined(CONFIG_DEBUG_BUILD) || defined(CONFIG_BENCHMARK_TRACK_KERNEL_ENTRIES) 619 ksKernelEntry.path = Entry_UserLevelFault; 620 ksKernelEntry.word = int_vector; 621#else 622 (void)int_vector; 623#endif /* DEBUG */ 624 625#ifdef CONFIG_BENCHMARK_TRACK_KERNEL_ENTRIES 626 benchmark_track_start(); 627#endif 628 629 ct = NODE_STATE(ksCurThread); 630 631 /* Software break request (INT3) is detected by the vector number */ 632 if (int_vector == int_software_break_request) { 633 current_fault = seL4_Fault_DebugException_new(getRestartPC(NODE_STATE(ksCurThread)), 634 0, seL4_SoftwareBreakRequest); 635 } else { 636 /* Hardware breakpoint trigger is detected using DR6 */ 637 active_bp = getAndResetActiveBreakpoint(ct); 638 if (active_bp.bp_num >= 0) { 639 current_fault = seL4_Fault_DebugException_new(active_bp.vaddr, 640 active_bp.bp_num, 641 active_bp.reason); 642 } else { 643 single_step_info = testAndResetSingleStepException(ct); 644 if (single_step_info.ret == true) { 645 /* If the caller asked us to skip over N instructions before 646 * generating the next single-step breakpoint, we shouldn't 647 * bother to construct a fault message until we've skipped N 648 * instructions. 649 */ 650 if (singleStepFaultCounterReady(ct) == false) { 651 return EXCEPTION_NONE; 652 } 653 current_fault = seL4_Fault_DebugException_new(single_step_info.instr_vaddr, 654 0, seL4_SingleStep); 655 } else { 656 return EXCEPTION_SYSCALL_ERROR; 657 } 658 } 659 } 660 661 handleFault(NODE_STATE(ksCurThread)); 662 663 schedule(); 664 activateThread(); 665 666 return EXCEPTION_NONE; 667} 668 669BOOT_CODE bool_t 670Arch_initHardwareBreakpoints(void) 671{ 672 x86_cpu_identity_t *modelinfo; 673 674 modelinfo = x86_cpuid_get_model_info(); 675 /* Intel manuals, vol3, section 17.2.4, "NOTES". */ 676 if (modelinfo->family == 15) { 677 if (modelinfo->model == 3 || modelinfo->model == 4 678 || modelinfo->model == 6) { 679 byte8_bps_supported = true; 680 } 681 } 682 if (modelinfo->family == 6) { 683 if (modelinfo->model == 15 || modelinfo->model == 23 684 || modelinfo->model == 0x1C) { 685 byte8_bps_supported = true; 686 } 687 } 688 return true; 689} 690 691void 692Arch_initBreakpointContext(user_breakpoint_state_t *uds) 693{ 694 memset(uds, 0, sizeof(*uds)); 695 696 /* Preload reserved values into register context */ 697 uds->dr[4] = readDr6Reg() & 698 ~(BIT(0) 699 | BIT(1) 700 | BIT(2) 701 | BIT(3) 702 | X86_DEBUG_DR6_SINGLE_STEP_FLAG); 703 704 uds->dr[5] = readDr7Reg() & 705 ~(X86_DEBUG_BP0_ENABLE_BIT | X86_DEBUG_BP1_ENABLE_BIT 706 | X86_DEBUG_BP2_ENABLE_BIT 707 | X86_DEBUG_BP3_ENABLE_BIT); 708} 709 710#endif 711