We use __read_cr4() vs __read_cr4_safe() inconsistently.  On
CR4-less CPUs, all CR4 bits are effectively clear, so we can make
the code simpler and more robust by making __read_cr4() always fix
up faults on 32-bit kernels.

This may fix some bugs on old 486-like CPUs, but I don't have any
easy way to test that.

Cc: [email protected]
Signed-off-by: Andy Lutomirski <[email protected]>
---
 arch/x86/include/asm/paravirt.h       |  4 ----
 arch/x86/include/asm/paravirt_types.h |  1 -
 arch/x86/include/asm/special_insns.h  | 22 +++++++---------------
 arch/x86/include/asm/tlbflush.h       |  2 +-
 arch/x86/kernel/paravirt.c            |  1 -
 arch/x86/kernel/process_32.c          |  2 +-
 arch/x86/kernel/setup.c               |  5 +++--
 arch/x86/power/cpu.c                  |  2 +-
 arch/x86/xen/enlighten.c              |  1 -
 9 files changed, 13 insertions(+), 27 deletions(-)

diff --git a/arch/x86/include/asm/paravirt.h b/arch/x86/include/asm/paravirt.h
index 2970d22d7766..91b6f4eed3fd 100644
--- a/arch/x86/include/asm/paravirt.h
+++ b/arch/x86/include/asm/paravirt.h
@@ -80,10 +80,6 @@ static inline unsigned long __read_cr4(void)
 {
        return PVOP_CALL0(unsigned long, pv_cpu_ops.read_cr4);
 }
