x86: Use "safe" helpers to implement unsafe CRs accessors
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@google.com>
Link: https://lore.kernel.org/r/20220608235238.3881916-5-seanjc@google.com
diff --git a/lib/x86/desc.c b/lib/x86/desc.c
index 6e4ed1a..a20be92 100644
--- a/lib/x86/desc.c
+++ b/lib/x86/desc.c
@@ -319,14 +319,6 @@
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 2e73824..2a285eb 100644
--- a/lib/x86/desc.h
+++ b/lib/x86/desc.h
@@ -214,7 +214,6 @@
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_desc_entry(idt_entry_t *e, size_t e_sz, void *addr,
diff --git a/lib/x86/processor.h b/lib/x86/processor.h
index e169aac..bc6c8d9 100644
--- a/lib/x86/processor.h
+++ b/lib/x86/processor.h
@@ -341,6 +341,12 @@
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 @@
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 @@
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 @@
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 5e08f57..4dfc6fd 100644
--- a/x86/pcid.c
+++ b/x86/pcid.c
@@ -10,14 +10,6 @@
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")