hibernate.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Hibernation support specific for ARM
  4. *
  5. * Derived from work on ARM hibernation support by:
  6. *
  7. * Ubuntu project, hibernation support for mach-dove
  8. * Copyright (C) 2010 Nokia Corporation (Hiroshi Doyu)
  9. * Copyright (C) 2010 Texas Instruments, Inc. (Teerth Reddy et al.)
  10. * https://lkml.org/lkml/2010/6/18/4
  11. * https://lists.linux-foundation.org/pipermail/linux-pm/2010-June/027422.html
  12. * https://patchwork.kernel.org/patch/96442/
  13. *
  14. * Copyright (C) 2006 Rafael J. Wysocki <rjw@sisk.pl>
  15. */
  16. #include <linux/mm.h>
  17. #include <linux/suspend.h>
  18. #include <asm/system_misc.h>
  19. #include <asm/idmap.h>
  20. #include <asm/suspend.h>
  21. #include <asm/memory.h>
  22. #include <asm/sections.h>
  23. #include "reboot.h"
  24. int pfn_is_nosave(unsigned long pfn)
  25. {
  26. unsigned long nosave_begin_pfn = virt_to_pfn(&__nosave_begin);
  27. unsigned long nosave_end_pfn = virt_to_pfn(&__nosave_end - 1);
  28. return (pfn >= nosave_begin_pfn) && (pfn <= nosave_end_pfn);
  29. }
  30. void notrace save_processor_state(void)
  31. {
  32. WARN_ON(num_online_cpus() != 1);
  33. local_fiq_disable();
  34. }
  35. void notrace restore_processor_state(void)
  36. {
  37. local_fiq_enable();
  38. }
  39. /*
  40. * Snapshot kernel memory and reset the system.
  41. *
  42. * swsusp_save() is executed in the suspend finisher so that the CPU
  43. * context pointer and memory are part of the saved image, which is
  44. * required by the resume kernel image to restart execution from
  45. * swsusp_arch_suspend().
  46. *
  47. * soft_restart is not technically needed, but is used to get success
  48. * returned from cpu_suspend.
  49. *
  50. * When soft reboot completes, the hibernation snapshot is written out.
  51. */
  52. static int notrace arch_save_image(unsigned long unused)
  53. {
  54. int ret;
  55. ret = swsusp_save();
  56. if (ret == 0)
  57. _soft_restart(virt_to_idmap(cpu_resume), false);
  58. return ret;
  59. }
  60. /*
  61. * Save the current CPU state before suspend / poweroff.
  62. */
  63. int notrace swsusp_arch_suspend(void)
  64. {
  65. return cpu_suspend(0, arch_save_image);
  66. }
  67. /*
  68. * Restore page contents for physical pages that were in use during loading
  69. * hibernation image. Switch to idmap_pgd so the physical page tables
  70. * are overwritten with the same contents.
  71. */
  72. static void notrace arch_restore_image(void *unused)
  73. {
  74. struct pbe *pbe;
  75. cpu_switch_mm(idmap_pgd, &init_mm);
  76. for (pbe = restore_pblist; pbe; pbe = pbe->next)
  77. copy_page(pbe->orig_address, pbe->address);
  78. _soft_restart(virt_to_idmap(cpu_resume), false);
  79. }
  80. static u64 resume_stack[PAGE_SIZE/2/sizeof(u64)] __nosavedata;
  81. /*
  82. * Resume from the hibernation image.
  83. * Due to the kernel heap / data restore, stack contents change underneath
  84. * and that would make function calls impossible; switch to a temporary
  85. * stack within the nosave region to avoid that problem.
  86. */
  87. int swsusp_arch_resume(void)
  88. {
  89. call_with_stack(arch_restore_image, 0,
  90. resume_stack + ARRAY_SIZE(resume_stack));
  91. return 0;
  92. }