-static inline unsigned long __read_cr4_safe(void)
-{
-       return PVOP_CALL0(unsigned long, pv_cpu_ops.read_cr4_safe);
-}
 
 static inline void __write_cr4(unsigned long x)
 {
diff --git a/arch/x86/include/asm/paravirt_types.h 
b/arch/x86/include/asm/paravirt_types.h
index 7fa9e7740ba3..fcf243f077ac 100644
--- a/arch/x86/include/asm/paravirt_types.h
+++ b/arch/x86/include/asm/paravirt_types.h
@@ -108,7 +108,6 @@ struct pv_cpu_ops {
        unsigned long (*read_cr0)(void);
        void (*write_cr0)(unsigned long);
 
-       unsigned long (*read_cr4_safe)(void);
        unsigned long (*read_cr4)(void);
        void (*write_cr4)(unsigned long);
 
diff --git a/arch/x86/include/asm/special_insns.h 
b/arch/x86/include/asm/special_insns.h
index 587d7914ea4b..19a2224f9e16 100644
--- a/arch/x86/include/asm/special_insns.h
+++ b/arch/x86/include/asm/special_insns.h
@@ -59,22 +59,19 @@ static inline void native_write_cr3(unsigned long val)
 static inline unsigned long native_read_cr4(void)
 {
        unsigned long val;
-       asm volatile("mov %%cr4,%0\n\t" : "=r" (val), "=m" (__force_order));
-       return val;
-}
-
-static inline unsigned long native_read_cr4_safe(void)
-{
-       unsigned long val;
-       /* This could fault if %cr4 does not exist. In x86_64, a cr4 always
-        * exists, so it will never fail. */
 #ifdef CONFIG_X86_32
+       /*
+        * This could fault if CR4 does not exist.  Non-existent CR4
+        * is functionally equivalent to CR4 == 0.  Keep it simple and pretend
+        * that CR4 == 0 on CPUs that don't have CR4.
+        */
        asm volatile("1: mov %%cr4, %0\n"
                     "2:\n"
                     _ASM_EXTABLE(1b, 2b)
                     : "=r" (val), "=m" (__force_order) : "0" (0));
 #else
-       val = native_read_cr4();
+       /* CR4 always exists on x86_64. */
+       asm volatile("mov %%cr4,%0\n\t" : "=r" (val), "=m" (__force_order));
 #endif
        return val;
 }
@@ -182,11 +179,6 @@ static inline unsigned long __read_cr4(void)
        return native_read_cr4();
 }
 
-static inline unsigned long __read_cr4_safe(void)
-{
-       return native_read_cr4_safe();
-}
-
 static inline void __write_cr4(unsigned long x)
 {
        native_write_cr4(x);
diff --git a/arch/x86/include/asm/tlbflush.h b/arch/x86/include/asm/tlbflush.h
index dee8a70382ba..6fa85944af83 100644
--- a/arch/x86/include/asm/tlbflush.h
+++ b/arch/x86/include/asm/tlbflush.h
@@ -81,7 +81,7 @@ DECLARE_PER_CPU_SHARED_ALIGNED(struct tlb_state, 
cpu_tlbstate);
 /* Initialize cr4 shadow for this CPU. */
 static inline void cr4_init_shadow(void)
 {
-       this_cpu_write(cpu_tlbstate.cr4, __read_cr4_safe());
+       this_cpu_write(cpu_tlbstate.cr4, __read_cr4());
 }
 
 /* Set in this cpu's CR4. */
diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c
index 1acfd76e3e26..ed03b1c5b1b9 100644
--- a/arch/x86/kernel/paravirt.c
+++ b/arch/x86/kernel/paravirt.c
@@ -332,7 +332,6 @@ __visible struct pv_cpu_ops pv_cpu_ops = {
        .read_cr0 = native_read_cr0,
        .write_cr0 = native_write_cr0,
        .read_cr4 = native_read_cr4,
-       .read_cr4_safe = native_read_cr4_safe,
        .write_cr4 = native_write_cr4,
 #ifdef CONFIG_X86_64
        .read_cr8 = native_read_cr8,
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c
index d86be29c38c7..e5da9ba220d1 100644
--- a/arch/x86/kernel/process_32.c
+++ b/arch/x86/kernel/process_32.c
@@ -101,7 +101,7 @@ void __show_regs(struct pt_regs *regs, int all)
        cr0 = read_cr0();
        cr2 = read_cr2();
        cr3 = read_cr3();
-       cr4 = __read_cr4_safe();
+       cr4 = __read_cr4();
        printk(KERN_DEFAULT "CR0: %08lx CR2: %08lx CR3: %08lx CR4: %08lx\n",
                        cr0, cr2, cr3, cr4);
 
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index 5930a4d191b4..09d245e8e2da 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -1140,9 +1140,10 @@ void __init setup_arch(char **cmdline_p)
        if (boot_cpu_data.cpuid_level >= 0) {
                /*
                 * CPUs without CPUID don't have CR4.  CPUs with CPUID
-                * usually have CR4.
+                * usually have CR4.  On CPUID-less CPUs, this avoids
+                * an unnecessary fixup, mainly for historical reasons.
                 */
-               mmu_cr4_features = __read_cr4_safe();
+               mmu_cr4_features = __read_cr4();
        }
 
        memblock_set_current_limit(get_max_mapped());
diff --git a/arch/x86/power/cpu.c b/arch/x86/power/cpu.c
index b12c26e2e309..53cace2ec0e2 100644
--- a/arch/x86/power/cpu.c
+++ b/arch/x86/power/cpu.c
@@ -130,7 +130,7 @@ static void __save_processor_state(struct saved_context 
*ctxt)
        ctxt->cr0 = read_cr0();
        ctxt->cr2 = read_cr2();
        ctxt->cr3 = read_cr3();
-       ctxt->cr4 = __read_cr4_safe();
+       ctxt->cr4 = __read_cr4();
 #ifdef CONFIG_X86_64
        ctxt->cr8 = read_cr8();
 #endif
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index b86ebb1a9a7f..e2cf8fcea6bb 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -1237,7 +1237,6 @@ static const struct pv_cpu_ops xen_cpu_ops __initconst = {
        .write_cr0 = xen_write_cr0,
 
        .read_cr4 = native_read_cr4,
-       .read_cr4_safe = native_read_cr4_safe,
        .write_cr4 = xen_write_cr4,
 
 #ifdef CONFIG_X86_64
-- 
2.7.4

Reply via email to