1 /*
2  * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
3  *
4  * SPDX-License-Identifier: GPL-2.0-only
5  */
6 
7 #pragma once
8 #include <assert.h>
9 
10 #ifdef CONFIG_HARDWARE_DEBUG_API
11 
12 #define X86_DEBUG_BP_N_REGS                 (4)
13 
readDr6Reg(void)14 static inline word_t readDr6Reg(void)
15 {
16     word_t ret;
17 
18     asm volatile(
19         "movl %%dr6, %0 \n\t"
20         : "=r"(ret));
21     return ret;
22 }
23 
writeDr6Reg(word_t val)24 static inline void writeDr6Reg(word_t val)
25 {
26     asm volatile(
27         "movl %0, %%dr6 \n\t"
28         :
29         : "r"(val));
30 }
31 
readDr7Reg(void)32 static inline word_t readDr7Reg(void)
33 {
34     word_t ret;
35 
36     asm volatile(
37         "movl %%dr7, %0 \n\t"
38         : "=r"(ret));
39     return ret;
40 }
41 
writeDr7Reg(word_t val)42 static inline void writeDr7Reg(word_t val)
43 {
44     asm volatile(
45         "movl %0, %%dr7 \n\t"
46         :
47         : "r"(val));
48 }
49 
readDrReg(uint8_t reg)50 static inline word_t readDrReg(uint8_t reg)
51 {
52     word_t ret;
53 
54     assert(reg < X86_DEBUG_BP_N_REGS);
55     switch (reg) {
56     case 0:
57         asm volatile("movl %%dr0, %0 \n\t" : "=r"(ret));
58         break;
59     case 1:
60         asm volatile("movl %%dr1, %0 \n\t" : "=r"(ret));
61         break;
62     case 2:
63         asm volatile("movl %%dr2, %0 \n\t" : "=r"(ret));
64         break;
65     default:
66         asm volatile("movl %%dr3, %0 \n\t" : "=r"(ret));
67         break;
68     }
69     return ret;
70 }
71 
writeDrReg(uint8_t reg,word_t val)72 static inline void writeDrReg(uint8_t reg, word_t val)
73 {
74     assert(reg < X86_DEBUG_BP_N_REGS);
75     switch (reg) {
76     case 0:
77         asm volatile("movl %0, %%dr0 \n\t" :: "r"(val));
78         break;
79     case 1:
80         asm volatile("movl %0, %%dr1 \n\t" :: "r"(val));
81         break;
82     case 2:
83         asm volatile("movl %0, %%dr2 \n\t" :: "r"(val));
84         break;
85     default:
86         asm volatile("movl %0, %%dr3 \n\t" :: "r"(val));
87         break;
88     }
89 }
90 
91 /** Restore debug register context from a block of memory.
92  *@param source The memory block from which to load the register values.
93  */
loadBreakpointState(tcb_t * source)94 static inline void loadBreakpointState(tcb_t *source)
95 {
96     /* Order does matter when restoring the registers: we want to restore the
97      * breakpoint control register (DR7) last since it is what "activates" the
98      * effects of the configuration described by the other registers.
99      */
100     asm volatile(
101         "movl %0, %%edx \n\t"
102         "movl (%%edx), %%ecx \n\t"
103         "movl %%ecx, %%dr0 \n\t"
104         "addl $4, %%edx \n\t"
105         "movl (%%edx), %%ecx \n\t"
106         "movl %%ecx, %%dr1 \n\t"
107         "addl $4, %%edx \n\t"
108         "movl (%%edx), %%ecx \n\t"
109         "movl %%ecx, %%dr2 \n\t"
110         "addl $4, %%edx \n\t"
111         "movl (%%edx), %%ecx \n\t"
112         "movl %%ecx, %%dr3 \n\t"
113         "addl $4, %%edx \n\t"
114         "movl (%%edx), %%ecx \n\t"
115         "movl %%ecx, %%dr6 \n\t"
116         "addl $4, %%edx \n\t"
117         "movl (%%edx), %%ecx \n\t"
118         "movl %%ecx, %%dr7 \n\t"
119         :
120         : "r"(source->tcbArch.tcbContext.breakpointState.dr)
121         : "edx", "ecx");
122 }
123 
124 #endif /* CONFIG_HARDWARE_DEBUG_API */
125