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")