debugreg.h 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. /* SPDX-License-Identifier: GPL-2.0 */
  2. #ifndef _ASM_X86_DEBUGREG_H
  3. #define _ASM_X86_DEBUGREG_H
  4. #include <linux/bug.h>
  5. #include <uapi/asm/debugreg.h>
  6. DECLARE_PER_CPU(unsigned long, cpu_dr7);
  7. #ifndef CONFIG_PARAVIRT_XXL
  8. /*
  9. * These special macros can be used to get or set a debugging register
  10. */
  11. #define get_debugreg(var, register) \
  12. (var) = native_get_debugreg(register)
  13. #define set_debugreg(value, register) \
  14. native_set_debugreg(register, value)
  15. #endif
  16. static __always_inline unsigned long native_get_debugreg(int regno)
  17. {
  18. unsigned long val = 0; /* Damn you, gcc! */
  19. switch (regno) {
  20. case 0:
  21. asm("mov %%db0, %0" :"=r" (val));
  22. break;
  23. case 1:
  24. asm("mov %%db1, %0" :"=r" (val));
  25. break;
  26. case 2:
  27. asm("mov %%db2, %0" :"=r" (val));
  28. break;
  29. case 3:
  30. asm("mov %%db3, %0" :"=r" (val));
  31. break;
  32. case 6:
  33. asm("mov %%db6, %0" :"=r" (val));
  34. break;
  35. case 7:
  36. /*
  37. * Apply __FORCE_ORDER to DR7 reads to forbid re-ordering them
  38. * with other code.
  39. *
  40. * This is needed because a DR7 access can cause a #VC exception
  41. * when running under SEV-ES. Taking a #VC exception is not a
  42. * safe thing to do just anywhere in the entry code and
  43. * re-ordering might place the access into an unsafe location.
  44. *
  45. * This happened in the NMI handler, where the DR7 read was
  46. * re-ordered to happen before the call to sev_es_ist_enter(),
  47. * causing stack recursion.
  48. */
  49. asm volatile("mov %%db7, %0" : "=r" (val) : __FORCE_ORDER);
  50. break;
  51. default:
  52. BUG();
  53. }
  54. return val;
  55. }
  56. static __always_inline void native_set_debugreg(int regno, unsigned long value)
  57. {
  58. switch (regno) {
  59. case 0:
  60. asm("mov %0, %%db0" ::"r" (value));
  61. break;
  62. case 1:
  63. asm("mov %0, %%db1" ::"r" (value));
  64. break;
  65. case 2:
  66. asm("mov %0, %%db2" ::"r" (value));
  67. break;
  68. case 3:
  69. asm("mov %0, %%db3" ::"r" (value));
  70. break;
  71. case 6:
  72. asm("mov %0, %%db6" ::"r" (value));
  73. break;
  74. case 7:
  75. /*
  76. * Apply __FORCE_ORDER to DR7 writes to forbid re-ordering them
  77. * with other code.
  78. *
  79. * While is didn't happen with a DR7 write (see the DR7 read
  80. * comment above which explains where it happened), add the
  81. * __FORCE_ORDER here too to avoid similar problems in the
  82. * future.
  83. */
  84. asm volatile("mov %0, %%db7" ::"r" (value), __FORCE_ORDER);
  85. break;
  86. default:
  87. BUG();
  88. }
  89. }
  90. static inline void hw_breakpoint_disable(void)
  91. {
  92. /* Zero the control register for HW Breakpoint */
  93. set_debugreg(0UL, 7);
  94. /* Zero-out the individual HW breakpoint address registers */
  95. set_debugreg(0UL, 0);
  96. set_debugreg(0UL, 1);
  97. set_debugreg(0UL, 2);
  98. set_debugreg(0UL, 3);
  99. }
  100. static __always_inline bool hw_breakpoint_active(void)
  101. {
  102. return __this_cpu_read(cpu_dr7) & DR_GLOBAL_ENABLE_MASK;
  103. }
  104. extern void hw_breakpoint_restore(void);
  105. static __always_inline unsigned long local_db_save(void)
  106. {
  107. unsigned long dr7;
  108. if (static_cpu_has(X86_FEATURE_HYPERVISOR) && !hw_breakpoint_active())
  109. return 0;
  110. get_debugreg(dr7, 7);
  111. dr7 &= ~0x400; /* architecturally set bit */
  112. if (dr7)
  113. set_debugreg(0, 7);
  114. /*
  115. * Ensure the compiler doesn't lower the above statements into
  116. * the critical section; disabling breakpoints late would not
  117. * be good.
  118. */
  119. barrier();
  120. return dr7;
  121. }
  122. static __always_inline void local_db_restore(unsigned long dr7)
  123. {
  124. /*
  125. * Ensure the compiler doesn't raise this statement into
  126. * the critical section; enabling breakpoints early would
  127. * not be good.
  128. */
  129. barrier();
  130. if (dr7)
  131. set_debugreg(dr7, 7);
  132. }
  133. #ifdef CONFIG_CPU_SUP_AMD
  134. extern void set_dr_addr_mask(unsigned long mask, int dr);
  135. #else
  136. static inline void set_dr_addr_mask(unsigned long mask, int dr) { }
  137. #endif
  138. #endif /* _ASM_X86_DEBUGREG_H */