cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

debugreg.h (2769B)


      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
      9DECLARE_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
     21static __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
     50static __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
     76static 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
     88static __always_inline bool hw_breakpoint_active(void)
     89{
     90	return __this_cpu_read(cpu_dr7) & DR_GLOBAL_ENABLE_MASK;
     91}
     92
     93extern void hw_breakpoint_restore(void);
     94
     95static __always_inline unsigned long local_db_save(void)
     96{
     97	unsigned long dr7;
     98
     99	if (static_cpu_has(X86_FEATURE_HYPERVISOR) && !hw_breakpoint_active())
    100		return 0;
    101
    102	get_debugreg(dr7, 7);
    103	dr7 &= ~0x400; /* architecturally set bit */
    104	if (dr7)
    105		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	barrier();
    112
    113	return dr7;
    114}
    115
    116static __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	barrier();
    124	if (dr7)
    125		set_debugreg(dr7, 7);
    126}
    127
    128#ifdef CONFIG_CPU_SUP_AMD
    129extern void set_dr_addr_mask(unsigned long mask, int dr);
    130#else
    131static inline void set_dr_addr_mask(unsigned long mask, int dr) { }
    132#endif
    133
    134#endif /* _ASM_X86_DEBUGREG_H */