|
@@ -295,7 +295,26 @@ int arch_hibernation_header_save(void *addr, unsigned int max_size)
|
|
return -EOVERFLOW;
|
|
return -EOVERFLOW;
|
|
rdr->jump_address = (unsigned long)restore_registers;
|
|
rdr->jump_address = (unsigned long)restore_registers;
|
|
rdr->jump_address_phys = __pa_symbol(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;
|
|
rdr->magic = RESTORE_MAGIC;
|
|
|
|
|
|
hibernation_e820_save(rdr->e820_digest);
|
|
hibernation_e820_save(rdr->e820_digest);
|