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