Line data Source code
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 1 : static __always_inline unsigned long native_get_debugreg(int regno) 22 : { 23 1 : unsigned long val = 0; /* Damn you, gcc! */ 24 : 25 1 : switch (regno) { 26 : case 0: 27 1 : asm("mov %%db0, %0" :"=r" (val)); 28 1 : break; 29 : case 1: 30 1 : asm("mov %%db1, %0" :"=r" (val)); 31 1 : break; 32 : case 2: 33 1 : asm("mov %%db2, %0" :"=r" (val)); 34 1 : break; 35 : case 3: 36 1 : asm("mov %%db3, %0" :"=r" (val)); 37 1 : break; 38 : case 6: 39 1 : asm("mov %%db6, %0" :"=r" (val)); 40 1 : break; 41 : case 7: 42 1 : asm("mov %%db7, %0" :"=r" (val)); 43 1 : break; 44 : default: 45 1 : BUG(); 46 : } 47 1 : return val; 48 : } 49 : 50 24 : static __always_inline void native_set_debugreg(int regno, unsigned long value) 51 : { 52 24 : switch (regno) { 53 4 : case 0: 54 4 : asm("mov %0, %%db0" ::"r" (value)); 55 4 : break; 56 4 : case 1: 57 4 : asm("mov %0, %%db1" ::"r" (value)); 58 4 : break; 59 4 : case 2: 60 4 : asm("mov %0, %%db2" ::"r" (value)); 61 4 : break; 62 4 : case 3: 63 4 : asm("mov %0, %%db3" ::"r" (value)); 64 4 : break; 65 4 : case 6: 66 4 : asm("mov %0, %%db6" ::"r" (value)); 67 4 : break; 68 4 : case 7: 69 4 : asm("mov %0, %%db7" ::"r" (value)); 70 4 : break; 71 0 : default: 72 0 : BUG(); 73 : } 74 0 : } 75 : 76 0 : static inline void hw_breakpoint_disable(void) 77 : { 78 : /* Zero the control register for HW Breakpoint */ 79 0 : set_debugreg(0UL, 7); 80 : 81 : /* Zero-out the individual HW breakpoint address registers */ 82 0 : set_debugreg(0UL, 0); 83 0 : set_debugreg(0UL, 1); 84 0 : set_debugreg(0UL, 2); 85 0 : set_debugreg(0UL, 3); 86 0 : } 87 : 88 228 : static __always_inline bool hw_breakpoint_active(void) 89 : { 90 228 : return __this_cpu_read(cpu_dr7) & DR_GLOBAL_ENABLE_MASK; 91 : } 92 : 93 : extern void hw_breakpoint_restore(void); 94 : 95 0 : static __always_inline unsigned long local_db_save(void) 96 : { 97 0 : unsigned long dr7; 98 : 99 0 : if (static_cpu_has(X86_FEATURE_HYPERVISOR) && !hw_breakpoint_active()) 100 : return 0; 101 : 102 0 : get_debugreg(dr7, 7); 103 0 : dr7 &= ~0x400; /* architecturally set bit */ 104 0 : if (dr7) 105 0 : set_debugreg(0, 7); 106 : /* 107 : * Ensure the compiler doesn't lower the above statements into 108 : * the critical section; disabling breakpoints late would not 109 : * be good. 110 : */ 111 0 : barrier(); 112 : 113 0 : return dr7; 114 : } 115 : 116 0 : static __always_inline void local_db_restore(unsigned long dr7) 117 : { 118 : /* 119 : * Ensure the compiler doesn't raise this statement into 120 : * the critical section; enabling breakpoints early would 121 : * not be good. 122 : */ 123 0 : barrier(); 124 0 : if (dr7) 125 0 : set_debugreg(dr7, 7); 126 : } 127 : 128 : #ifdef CONFIG_CPU_SUP_AMD 129 : extern void set_dr_addr_mask(unsigned long mask, int dr); 130 : #else 131 : static inline void set_dr_addr_mask(unsigned long mask, int dr) { } 132 : #endif 133 : 134 : #endif /* _ASM_X86_DEBUGREG_H */