From: Stefano Stabellini [PATCH -v4] x86: Save cr4 to mmu_cr4_features at boot time Save cr4 to mmu_cr4_features at boot time Michael reported 2.6.38.2 hibernation is broken by one backported patch. it cause a freeze when resuming from hibernation | "x86: Cleanup highmap after brk is concluded" | commit id e5f15b45ddf3afa2bbbb10c7ea34fb32b6de0a0e. it turns out the mmu_cr4 save it lost somehow. -v3: read back cr4 for 32bit too according to HPA -v4: use cpuid_level to check if we can read cr4 according to HPA don't touch mmu_cr4_features if CONFIG_HIBERNATION is defined from Yinghai Bisected-and-tested-by: Michael Leun Signed-off-by: Stefano Stabellini Signed-off-by: Yinghai Lu --- arch/x86/include/asm/processor.h | 4 ++++ arch/x86/kernel/setup.c | 11 ++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) Index: linux-2.6/arch/x86/kernel/setup.c =================================================================== --- linux-2.6.orig/arch/x86/kernel/setup.c +++ linux-2.6/arch/x86/kernel/setup.c @@ -212,7 +212,11 @@ struct cpuinfo_x86 boot_cpu_data __read_ EXPORT_SYMBOL(boot_cpu_data); #endif - +/* + * mmu_cr4_features two purpose: + * a. head_32.S will access cr4 according if X86_CR4_PAE is set in it. + * b. store read back cr4 for hibernation + */ #if !defined(CONFIG_X86_PAE) || defined(CONFIG_X86_64) unsigned long mmu_cr4_features; #else @@ -892,6 +896,11 @@ void __init setup_arch(char **cmdline_p) high_memory = (void *)__va(max_pfn * PAGE_SIZE - 1) + 1; #endif +#ifdef CONFIG_HIBERNATION + /* a CPU has CR4 iff it has CPUID --- hpa */ + if (boot_cpu_data.cpuid_level >= 0) + mmu_cr4_features = read_cr4(); +#endif /* * Find and reserve possible boot-time SMP configuration: Index: linux-2.6/arch/x86/include/asm/processor.h =================================================================== --- linux-2.6.orig/arch/x86/include/asm/processor.h +++ linux-2.6/arch/x86/include/asm/processor.h @@ -601,7 +601,9 @@ static inline void set_in_cr4(unsigned l { unsigned long cr4; +#ifdef CONFIG_HIBERNATION mmu_cr4_features |= mask; +#endif cr4 = read_cr4(); cr4 |= mask; write_cr4(cr4); @@ -611,7 +613,9 @@ static inline void clear_in_cr4(unsigned { unsigned long cr4; +#ifdef CONFIG_HIBERNATION mmu_cr4_features &= ~mask; +#endif cr4 = read_cr4(); cr4 &= ~mask; write_cr4(cr4);