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