Skip to content

Commit f6c46b1

Browse files
dwmw2rafaeljw
authored andcommitted
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: David Woodhouse <dwmw@amazon.co.uk> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
1 parent a759de6 commit f6c46b1

File tree

3 files changed

+25
-11
lines changed

3 files changed

+25
-11
lines changed

arch/x86/kernel/acpi/sleep.c

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <asm/desc.h>
1616
#include <asm/cacheflush.h>
1717
#include <asm/realmode.h>
18+
#include <asm/hypervisor.h>
1819

1920
#include <linux/ftrace.h>
2021
#include "../../realmode/rm/wakeup.h"
@@ -140,9 +141,9 @@ static int __init acpi_sleep_setup(char *str)
140141
acpi_realmode_flags |= 4;
141142
#ifdef CONFIG_HIBERNATION
142143
if (strncmp(str, "s4_hwsig", 8) == 0)
143-
acpi_check_s4_hw_signature(1);
144+
acpi_check_s4_hw_signature = 1;
144145
if (strncmp(str, "s4_nohwsig", 10) == 0)
145-
acpi_check_s4_hw_signature(0);
146+
acpi_check_s4_hw_signature = 0;
146147
#endif
147148
if (strncmp(str, "nonvs", 5) == 0)
148149
acpi_nvs_nosave();
@@ -160,3 +161,21 @@ static int __init acpi_sleep_setup(char *str)
160161
}
161162

162163
__setup("acpi_sleep=", acpi_sleep_setup);
164+
165+
#if defined(CONFIG_HIBERNATION) && defined(CONFIG_HYPERVISOR_GUEST)
166+
static int __init init_s4_sigcheck(void)
167+
{
168+
/*
169+
* If running on a hypervisor, honour the ACPI specification
170+
* by default and trigger a clean reboot when the hardware
171+
* signature in FACS is changed after hibernation.
172+
*/
173+
if (acpi_check_s4_hw_signature == -1 &&
174+
!hypervisor_is_type(X86_HYPER_NATIVE))
175+
acpi_check_s4_hw_signature = 1;
176+
177+
return 0;
178+
}
179+
/* This must happen before acpi_init() which is a subsys initcall */
180+
arch_initcall(init_s4_sigcheck);
181+
#endif

drivers/acpi/sleep.c

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -869,12 +869,7 @@ static inline void acpi_sleep_syscore_init(void) {}
869869
#ifdef CONFIG_HIBERNATION
870870
static unsigned long s4_hardware_signature;
871871
static struct acpi_table_facs *facs;
872-
static int sigcheck = -1; /* Default behaviour is just to warn */
873-
874-
void __init acpi_check_s4_hw_signature(int check)
875-
{
876-
sigcheck = check;
877-
}
872+
int acpi_check_s4_hw_signature = -1; /* Default behaviour is just to warn */
878873

879874
static int acpi_hibernation_begin(pm_message_t stage)
880875
{
@@ -999,7 +994,7 @@ static void acpi_sleep_hibernate_setup(void)
999994
hibernation_set_ops(old_suspend_ordering ?
1000995
&acpi_hibernation_ops_old : &acpi_hibernation_ops);
1001996
sleep_states[ACPI_STATE_S4] = 1;
1002-
if (!sigcheck)
997+
if (!acpi_check_s4_hw_signature)
1003998
return;
1004999

10051000
acpi_get_table(ACPI_SIG_FACS, 1, (struct acpi_table_header **)&facs);
@@ -1011,7 +1006,7 @@ static void acpi_sleep_hibernate_setup(void)
10111006
*/
10121007
s4_hardware_signature = facs->hardware_signature;
10131008

1014-
if (sigcheck > 0) {
1009+
if (acpi_check_s4_hw_signature > 0) {
10151010
/*
10161011
* If we're actually obeying the ACPI specification
10171012
* then the signature is written out as part of the

include/linux/acpi.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -526,7 +526,7 @@ acpi_status acpi_release_memory(acpi_handle handle, struct resource *res,
526526
int acpi_resources_are_enforced(void);
527527

528528
#ifdef CONFIG_HIBERNATION
529-
void __init acpi_check_s4_hw_signature(int check);
529+
extern int acpi_check_s4_hw_signature;
530530
#endif
531531

532532
#ifdef CONFIG_PM_SLEEP

0 commit comments

Comments
 (0)