ACPI defines a hardware signature. BIOS calculates the signature
according to hardware configure, if hardware changes, the signature will
change, in this case, S4 resume should fail.

Signed-off-by: Shaohua Li <[EMAIL PROTECTED]>
---
 drivers/acpi/sleep/main.c |   13 +++++++++++++
 include/linux/suspend.h   |    5 +++++
 kernel/power/disk.c       |   21 ++++++++++++++++++---
 kernel/power/power.h      |    6 +++---
 kernel/power/swap.c       |   24 +++++++++++++++---------
 5 files changed, 54 insertions(+), 15 deletions(-)

Index: linux/drivers/acpi/sleep/main.c
===================================================================
--- linux.orig/drivers/acpi/sleep/main.c        2008-01-02 14:04:41.000000000 
+0800
+++ linux/drivers/acpi/sleep/main.c     2008-01-02 14:44:06.000000000 +0800
@@ -295,6 +295,18 @@ static void acpi_hibernation_restore_cle
        acpi_hw_enable_all_runtime_gpes();
 }
 
+static unsigned long acpi_hibernation_hardware_signature(void)
+{
+       acpi_status status;
+       struct acpi_table_facs *facs;
+
+       status = acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS,
+               (struct acpi_table_header **)&facs);
+       if (ACPI_FAILURE(status))
+               return 0;
+       return facs->hardware_signature;
+}
+
 static struct platform_hibernation_ops acpi_hibernation_ops = {
        .start = acpi_hibernation_start,
        .pre_snapshot = acpi_hibernation_prepare,
@@ -304,6 +316,7 @@ static struct platform_hibernation_ops a
        .leave = acpi_hibernation_leave,
        .pre_restore = acpi_hibernation_pre_restore,
        .restore_cleanup = acpi_hibernation_restore_cleanup,
+       .hardware_signature = acpi_hibernation_hardware_signature,
 };
 #endif                         /* CONFIG_HIBERNATION */
 
