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 __always_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 __always_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 __always_inline bool 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 static __always_inline unsigned long local_db_save(void) 98 { 99 unsigned long dr7; 100 101 if (static_cpu_has(X86_FEATURE_HYPERVISOR) && !hw_breakpoint_active()) 102 return 0; 103 104 get_debugreg(dr7, 7); 105 dr7 &= ~0x400; /* architecturally set bit */ 106 if (dr7) 107 set_debugreg(0, 7); 108 /* 109 * Ensure the compiler doesn't lower the above statements into 110 * the critical section; disabling breakpoints late would not 111 * be good. 112 */ 113 barrier(); 114 115 return dr7; 116 } 117 118 static __always_inline void local_db_restore(unsigned long dr7) 119 { 120 /* 121 * Ensure the compiler doesn't raise this statement into 122 * the critical section; enabling breakpoints early would 123 * not be good. 124 */ 125 barrier(); 126 if (dr7) 127 set_debugreg(dr7, 7); 128 } 129 130 #ifdef CONFIG_CPU_SUP_AMD 131 extern void set_dr_addr_mask(unsigned long mask, int dr); 132 #else 133 static inline void set_dr_addr_mask(unsigned long mask, int dr) { } 134 #endif 135 136 #endif /* _ASM_X86_DEBUGREG_H */ 137