tuxonice_builtin.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. /*
  2. * Copyright (C) 2004-2014 Nigel Cunningham (nigel at tuxonice net)
  3. *
  4. * This file is released under the GPLv2.
  5. */
  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 <linux/kthread.h>
  20. #include "tuxonice_io.h"
  21. #include "tuxonice.h"
  22. #include "tuxonice_extent.h"
  23. #include "tuxonice_netlink.h"
  24. #include "tuxonice_prepare_image.h"
  25. #include "tuxonice_ui.h"
  26. #include "tuxonice_sysfs.h"
  27. #include "tuxonice_pagedir.h"
  28. #include "tuxonice_modules.h"
  29. #include "tuxonice_builtin.h"
  30. #include "tuxonice_power_off.h"
  31. #include "tuxonice_alloc.h"
  32. unsigned long toi_bootflags_mask;
  33. EXPORT_SYMBOL_GPL(toi_bootflags_mask);
  34. /*
  35. * Highmem related functions (x86 only).
  36. */
  37. #ifdef CONFIG_HIGHMEM
  38. /**
  39. * copyback_high: Restore highmem pages.
  40. *
  41. * Highmem data and pbe lists are/can be stored in highmem.
  42. * The format is slightly different to the lowmem pbe lists
  43. * used for the assembly code: the last pbe in each page is
  44. * a struct page * instead of struct pbe *, pointing to the
  45. * next page where pbes are stored (or NULL if happens to be
  46. * the end of the list). Since we don't want to generate
  47. * unnecessary deltas against swsusp code, we use a cast
  48. * instead of a union.
  49. **/
  50. static void copyback_high(void)
  51. {
  52. struct page *pbe_page = (struct page *)restore_highmem_pblist;
  53. struct pbe *this_pbe, *first_pbe;
  54. unsigned long *origpage, *copypage;
  55. int pbe_index = 1;
  56. if (!pbe_page)
  57. return;
  58. this_pbe = (struct pbe *)kmap_atomic(pbe_page);
  59. first_pbe = this_pbe;
  60. while (this_pbe) {
  61. int loop = (PAGE_SIZE / sizeof(unsigned long)) - 1;
  62. origpage = kmap_atomic(pfn_to_page((unsigned long)this_pbe->orig_address));
  63. copypage = kmap_atomic((struct page *)this_pbe->address);
  64. while (loop >= 0) {
  65. *(origpage + loop) = *(copypage + loop);
  66. loop--;
  67. }
  68. kunmap_atomic(origpage);
  69. kunmap_atomic(copypage);
  70. if (!this_pbe->next)
  71. break;
  72. if (pbe_index < PBES_PER_PAGE) {
  73. this_pbe++;
  74. pbe_index++;
  75. } else {
  76. pbe_page = (struct page *)this_pbe->next;
  77. kunmap_atomic(first_pbe);
  78. if (!pbe_page)
  79. return;
  80. this_pbe = (struct pbe *)kmap_atomic(pbe_page);
  81. first_pbe = this_pbe;
  82. pbe_index = 1;
  83. }
  84. }
  85. kunmap_atomic(first_pbe);
  86. }
  87. #else /* CONFIG_HIGHMEM */
  88. static void copyback_high(void)
  89. {
  90. }
  91. #endif
  92. char toi_wait_for_keypress_dev_console(int timeout)
  93. {
  94. int fd, this_timeout = 255, orig_kthread = 0;
  95. char key = '\0';
  96. struct termios t, t_backup;
  97. /* We should be guaranteed /dev/console exists after populate_rootfs()
  98. * in init/main.c.
  99. */
  100. fd = sys_open("/dev/console", O_RDONLY, 0);
  101. if (fd < 0) {
  102. pr_warn("Couldn't open /dev/console.\n");
  103. return key;
  104. }
  105. if (sys_ioctl(fd, TCGETS, (long)&t) < 0)
  106. goto out_close;
  107. memcpy(&t_backup, &t, sizeof(t));
  108. t.c_lflag &= ~(ISIG | ICANON | ECHO);
  109. t.c_cc[VMIN] = 0;
  110. new_timeout:
  111. if (timeout > 0) {
  112. this_timeout = timeout < 26 ? timeout : 25;
  113. timeout -= this_timeout;
  114. this_timeout *= 10;
  115. }
  116. t.c_cc[VTIME] = this_timeout;
  117. if (sys_ioctl(fd, TCSETS, (long)&t) < 0)
  118. goto out_restore;
  119. if (current->flags & PF_KTHREAD) {
  120. orig_kthread = (current->flags & PF_KTHREAD);
  121. current->flags &= ~PF_KTHREAD;
  122. }
  123. while (1) {
  124. if (sys_read(fd, &key, 1) <= 0) {
  125. if (timeout)
  126. goto new_timeout;
  127. key = '\0';
  128. break;
  129. }
  130. key = tolower(key);
  131. if (test_toi_state(TOI_SANITY_CHECK_PROMPT)) {
  132. if (key == 'c') {
  133. set_toi_state(TOI_CONTINUE_REQ);
  134. break;
  135. } else if (key == ' ')
  136. break;
  137. } else
  138. break;
  139. }
  140. if (orig_kthread)
  141. current->flags |= PF_KTHREAD;
  142. out_restore:
  143. sys_ioctl(fd, TCSETS, (long)&t_backup);
  144. out_close:
  145. sys_close(fd);
  146. return key;
  147. }
  148. EXPORT_SYMBOL_GPL(toi_wait_for_keypress_dev_console);
  149. struct toi_boot_kernel_data __nosavedata __aligned(PAGE_SIZE) toi_bkd = {
  150. MY_BOOT_KERNEL_DATA_VERSION,
  151. 0,
  152. #ifdef CONFIG_TOI_REPLACE_SWSUSP
  153. (1 << TOI_REPLACE_SWSUSP) |
  154. #endif
  155. (1 << TOI_NO_FLUSHER_THREAD) | (1 << TOI_PAGESET2_FULL)
  156. };
  157. EXPORT_SYMBOL_GPL(toi_bkd);
  158. struct block_device *toi_open_by_devnum(dev_t dev)
  159. {
  160. struct block_device *bdev = bdget(dev);
  161. int err = -ENOMEM;
  162. if (bdev)
  163. err = blkdev_get(bdev, FMODE_READ | FMODE_NDELAY, NULL);
  164. return err ? ERR_PTR(err) : bdev;
  165. }
  166. EXPORT_SYMBOL_GPL(toi_open_by_devnum);
  167. /**
  168. * toi_close_bdev: Close a swap bdev.
  169. *
  170. * int: The swap entry number to close.
  171. */
  172. void toi_close_bdev(struct block_device *bdev)
  173. {
  174. blkdev_put(bdev, FMODE_READ | FMODE_NDELAY);
  175. }
  176. EXPORT_SYMBOL_GPL(toi_close_bdev);
  177. int toi_wait = CONFIG_TOI_DEFAULT_WAIT;
  178. EXPORT_SYMBOL_GPL(toi_wait);
  179. struct toi_core_fns *toi_core_fns;
  180. EXPORT_SYMBOL_GPL(toi_core_fns);
  181. unsigned long toi_result;
  182. EXPORT_SYMBOL_GPL(toi_result);
  183. struct pagedir pagedir1 = { 1 };
  184. EXPORT_SYMBOL_GPL(pagedir1);
  185. unsigned long toi_get_nonconflicting_page(void)
  186. {
  187. return toi_core_fns->get_nonconflicting_page();
  188. }
  189. int toi_post_context_save(void)
  190. {
  191. return toi_core_fns->post_context_save();
  192. }
  193. int try_tuxonice_hibernate(void)
  194. {
  195. if (!toi_core_fns)
  196. return -ENODEV;
  197. return toi_core_fns->try_hibernate();
  198. }
  199. static int num_resume_calls;
  200. #ifdef CONFIG_TOI_IGNORE_LATE_INITCALL
  201. static int ignore_late_initcall = 1;
  202. #else
  203. static int ignore_late_initcall;
  204. #endif
  205. #ifdef CONFIG_TOI_ENHANCE
  206. int toi_ignore_late_initcall(void)
  207. {
  208. return ignore_late_initcall;
  209. }
  210. EXPORT_SYMBOL_GPL(toi_ignore_late_initcall);
  211. #endif
  212. int toi_translate_err_default = TOI_CONTINUE_REQ;
  213. EXPORT_SYMBOL_GPL(toi_translate_err_default);
  214. void try_tuxonice_resume(void)
  215. {
  216. if (!hibernation_available())
  217. return;
  218. /* Don't let it wrap around eventually */
  219. if (num_resume_calls < 2)
  220. num_resume_calls++;
  221. if (num_resume_calls == 1 && ignore_late_initcall) {
  222. pr_warn("TuxOnIce: Ignoring late initcall, as requested.\n");
  223. return;
  224. }
  225. if (toi_core_fns)
  226. toi_core_fns->try_resume();
  227. else
  228. pr_warn("TuxOnIce core not loaded yet.\n");
  229. }
  230. int toi_lowlevel_builtin(void)
  231. {
  232. int error = 0;
  233. save_processor_state();
  234. error = swsusp_arch_suspend();
  235. if (error)
  236. pr_err("Error %d hibernating\n", error);
  237. #ifdef CONFIG_TOI_ENHANCE
  238. if (test_result_state(TOI_ARCH_PREPARE_FAILED))
  239. hib_err("CAUTION: error(%d/0x%08x)\n", error, (unsigned int)toi_result);
  240. #endif
  241. /* Restore control flow appears here */
  242. if (!toi_in_hibernate) {
  243. copyback_high();
  244. set_toi_state(TOI_NOW_RESUMING);
  245. }
  246. restore_processor_state();
  247. return error;
  248. }
  249. EXPORT_SYMBOL_GPL(toi_lowlevel_builtin);
  250. unsigned long toi_compress_bytes_in;
  251. EXPORT_SYMBOL_GPL(toi_compress_bytes_in);
  252. unsigned long toi_compress_bytes_out;
  253. EXPORT_SYMBOL_GPL(toi_compress_bytes_out);
  254. int toi_in_suspend(void)
  255. {
  256. return in_suspend;
  257. }
  258. EXPORT_SYMBOL_GPL(toi_in_suspend);
  259. unsigned long toi_state = ((1 << TOI_BOOT_TIME) |
  260. (1 << TOI_IGNORE_LOGLEVEL) | (1 << TOI_IO_STOPPED));
  261. EXPORT_SYMBOL_GPL(toi_state);
  262. /* The number of hibernates we have started (some may have been cancelled) */
  263. unsigned int nr_hibernates;
  264. EXPORT_SYMBOL_GPL(nr_hibernates);
  265. int toi_running;
  266. EXPORT_SYMBOL_GPL(toi_running);
  267. __nosavedata int toi_in_hibernate;
  268. EXPORT_SYMBOL_GPL(toi_in_hibernate);
  269. __nosavedata struct pbe *restore_highmem_pblist;
  270. EXPORT_SYMBOL_GPL(restore_highmem_pblist);
  271. int toi_trace_allocs;
  272. EXPORT_SYMBOL_GPL(toi_trace_allocs);
  273. void toi_read_lock_tasklist(void)
  274. {
  275. read_lock(&tasklist_lock);
  276. }
  277. EXPORT_SYMBOL_GPL(toi_read_lock_tasklist);
  278. void toi_read_unlock_tasklist(void)
  279. {
  280. read_unlock(&tasklist_lock);
  281. }
  282. EXPORT_SYMBOL_GPL(toi_read_unlock_tasklist);
  283. #ifdef CONFIG_TOI_ZRAM_SUPPORT
  284. int (*toi_flag_zram_disks)(void);
  285. int toi_do_flag_zram_disks(void)
  286. {
  287. return toi_flag_zram_disks ? (*toi_flag_zram_disks) () : 0;
  288. }
  289. EXPORT_SYMBOL_GPL(toi_do_flag_zram_disks);
  290. #endif
  291. static int __init toi_wait_setup(char *str)
  292. {
  293. int value;
  294. if (sscanf(str, "=%d", &value) == 1) {
  295. if (value < -1 || value > 255)
  296. pr_warn("TuxOnIce_wait outside range -1 to " "255.\n");
  297. else
  298. toi_wait = value;
  299. }
  300. return 1;
  301. }
  302. __setup("toi_wait", toi_wait_setup);
  303. static int __init toi_translate_retry_setup(char *str)
  304. {
  305. toi_translate_err_default = 0;
  306. return 1;
  307. }
  308. __setup("toi_translate_retry", toi_translate_retry_setup);
  309. static int __init toi_debug_setup(char *str)
  310. {
  311. toi_bkd.toi_action |= (1 << TOI_LOGALL);
  312. toi_bootflags_mask |= (1 << TOI_LOGALL);
  313. toi_bkd.toi_debug_state = 255;
  314. toi_bkd.toi_default_console_level = 7;
  315. return 1;
  316. }
  317. __setup("toi_debug_setup", toi_debug_setup);
  318. static int __init toi_pause_setup(char *str)
  319. {
  320. toi_bkd.toi_action |= (1 << TOI_PAUSE);
  321. toi_bootflags_mask |= (1 << TOI_PAUSE);
  322. return 1;
  323. }
  324. __setup("toi_pause", toi_pause_setup);
  325. #ifdef CONFIG_PM_DEBUG
  326. static int __init toi_trace_allocs_setup(char *str)
  327. {
  328. int value;
  329. if (sscanf(str, "=%d", &value) == 1)
  330. toi_trace_allocs = value;
  331. return 1;
  332. }
  333. __setup("toi_trace_allocs", toi_trace_allocs_setup);
  334. #endif
  335. static int __init toi_ignore_late_initcall_setup(char *str)
  336. {
  337. int value;
  338. if (sscanf(str, "=%d", &value) == 1)
  339. ignore_late_initcall = value;
  340. return 1;
  341. }
  342. __setup("toi_initramfs_resume_only", toi_ignore_late_initcall_setup);
  343. static int __init toi_force_no_multithreaded_setup(char *str)
  344. {
  345. int value;
  346. toi_bkd.toi_action &= ~(1 << TOI_NO_MULTITHREADED_IO);
  347. toi_bootflags_mask |= (1 << TOI_NO_MULTITHREADED_IO);
  348. if (sscanf(str, "=%d", &value) == 1 && value)
  349. toi_bkd.toi_action |= (1 << TOI_NO_MULTITHREADED_IO);
  350. return 1;
  351. }
  352. __setup("toi_no_multithreaded", toi_force_no_multithreaded_setup);
  353. #ifdef CONFIG_KGDB
  354. static int __init toi_post_resume_breakpoint_setup(char *str)
  355. {
  356. int value;
  357. toi_bkd.toi_action &= ~(1 << TOI_POST_RESUME_BREAKPOINT);
  358. toi_bootflags_mask |= (1 << TOI_POST_RESUME_BREAKPOINT);
  359. if (sscanf(str, "=%d", &value) == 1 && value)
  360. toi_bkd.toi_action |= (1 << TOI_POST_RESUME_BREAKPOINT);
  361. return 1;
  362. }
  363. __setup("toi_post_resume_break", toi_post_resume_breakpoint_setup);
  364. #endif
  365. static int __init toi_disable_readahead_setup(char *str)
  366. {
  367. int value;
  368. toi_bkd.toi_action &= ~(1 << TOI_NO_READAHEAD);
  369. toi_bootflags_mask |= (1 << TOI_NO_READAHEAD);
  370. if (sscanf(str, "=%d", &value) == 1 && value)
  371. toi_bkd.toi_action |= (1 << TOI_NO_READAHEAD);
  372. return 1;
  373. }
  374. __setup("toi_no_readahead", toi_disable_readahead_setup);