mirror of
https://kernel.googlesource.com/pub/scm/linux/kernel/git/torvalds/linux
synced 2025-09-14 00:29:50 +10:00
- Make sure DR6 and DR7 are initialized to their architectural values and not
accidentally cleared, leading to misconfigurations -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEzv7L6UO9uDPlPSfHEsHwGGHeVUoFAmhg/UQACgkQEsHwGGHe VUrmXBAAtOrpEtR4geeBeZtCEaUxE4DE8Zvj36dr+sAScHTXNTzYK94mAy/AHU22 V3rF12/kuyyZSrwROXLBD6PgkHEn8u0WLztSeqP/SisnoLjMTV9H9TuGYBUoz1NS clkoElQ6DJP5BVzmYpZlJrcofqNjkS/mAxfMRoIAq+LzKkb3iL/Lge+Ox/IDUg8z L9wRlKh/IaJ5EETWlqh0gkFeS/M9DXYmfkasDQeVkUxnKFeXBdyUGc2jFzBGX5RA rsdnz+C3x3ow2U9N+ZMVr+n06yTZvh+fAiU8emeBQm0q5fZBBHWDbnZZtWf+KG6s 43tlWyVqic5yzyQbUpRC2sttOkIAtOCMx36XexbGm1eKRNNc6fTz9IlgO/97HkuE lYBNq0zd/p5Kb53lXb3uwBVy4sjIEZUyD/K5DO4YfTgamcwXl8BP5xnKtNPqImI5 aaF3xKKLOUDOTL1CcK5YG0joaU1k+I0F0KO7HYqkDi8Uf5naWZSUNil8nPQn8RX7 3f3LJx0e3j2o0f60AHI4mjUAUJHsxExmpaTl079k03wt8YVE3ucNaUN6se6nidVz H5q0JU4q3C3DCu0I3Ub4wa5QXGA+TOHKuqhJCapKAVAAQDlbV2z8GxA/3B2YbRM+ eZ6/RVyk++VrRXIyfmfwLPu0CLVoSNhaUhu/hFrYbjA3NX+85qw= =fjgT -----END PGP SIGNATURE----- Merge tag 'x86_urgent_for_v6.16_rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip Pull x86 fixes from Borislav Petkov: - Make sure DR6 and DR7 are initialized to their architectural values and not accidentally cleared, leading to misconfigurations * tag 'x86_urgent_for_v6.16_rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/traps: Initialize DR7 by writing its architectural reset value x86/traps: Initialize DR6 by writing its architectural reset value
This commit is contained in:
commit
cc69ac7a65
@ -9,6 +9,14 @@
|
||||
#include <asm/cpufeature.h>
|
||||
#include <asm/msr.h>
|
||||
|
||||
/*
|
||||
* Define bits that are always set to 1 in DR7, only bit 10 is
|
||||
* architecturally reserved to '1'.
|
||||
*
|
||||
* This is also the init/reset value for DR7.
|
||||
*/
|
||||
#define DR7_FIXED_1 0x00000400
|
||||
|
||||
DECLARE_PER_CPU(unsigned long, cpu_dr7);
|
||||
|
||||
#ifndef CONFIG_PARAVIRT_XXL
|
||||
@ -100,8 +108,8 @@ static __always_inline void native_set_debugreg(int regno, unsigned long value)
|
||||
|
||||
static inline void hw_breakpoint_disable(void)
|
||||
{
|
||||
/* Zero the control register for HW Breakpoint */
|
||||
set_debugreg(0UL, 7);
|
||||
/* Reset the control register for HW Breakpoint */
|
||||
set_debugreg(DR7_FIXED_1, 7);
|
||||
|
||||
/* Zero-out the individual HW breakpoint address registers */
|
||||
set_debugreg(0UL, 0);
|
||||
@ -125,9 +133,12 @@ static __always_inline unsigned long local_db_save(void)
|
||||
return 0;
|
||||
|
||||
get_debugreg(dr7, 7);
|
||||
dr7 &= ~0x400; /* architecturally set bit */
|
||||
|
||||
/* Architecturally set bit */
|
||||
dr7 &= ~DR7_FIXED_1;
|
||||
if (dr7)
|
||||
set_debugreg(0, 7);
|
||||
set_debugreg(DR7_FIXED_1, 7);
|
||||
|
||||
/*
|
||||
* Ensure the compiler doesn't lower the above statements into
|
||||
* the critical section; disabling breakpoints late would not
|
||||
|
@ -31,6 +31,7 @@
|
||||
|
||||
#include <asm/apic.h>
|
||||
#include <asm/pvclock-abi.h>
|
||||
#include <asm/debugreg.h>
|
||||
#include <asm/desc.h>
|
||||
#include <asm/mtrr.h>
|
||||
#include <asm/msr-index.h>
|
||||
@ -249,7 +250,6 @@ enum x86_intercept_stage;
|
||||
#define DR7_BP_EN_MASK 0x000000ff
|
||||
#define DR7_GE (1 << 9)
|
||||
#define DR7_GD (1 << 13)
|
||||
#define DR7_FIXED_1 0x00000400
|
||||
#define DR7_VOLATILE 0xffff2bff
|
||||
|
||||
#define KVM_GUESTDBG_VALID_MASK \
|
||||
|
@ -15,7 +15,26 @@
|
||||
which debugging register was responsible for the trap. The other bits
|
||||
are either reserved or not of interest to us. */
|
||||
|
||||
/* Define reserved bits in DR6 which are always set to 1 */
|
||||
/*
|
||||
* Define bits in DR6 which are set to 1 by default.
|
||||
*
|
||||
* This is also the DR6 architectural value following Power-up, Reset or INIT.
|
||||
*
|
||||
* Note, with the introduction of Bus Lock Detection (BLD) and Restricted
|
||||
* Transactional Memory (RTM), the DR6 register has been modified:
|
||||
*
|
||||
* 1) BLD flag (bit 11) is no longer reserved to 1 if the CPU supports
|
||||
* Bus Lock Detection. The assertion of a bus lock could clear it.
|
||||
*
|
||||
* 2) RTM flag (bit 16) is no longer reserved to 1 if the CPU supports
|
||||
* restricted transactional memory. #DB occurred inside an RTM region
|
||||
* could clear it.
|
||||
*
|
||||
* Apparently, DR6.BLD and DR6.RTM are active low bits.
|
||||
*
|
||||
* As a result, DR6_RESERVED is an incorrect name now, but it is kept for
|
||||
* compatibility.
|
||||
*/
|
||||
#define DR6_RESERVED (0xFFFF0FF0)
|
||||
|
||||
#define DR_TRAP0 (0x1) /* db0 */
|
||||
|
@ -2243,20 +2243,16 @@ EXPORT_PER_CPU_SYMBOL(__stack_chk_guard);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Clear all 6 debug registers:
|
||||
*/
|
||||
static void clear_all_debug_regs(void)
|
||||
static void initialize_debug_regs(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
/* Ignore db4, db5 */
|
||||
if ((i == 4) || (i == 5))
|
||||
continue;
|
||||
|
||||
set_debugreg(0, i);
|
||||
}
|
||||
/* Control register first -- to make sure everything is disabled. */
|
||||
set_debugreg(DR7_FIXED_1, 7);
|
||||
set_debugreg(DR6_RESERVED, 6);
|
||||
/* dr5 and dr4 don't exist */
|
||||
set_debugreg(0, 3);
|
||||
set_debugreg(0, 2);
|
||||
set_debugreg(0, 1);
|
||||
set_debugreg(0, 0);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_KGDB
|
||||
@ -2417,7 +2413,7 @@ void cpu_init(void)
|
||||
|
||||
load_mm_ldt(&init_mm);
|
||||
|
||||
clear_all_debug_regs();
|
||||
initialize_debug_regs();
|
||||
dbg_restore_debug_regs();
|
||||
|
||||
doublefault_init_cpu_tss();
|
||||
|
@ -385,7 +385,7 @@ static void kgdb_disable_hw_debug(struct pt_regs *regs)
|
||||
struct perf_event *bp;
|
||||
|
||||
/* Disable hardware debugging while we are in kgdb: */
|
||||
set_debugreg(0UL, 7);
|
||||
set_debugreg(DR7_FIXED_1, 7);
|
||||
for (i = 0; i < HBP_NUM; i++) {
|
||||
if (!breakinfo[i].enabled)
|
||||
continue;
|
||||
|
@ -93,7 +93,7 @@ void __show_regs(struct pt_regs *regs, enum show_regs_mode mode,
|
||||
|
||||
/* Only print out debug registers if they are in their non-default state. */
|
||||
if ((d0 == 0) && (d1 == 0) && (d2 == 0) && (d3 == 0) &&
|
||||
(d6 == DR6_RESERVED) && (d7 == 0x400))
|
||||
(d6 == DR6_RESERVED) && (d7 == DR7_FIXED_1))
|
||||
return;
|
||||
|
||||
printk("%sDR0: %08lx DR1: %08lx DR2: %08lx DR3: %08lx\n",
|
||||
|
@ -133,7 +133,7 @@ void __show_regs(struct pt_regs *regs, enum show_regs_mode mode,
|
||||
|
||||
/* Only print out debug registers if they are in their non-default state. */
|
||||
if (!((d0 == 0) && (d1 == 0) && (d2 == 0) && (d3 == 0) &&
|
||||
(d6 == DR6_RESERVED) && (d7 == 0x400))) {
|
||||
(d6 == DR6_RESERVED) && (d7 == DR7_FIXED_1))) {
|
||||
printk("%sDR0: %016lx DR1: %016lx DR2: %016lx\n",
|
||||
log_lvl, d0, d1, d2);
|
||||
printk("%sDR3: %016lx DR6: %016lx DR7: %016lx\n",
|
||||
|
@ -1022,24 +1022,32 @@ static bool is_sysenter_singlestep(struct pt_regs *regs)
|
||||
#endif
|
||||
}
|
||||
|
||||
static __always_inline unsigned long debug_read_clear_dr6(void)
|
||||
static __always_inline unsigned long debug_read_reset_dr6(void)
|
||||
{
|
||||
unsigned long dr6;
|
||||
|
||||
get_debugreg(dr6, 6);
|
||||
dr6 ^= DR6_RESERVED; /* Flip to positive polarity */
|
||||
|
||||
/*
|
||||
* The Intel SDM says:
|
||||
*
|
||||
* Certain debug exceptions may clear bits 0-3. The remaining
|
||||
* contents of the DR6 register are never cleared by the
|
||||
* processor. To avoid confusion in identifying debug
|
||||
* exceptions, debug handlers should clear the register before
|
||||
* returning to the interrupted task.
|
||||
* Certain debug exceptions may clear bits 0-3 of DR6.
|
||||
*
|
||||
* Keep it simple: clear DR6 immediately.
|
||||
* BLD induced #DB clears DR6.BLD and any other debug
|
||||
* exception doesn't modify DR6.BLD.
|
||||
*
|
||||
* RTM induced #DB clears DR6.RTM and any other debug
|
||||
* exception sets DR6.RTM.
|
||||
*
|
||||
* To avoid confusion in identifying debug exceptions,
|
||||
* debug handlers should set DR6.BLD and DR6.RTM, and
|
||||
* clear other DR6 bits before returning.
|
||||
*
|
||||
* Keep it simple: write DR6 with its architectural reset
|
||||
* value 0xFFFF0FF0, defined as DR6_RESERVED, immediately.
|
||||
*/
|
||||
get_debugreg(dr6, 6);
|
||||
set_debugreg(DR6_RESERVED, 6);
|
||||
dr6 ^= DR6_RESERVED; /* Flip to positive polarity */
|
||||
|
||||
return dr6;
|
||||
}
|
||||
@ -1239,13 +1247,13 @@ out:
|
||||
/* IST stack entry */
|
||||
DEFINE_IDTENTRY_DEBUG(exc_debug)
|
||||
{
|
||||
exc_debug_kernel(regs, debug_read_clear_dr6());
|
||||
exc_debug_kernel(regs, debug_read_reset_dr6());
|
||||
}
|
||||
|
||||
/* User entry, runs on regular task stack */
|
||||
DEFINE_IDTENTRY_DEBUG_USER(exc_debug)
|
||||
{
|
||||
exc_debug_user(regs, debug_read_clear_dr6());
|
||||
exc_debug_user(regs, debug_read_reset_dr6());
|
||||
}
|
||||
|
||||
#ifdef CONFIG_X86_FRED
|
||||
@ -1264,7 +1272,7 @@ DEFINE_FREDENTRY_DEBUG(exc_debug)
|
||||
{
|
||||
/*
|
||||
* FRED #DB stores DR6 on the stack in the format which
|
||||
* debug_read_clear_dr6() returns for the IDT entry points.
|
||||
* debug_read_reset_dr6() returns for the IDT entry points.
|
||||
*/
|
||||
unsigned long dr6 = fred_event_data(regs);
|
||||
|
||||
@ -1279,7 +1287,7 @@ DEFINE_FREDENTRY_DEBUG(exc_debug)
|
||||
/* 32 bit does not have separate entry points. */
|
||||
DEFINE_IDTENTRY_RAW(exc_debug)
|
||||
{
|
||||
unsigned long dr6 = debug_read_clear_dr6();
|
||||
unsigned long dr6 = debug_read_reset_dr6();
|
||||
|
||||
if (user_mode(regs))
|
||||
exc_debug_user(regs, dr6);
|
||||
|
@ -11035,7 +11035,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
|
||||
|
||||
if (unlikely(vcpu->arch.switch_db_regs &&
|
||||
!(vcpu->arch.switch_db_regs & KVM_DEBUGREG_AUTO_SWITCH))) {
|
||||
set_debugreg(0, 7);
|
||||
set_debugreg(DR7_FIXED_1, 7);
|
||||
set_debugreg(vcpu->arch.eff_db[0], 0);
|
||||
set_debugreg(vcpu->arch.eff_db[1], 1);
|
||||
set_debugreg(vcpu->arch.eff_db[2], 2);
|
||||
@ -11044,7 +11044,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
|
||||
if (unlikely(vcpu->arch.switch_db_regs & KVM_DEBUGREG_WONT_EXIT))
|
||||
kvm_x86_call(set_dr6)(vcpu, vcpu->arch.dr6);
|
||||
} else if (unlikely(hw_breakpoint_active())) {
|
||||
set_debugreg(0, 7);
|
||||
set_debugreg(DR7_FIXED_1, 7);
|
||||
}
|
||||
|
||||
vcpu->arch.host_debugctl = get_debugctlmsr();
|
||||
|
Loading…
Reference in New Issue
Block a user