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