1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2 | #ifndef _ASM_X86_DEBUGREG_H |
3 | #define _ASM_X86_DEBUGREG_H |
4 | |
5 | |
6 | #include <linux/bug.h> |
7 | #include <uapi/asm/debugreg.h> |
8 | |
9 | DECLARE_PER_CPU(unsigned long, cpu_dr7); |
10 | |
11 | #ifndef CONFIG_PARAVIRT_XXL |
12 | /* |
13 | * These special macros can be used to get or set a debugging register |
14 | */ |
15 | #define get_debugreg(var, register) \ |
16 | (var) = native_get_debugreg(register) |
17 | #define set_debugreg(value, register) \ |
18 | native_set_debugreg(register, value) |
19 | #endif |
20 | |
21 | static inline unsigned long native_get_debugreg(int regno) |
22 | { |
23 | unsigned long val = 0; /* Damn you, gcc! */ |
24 | |
25 | switch (regno) { |
26 | case 0: |
27 | asm("mov %%db0, %0" :"=r" (val)); |
28 | break; |
29 | case 1: |
30 | asm("mov %%db1, %0" :"=r" (val)); |
31 | break; |
32 | case 2: |
33 | asm("mov %%db2, %0" :"=r" (val)); |
34 | break; |
35 | case 3: |
36 | asm("mov %%db3, %0" :"=r" (val)); |
37 | break; |
38 | case 6: |
39 | asm("mov %%db6, %0" :"=r" (val)); |
40 | break; |
41 | case 7: |
42 | asm("mov %%db7, %0" :"=r" (val)); |
43 | break; |
44 | default: |
45 | BUG(); |
46 | } |
47 | return val; |
48 | } |
49 | |
50 | static inline void native_set_debugreg(int regno, unsigned long value) |
51 | { |
52 | switch (regno) { |
53 | case 0: |
54 | asm("mov %0, %%db0" ::"r" (value)); |
55 | break; |
56 | case 1: |
57 | asm("mov %0, %%db1" ::"r" (value)); |
58 | break; |
59 | case 2: |
60 | asm("mov %0, %%db2" ::"r" (value)); |
61 | break; |
62 | case 3: |
63 | asm("mov %0, %%db3" ::"r" (value)); |
64 | break; |
65 | case 6: |
66 | asm("mov %0, %%db6" ::"r" (value)); |
67 | break; |
68 | case 7: |
69 | asm("mov %0, %%db7" ::"r" (value)); |
70 | break; |
71 | default: |
72 | BUG(); |
73 | } |
74 | } |
75 | |
76 | static inline void hw_breakpoint_disable(void) |
77 | { |
78 | /* Zero the control register for HW Breakpoint */ |
79 | set_debugreg(0UL, 7); |
80 | |
81 | /* Zero-out the individual HW breakpoint address registers */ |
82 | set_debugreg(0UL, 0); |
83 | set_debugreg(0UL, 1); |
84 | set_debugreg(0UL, 2); |
85 | set_debugreg(0UL, 3); |
86 | } |
87 | |
88 | static inline int hw_breakpoint_active(void) |
89 | { |
90 | return __this_cpu_read(cpu_dr7) & DR_GLOBAL_ENABLE_MASK; |
91 | } |
92 | |
93 | extern void aout_dump_debugregs(struct user *dump); |
94 | |
95 | extern void hw_breakpoint_restore(void); |
96 | |
97 | #ifdef CONFIG_X86_64 |
98 | DECLARE_PER_CPU(int, debug_stack_usage); |
99 | static inline void debug_stack_usage_inc(void) |
100 | { |
101 | __this_cpu_inc(debug_stack_usage); |
102 | } |
103 | static inline void debug_stack_usage_dec(void) |
104 | { |
105 | __this_cpu_dec(debug_stack_usage); |
106 | } |
107 | int is_debug_stack(unsigned long addr); |
108 | void debug_stack_set_zero(void); |
109 | void debug_stack_reset(void); |
110 | #else /* !X86_64 */ |
111 | static inline int is_debug_stack(unsigned long addr) { return 0; } |
112 | static inline void debug_stack_set_zero(void) { } |
113 | static inline void debug_stack_reset(void) { } |
114 | static inline void debug_stack_usage_inc(void) { } |
115 | static inline void debug_stack_usage_dec(void) { } |
116 | #endif /* X86_64 */ |
117 | |
118 | #ifdef CONFIG_CPU_SUP_AMD |
119 | extern void set_dr_addr_mask(unsigned long mask, int dr); |
120 | #else |
121 | static inline void set_dr_addr_mask(unsigned long mask, int dr) { } |
122 | #endif |
123 | |
124 | #endif /* _ASM_X86_DEBUGREG_H */ |
125 | |