Commit f6c46b1d authored by David Woodhouse's avatar David Woodhouse Committed by Rafael J. Wysocki

PM: hibernate: Honour ACPI hardware signature by default for virtual guests

The ACPI specification says that OSPM should refuse to restore from
hibernate if the hardware signature changes, and should boot from
scratch. However, real BIOSes often vary the hardware signature in cases
where we *do* want to resume from hibernate, so Linux doesn't follow the
spec by default.

However, in a virtual environment there's no reason for the VMM to vary
the hardware signature *unless* it wants to trigger a clean reboot as
defined by the ACPI spec. So enable the check by default if a hypervisor
is detected.
Signed-off-by: default avatarDavid Woodhouse <dwmw@amazon.co.uk>
Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
parent a759de69
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <asm/desc.h> #include <asm/desc.h>
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
#include <asm/realmode.h> #include <asm/realmode.h>
#include <asm/hypervisor.h>
#include <linux/ftrace.h> #include <linux/ftrace.h>
#include "../../realmode/rm/wakeup.h" #include "../../realmode/rm/wakeup.h"
...@@ -140,9 +141,9 @@ static int __init acpi_sleep_setup(char *str) ...@@ -140,9 +141,9 @@ static int __init acpi_sleep_setup(char *str)
acpi_realmode_flags |= 4; acpi_realmode_flags |= 4;
#ifdef CONFIG_HIBERNATION #ifdef CONFIG_HIBERNATION
if (strncmp(str, "s4_hwsig", 8) == 0) if (strncmp(str, "s4_hwsig", 8) == 0)
acpi_check_s4_hw_signature(1); acpi_check_s4_hw_signature = 1;
if (strncmp(str, "s4_nohwsig", 10) == 0) if (strncmp(str, "s4_nohwsig", 10) == 0)
acpi_check_s4_hw_signature(0); acpi_check_s4_hw_signature = 0;
#endif #endif
if (strncmp(str, "nonvs", 5) == 0) if (strncmp(str, "nonvs", 5) == 0)
acpi_nvs_nosave(); acpi_nvs_nosave();
...@@ -160,3 +161,21 @@ static int __init acpi_sleep_setup(char *str) ...@@ -160,3 +161,21 @@ static int __init acpi_sleep_setup(char *str)
} }
__setup("acpi_sleep=", acpi_sleep_setup); __setup("acpi_sleep=", acpi_sleep_setup);
#if defined(CONFIG_HIBERNATION) && defined(CONFIG_HYPERVISOR_GUEST)
static int __init init_s4_sigcheck(void)
{
/*
* If running on a hypervisor, honour the ACPI specification
* by default and trigger a clean reboot when the hardware
* signature in FACS is changed after hibernation.
*/
if (acpi_check_s4_hw_signature == -1 &&
!hypervisor_is_type(X86_HYPER_NATIVE))
acpi_check_s4_hw_signature = 1;
return 0;
}
/* This must happen before acpi_init() which is a subsys initcall */
arch_initcall(init_s4_sigcheck);
#endif
...@@ -869,12 +869,7 @@ static inline void acpi_sleep_syscore_init(void) {} ...@@ -869,12 +869,7 @@ static inline void acpi_sleep_syscore_init(void) {}
#ifdef CONFIG_HIBERNATION #ifdef CONFIG_HIBERNATION
static unsigned long s4_hardware_signature; static unsigned long s4_hardware_signature;
static struct acpi_table_facs *facs; static struct acpi_table_facs *facs;
static int sigcheck = -1; /* Default behaviour is just to warn */ int acpi_check_s4_hw_signature = -1; /* Default behaviour is just to warn */
void __init acpi_check_s4_hw_signature(int check)
{
sigcheck = check;
}
static int acpi_hibernation_begin(pm_message_t stage) static int acpi_hibernation_begin(pm_message_t stage)
{ {
...@@ -999,7 +994,7 @@ static void acpi_sleep_hibernate_setup(void) ...@@ -999,7 +994,7 @@ static void acpi_sleep_hibernate_setup(void)
hibernation_set_ops(old_suspend_ordering ? hibernation_set_ops(old_suspend_ordering ?
&acpi_hibernation_ops_old : &acpi_hibernation_ops); &acpi_hibernation_ops_old : &acpi_hibernation_ops);
sleep_states[ACPI_STATE_S4] = 1; sleep_states[ACPI_STATE_S4] = 1;
if (!sigcheck) if (!acpi_check_s4_hw_signature)
return; return;
acpi_get_table(ACPI_SIG_FACS, 1, (struct acpi_table_header **)&facs); acpi_get_table(ACPI_SIG_FACS, 1, (struct acpi_table_header **)&facs);
...@@ -1011,7 +1006,7 @@ static void acpi_sleep_hibernate_setup(void) ...@@ -1011,7 +1006,7 @@ static void acpi_sleep_hibernate_setup(void)
*/ */
s4_hardware_signature = facs->hardware_signature; s4_hardware_signature = facs->hardware_signature;
if (sigcheck > 0) { if (acpi_check_s4_hw_signature > 0) {
/* /*
* If we're actually obeying the ACPI specification * If we're actually obeying the ACPI specification
* then the signature is written out as part of the * then the signature is written out as part of the
......
...@@ -526,7 +526,7 @@ acpi_status acpi_release_memory(acpi_handle handle, struct resource *res, ...@@ -526,7 +526,7 @@ acpi_status acpi_release_memory(acpi_handle handle, struct resource *res,
int acpi_resources_are_enforced(void); int acpi_resources_are_enforced(void);
#ifdef CONFIG_HIBERNATION #ifdef CONFIG_HIBERNATION
void __init acpi_check_s4_hw_signature(int check); extern int acpi_check_s4_hw_signature;
#endif #endif
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment