2 * Copyright (C) 2004-2010 Nigel Cunningham (nigel at tuxonice net)
4 * This file is released under the GPLv2.
6 #include <linux/resume-trace.h>
7 #include <linux/kernel.h>
8 #include <linux/swap.h>
9 #include <linux/syscalls.h>
10 #include <linux/bio.h>
11 #include <linux/root_dev.h>
12 #include <linux/freezer.h>
13 #include <linux/reboot.h>
14 #include <linux/writeback.h>
15 #include <linux/tty.h>
16 #include <linux/crypto.h>
17 #include <linux/cpu.h>
18 #include <linux/ctype.h>
19 #include "tuxonice_io.h"
21 #include "tuxonice_extent.h"
22 #include "tuxonice_netlink.h"
23 #include "tuxonice_prepare_image.h"
24 #include "tuxonice_ui.h"
25 #include "tuxonice_sysfs.h"
26 #include "tuxonice_pagedir.h"
27 #include "tuxonice_modules.h"
28 #include "tuxonice_builtin.h"
29 #include "tuxonice_power_off.h"
30 #include "tuxonice_alloc.h"
32 unsigned long toi_bootflags_mask
;
33 EXPORT_SYMBOL_GPL(toi_bootflags_mask
);
36 * Highmem related functions (x86 only).
42 * copyback_high: Restore highmem pages.
44 * Highmem data and pbe lists are/can be stored in highmem.
45 * The format is slightly different to the lowmem pbe lists
46 * used for the assembly code: the last pbe in each page is
47 * a struct page * instead of struct pbe *, pointing to the
48 * next page where pbes are stored (or NULL if happens to be
49 * the end of the list). Since we don't want to generate
50 * unnecessary deltas against swsusp code, we use a cast
54 static void copyback_high(void)
56 struct page
*pbe_page
= (struct page
*)restore_highmem_pblist
;
57 struct pbe
*this_pbe
, *first_pbe
;
58 unsigned long *origpage
, *copypage
;
64 this_pbe
= (struct pbe
*)kmap_atomic(pbe_page
);
68 int loop
= (PAGE_SIZE
/ sizeof(unsigned long)) - 1;
70 origpage
= kmap_atomic(pfn_to_page((unsigned long)this_pbe
->orig_address
));
71 copypage
= kmap_atomic((struct page
*)this_pbe
->address
);
74 *(origpage
+ loop
) = *(copypage
+ loop
);
78 kunmap_atomic(origpage
);
79 kunmap_atomic(copypage
);
84 if (pbe_index
< PBES_PER_PAGE
) {
88 pbe_page
= (struct page
*)this_pbe
->next
;
89 kunmap_atomic(first_pbe
);
92 this_pbe
= (struct pbe
*)kmap_atomic(pbe_page
);
97 kunmap_atomic(first_pbe
);
100 #else /* CONFIG_HIGHMEM */
101 static void copyback_high(void)
106 char toi_wait_for_keypress_dev_console(int timeout
)
108 int fd
, this_timeout
= 255;
110 struct termios t
, t_backup
;
112 /* We should be guaranteed /dev/console exists after populate_rootfs()
115 fd
= sys_open("/dev/console", O_RDONLY
, 0);
117 printk(KERN_INFO
"Couldn't open /dev/console.\n");
121 if (sys_ioctl(fd
, TCGETS
, (long)&t
) < 0)
124 memcpy(&t_backup
, &t
, sizeof(t
));
126 t
.c_lflag
&= ~(ISIG
| ICANON
| ECHO
);
131 this_timeout
= timeout
< 26 ? timeout
: 25;
132 timeout
-= this_timeout
;
136 t
.c_cc
[VTIME
] = this_timeout
;
138 if (sys_ioctl(fd
, TCSETS
, (long)&t
) < 0)
142 if (sys_read(fd
, &key
, 1) <= 0) {
149 if (test_toi_state(TOI_SANITY_CHECK_PROMPT
)) {
151 set_toi_state(TOI_CONTINUE_REQ
);
153 } else if (key
== ' ')
160 sys_ioctl(fd
, TCSETS
, (long)&t_backup
);
166 EXPORT_SYMBOL_GPL(toi_wait_for_keypress_dev_console
);
168 struct toi_boot_kernel_data toi_bkd __nosavedata
__attribute__ ((aligned(PAGE_SIZE
))) = {
169 MY_BOOT_KERNEL_DATA_VERSION
, 0,
170 #ifdef CONFIG_TOI_REPLACE_SWSUSP
171 (1 << TOI_REPLACE_SWSUSP
) |
173 (1 << TOI_NO_FLUSHER_THREAD
) |
174 /* (1 << TOI_NO_MULTITHREADED_IO) | */
175 (1 << TOI_LATE_CPU_HOTPLUG
) | (1 << TOI_PAGESET2_FULL
),};
177 EXPORT_SYMBOL_GPL(toi_bkd
);
179 struct block_device
*toi_open_by_devnum(dev_t dev
)
181 struct block_device
*bdev
= bdget(dev
);
184 err
= blkdev_get(bdev
, FMODE_READ
| FMODE_NDELAY
, NULL
);
185 return err
? ERR_PTR(err
) : bdev
;
187 EXPORT_SYMBOL_GPL(toi_open_by_devnum
);
190 * toi_close_bdev: Close a swap bdev.
192 * int: The swap entry number to close.
194 void toi_close_bdev(struct block_device
*bdev
)
196 blkdev_put(bdev
, FMODE_READ
| FMODE_NDELAY
);
198 EXPORT_SYMBOL_GPL(toi_close_bdev
);
200 int toi_wait
= CONFIG_TOI_DEFAULT_WAIT
;
201 EXPORT_SYMBOL_GPL(toi_wait
);
203 struct toi_core_fns
*toi_core_fns
;
204 EXPORT_SYMBOL_GPL(toi_core_fns
);
206 unsigned long toi_result
;
207 EXPORT_SYMBOL_GPL(toi_result
);
209 struct pagedir pagedir1
= { 1 };
211 EXPORT_SYMBOL_GPL(pagedir1
);
213 unsigned long toi_get_nonconflicting_page(void)
215 return toi_core_fns
->get_nonconflicting_page();
218 int toi_post_context_save(void)
220 return toi_core_fns
->post_context_save();
223 int try_tuxonice_hibernate(void)
228 return toi_core_fns
->try_hibernate();
231 static int num_resume_calls
;
232 #ifdef CONFIG_TOI_IGNORE_LATE_INITCALL
233 static int ignore_late_initcall
= 1;
235 static int ignore_late_initcall
;
238 #ifdef CONFIG_TOI_ENHANCE
239 int toi_ignore_late_initcall(void)
241 return ignore_late_initcall
;
243 EXPORT_SYMBOL_GPL(toi_ignore_late_initcall
);
246 int toi_translate_err_default
= TOI_CONTINUE_REQ
;
247 EXPORT_SYMBOL_GPL(toi_translate_err_default
);
249 void try_tuxonice_resume(void)
251 /* Don't let it wrap around eventually */
252 if (num_resume_calls
< 2)
255 if (num_resume_calls
== 1 && ignore_late_initcall
) {
256 printk(KERN_INFO
"TuxOnIce: Ignoring late initcall, as requested.\n");
261 toi_core_fns
->try_resume();
263 printk(KERN_INFO
"TuxOnIce core not loaded yet.\n");
266 int toi_lowlevel_builtin(void)
270 save_processor_state();
271 error
= swsusp_arch_suspend();
273 printk(KERN_ERR
"Error %d hibernating\n", error
);
275 #ifdef CONFIG_TOI_ENHANCE
276 if (test_result_state(TOI_ARCH_PREPARE_FAILED
)) {
277 hib_err("CAUTION: error(%d/0x%08x)\n", error
, (unsigned int)toi_result
);
281 /* Restore control flow appears here */
282 if (!toi_in_hibernate
) {
284 set_toi_state(TOI_NOW_RESUMING
);
287 restore_processor_state();
290 EXPORT_SYMBOL_GPL(toi_lowlevel_builtin
);
292 unsigned long toi_compress_bytes_in
;
293 EXPORT_SYMBOL_GPL(toi_compress_bytes_in
);
295 unsigned long toi_compress_bytes_out
;
296 EXPORT_SYMBOL_GPL(toi_compress_bytes_out
);
298 int toi_in_suspend(void)
302 EXPORT_SYMBOL_GPL(toi_in_suspend
);
304 unsigned long toi_state
= ((1 << TOI_BOOT_TIME
) |
305 (1 << TOI_IGNORE_LOGLEVEL
) | (1 << TOI_IO_STOPPED
));
306 EXPORT_SYMBOL_GPL(toi_state
);
308 /* The number of hibernates we have started (some may have been cancelled) */
309 unsigned int nr_hibernates
;
310 EXPORT_SYMBOL_GPL(nr_hibernates
);
313 EXPORT_SYMBOL_GPL(toi_running
);
315 __nosavedata
int toi_in_hibernate
;
316 EXPORT_SYMBOL_GPL(toi_in_hibernate
);
318 __nosavedata
struct pbe
*restore_highmem_pblist
;
319 EXPORT_SYMBOL_GPL(restore_highmem_pblist
);
321 int toi_trace_allocs
;
322 EXPORT_SYMBOL_GPL(toi_trace_allocs
);
324 void toi_read_lock_tasklist(void)
326 read_lock(&tasklist_lock
);
328 EXPORT_SYMBOL_GPL(toi_read_lock_tasklist
);
330 void toi_read_unlock_tasklist(void)
332 read_unlock(&tasklist_lock
);
334 EXPORT_SYMBOL_GPL(toi_read_unlock_tasklist
);
336 #ifdef CONFIG_TOI_ZRAM_SUPPORT
337 int (*toi_flag_zram_disks
) (void);
338 EXPORT_SYMBOL_GPL(toi_flag_zram_disks
);
340 int toi_do_flag_zram_disks(void)
342 return toi_flag_zram_disks
? (*toi_flag_zram_disks
) () : 0;
344 EXPORT_SYMBOL_GPL(toi_do_flag_zram_disks
);
347 static int __init
toi_wait_setup(char *str
)
351 if (sscanf(str
, "=%d", &value
)) {
352 if (value
< -1 || value
> 255)
353 printk(KERN_INFO
"TuxOnIce_wait outside range -1 to " "255.\n");
361 __setup("toi_wait", toi_wait_setup
);
363 static int __init
toi_translate_retry_setup(char *str
)
365 toi_translate_err_default
= 0;
369 __setup("toi_translate_retry", toi_translate_retry_setup
);
371 static int __init
toi_debug_setup(char *str
)
373 toi_bkd
.toi_action
|= (1 << TOI_LOGALL
);
374 toi_bootflags_mask
|= (1 << TOI_LOGALL
);
375 toi_bkd
.toi_debug_state
= 255;
376 toi_bkd
.toi_default_console_level
= 7;
380 __setup("toi_debug_setup", toi_debug_setup
);
382 static int __init
toi_pause_setup(char *str
)
384 toi_bkd
.toi_action
|= (1 << TOI_PAUSE
);
385 toi_bootflags_mask
|= (1 << TOI_PAUSE
);
389 __setup("toi_pause", toi_pause_setup
);
391 #ifdef CONFIG_PM_DEBUG
392 static int __init
toi_trace_allocs_setup(char *str
)
396 if (sscanf(str
, "=%d", &value
))
397 toi_trace_allocs
= value
;
402 __setup("toi_trace_allocs", toi_trace_allocs_setup
);
405 static int __init
toi_ignore_late_initcall_setup(char *str
)
409 if (sscanf(str
, "=%d", &value
))
410 ignore_late_initcall
= value
;
415 __setup("toi_initramfs_resume_only", toi_ignore_late_initcall_setup
);
417 static int __init
toi_force_no_multithreaded_setup(char *str
)
421 toi_bkd
.toi_action
&= ~(1 << TOI_NO_MULTITHREADED_IO
);
422 toi_bootflags_mask
|= (1 << TOI_NO_MULTITHREADED_IO
);
424 if (sscanf(str
, "=%d", &value
) && value
)
425 toi_bkd
.toi_action
|= (1 << TOI_NO_MULTITHREADED_IO
);
430 __setup("toi_no_multithreaded", toi_force_no_multithreaded_setup
);
433 static int __init
toi_post_resume_breakpoint_setup(char *str
)
437 toi_bkd
.toi_action
&= ~(1 << TOI_POST_RESUME_BREAKPOINT
);
438 toi_bootflags_mask
|= (1 << TOI_POST_RESUME_BREAKPOINT
);
439 if (sscanf(str
, "=%d", &value
) && value
)
440 toi_bkd
.toi_action
|= (1 << TOI_POST_RESUME_BREAKPOINT
);
445 __setup("toi_post_resume_break", toi_post_resume_breakpoint_setup
);
448 static int __init
toi_disable_readahead_setup(char *str
)
452 toi_bkd
.toi_action
&= ~(1 << TOI_NO_READAHEAD
);
453 toi_bootflags_mask
|= (1 << TOI_NO_READAHEAD
);
454 if (sscanf(str
, "=%d", &value
) && value
)
455 toi_bkd
.toi_action
|= (1 << TOI_NO_READAHEAD
);
460 __setup("toi_no_readahead", toi_disable_readahead_setup
);