Browse Source

Merge branch 'pm-sleep'

* pm-sleep:
  x86, kaslr: boot-time selectable with hibernation
  PM / hibernate: introduce "nohibernate" boot parameter
Rafael J. Wysocki 11 years ago
parent
commit
639bb92a1f

+ 10 - 4
Documentation/kernel-parameters.txt

@@ -1474,6 +1474,13 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 	js=		[HW,JOY] Analog joystick
 	js=		[HW,JOY] Analog joystick
 			See Documentation/input/joystick.txt.
 			See Documentation/input/joystick.txt.
 
 
+	kaslr/nokaslr	[X86]
+			Enable/disable kernel and module base offset ASLR
+			(Address Space Layout Randomization) if built into
+			the kernel. When CONFIG_HIBERNATION is selected,
+			kASLR is disabled by default. When kASLR is enabled,
+			hibernation will be disabled.
+
 	keepinitrd	[HW,ARM]
 	keepinitrd	[HW,ARM]
 
 
 	kernelcore=nn[KMG]	[KNL,X86,IA-64,PPC] This parameter
 	kernelcore=nn[KMG]	[KNL,X86,IA-64,PPC] This parameter
@@ -2110,10 +2117,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 	noapic		[SMP,APIC] Tells the kernel to not make use of any
 	noapic		[SMP,APIC] Tells the kernel to not make use of any
 			IOAPICs that may be present in the system.
 			IOAPICs that may be present in the system.
 
 
-	nokaslr		[X86]
-			Disable kernel and module base offset ASLR (Address
-			Space Layout Randomization) if built into the kernel.
-
 	noautogroup	Disable scheduler automatic task group creation.
 	noautogroup	Disable scheduler automatic task group creation.
 
 
 	nobats		[PPC] Do not use BATs for mapping kernel lowmem
 	nobats		[PPC] Do not use BATs for mapping kernel lowmem
@@ -2184,6 +2187,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 			in certain environments such as networked servers or
 			in certain environments such as networked servers or
 			real-time systems.
 			real-time systems.
 
 
+	nohibernate	[HIBERNATION] Disable hibernation and resume.
+
 	nohz=		[KNL] Boottime enable/disable dynamic ticks
 	nohz=		[KNL] Boottime enable/disable dynamic ticks
 			Valid arguments: on, off
 			Valid arguments: on, off
 			Default: on
 			Default: on
@@ -2980,6 +2985,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 		noresume	Don't check if there's a hibernation image
 		noresume	Don't check if there's a hibernation image
 				present during boot.
 				present during boot.
 		nocompress	Don't compress/decompress hibernation images.
 		nocompress	Don't compress/decompress hibernation images.
+		no		Disable hibernation and resume.
 
 
 	retain_initrd	[RAM] Keep initrd memory after extraction
 	retain_initrd	[RAM] Keep initrd memory after extraction
 
 

+ 0 - 1
arch/x86/Kconfig

@@ -1672,7 +1672,6 @@ config RELOCATABLE
 config RANDOMIZE_BASE
 config RANDOMIZE_BASE
 	bool "Randomize the address of the kernel image"
 	bool "Randomize the address of the kernel image"
 	depends on RELOCATABLE
 	depends on RELOCATABLE
-	depends on !HIBERNATION
 	default n
 	default n
 	---help---
 	---help---
 	   Randomizes the physical and virtual address at which the
 	   Randomizes the physical and virtual address at which the

+ 8 - 1
arch/x86/boot/compressed/aslr.c

