Use the "safe" helpers to read and write CR0, CR3, and CR4, so that an unexpected fault results in a detailed message instead of an generic "unexpected fault" explosion. Do not give RDMSR/WRMSR the same treatment. KUT's exception fixup uses per-CPU data and thus needs a stable GS.base. Various tests modify MSR_GS_BASE and routing them through the safe variants will cause fireworks when trying to clear/read the exception vector with a garbage GS.base. Signed-off-by: Sean Christopherson <seanjc@xxxxxxxxxx> --- lib/x86/desc.c | 8 -------- lib/x86/desc.h | 1 - lib/x86/processor.h | 45 ++++++++++++++++++++++++++++++++++++++++++--- x86/pcid.c | 8 -------- 4 files changed, 42 insertions(+), 20 deletions(-) diff --git a/lib/x86/desc.c b/lib/x86/desc.c index ff9bd6b7..7620dc81 100644 --- a/lib/x86/desc.c +++ b/lib/x86/desc.c @@ -299,14 +299,6 @@ unsigned exception_vector(void) return this_cpu_read_exception_vector(); } -int write_cr4_safe(unsigned long val) -{ - asm volatile(ASM_TRY("1f") - "mov %0,%%cr4\n\t" - "1:": : "r" (val)); - return exception_vector(); -} - unsigned exception_error_code(void) { return this_cpu_read_exception_error_code(); diff --git a/lib/x86/desc.h b/lib/x86/desc.h index 0bd44445..ac843c35 100644 --- a/lib/x86/desc.h +++ b/lib/x86/desc.h @@ -213,7 +213,6 @@ extern tss64_t tss[]; extern gdt_entry_t gdt[]; unsigned exception_vector(void); -int write_cr4_safe(unsigned long val); unsigned exception_error_code(void); bool exception_rflags_rf(void); void set_idt_entry(int vec, void *addr, int dpl); diff --git a/lib/x86/processor.h b/lib/x86/processor.h index e169aac8..bc6c8d94 100644 --- a/lib/x86/processor.h +++ b/lib/x86/processor.h @@ -341,6 +341,12 @@ static inline void set_iopl(int iopl) write_rflags(flags); } +/* + * Don't use the safe variants for rdmsr() or wrmsr(). The exception fixup + * infrastructure uses per-CPU data and thus consumes GS.base. Various tests + * temporarily modify MSR_GS_BASE and will explode when trying to determine + * whether or not RDMSR/WRMSR faulted. + */ static inline u64 rdmsr(u32 index) { u32 a, d; @@ -381,9 +387,20 @@ static inline uint64_t rdpmc(uint32_t index) return a | ((uint64_t)d << 32); } +static inline int write_cr0_safe(ulong val) +{ + asm volatile(ASM_TRY("1f") + "mov %0,%%cr0\n\t" + "1:": : "r" (val)); + return exception_vector(); +} + static inline void write_cr0(ulong val) { - asm volatile ("mov %0, %%cr0" : : "r"(val) : "memory"); + int vector = write_cr0_safe(val); + + assert_msg(!vector, "Unexpected fault '%d' writing CR0 = %lx", + vector, val); } static inline ulong read_cr0(void) @@ -405,9 +422,20 @@ static inline ulong read_cr2(void) return val; } +static inline int write_cr3_safe(ulong val) +{ + asm volatile(ASM_TRY("1f") + "mov %0,%%cr3\n\t" + "1:": : "r" (val)); + return exception_vector(); +} + static inline void write_cr3(ulong val) { - asm volatile ("mov %0, %%cr3" : : "r"(val) : "memory"); + int vector = write_cr3_safe(val); + + assert_msg(!vector, "Unexpected fault '%d' writing CR3 = %lx", + vector, val); } static inline ulong read_cr3(void) @@ -422,9 +450,20 @@ static inline void update_cr3(void *cr3) write_cr3((ulong)cr3); } +static inline int write_cr4_safe(ulong val) +{ + asm volatile(ASM_TRY("1f") + "mov %0,%%cr4\n\t" + "1:": : "r" (val)); + return exception_vector(); +} + static inline void write_cr4(ulong val) { - asm volatile ("mov %0, %%cr4" : : "r"(val) : "memory"); + int vector = write_cr4_safe(val); + + assert_msg(!vector, "Unexpected fault '%d' writing CR4 = %lx", + vector, val); } static inline ulong read_cr4(void) diff --git a/x86/pcid.c b/x86/pcid.c index 5e08f576..4dfc6fd0 100644 --- a/x86/pcid.c +++ b/x86/pcid.c @@ -10,14 +10,6 @@ struct invpcid_desc { u64 addr : 64; }; -static int write_cr0_safe(unsigned long val) -{ - asm volatile(ASM_TRY("1f") - "mov %0, %%cr0\n\t" - "1:": : "r" (val)); - return exception_vector(); -} - static int invpcid_safe(unsigned long type, void *desc) { asm volatile (ASM_TRY("1f") -- 2.36.1.255.ge46751e96f-goog