symbols.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. /* Code for managing symbols and pointers in efiemu */
  2. /*
  3. * GRUB -- GRand Unified Bootloader
  4. * Copyright (C) 2009 Free Software Foundation, Inc.
  5. *
  6. * GRUB is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * GRUB is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include <grub/err.h>
  20. #include <grub/mm.h>
  21. #include <grub/misc.h>
  22. #include <grub/efiemu/efiemu.h>
  23. #include <grub/efiemu/runtime.h>
  24. GRUB_EXPORT(grub_efiemu_set_virtual_address_map);
  25. static int ptv_written = 0;
  26. static int ptv_alloc = 0;
  27. static int ptv_handle = 0;
  28. static int relocated_handle = 0;
  29. static int ptv_requested = 0;
  30. static struct grub_efiemu_sym *efiemu_syms = 0;
  31. struct grub_efiemu_sym
  32. {
  33. struct grub_efiemu_sym *next;
  34. char *name;
  35. int handle;
  36. grub_off_t off;
  37. };
  38. void
  39. grub_efiemu_free_syms (void)
  40. {
  41. struct grub_efiemu_sym *cur, *d;
  42. for (cur = efiemu_syms; cur;)
  43. {
  44. d = cur->next;
  45. grub_free (cur->name);
  46. grub_free (cur);
  47. cur = d;
  48. }
  49. efiemu_syms = 0;
  50. ptv_written = 0;
  51. ptv_alloc = 0;
  52. ptv_requested = 0;
  53. grub_efiemu_mm_return_request (ptv_handle);
  54. ptv_handle = 0;
  55. grub_efiemu_mm_return_request (relocated_handle);
  56. relocated_handle = 0;
  57. }
  58. /* Announce that the module will need NUM allocators */
  59. /* Because of deferred memory allocation all the relocators have to be
  60. announced during phase 1*/
  61. grub_err_t
  62. grub_efiemu_request_symbols (int num)
  63. {
  64. if (ptv_alloc)
  65. return grub_error (GRUB_ERR_BAD_ARGUMENT,
  66. "symbols have already been allocated");
  67. if (num < 0)
  68. return grub_error (GRUB_ERR_BAD_ARGUMENT,
  69. "can't request negative symbols");
  70. ptv_requested += num;
  71. return GRUB_ERR_NONE;
  72. }
  73. /* Resolve the symbol name NAME and set HANDLE and OFF accordingly */
  74. grub_err_t
  75. grub_efiemu_resolve_symbol (const char *name, int *handle, grub_off_t *off)
  76. {
  77. struct grub_efiemu_sym *cur;
  78. for (cur = efiemu_syms; cur; cur = cur->next)
  79. if (!grub_strcmp (name, cur->name))
  80. {
  81. *handle = cur->handle;
  82. *off = cur->off;
  83. return GRUB_ERR_NONE;
  84. }
  85. grub_dprintf ("efiemu", "%s not found\n", name);
  86. return grub_error (GRUB_ERR_BAD_OS, "symbol %s isn't found", name);
  87. }
  88. /* Register symbol named NAME in memory handle HANDLE at offset OFF */
  89. grub_err_t
  90. grub_efiemu_register_symbol (const char *name, int handle, grub_off_t off)
  91. {
  92. struct grub_efiemu_sym *cur;
  93. cur = (struct grub_efiemu_sym *) grub_malloc (sizeof (*cur));
  94. grub_dprintf ("efiemu", "registering symbol '%s'\n", name);
  95. if (!cur)
  96. return grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't register symbol");
  97. cur->name = grub_strdup (name);
  98. cur->next = efiemu_syms;
  99. cur->handle = handle;
  100. cur->off = off;
  101. efiemu_syms = cur;
  102. return 0;
  103. }
  104. /* Go from phase 1 to phase 2. Must be called before similar function in mm.c */
  105. grub_err_t
  106. grub_efiemu_alloc_syms (void)
  107. {
  108. ptv_alloc = ptv_requested;
  109. ptv_handle = grub_efiemu_request_memalign
  110. (1, (ptv_requested + 1) * sizeof (struct grub_efiemu_ptv_rel),
  111. GRUB_EFI_RUNTIME_SERVICES_DATA);
  112. relocated_handle = grub_efiemu_request_memalign
  113. (1, sizeof (grub_uint8_t), GRUB_EFI_RUNTIME_SERVICES_DATA);
  114. grub_efiemu_register_symbol ("efiemu_ptv_relocated", relocated_handle, 0);
  115. grub_efiemu_register_symbol ("efiemu_ptv_relloc", ptv_handle, 0);
  116. return grub_errno;
  117. }
  118. grub_err_t
  119. grub_efiemu_write_sym_markers (void)
  120. {
  121. struct grub_efiemu_ptv_rel *ptv_rels
  122. = grub_efiemu_mm_obtain_request (ptv_handle);
  123. grub_uint8_t *relocated = grub_efiemu_mm_obtain_request (relocated_handle);
  124. grub_memset (ptv_rels, 0, (ptv_requested + 1)
  125. * sizeof (struct grub_efiemu_ptv_rel));
  126. *relocated = 0;
  127. return GRUB_ERR_NONE;
  128. }
  129. /* Write value (pointer to memory PLUS_HANDLE)
  130. - (pointer to memory MINUS_HANDLE) + VALUE to ADDR assuming that the
  131. size SIZE bytes. If PTV_NEEDED is 1 then announce it to runtime that this
  132. value needs to be recomputed before going to virtual mode
  133. */
  134. grub_err_t
  135. grub_efiemu_write_value (void *addr, grub_uint32_t value, int plus_handle,
  136. int minus_handle, int ptv_needed, int size)
  137. {
  138. /* Announce relocator to runtime */
  139. if (ptv_needed)
  140. {
  141. struct grub_efiemu_ptv_rel *ptv_rels
  142. = grub_efiemu_mm_obtain_request (ptv_handle);
  143. if (ptv_needed && ptv_written >= ptv_alloc)
  144. return grub_error (GRUB_ERR_OUT_OF_MEMORY,
  145. "your module didn't declare efiemu "
  146. " relocators correctly");
  147. if (minus_handle)
  148. ptv_rels[ptv_written].minustype
  149. = grub_efiemu_mm_get_type (minus_handle);
  150. else
  151. ptv_rels[ptv_written].minustype = 0;
  152. if (plus_handle)
  153. ptv_rels[ptv_written].plustype
  154. = grub_efiemu_mm_get_type (plus_handle);
  155. else
  156. ptv_rels[ptv_written].plustype = 0;
  157. ptv_rels[ptv_written].addr = PTR_TO_UINT64 (addr);
  158. ptv_rels[ptv_written].size = size;
  159. ptv_written++;
  160. /* memset next value to zero to mark the end */
  161. grub_memset (&ptv_rels[ptv_written], 0, sizeof (ptv_rels[ptv_written]));
  162. }
  163. /* Compute the value */
  164. if (minus_handle)
  165. value -= PTR_TO_UINT32 (grub_efiemu_mm_obtain_request (minus_handle));
  166. if (plus_handle)
  167. value += PTR_TO_UINT32 (grub_efiemu_mm_obtain_request (plus_handle));
  168. /* Write the value */
  169. switch (size)
  170. {
  171. case 8:
  172. *((grub_uint64_t *) addr) = value;
  173. break;
  174. case 4:
  175. *((grub_uint32_t *) addr) = value;
  176. break;
  177. case 2:
  178. *((grub_uint16_t *) addr) = value;
  179. break;
  180. case 1:
  181. *((grub_uint8_t *) addr) = value;
  182. break;
  183. default:
  184. return grub_error (GRUB_ERR_BAD_ARGUMENT, "wrong symbol size");
  185. }
  186. return GRUB_ERR_NONE;
  187. }
  188. grub_err_t
  189. grub_efiemu_set_virtual_address_map (grub_efi_uintn_t memory_map_size,
  190. grub_efi_uintn_t descriptor_size,
  191. grub_efi_uint32_t descriptor_version
  192. __attribute__ ((unused)),
  193. grub_efi_memory_descriptor_t *virtual_map)
  194. {
  195. grub_uint8_t *ptv_relocated;
  196. struct grub_efiemu_ptv_rel *cur_relloc;
  197. struct grub_efiemu_ptv_rel *ptv_rels;
  198. ptv_relocated = grub_efiemu_mm_obtain_request (relocated_handle);
  199. ptv_rels = grub_efiemu_mm_obtain_request (ptv_handle);
  200. /* Ensure that we are called only once */
  201. if (*ptv_relocated)
  202. return grub_error (GRUB_ERR_BAD_ARGUMENT, "EfiEmu is already relocated");
  203. *ptv_relocated = 1;
  204. /* Correct addresses using information supplied by grub */
  205. for (cur_relloc = ptv_rels; cur_relloc->size; cur_relloc++)
  206. {
  207. grub_int64_t corr = 0;
  208. grub_efi_memory_descriptor_t *descptr;
  209. /* Compute correction */
  210. for (descptr = virtual_map;
  211. (grub_size_t) ((grub_uint8_t *) descptr
  212. - (grub_uint8_t *) virtual_map) < memory_map_size;
  213. descptr = (grub_efi_memory_descriptor_t *)
  214. ((grub_uint8_t *) descptr + descriptor_size))
  215. {
  216. if (descptr->type == cur_relloc->plustype)
  217. corr += descptr->virtual_start - descptr->physical_start;
  218. if (descptr->type == cur_relloc->minustype)
  219. corr -= descptr->virtual_start - descptr->physical_start;
  220. }
  221. /* Apply correction */
  222. switch (cur_relloc->size)
  223. {
  224. case 8:
  225. *((grub_uint64_t *) UINT_TO_PTR (cur_relloc->addr)) += corr;
  226. break;
  227. case 4:
  228. *((grub_uint32_t *) UINT_TO_PTR (cur_relloc->addr)) += corr;
  229. break;
  230. case 2:
  231. *((grub_uint16_t *) UINT_TO_PTR (cur_relloc->addr)) += corr;
  232. break;
  233. case 1:
  234. *((grub_uint8_t *) UINT_TO_PTR (cur_relloc->addr)) += corr;
  235. break;
  236. }
  237. }
  238. /* Recompute crc32 of system table and runtime services */
  239. if (grub_efiemu_sizeof_uintn_t () == 4)
  240. return grub_efiemu_crc32 ();
  241. else
  242. return grub_efiemu_crc64 ();
  243. }