@@ -289,10 +289,17 @@ unsigned char *choose_kernel_location(unsigned char *input,
 	unsigned long choice = (unsigned long)output;
 	unsigned long choice = (unsigned long)output;
 	unsigned long random;
 	unsigned long random;
 
 
+#ifdef CONFIG_HIBERNATION
+	if (!cmdline_find_option_bool("kaslr")) {
+		debug_putstr("KASLR disabled by default...\n");
+		goto out;
+	}
+#else
 	if (cmdline_find_option_bool("nokaslr")) {
 	if (cmdline_find_option_bool("nokaslr")) {
-		debug_putstr("KASLR disabled...\n");
+		debug_putstr("KASLR disabled by cmdline...\n");
 		goto out;
 		goto out;
 	}
 	}
+#endif
 
 
 	/* Record the various known unsafe memory ranges. */
 	/* Record the various known unsafe memory ranges. */
 	mem_avoid_init((unsigned long)input, input_size,
 	mem_avoid_init((unsigned long)input, input_size,

+ 2 - 0
include/linux/suspend.h

@@ -327,6 +327,7 @@ extern unsigned long get_safe_page(gfp_t gfp_mask);
 extern void hibernation_set_ops(const struct platform_hibernation_ops *ops);
 extern void hibernation_set_ops(const struct platform_hibernation_ops *ops);
 extern int hibernate(void);
 extern int hibernate(void);
 extern bool system_entering_hibernation(void);
 extern bool system_entering_hibernation(void);
+extern bool hibernation_available(void);
 asmlinkage int swsusp_save(void);
 asmlinkage int swsusp_save(void);
 extern struct pbe *restore_pblist;
 extern struct pbe *restore_pblist;
 #else /* CONFIG_HIBERNATION */
 #else /* CONFIG_HIBERNATION */
@@ -339,6 +340,7 @@ static inline void swsusp_unset_page_free(struct page *p) {}
 static inline void hibernation_set_ops(const struct platform_hibernation_ops *ops) {}
 static inline void hibernation_set_ops(const struct platform_hibernation_ops *ops) {}
 static inline int hibernate(void) { return -ENOSYS; }
 static inline int hibernate(void) { return -ENOSYS; }
 static inline bool system_entering_hibernation(void) { return false; }
 static inline bool system_entering_hibernation(void) { return false; }
+static inline bool hibernation_available(void) { return false; }
 #endif /* CONFIG_HIBERNATION */
 #endif /* CONFIG_HIBERNATION */
 
 
 /* Hibernation and suspend events */
 /* Hibernation and suspend events */

+ 36 - 1
kernel/power/hibernate.c

@@ -35,6 +35,7 @@
 
 
 static int nocompress;
 static int nocompress;
 static int noresume;
 static int noresume;
+static int nohibernate;
 static int resume_wait;
 static int resume_wait;
 static unsigned int resume_delay;
 static unsigned int resume_delay;
 static char resume_file[256] = CONFIG_PM_STD_PARTITION;
 static char resume_file[256] = CONFIG_PM_STD_PARTITION;
@@ -62,6 +63,11 @@ bool freezer_test_done;
 
 
 static const struct platform_hibernation_ops *hibernation_ops;
 static const struct platform_hibernation_ops *hibernation_ops;
 
 
+bool hibernation_available(void)
+{
+	return (nohibernate == 0);
+}
+
 /**
 /**
  * hibernation_set_ops - Set the global hibernate operations.
  * hibernation_set_ops - Set the global hibernate operations.
  * @ops: Hibernation operations to use in subsequent hibernation transitions.
  * @ops: Hibernation operations to use in subsequent hibernation transitions.
@@ -642,6 +648,11 @@ int hibernate(void)
 {
 {
 	int error;
 	int error;
 
 
+	if (!hibernation_available()) {
+		pr_debug("PM: Hibernation not available.\n");
+		return -EPERM;
+	}
+
 	lock_system_sleep();
 	lock_system_sleep();
 	/* The snapshot device should not be opened while we're running */
 	/* The snapshot device should not be opened while we're running */
 	if (!atomic_add_unless(&snapshot_device_available, -1, 0)) {
 	if (!atomic_add_unless(&snapshot_device_available, -1, 0)) {
@@ -734,7 +745,7 @@ static int software_resume(void)
 	/*
 	/*
 	 * If the user said "noresume".. bail out early.
 	 * If the user said "noresume".. bail out early.
 	 */
 	 */
-	if (noresume)
+	if (noresume || !hibernation_available())
 		return 0;
 		return 0;
 
 
 	/*
 	/*
@@ -900,6 +911,9 @@ static ssize_t disk_show(struct kobject *kobj, struct kobj_attribute *attr,
 	int i;
 	int i;
 	char *start = buf;
 	char *start = buf;
 
 
+	if (!hibernation_available())
+		return sprintf(buf, "[disabled]\n");
+
 	for (i = HIBERNATION_FIRST; i <= HIBERNATION_MAX; i++) {
 	for (i = HIBERNATION_FIRST; i <= HIBERNATION_MAX; i++) {
 		if (!hibernation_modes[i])
 		if (!hibernation_modes[i])
 			continue;
 			continue;
@@ -934,6 +948,9 @@ static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr,
 	char *p;
 	char *p;
 	int mode = HIBERNATION_INVALID;
 	int mode = HIBERNATION_INVALID;
 
 
+	if (!hibernation_available())
+		return -EPERM;
+
 	p = memchr(buf, '\n', n);
 	p = memchr(buf, '\n', n);
 	len = p ? p - buf : n;
 	len = p ? p - buf : n;
 
 
@@ -1101,6 +1118,10 @@ static int __init hibernate_setup(char *str)
 		noresume = 1;
 		noresume = 1;
 	else if (!strncmp(str, "nocompress", 10))
 	else if (!strncmp(str, "nocompress", 10))
 		nocompress = 1;
 		nocompress = 1;
+	else if (!strncmp(str, "no", 2)) {
+		noresume = 1;
+		nohibernate = 1;
+	}
 	return 1;
 	return 1;
 }
 }
 
 
@@ -1125,9 +1146,23 @@ static int __init resumedelay_setup(char *str)
 	return 1;
 	return 1;
 }
 }
 
 
+static int __init nohibernate_setup(char *str)
+{
+	noresume = 1;
+	nohibernate = 1;
+	return 1;
+}
+
+static int __init kaslr_nohibernate_setup(char *str)
+{
+	return nohibernate_setup(str);
+}
+
 __setup("noresume", noresume_setup);
 __setup("noresume", noresume_setup);
 __setup("resume_offset=", resume_offset_setup);
 __setup("resume_offset=", resume_offset_setup);
 __setup("resume=", resume_setup);
 __setup("resume=", resume_setup);
 __setup("hibernate=", hibernate_setup);
 __setup("hibernate=", hibernate_setup);
 __setup("resumewait", resumewait_setup);
 __setup("resumewait", resumewait_setup);
 __setup("resumedelay=", resumedelay_setup);
 __setup("resumedelay=", resumedelay_setup);
+__setup("nohibernate", nohibernate_setup);
+__setup("kaslr", kaslr_nohibernate_setup);

+ 2 - 4
kernel/power/main.c

@@ -300,13 +300,11 @@ static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr,
 			s += sprintf(s,"%s ", pm_states[i].label);
 			s += sprintf(s,"%s ", pm_states[i].label);
 
 
 #endif
 #endif
-#ifdef CONFIG_HIBERNATION
-	s += sprintf(s, "%s\n", "disk");
-#else
+	if (hibernation_available())
+		s += sprintf(s, "disk ");
 	if (s != buf)
 	if (s != buf)
 		/* convert the last space to a newline */
 		/* convert the last space to a newline */
 		*(s-1) = '\n';
 		*(s-1) = '\n';
-#endif
 	return (s - buf);
 	return (s - buf);
 }
 }
 
 

+ 3 - 0
kernel/power/user.c

@@ -49,6 +49,9 @@ static int snapshot_open(struct inode *inode, struct file *filp)
 	struct snapshot_data *data;
 	struct snapshot_data *data;
 	int error;
 	int error;
 
 
+	if (!hibernation_available())
+		return -EPERM;
+
 	lock_system_sleep();
 	lock_system_sleep();
 
 
 	if (!atomic_add_unless(&snapshot_device_available, -1, 0)) {
 	if (!atomic_add_unless(&snapshot_device_available, -1, 0)) {