Index: linux/include/linux/suspend.h
===================================================================
--- linux.orig/include/linux/suspend.h  2008-01-02 14:04:41.000000000 +0800
+++ linux/include/linux/suspend.h       2008-01-02 14:33:34.000000000 +0800
@@ -169,6 +169,10 @@ extern void mark_free_pages(struct zone 
  * @restore_cleanup: Clean up after a failing image restoration.
  *     Called right after the nonboot CPUs have been enabled and before
  *     thawing devices (runs with IRQs on).
+ *
+ * @hardware_signature: Hardware signature in the platform.
+ *     If platform hardware changes, the signature will change. Hibernation
+ *     will check if the signature before/after a suspend matches.
  */
 struct platform_hibernation_ops {
        int (*start)(void);
@@ -179,6 +183,7 @@ struct platform_hibernation_ops {
        void (*leave)(void);
        int (*pre_restore)(void);
        void (*restore_cleanup)(void);
+       unsigned long (*hardware_signature)(void);
 };
 
 #ifdef CONFIG_HIBERNATION
Index: linux/kernel/power/disk.c
===================================================================
--- linux.orig/kernel/power/disk.c      2008-01-02 14:04:41.000000000 +0800
+++ linux/kernel/power/disk.c   2008-01-02 14:43:10.000000000 +0800
@@ -139,6 +139,14 @@ static void platform_restore_cleanup(int
                hibernation_ops->restore_cleanup();
 }
 
+static unsigned long platform_hardware_signature(int platform_mode)
+{
+       if (platform_mode && hibernation_ops &&
+           hibernation_ops->hardware_signature)
+               return hibernation_ops->hardware_signature();
+       return 0;
+}
+
 /**
  *     create_image - freeze devices that need to be frozen with interrupts
  *     off, create the hibernation image and thaw those devices.  Control
@@ -381,6 +389,7 @@ static int prepare_processes(void)
 int hibernate(void)
 {
        int error;
+       unsigned long hd_sig;
 
        mutex_lock(&pm_mutex);
        /* The snapshot device should not be opened while we're running */
@@ -389,6 +398,7 @@ int hibernate(void)
                goto Unlock;
        }
 
+       hd_sig = platform_hardware_signature(hibernation_mode == 
HIBERNATION_PLATFORM);
        error = pm_notifier_call_chain(PM_HIBERNATION_PREPARE);
        if (error)
                goto Exit;
@@ -418,7 +428,7 @@ int hibernate(void)
                if (hibernation_mode == HIBERNATION_PLATFORM)
                        flags |= SF_PLATFORM_MODE;
                pr_debug("PM: writing image.\n");
-               error = swsusp_write(flags);
+               error = swsusp_write(flags, hd_sig);
                swsusp_free();
                if (!error)
                        power_down();
@@ -455,6 +465,7 @@ static int software_resume(void)
 {
        int error;
        unsigned int flags;
+       unsigned long hd_sig;
 
        /*
         * name_to_dev_t() below takes a sysfs buffer mutex when sysfs
@@ -489,9 +500,13 @@ static int software_resume(void)
        }
 
        pr_debug("PM: Checking swsusp image.\n");
-       error = swsusp_check();
+       error = swsusp_check(&flags, &hd_sig);
        if (error)
                goto Unlock;
+       if (hd_sig != platform_hardware_signature(flags & SF_PLATFORM_MODE)) {
+               printk(KERN_ERR"PM: Hardware changed, can't resume.\n");
+               goto Unlock;
+       }
 
        /* The snapshot device should not be opened while we're running */
        if (!atomic_add_unless(&snapshot_device_available, -1, 0)) {
@@ -512,7 +527,7 @@ static int software_resume(void)
 
        pr_debug("PM: Reading swsusp image.\n");
 
-       error = swsusp_read(&flags);
+       error = swsusp_read();
        if (!error)
                hibernation_restore(flags & SF_PLATFORM_MODE);
 
Index: linux/kernel/power/power.h
===================================================================
--- linux.orig/kernel/power/power.h     2008-01-02 14:04:41.000000000 +0800
+++ linux/kernel/power/power.h  2008-01-02 14:06:05.000000000 +0800
@@ -180,12 +180,12 @@ extern int swsusp_swap_in_use(void);
 #define SF_PLATFORM_MODE       1
 
 /* kernel/power/disk.c */
-extern int swsusp_check(void);
+extern int swsusp_check(unsigned int *flags_p, unsigned long *hd_sig);
 extern int swsusp_shrink_memory(void);
 extern void swsusp_free(void);
 extern int swsusp_resume(void);
-extern int swsusp_read(unsigned int *flags_p);
-extern int swsusp_write(unsigned int flags);
+extern int swsusp_read(void);
+extern int swsusp_write(unsigned int flags, unsigned long hd_sig);
 extern void swsusp_close(void);
 
 struct timeval;
Index: linux/kernel/power/swap.c
===================================================================
--- linux.orig/kernel/power/swap.c      2008-01-02 14:04:41.000000000 +0800
+++ linux/kernel/power/swap.c   2008-01-02 14:34:49.000000000 +0800
@@ -33,9 +33,10 @@ extern char resume_file[];
 #define SWSUSP_SIG     "S1SUSPEND"
 
 struct swsusp_header {
-       char reserved[PAGE_SIZE - 20 - sizeof(sector_t) - sizeof(int)];
+       char reserved[PAGE_SIZE - 20 - sizeof(sector_t) - sizeof(int) - 
sizeof(unsigned long)];
        sector_t image;
        unsigned int flags;     /* Flags to pass to the "boot" kernel */
+       unsigned long hardware_signature;
        char    orig_sig[10];
        char    sig[10];
 } __attribute__((packed));
@@ -139,7 +140,7 @@ static int wait_on_bio_chain(struct bio 
  * Saving part
  */
 
-static int mark_swapfiles(sector_t start, unsigned int flags)
+static int mark_swapfiles(sector_t start, unsigned int flags, unsigned long 
hd_sig)
 {
        int error;
 
@@ -150,6 +151,7 @@ static int mark_swapfiles(sector_t start
                memcpy(swsusp_header->sig,SWSUSP_SIG, 10);
                swsusp_header->image = start;
                swsusp_header->flags = flags;
+               swsusp_header->hardware_signature = hd_sig;
                error = bio_write_page(swsusp_resume_block,
                                        swsusp_header, NULL);
        } else {
@@ -379,7 +381,7 @@ static int enough_swap(unsigned int nr_p
  *     correctly, we'll mark system clean, anyway.)
  */
 
-int swsusp_write(unsigned int flags)
+int swsusp_write(unsigned int flags, unsigned long hd_sig)
 {
        struct swap_map_handle handle;
        struct snapshot_handle snapshot;
@@ -418,7 +420,7 @@ int swsusp_write(unsigned int flags)
                if (!error) {
                        flush_swap_writer(&handle);
                        printk("S");
-                       error = mark_swapfiles(start, flags);
+                       error = mark_swapfiles(start, flags, hd_sig);
                        printk("|\n");
                }
        }
@@ -545,18 +547,15 @@ static int load_image(struct swap_map_ha
 
 /**
  *     swsusp_read - read the hibernation image.
- *     @flags_p: flags passed by the "frozen" kernel in the image header should
- *               be written into this memeory location
  */
 
-int swsusp_read(unsigned int *flags_p)
+int swsusp_read()
 {
        int error;
        struct swap_map_handle handle;
        struct snapshot_handle snapshot;
        struct swsusp_info *header;
 
-       *flags_p = swsusp_header->flags;
        if (IS_ERR(resume_bdev)) {
                pr_debug("swsusp: block device not initialised\n");
                return PTR_ERR(resume_bdev);
@@ -585,9 +584,13 @@ int swsusp_read(unsigned int *flags_p)
 
 /**
  *      swsusp_check - Check for swsusp signature in the resume device
+ *     @flags_p: flags passed by the "frozen" kernel in the image header should
+ *               be written into this memeory location
+ *     @hd_sig: hardware signature passed by the "frozen" kernel in the image
+ *              header should be written into this memeory location
  */
 
-int swsusp_check(void)
+int swsusp_check(unsigned int *flags_p, unsigned long *hd_sig)
 {
        int error;
 
@@ -605,6 +608,9 @@ int swsusp_check(void)
                        /* Reset swap signature now */
                        error = bio_write_page(swsusp_resume_block,
                                                swsusp_header, NULL);
+
+                       *flags_p = swsusp_header->flags;
+                       *hd_sig = swsusp_header->hardware_signature;
                } else {
                        return -EINVAL;
                }


-
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to