|
Lee, Chun-Yi |
5b696a |
From 9f5eff10f723d39ddac3ed9300cb3246e9298156 Mon Sep 17 00:00:00 2001
|
|
Lee, Chun-Yi |
5b696a |
From: "Lee, Chun-Yi" <jlee@suse.com>
|
|
Lee, Chun-Yi |
5b696a |
Date: Tue, 12 Dec 2017 14:55:01 +0800
|
|
Lee, Chun-Yi |
5b696a |
Subject: [PATCH 07/11] PM / hibernate: encrypt hidden area
|
|
Lee, Chun-Yi |
5b696a |
Patch-mainline: No, will be submitted to upstream
|
|
Lee, Chun-Yi |
5b696a |
References: fate#316350
|
|
Lee, Chun-Yi |
5b696a |
|
|
Lee, Chun-Yi |
5b696a |
The hidden area keeps sensitive data (symmetric key, password...) that
|
|
Lee, Chun-Yi |
5b696a |
it can not be leaked to user space. So the hidden area page is ignored
|
|
Lee, Chun-Yi |
5b696a |
by snapshot process. But it causes that the hidden area is empty after
|
|
Lee, Chun-Yi |
5b696a |
system resumed, then all sensitive data are lost.
|
|
Lee, Chun-Yi |
5b696a |
|
|
Lee, Chun-Yi |
5b696a |
The idea against this situation is that using EFI secret key to
|
|
Lee, Chun-Yi |
5b696a |
encrypt/backup the hidden area when producing snapshot image, then
|
|
Lee, Chun-Yi |
5b696a |
decrypt/restore hidden area after system resumed. In resuming process,
|
|
Lee, Chun-Yi |
5b696a |
the boot kernel must transfers secret key to target kernel, otherwise
|
|
Lee, Chun-Yi |
5b696a |
target kernel doesn't have secret key to decrypt hidden area because
|
|
Lee, Chun-Yi |
5b696a |
hidden area (including secret key) was ignored by snapshot.
|
|
Lee, Chun-Yi |
5b696a |
|
|
Lee, Chun-Yi |
5b696a |
For transferring secret key to targer kernel, hibernation creates a
|
|
Lee, Chun-Yi |
5b696a |
trampoline page in snapshot image. The trampoline page can be used
|
|
Lee, Chun-Yi |
5b696a |
by boot kernel to fill in secret key before whole system be restored
|
|
Lee, Chun-Yi |
5b696a |
from snapshot image. After system is restored, kernel uses the secret
|
|
Lee, Chun-Yi |
5b696a |
key in trampoline page to decrypt/restore hidden area. Then all
|
|
Lee, Chun-Yi |
5b696a |
sensitive data are back.
|
|
Lee, Chun-Yi |
5b696a |
|
|
Lee, Chun-Yi |
5b696a |
Signed-off-by: Lee, Chun-Yi <jlee@suse.com>
|
|
Lee, Chun-Yi |
5b696a |
---
|
|
Lee, Chun-Yi |
5b696a |
kernel/power/hibernate.c | 19 ++++++
|
|
Lee, Chun-Yi |
5b696a |
kernel/power/power.h | 5 +
|
|
Lee, Chun-Yi |
5b696a |
kernel/power/snapshot.c | 133 +++++++++++++++++++++++++++++++++++++++++++++--
|
|
Lee, Chun-Yi |
5b696a |
kernel/power/swap.c | 2
|
|
Lee, Chun-Yi |
5b696a |
kernel/power/user.c | 5 +
|
|
Lee, Chun-Yi |
5b696a |
5 files changed, 161 insertions(+), 3 deletions(-)
|
|
Lee, Chun-Yi |
5b696a |
|
|
Lee, Chun-Yi |
5b696a |
--- a/kernel/power/hibernate.c
|
|
Lee, Chun-Yi |
5b696a |
+++ b/kernel/power/hibernate.c
|
|
Lee, Chun-Yi |
5b696a |
@@ -32,6 +32,8 @@
|
|
Lee, Chun-Yi |
5b696a |
#include <linux/ctype.h>
|
|
Lee, Chun-Yi |
5b696a |
#include <linux/genhd.h>
|
|
Lee, Chun-Yi |
5b696a |
#include <linux/ktime.h>
|
|
Lee, Chun-Yi |
5b696a |
+#include <linux/efi.h>
|
|
Lee, Chun-Yi |
5b696a |
+#include <linux/security.h>
|
|
Lee, Chun-Yi |
5b696a |
#include <trace/events/power.h>
|
|
Lee, Chun-Yi |
5b696a |
|
|
Lee, Chun-Yi |
5b696a |
#include "power.h"
|
|
Lee, Chun-Yi |
5b696a |
@@ -679,12 +681,28 @@ int hibernate(void)
|
|
Lee, Chun-Yi |
5b696a |
{
|
|
Lee, Chun-Yi |
5b696a |
int error, nr_calls = 0;
|
|
Lee, Chun-Yi |
5b696a |
bool snapshot_test = false;
|
|
Lee, Chun-Yi |
5b696a |
+ void *secret_key;
|
|
Lee, Chun-Yi |
5b696a |
|
|
Lee, Chun-Yi |
5b696a |
if (!hibernation_available()) {
|
|
Lee, Chun-Yi |
5b696a |
pr_debug("Hibernation not available.\n");
|
|
Lee, Chun-Yi |
5b696a |
return -EPERM;
|
|
Lee, Chun-Yi |
5b696a |
}
|
|
Lee, Chun-Yi |
5b696a |
|
|
Lee, Chun-Yi |
5b696a |
+ error = snapshot_create_trampoline();
|
|
Lee, Chun-Yi |
5b696a |
+ if (error)
|
|
Lee, Chun-Yi |
5b696a |
+ return error;
|
|
Lee, Chun-Yi |
5b696a |
+
|
|
Lee, Chun-Yi |
5b696a |
+ /* using EFI secret key to encrypt hidden area */
|
|
Lee, Chun-Yi |
5b696a |
+ secret_key = get_efi_secret_key();
|
|
Lee, Chun-Yi |
5b696a |
+ if (secret_key) {
|
|
Lee, Chun-Yi |
5b696a |
+ error = encrypt_backup_hidden_area(secret_key, SECRET_KEY_SIZE);
|
|
Lee, Chun-Yi |
5b696a |
+ if (error) {
|
|
Lee, Chun-Yi |
5b696a |
+ pr_err("Encrypt hidden area failed: %d\n", error);
|
|
Lee, Chun-Yi |
5b696a |
+ snapshot_free_trampoline();
|
|
Lee, Chun-Yi |
5b696a |
+ return error;
|
|
Lee, Chun-Yi |
5b696a |
+ }
|
|
Lee, Chun-Yi |
5b696a |
+ }
|
|
Lee, Chun-Yi |
5b696a |
+
|
|
Lee, Chun-Yi |
5b696a |
lock_system_sleep();
|
|
Lee, Chun-Yi |
5b696a |
/* The snapshot device should not be opened while we're running */
|
|
Lee, Chun-Yi |
5b696a |
if (!atomic_add_unless(&snapshot_device_available, -1, 0)) {
|
|
Lee, Chun-Yi |
5b696a |
@@ -740,6 +758,7 @@ int hibernate(void)
|
|
Lee, Chun-Yi |
5b696a |
pm_restore_gfp_mask();
|
|
Lee, Chun-Yi |
5b696a |
} else {
|
|
Lee, Chun-Yi |
5b696a |
pr_debug("Image restored successfully.\n");
|
|
Lee, Chun-Yi |
5b696a |
+ snapshot_restore_trampoline();
|
|
Lee, Chun-Yi |
5b696a |
}
|
|
Lee, Chun-Yi |
5b696a |
|
|
Lee, Chun-Yi |
5b696a |
Free_bitmaps:
|
|
Lee, Chun-Yi |
5b696a |
--- a/kernel/power/power.h
|
|
Lee, Chun-Yi |
5b696a |
+++ b/kernel/power/power.h
|
|
Lee, Chun-Yi |
5b696a |
@@ -12,6 +12,7 @@ struct swsusp_info {
|
|
Lee, Chun-Yi |
5b696a |
unsigned long image_pages;
|
|
Lee, Chun-Yi |
5b696a |
unsigned long pages;
|
|
Lee, Chun-Yi |
5b696a |
unsigned long size;
|
|
Lee, Chun-Yi |
5b696a |
+ unsigned long trampoline_pfn;
|
|
Lee, Chun-Yi |
5b696a |
} __aligned(PAGE_SIZE);
|
|
Lee, Chun-Yi |
5b696a |
|
|
Lee, Chun-Yi |
5b696a |
#ifdef CONFIG_HIBERNATION
|
|
Lee, Chun-Yi |
5b696a |
@@ -157,6 +158,10 @@ extern int snapshot_read_next(struct sna
|
|
Lee, Chun-Yi |
5b696a |
extern int snapshot_write_next(struct snapshot_handle *handle);
|
|
Lee, Chun-Yi |
5b696a |
extern void snapshot_write_finalize(struct snapshot_handle *handle);
|
|
Lee, Chun-Yi |
5b696a |
extern int snapshot_image_loaded(struct snapshot_handle *handle);
|
|
Lee, Chun-Yi |
5b696a |
+extern int snapshot_create_trampoline(void);
|
|
Lee, Chun-Yi |
5b696a |
+extern void snapshot_init_trampoline(void);
|
|
Lee, Chun-Yi |
5b696a |
+extern void snapshot_restore_trampoline(void);
|
|
Lee, Chun-Yi |
5b696a |
+extern void snapshot_free_trampoline(void);
|
|
Lee, Chun-Yi |
5b696a |
|
|
Lee, Chun-Yi |
5b696a |
/* If unset, the snapshot device cannot be open. */
|
|
Lee, Chun-Yi |
5b696a |
extern atomic_t snapshot_device_available;
|
|
Lee, Chun-Yi |
5b696a |
--- a/kernel/power/snapshot.c
|
|
Lee, Chun-Yi |
5b696a |
+++ b/kernel/power/snapshot.c
|
|
Lee, Chun-Yi |
5b696a |
@@ -31,6 +31,7 @@
|
|
Lee, Chun-Yi |
5b696a |
#include <linux/compiler.h>
|
|
Lee, Chun-Yi |
5b696a |
#include <linux/ktime.h>
|
|
Lee, Chun-Yi |
5b696a |
#include <linux/security.h>
|
|
Lee, Chun-Yi |
5b696a |
+#include <linux/efi.h>
|
|
Lee, Chun-Yi |
5b696a |
|
|
Lee, Chun-Yi |
5b696a |
#include <linux/uaccess.h>
|
|
Lee, Chun-Yi |
5b696a |
#include <asm/mmu_context.h>
|
|
Lee, Chun-Yi |
5b696a |
@@ -80,6 +81,24 @@ static inline void hibernate_restore_pro
|
|
Lee, Chun-Yi |
5b696a |
static inline void hibernate_restore_unprotect_page(void *page_address) {}
|
|
Takashi Iwai |
68d869 |
#endif /* CONFIG_STRICT_KERNEL_RWX && CONFIG_ARCH_HAS_SET_MEMORY */
|
|
Lee, Chun-Yi |
5b696a |
|
|
Lee, Chun-Yi |
5b696a |
+/*
|
|
Lee, Chun-Yi |
5b696a |
+ * The trampoline is used to forward information from boot kernel
|
|
Lee, Chun-Yi |
5b696a |
+ * to image kernel.
|
|
Lee, Chun-Yi |
5b696a |
+ */
|
|
Lee, Chun-Yi |
5b696a |
+struct trampoline {
|
|
Lee, Chun-Yi |
5b696a |
+ bool secret_key_valid;
|
|
Lee, Chun-Yi |
5b696a |
+ u8 secret_key[SECRET_KEY_SIZE];
|
|
Lee, Chun-Yi |
5b696a |
+};
|
|
Lee, Chun-Yi |
5b696a |
+
|
|
Lee, Chun-Yi |
5b696a |
+/* the trampoline is used by image kernel */
|
|
Lee, Chun-Yi |
5b696a |
+static void *trampoline_virt;
|
|
Lee, Chun-Yi |
5b696a |
+
|
|
Lee, Chun-Yi |
5b696a |
+/* trampoline pfn from swsusp_info in snapshot for snapshot_write_next() */
|
|
Lee, Chun-Yi |
5b696a |
+static unsigned long trampoline_pfn;
|
|
Lee, Chun-Yi |
5b696a |
+
|
|
Lee, Chun-Yi |
5b696a |
+/* Keep the buffer for foward page in snapshot_write_next() */
|
|
Lee, Chun-Yi |
5b696a |
+static void *trampoline_buff;
|
|
Lee, Chun-Yi |
5b696a |
+
|
|
Lee, Chun-Yi |
5b696a |
static int swsusp_page_is_free(struct page *);
|
|
Lee, Chun-Yi |
5b696a |
static void swsusp_set_page_forbidden(struct page *);
|
|
Lee, Chun-Yi |
5b696a |
static void swsusp_unset_page_forbidden(struct page *);
|
|
Lee, Chun-Yi |
5b696a |
@@ -2048,10 +2067,109 @@ static int init_header(struct swsusp_inf
|
|
Lee, Chun-Yi |
5b696a |
info->pages = snapshot_get_image_size();
|
|
Lee, Chun-Yi |
5b696a |
info->size = info->pages;
|
|
Lee, Chun-Yi |
5b696a |
info->size <<= PAGE_SHIFT;
|
|
Lee, Chun-Yi |
5b696a |
+ info->trampoline_pfn = page_to_pfn(virt_to_page(trampoline_virt));
|
|
Lee, Chun-Yi |
5b696a |
return init_header_complete(info);
|
|
Lee, Chun-Yi |
5b696a |
}
|
|
Lee, Chun-Yi |
5b696a |
|
|
Lee, Chun-Yi |
5b696a |
/**
|
|
Lee, Chun-Yi |
5b696a |
+ * create trampoline - Create a trampoline page before snapshot be created
|
|
Lee, Chun-Yi |
5b696a |
+ * In hibernation process, this routine will be called by kernel before
|
|
Lee, Chun-Yi |
5b696a |
+ * the snapshot image be created. It can be used in resuming process.
|
|
Lee, Chun-Yi |
5b696a |
+ */
|
|
Lee, Chun-Yi |
5b696a |
+int snapshot_create_trampoline(void)
|
|
Lee, Chun-Yi |
5b696a |
+{
|
|
Lee, Chun-Yi |
5b696a |
+ if (trampoline_virt) {
|
|
Lee, Chun-Yi |
5b696a |
+ pr_warn("PM: Tried to create trampoline again\n");
|
|
Lee, Chun-Yi |
5b696a |
+ return 0;
|
|
Lee, Chun-Yi |
5b696a |
+ }
|
|
Lee, Chun-Yi |
5b696a |
+
|
|
Lee, Chun-Yi |
5b696a |
+ trampoline_virt = (void *)get_zeroed_page(GFP_KERNEL);
|
|
Lee, Chun-Yi |
5b696a |
+ if (!trampoline_virt) {
|
|
Lee, Chun-Yi |
5b696a |
+ pr_err("PM: Allocate trampoline page failed\n");
|
|
Lee, Chun-Yi |
5b696a |
+ return -ENOMEM;
|
|
Lee, Chun-Yi |
5b696a |
+ }
|
|
Lee, Chun-Yi |
5b696a |
+ trampoline_pfn = 0;
|
|
Lee, Chun-Yi |
5b696a |
+ trampoline_buff = NULL;
|
|
Lee, Chun-Yi |
5b696a |
+
|
|
Lee, Chun-Yi |
5b696a |
+ return 0;
|
|
Lee, Chun-Yi |
5b696a |
+}
|
|
Lee, Chun-Yi |
5b696a |
+
|
|
Lee, Chun-Yi |
5b696a |
+/**
|
|
Lee, Chun-Yi |
5b696a |
+ * initial trampoline - Put data to trampoline buffer for target kernel
|
|
Lee, Chun-Yi |
5b696a |
+ *
|
|
Lee, Chun-Yi |
5b696a |
+ * In resuming process, this routine will be called by boot kernel before
|
|
Lee, Chun-Yi |
5b696a |
+ * the target kernel be restored. The boot kernel uses trampoline buffer
|
|
Lee, Chun-Yi |
5b696a |
+ * to transfer information to target kernel.
|
|
Lee, Chun-Yi |
5b696a |
+ */
|
|
Lee, Chun-Yi |
5b696a |
+void snapshot_init_trampoline(void)
|
|
Lee, Chun-Yi |
5b696a |
+{
|
|
Lee, Chun-Yi |
5b696a |
+ struct trampoline *t;
|
|
Lee, Chun-Yi |
5b696a |
+ void *efi_secret_key;
|
|
Lee, Chun-Yi |
5b696a |
+
|
|
Lee, Chun-Yi |
5b696a |
+ if (!trampoline_pfn || !trampoline_buff) {
|
|
Lee, Chun-Yi |
5b696a |
+ pr_err("PM: Did not find trampoline buffer, pfn: %ld\n",
|
|
Lee, Chun-Yi |
5b696a |
+ trampoline_pfn);
|
|
Lee, Chun-Yi |
5b696a |
+ return;
|
|
Lee, Chun-Yi |
5b696a |
+ }
|
|
Lee, Chun-Yi |
5b696a |
+
|
|
Lee, Chun-Yi |
5b696a |
+ hibernate_restore_unprotect_page(trampoline_buff);
|
|
Lee, Chun-Yi |
5b696a |
+ memset(trampoline_buff, 0, PAGE_SIZE);
|
|
Lee, Chun-Yi |
5b696a |
+ t = (struct trampoline *)trampoline_buff;
|
|
Lee, Chun-Yi |
5b696a |
+
|
|
Lee, Chun-Yi |
5b696a |
+ efi_secret_key = get_efi_secret_key();
|
|
Lee, Chun-Yi |
5b696a |
+ if (efi_secret_key) {
|
|
Lee, Chun-Yi |
5b696a |
+ memset(t->secret_key, 0, SECRET_KEY_SIZE);
|
|
Lee, Chun-Yi |
5b696a |
+ memcpy(t->secret_key, efi_secret_key, SECRET_KEY_SIZE);
|
|
Lee, Chun-Yi |
5b696a |
+ t->secret_key_valid = true;
|
|
Lee, Chun-Yi |
5b696a |
+ }
|
|
Lee, Chun-Yi |
5b696a |
+ pr_info("PM: Hibernation trampoline page prepared\n");
|
|
Lee, Chun-Yi |
5b696a |
+}
|
|
Lee, Chun-Yi |
5b696a |
+
|
|
Lee, Chun-Yi |
5b696a |
+/**
|
|
Lee, Chun-Yi |
5b696a |
+ * restore trampoline - Handle the data from boot kernel and free.
|
|
Lee, Chun-Yi |
5b696a |
+ *
|
|
Lee, Chun-Yi |
5b696a |
+ * In resuming process, this routine will be called by target kernel
|
|
Lee, Chun-Yi |
5b696a |
+ * after target kernel is restored. The target kernel handles
|
|
Lee, Chun-Yi |
5b696a |
+ * the data in trampoline that it is transferred from boot kernel.
|
|
Lee, Chun-Yi |
5b696a |
+ */
|
|
Lee, Chun-Yi |
5b696a |
+void snapshot_restore_trampoline(void)
|
|
Lee, Chun-Yi |
5b696a |
+{
|
|
Lee, Chun-Yi |
5b696a |
+ struct trampoline *t;
|
|
Lee, Chun-Yi |
5b696a |
+ int ret;
|
|
Lee, Chun-Yi |
5b696a |
+
|
|
Lee, Chun-Yi |
5b696a |
+ if (!trampoline_virt) {
|
|
Lee, Chun-Yi |
5b696a |
+ pr_err("PM: Doesn't have trampoline page\n");
|
|
Lee, Chun-Yi |
5b696a |
+ return;
|
|
Lee, Chun-Yi |
5b696a |
+ }
|
|
Lee, Chun-Yi |
5b696a |
+
|
|
Lee, Chun-Yi |
5b696a |
+ t = (struct trampoline *)trampoline_virt;
|
|
Lee, Chun-Yi |
5b696a |
+ if (t->secret_key_valid) {
|
|
Lee, Chun-Yi |
5b696a |
+ ret = decrypt_restore_hidden_area(t->secret_key, SECRET_KEY_SIZE);
|
|
Lee, Chun-Yi |
5b696a |
+ if (ret)
|
|
Lee, Chun-Yi |
5b696a |
+ pr_err("PM: Decrypted hidden area failed: %d\n", ret);
|
|
Lee, Chun-Yi |
5b696a |
+ else
|
|
Lee, Chun-Yi |
5b696a |
+ pr_info("PM: Hidden area decrypted\n");
|
|
Lee, Chun-Yi |
5b696a |
+ }
|
|
Lee, Chun-Yi |
5b696a |
+
|
|
Lee, Chun-Yi |
5b696a |
+ snapshot_free_trampoline();
|
|
Lee, Chun-Yi |
5b696a |
+}
|
|
Lee, Chun-Yi |
5b696a |
+
|
|
Lee, Chun-Yi |
5b696a |
+void snapshot_free_trampoline(void)
|
|
Lee, Chun-Yi |
5b696a |
+{
|
|
Lee, Chun-Yi |
5b696a |
+ if (!trampoline_virt) {
|
|
Lee, Chun-Yi |
5b696a |
+ pr_err("PM: No trampoline page can be freed\n");
|
|
Lee, Chun-Yi |
5b696a |
+ return;
|
|
Lee, Chun-Yi |
5b696a |
+ }
|
|
Lee, Chun-Yi |
5b696a |
+
|
|
Lee, Chun-Yi |
5b696a |
+ trampoline_pfn = 0;
|
|
Lee, Chun-Yi |
5b696a |
+ trampoline_buff = NULL;
|
|
Lee, Chun-Yi |
5b696a |
+ memset(trampoline_virt, 0, PAGE_SIZE);
|
|
Lee, Chun-Yi |
5b696a |
+ free_page((unsigned long)trampoline_virt);
|
|
Lee, Chun-Yi |
5b696a |
+ trampoline_virt = NULL;
|
|
Lee, Chun-Yi |
5b696a |
+ pr_info("PM: Trampoline freed\n");
|
|
Lee, Chun-Yi |
5b696a |
+}
|
|
Lee, Chun-Yi |
5b696a |
+
|
|
Lee, Chun-Yi |
5b696a |
+/**
|
|
Lee, Chun-Yi |
5b696a |
* pack_pfns - Prepare PFNs for saving.
|
|
Lee, Chun-Yi |
5b696a |
* @bm: Memory bitmap.
|
|
Lee, Chun-Yi |
5b696a |
* @buf: Memory buffer to store the PFNs in.
|
|
Lee, Chun-Yi |
5b696a |
@@ -2198,6 +2316,7 @@ static int load_header(struct swsusp_inf
|
|
Lee, Chun-Yi |
5b696a |
if (!error) {
|
|
Lee, Chun-Yi |
5b696a |
nr_copy_pages = info->image_pages;
|
|
Lee, Chun-Yi |
5b696a |
nr_meta_pages = info->pages - info->image_pages - 1;
|
|
Lee, Chun-Yi |
5b696a |
+ trampoline_pfn = info->trampoline_pfn;
|
|
Lee, Chun-Yi |
5b696a |
}
|
|
Lee, Chun-Yi |
5b696a |
return error;
|
|
Lee, Chun-Yi |
5b696a |
}
|
|
Lee, Chun-Yi |
5b696a |
@@ -2531,7 +2650,8 @@ static int prepare_image(struct memory_b
|
|
Lee, Chun-Yi |
5b696a |
* Get the address that snapshot_write_next() should return to its caller to
|
|
Lee, Chun-Yi |
5b696a |
* write to.
|
|
Lee, Chun-Yi |
5b696a |
*/
|
|
Lee, Chun-Yi |
5b696a |
-static void *get_buffer(struct memory_bitmap *bm, struct chain_allocator *ca)
|
|
Lee, Chun-Yi |
5b696a |
+static void *get_buffer(struct memory_bitmap *bm, struct chain_allocator *ca,
|
|
Lee, Chun-Yi |
5b696a |
+ unsigned long *pfn_out)
|
|
Lee, Chun-Yi |
5b696a |
{
|
|
Lee, Chun-Yi |
5b696a |
struct pbe *pbe;
|
|
Lee, Chun-Yi |
5b696a |
struct page *page;
|
|
Lee, Chun-Yi |
5b696a |
@@ -2540,6 +2660,9 @@ static void *get_buffer(struct memory_bi
|
|
Lee, Chun-Yi |
5b696a |
if (pfn == BM_END_OF_MAP)
|
|
Lee, Chun-Yi |
5b696a |
return ERR_PTR(-EFAULT);
|
|
Lee, Chun-Yi |
5b696a |
|
|
Lee, Chun-Yi |
5b696a |
+ if (pfn_out)
|
|
Lee, Chun-Yi |
5b696a |
+ *pfn_out = pfn;
|
|
Lee, Chun-Yi |
5b696a |
+
|
|
Lee, Chun-Yi |
5b696a |
page = pfn_to_page(pfn);
|
|
Lee, Chun-Yi |
5b696a |
if (PageHighMem(page))
|
|
Lee, Chun-Yi |
5b696a |
return get_highmem_page_buffer(page, ca);
|
|
Lee, Chun-Yi |
5b696a |
@@ -2587,6 +2710,7 @@ static void *get_buffer(struct memory_bi
|
|
Lee, Chun-Yi |
5b696a |
int snapshot_write_next(struct snapshot_handle *handle)
|
|
Lee, Chun-Yi |
5b696a |
{
|
|
Lee, Chun-Yi |
5b696a |
static struct chain_allocator ca;
|
|
Lee, Chun-Yi |
5b696a |
+ unsigned long pfn;
|
|
Lee, Chun-Yi |
5b696a |
int error = 0;
|
|
Lee, Chun-Yi |
5b696a |
|
|
Lee, Chun-Yi |
5b696a |
/* Check if we have already loaded the entire image */
|
|
Lee, Chun-Yi |
5b696a |
@@ -2634,7 +2758,7 @@ int snapshot_write_next(struct snapshot_
|
|
Lee, Chun-Yi |
5b696a |
chain_init(&ca, GFP_ATOMIC, PG_SAFE);
|
|
Lee, Chun-Yi |
5b696a |
memory_bm_position_reset(&orig_bm);
|
|
Lee, Chun-Yi |
5b696a |
restore_pblist = NULL;
|
|
Lee, Chun-Yi |
5b696a |
- handle->buffer = get_buffer(&orig_bm, &ca);
|
|
Lee, Chun-Yi |
5b696a |
+ handle->buffer = get_buffer(&orig_bm, &ca, &pfn;;
|
|
Lee, Chun-Yi |
5b696a |
handle->sync_read = 0;
|
|
Lee, Chun-Yi |
5b696a |
if (IS_ERR(handle->buffer))
|
|
Lee, Chun-Yi |
5b696a |
return PTR_ERR(handle->buffer);
|
|
Lee, Chun-Yi |
5b696a |
@@ -2644,11 +2768,14 @@ int snapshot_write_next(struct snapshot_
|
|
Lee, Chun-Yi |
5b696a |
/* Restore page key for data page (s390 only). */
|
|
Lee, Chun-Yi |
5b696a |
page_key_write(handle->buffer);
|
|
Lee, Chun-Yi |
5b696a |
hibernate_restore_protect_page(handle->buffer);
|
|
Lee, Chun-Yi |
5b696a |
- handle->buffer = get_buffer(&orig_bm, &ca);
|
|
Lee, Chun-Yi |
5b696a |
+ handle->buffer = get_buffer(&orig_bm, &ca, &pfn;;
|
|
Lee, Chun-Yi |
5b696a |
if (IS_ERR(handle->buffer))
|
|
Lee, Chun-Yi |
5b696a |
return PTR_ERR(handle->buffer);
|
|
Lee, Chun-Yi |
5b696a |
if (handle->buffer != buffer)
|
|
Lee, Chun-Yi |
5b696a |
handle->sync_read = 0;
|
|
Lee, Chun-Yi |
5b696a |
+ /* Capture the trampoline for transfer data */
|
|
Lee, Chun-Yi |
5b696a |
+ if (pfn == trampoline_pfn && trampoline_pfn)
|
|
Lee, Chun-Yi |
5b696a |
+ trampoline_buff = handle->buffer;
|
|
Lee, Chun-Yi |
5b696a |
}
|
|
Lee, Chun-Yi |
5b696a |
handle->cur++;
|
|
Lee, Chun-Yi |
5b696a |
return PAGE_SIZE;
|
|
Lee, Chun-Yi |
5b696a |
--- a/kernel/power/swap.c
|
|
Lee, Chun-Yi |
5b696a |
+++ b/kernel/power/swap.c
|
|
Lee, Chun-Yi |
5b696a |
@@ -1102,6 +1102,7 @@ static int load_image(struct swap_map_ha
|
|
Lee, Chun-Yi |
5b696a |
if (!snapshot_image_loaded(snapshot))
|
|
Lee, Chun-Yi |
5b696a |
ret = -ENODATA;
|
|
Lee, Chun-Yi |
5b696a |
|
|
Lee, Chun-Yi |
5b696a |
+ snapshot_init_trampoline();
|
|
Lee, Chun-Yi |
5b696a |
/* clean the hidden area in boot kernel */
|
|
Lee, Chun-Yi |
5b696a |
clean_hidden_area();
|
|
Lee, Chun-Yi |
5b696a |
}
|
|
Lee, Chun-Yi |
5b696a |
@@ -1465,6 +1466,7 @@ out_finish:
|
|
Lee, Chun-Yi |
5b696a |
}
|
|
Lee, Chun-Yi |
5b696a |
}
|
|
Lee, Chun-Yi |
5b696a |
}
|
|
Lee, Chun-Yi |
5b696a |
+ snapshot_init_trampoline();
|
|
Lee, Chun-Yi |
5b696a |
/* clean the hidden area in boot kernel */
|
|
Lee, Chun-Yi |
5b696a |
clean_hidden_area();
|
|
Lee, Chun-Yi |
5b696a |
}
|
|
Lee, Chun-Yi |
5b696a |
--- a/kernel/power/user.c
|
|
Lee, Chun-Yi |
5b696a |
+++ b/kernel/power/user.c
|
|
Takashi Iwai |
68d869 |
@@ -249,6 +249,7 @@ static long snapshot_ioctl(struct file *
|
|
Lee, Chun-Yi |
5b696a |
if (!data->frozen || data->ready)
|
|
Lee, Chun-Yi |
5b696a |
break;
|
|
Lee, Chun-Yi |
5b696a |
pm_restore_gfp_mask();
|
|
Lee, Chun-Yi |
5b696a |
+ snapshot_restore_trampoline();
|
|
Lee, Chun-Yi |
5b696a |
free_basic_memory_bitmaps();
|
|
Lee, Chun-Yi |
5b696a |
data->free_bitmaps = false;
|
|
Lee, Chun-Yi |
5b696a |
thaw_processes();
|
|
Takashi Iwai |
68d869 |
@@ -260,6 +261,9 @@ static long snapshot_ioctl(struct file *
|
|
Lee, Chun-Yi |
5b696a |
error = -EPERM;
|
|
Lee, Chun-Yi |
5b696a |
break;
|
|
Lee, Chun-Yi |
5b696a |
}
|
|
Lee, Chun-Yi |
5b696a |
+ error = snapshot_create_trampoline();
|
|
Lee, Chun-Yi |
5b696a |
+ if (error)
|
|
Lee, Chun-Yi |
5b696a |
+ return error;
|
|
Lee, Chun-Yi |
5b696a |
pm_restore_gfp_mask();
|
|
Lee, Chun-Yi |
5b696a |
error = hibernation_snapshot(data->platform_support);
|
|
Lee, Chun-Yi |
5b696a |
if (!error) {
|
|
Takashi Iwai |
68d869 |
@@ -276,6 +280,7 @@ static long snapshot_ioctl(struct file *
|
|
Lee, Chun-Yi |
5b696a |
error = -EPERM;
|
|
Lee, Chun-Yi |
5b696a |
break;
|
|
Lee, Chun-Yi |
5b696a |
}
|
|
Lee, Chun-Yi |
5b696a |
+ snapshot_init_trampoline();
|
|
Lee, Chun-Yi |
5b696a |
/* clean the hidden area in boot kernel */
|
|
Lee, Chun-Yi |
5b696a |
clean_hidden_area();
|
|
Lee, Chun-Yi |
5b696a |
error = hibernation_restore(data->platform_support);
|