summaryrefslogtreecommitdiff
path: root/arch/x86/power/hibernate_64.c
diff options
context:
space:
mode:
authorJames Morris <james.l.morris@oracle.com>2017-09-24 22:41:55 -0700
committerJames Morris <james.l.morris@oracle.com>2017-09-24 22:41:55 -0700
commit25eabb13c7d67ae32298015c5e28d00f604f412c (patch)
tree5bd75c2c1e385c79425bb099f0d19db7fb9c391f /arch/x86/power/hibernate_64.c
parentab5348c9c23cd253f5902980d2d8fe067dc24c82 (diff)
parente19b205be43d11bff638cad4487008c48d21c103 (diff)
Merge tag 'v4.14-rc2' into next-general
Linux 4.14-rc2 Sync to v4.14-rc2 for security subsystem developers to track.
Diffstat (limited to 'arch/x86/power/hibernate_64.c')
-rw-r--r--arch/x86/power/hibernate_64.c21
1 files changed, 20 insertions, 1 deletions
diff --git a/arch/x86/power/hibernate_64.c b/arch/x86/power/hibernate_64.c
index f2598d81cd55..f910c514438f 100644
--- a/arch/x86/power/hibernate_64.c
+++ b/arch/x86/power/hibernate_64.c
@@ -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);