Merge tag 'usb-4.15-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
[sfrench/cifs-2.6.git] / arch / x86 / power / hibernate_64.c
index f2598d81cd55067ffd695a18bde0352a5d98264b..f910c514438f168a5f09afbd312311498abe2c50 100644 (file)
@@ -295,7 +295,26 @@ int arch_hibernation_header_save(void *addr, unsigned int max_size)
                return -EOVERFLOW;
        rdr->jump_address = (unsigned long)restore_registers;
        rdr->jump_address_phys = __pa_symbol(restore_registers);
-       rdr->cr3 = restore_cr3;
+
+       /*
+        * The restore code fixes up CR3 and CR4 in the following sequence:
+        *
+        * [in hibernation asm]
+        * 1. CR3 <= temporary page tables
+        * 2. CR4 <= mmu_cr4_features (from the kernel that restores us)
+        * 3. CR3 <= rdr->cr3
+        * 4. CR4 <= mmu_cr4_features (from us, i.e. the image kernel)
+        * [in restore_processor_state()]
+        * 5. CR4 <= saved CR4
+        * 6. CR3 <= saved CR3
+        *
+        * Our mmu_cr4_features has CR4.PCIDE=0, and toggling
+        * CR4.PCIDE while CR3's PCID bits are nonzero is illegal, so
+        * rdr->cr3 needs to point to valid page tables but must not
+        * have any of the PCID bits set.
+        */
+       rdr->cr3 = restore_cr3 & ~CR3_PCID_MASK;
+
        rdr->magic = RESTORE_MAGIC;
 
        hibernation_e820_save(rdr->e820_digest);