File Index
Files and directories
Sign in
FILE

debugreg.h

File preview with syntax highlighting.

linux-6.19.14/arch/x86/include/asm/debugreg.h C
  1/* SPDX-License-Identifier: GPL-2.0 */
  2#ifndef _ASM_X86_DEBUGREG_H
  3#define _ASM_X86_DEBUGREG_H
  4
  5#include <linux/bug.h>
  6#include <linux/percpu.h>
  7#include <uapi/asm/debugreg.h>
  8
  9#include <asm/cpufeature.h>
 10#include <asm/msr.h>
 11
 12/*
 13 * Define bits that are always set to 1 in DR7, only bit 10 is
 14 * architecturally reserved to '1'.
 15 *
 16 * This is also the init/reset value for DR7.
 17 */
 18#define DR7_FIXED_1	0x00000400
 19
 20DECLARE_PER_CPU(unsigned long, cpu_dr7);
 21
 22#ifndef CONFIG_PARAVIRT_XXL
 23/*
 24 * These special macros can be used to get or set a debugging register
 25 */
 26#define get_debugreg(var, register)				\
 27	(var) = native_get_debugreg(register)
 28#define set_debugreg(value, register)				\
 29	native_set_debugreg(register, value)
 30#endif
 31
 32static __always_inline unsigned long native_get_debugreg(int regno)
 33{
 34	unsigned long val;
 35
 36	switch (regno) {
 37	case 0:
 38		asm("mov %%db0, %0" :"=r" (val));
 39		break;
 40	case 1:
 41		asm("mov %%db1, %0" :"=r" (val));
 42		break;
 43	case 2:
 44		asm("mov %%db2, %0" :"=r" (val));
 45		break;
 46	case 3:
 47		asm("mov %%db3, %0" :"=r" (val));
 48		break;
 49	case 6:
 50		asm("mov %%db6, %0" :"=r" (val));
 51		break;
 52	case 7:
 53		/*
 54		 * Use "asm volatile" for DR7 reads to forbid re-ordering them
 55		 * with other code.
 56		 *
 57		 * This is needed because a DR7 access can cause a #VC exception
 58		 * when running under SEV-ES. Taking a #VC exception is not a
 59		 * safe thing to do just anywhere in the entry code and
 60		 * re-ordering might place the access into an unsafe location.
 61		 *
 62		 * This happened in the NMI handler, where the DR7 read was
 63		 * re-ordered to happen before the call to sev_es_ist_enter(),
 64		 * causing stack recursion.
 65		 */
 66		asm volatile("mov %%db7, %0" : "=r" (val));
 67		break;
 68	default:
 69		BUG();
 70	}
 71	return val;
 72}
 73
 74static __always_inline void native_set_debugreg(int regno, unsigned long value)
 75{
 76	switch (regno) {
 77	case 0:
 78		asm("mov %0, %%db0"	::"r" (value));
 79		break;
 80	case 1:
 81		asm("mov %0, %%db1"	::"r" (value));
 82		break;
 83	case 2:
 84		asm("mov %0, %%db2"	::"r" (value));
 85		break;
 86	case 3:
 87		asm("mov %0, %%db3"	::"r" (value));
 88		break;
 89	case 6:
 90		asm("mov %0, %%db6"	::"r" (value));
 91		break;
 92	case 7:
 93		/*
 94		 * Use "asm volatile" for DR7 writes to forbid re-ordering them
 95		 * with other code.
 96		 *
 97		 * While is didn't happen with a DR7 write (see the DR7 read
 98		 * comment above which explains where it happened), add the
 99		 * "asm volatile" here too to avoid similar problems in the
100		 * future.
101		 */
102		asm volatile("mov %0, %%db7"	::"r" (value));
103		break;
104	default:
105		BUG();
106	}
107}
108
109static inline void hw_breakpoint_disable(void)
110{
111	/* Reset the control register for HW Breakpoint */
112	set_debugreg(DR7_FIXED_1, 7);
113
114	/* Zero-out the individual HW breakpoint address registers */
115	set_debugreg(0UL, 0);
116	set_debugreg(0UL, 1);
117	set_debugreg(0UL, 2);
118	set_debugreg(0UL, 3);
119}
120
121static __always_inline bool hw_breakpoint_active(void)
122{
123	return __this_cpu_read(cpu_dr7) & DR_GLOBAL_ENABLE_MASK;
124}
125
126extern void hw_breakpoint_restore(void);
127
128static __always_inline unsigned long local_db_save(void)
129{
130	unsigned long dr7;
131
132	if (static_cpu_has(X86_FEATURE_HYPERVISOR) && !hw_breakpoint_active())
133		return 0;
134
135	get_debugreg(dr7, 7);
136
137	/* Architecturally set bit */
138	dr7 &= ~DR7_FIXED_1;
139	if (dr7)
140		set_debugreg(DR7_FIXED_1, 7);
141
142	/*
143	 * Ensure the compiler doesn't lower the above statements into
144	 * the critical section; disabling breakpoints late would not
145	 * be good.
146	 */
147	barrier();
148
149	return dr7;
150}
151
152static __always_inline void local_db_restore(unsigned long dr7)
153{
154	/*
155	 * Ensure the compiler doesn't raise this statement into
156	 * the critical section; enabling breakpoints early would
157	 * not be good.
158	 */
159	barrier();
160	if (dr7)
161		set_debugreg(dr7, 7);
162}
163
164#ifdef CONFIG_CPU_SUP_AMD
165extern void amd_set_dr_addr_mask(unsigned long mask, unsigned int dr);
166extern unsigned long amd_get_dr_addr_mask(unsigned int dr);
167#else
168static inline void amd_set_dr_addr_mask(unsigned long mask, unsigned int dr) { }
169static inline unsigned long amd_get_dr_addr_mask(unsigned int dr)
170{
171	return 0;
172}
173#endif
174
175static inline unsigned long get_debugctlmsr(void)
176{
177	unsigned long debugctlmsr = 0;
178
179#ifndef CONFIG_X86_DEBUGCTLMSR
180	if (boot_cpu_data.x86 < 6)
181		return 0;
182#endif
183	rdmsrq(MSR_IA32_DEBUGCTLMSR, debugctlmsr);
184
185	return debugctlmsr;
186}
187
188static inline void update_debugctlmsr(unsigned long debugctlmsr)
189{
190#ifndef CONFIG_X86_DEBUGCTLMSR
191	if (boot_cpu_data.x86 < 6)
192		return;
193#endif
194	wrmsrq(MSR_IA32_DEBUGCTLMSR, debugctlmsr);
195}
196
197#endif /* _ASM_X86_DEBUGREG_H */
~/ Read-only file preview.