xnu_resume.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. /*
  2. * GRUB -- GRand Unified Bootloader
  3. * Copyright (C) 2009 Free Software Foundation, Inc.
  4. *
  5. * GRUB is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * GRUB is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include <grub/normal.h>
  19. #include <grub/dl.h>
  20. #include <grub/file.h>
  21. #include <grub/disk.h>
  22. #include <grub/misc.h>
  23. #include <grub/xnu.h>
  24. #include <grub/cpu/xnu.h>
  25. #include <grub/mm.h>
  26. #include <grub/loader.h>
  27. #include <grub/i18n.h>
  28. static void *grub_xnu_hibernate_image;
  29. static grub_err_t
  30. grub_xnu_resume_unload (void)
  31. {
  32. /* Free loaded image */
  33. if (grub_xnu_hibernate_image)
  34. grub_free (grub_xnu_hibernate_image);
  35. grub_xnu_hibernate_image = 0;
  36. grub_xnu_unlock ();
  37. return GRUB_ERR_NONE;
  38. }
  39. grub_err_t
  40. grub_xnu_resume (char *imagename)
  41. {
  42. grub_file_t file;
  43. grub_size_t total_header_size;
  44. struct grub_xnu_hibernate_header hibhead;
  45. void *code;
  46. void *image;
  47. grub_uint32_t codedest;
  48. grub_uint32_t codesize;
  49. grub_addr_t target_image;
  50. grub_err_t err;
  51. grub_file_filter_disable_compression ();
  52. file = grub_file_open (imagename);
  53. if (! file)
  54. return 0;
  55. /* Read the header. */
  56. if (grub_file_read (file, &hibhead, sizeof (hibhead))
  57. != sizeof (hibhead))
  58. {
  59. grub_file_close (file);
  60. if (!grub_errno)
  61. grub_error (GRUB_ERR_READ_ERROR,
  62. N_("premature end of file %s"), imagename);
  63. return grub_errno;
  64. }
  65. /* Check the header. */
  66. if (hibhead.magic != GRUB_XNU_HIBERNATE_MAGIC)
  67. {
  68. grub_file_close (file);
  69. return grub_error (GRUB_ERR_BAD_OS,
  70. "hibernate header has incorrect magic number");
  71. }
  72. if (hibhead.encoffset)
  73. {
  74. grub_file_close (file);
  75. return grub_error (GRUB_ERR_BAD_OS,
  76. "encrypted images aren't supported yet");
  77. }
  78. if (hibhead.image_size == 0)
  79. {
  80. grub_file_close (file);
  81. return grub_error (GRUB_ERR_BAD_OS,
  82. "hibernate image is empty");
  83. }
  84. codedest = hibhead.launchcode_target_page;
  85. codedest *= GRUB_XNU_PAGESIZE;
  86. codesize = hibhead.launchcode_numpages;
  87. codesize *= GRUB_XNU_PAGESIZE;
  88. /* FIXME: check that codedest..codedest+codesize is available. */
  89. /* Calculate total size before pages to copy. */
  90. total_header_size = hibhead.extmapsize + sizeof (hibhead);
  91. /* Unload image if any. */
  92. if (grub_xnu_hibernate_image)
  93. grub_free (grub_xnu_hibernate_image);
  94. /* Try to allocate necessary space.
  95. FIXME: mm isn't good enough yet to handle huge allocations.
  96. */
  97. grub_xnu_relocator = grub_relocator_new ();
  98. if (!grub_xnu_relocator)
  99. {
  100. grub_file_close (file);
  101. return grub_errno;
  102. }
  103. {
  104. grub_relocator_chunk_t ch;
  105. err = grub_relocator_alloc_chunk_addr (grub_xnu_relocator, &ch, codedest,
  106. codesize + GRUB_XNU_PAGESIZE);
  107. if (err)
  108. {
  109. grub_file_close (file);
  110. return err;
  111. }
  112. code = get_virtual_current_address (ch);
  113. }
  114. {
  115. grub_relocator_chunk_t ch;
  116. err = grub_relocator_alloc_chunk_align (grub_xnu_relocator, &ch, 0,
  117. (0xffffffff - hibhead.image_size) + 1,
  118. hibhead.image_size,
  119. GRUB_XNU_PAGESIZE,
  120. GRUB_RELOCATOR_PREFERENCE_NONE, 0);
  121. if (err)
  122. {
  123. grub_file_close (file);
  124. return err;
  125. }
  126. image = get_virtual_current_address (ch);
  127. target_image = get_physical_target_address (ch);
  128. }
  129. /* Read code part. */
  130. if (grub_file_seek (file, total_header_size) == (grub_off_t) -1
  131. || grub_file_read (file, code, codesize)
  132. != (grub_ssize_t) codesize)
  133. {
  134. grub_file_close (file);
  135. if (!grub_errno)
  136. grub_error (GRUB_ERR_READ_ERROR,
  137. N_("premature end of file %s"), imagename);
  138. return grub_errno;
  139. }
  140. /* Read image. */
  141. if (grub_file_seek (file, 0) == (grub_off_t) -1
  142. || grub_file_read (file, image, hibhead.image_size)
  143. != (grub_ssize_t) hibhead.image_size)
  144. {
  145. grub_file_close (file);
  146. if (!grub_errno)
  147. grub_error (GRUB_ERR_READ_ERROR,
  148. N_("premature end of file %s"), imagename);
  149. return grub_errno;
  150. }
  151. grub_file_close (file);
  152. /* Setup variables needed by asm helper. */
  153. grub_xnu_heap_target_start = codedest;
  154. grub_xnu_heap_size = target_image + hibhead.image_size - codedest;
  155. grub_xnu_stack = (codedest + hibhead.stack);
  156. grub_xnu_entry_point = (codedest + hibhead.entry_point);
  157. grub_xnu_arg1 = target_image;
  158. grub_dprintf ("xnu", "entry point 0x%x\n", codedest + hibhead.entry_point);
  159. grub_dprintf ("xnu", "image at 0x%x\n",
  160. codedest + codesize + GRUB_XNU_PAGESIZE);
  161. /* We're ready now. */
  162. grub_loader_set (grub_xnu_boot_resume,
  163. grub_xnu_resume_unload, 0);
  164. /* Prevent module from unloading. */
  165. grub_xnu_lock ();
  166. return GRUB_ERR_NONE;
  167. }