main.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  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. /* This is an emulation of EFI runtime services.
  19. This allows a more uniform boot on i386 machines.
  20. As it emulates only runtime service it isn't able
  21. to chainload EFI bootloader on non-EFI system. */
  22. #include <grub/file.h>
  23. #include <grub/err.h>
  24. #include <grub/normal.h>
  25. #include <grub/mm.h>
  26. #include <grub/dl.h>
  27. #include <grub/misc.h>
  28. #include <grub/efiemu/efiemu.h>
  29. #include <grub/command.h>
  30. #include <grub/i18n.h>
  31. GRUB_MOD_LICENSE ("GPLv3+");
  32. /* System table. Two version depending on mode */
  33. grub_efi_system_table32_t *grub_efiemu_system_table32 = 0;
  34. grub_efi_system_table64_t *grub_efiemu_system_table64 = 0;
  35. /* Modules may need to execute some actions after memory allocation happens */
  36. static struct grub_efiemu_prepare_hook *efiemu_prepare_hooks = 0;
  37. /* Linked list of configuration tables */
  38. static struct grub_efiemu_configuration_table *efiemu_config_tables = 0;
  39. static int prepared = 0;
  40. /* Free all allocated space */
  41. grub_err_t
  42. grub_efiemu_unload (void)
  43. {
  44. struct grub_efiemu_configuration_table *cur, *d;
  45. struct grub_efiemu_prepare_hook *curhook, *d2;
  46. grub_efiemu_loadcore_unload ();
  47. grub_efiemu_mm_unload ();
  48. for (cur = efiemu_config_tables; cur;)
  49. {
  50. d = cur->next;
  51. if (cur->unload)
  52. cur->unload (cur->data);
  53. grub_free (cur);
  54. cur = d;
  55. }
  56. efiemu_config_tables = 0;
  57. for (curhook = efiemu_prepare_hooks; curhook;)
  58. {
  59. d2 = curhook->next;
  60. if (curhook->unload)
  61. curhook->unload (curhook->data);
  62. grub_free (curhook);
  63. curhook = d2;
  64. }
  65. efiemu_prepare_hooks = 0;
  66. prepared = 0;
  67. return GRUB_ERR_NONE;
  68. }
  69. /* Remove previously registered table from the list */
  70. grub_err_t
  71. grub_efiemu_unregister_configuration_table (grub_guid_t guid)
  72. {
  73. struct grub_efiemu_configuration_table *cur, *prev;
  74. /* Special treating if head is to remove */
  75. while (efiemu_config_tables
  76. && !grub_memcmp (&(efiemu_config_tables->guid), &guid, sizeof (guid)))
  77. {
  78. if (efiemu_config_tables->unload)
  79. efiemu_config_tables->unload (efiemu_config_tables->data);
  80. cur = efiemu_config_tables->next;
  81. grub_free (efiemu_config_tables);
  82. efiemu_config_tables = cur;
  83. }
  84. if (!efiemu_config_tables)
  85. return GRUB_ERR_NONE;
  86. /* Remove from chain */
  87. for (prev = efiemu_config_tables, cur = prev->next; cur;)
  88. if (grub_memcmp (&(cur->guid), &guid, sizeof (guid)) == 0)
  89. {
  90. if (cur->unload)
  91. cur->unload (cur->data);
  92. prev->next = cur->next;
  93. grub_free (cur);
  94. cur = prev->next;
  95. }
  96. else
  97. {
  98. prev = cur;
  99. cur = cur->next;
  100. }
  101. return GRUB_ERR_NONE;
  102. }
  103. grub_err_t
  104. grub_efiemu_register_prepare_hook (grub_err_t (*hook) (void *data),
  105. void (*unload) (void *data),
  106. void *data)
  107. {
  108. struct grub_efiemu_prepare_hook *nhook;
  109. nhook = (struct grub_efiemu_prepare_hook *) grub_malloc (sizeof (*nhook));
  110. if (! nhook)
  111. return grub_errno;
  112. nhook->hook = hook;
  113. nhook->unload = unload;
  114. nhook->data = data;
  115. nhook->next = efiemu_prepare_hooks;
  116. efiemu_prepare_hooks = nhook;
  117. return GRUB_ERR_NONE;
  118. }
  119. /* Register a configuration table either supplying the address directly
  120. or with a hook
  121. */
  122. grub_err_t
  123. grub_efiemu_register_configuration_table (grub_guid_t guid,
  124. void * (*get_table) (void *data),
  125. void (*unload) (void *data),
  126. void *data)
  127. {
  128. struct grub_efiemu_configuration_table *tbl;
  129. grub_err_t err;
  130. err = grub_efiemu_unregister_configuration_table (guid);
  131. if (err)
  132. return err;
  133. tbl = (struct grub_efiemu_configuration_table *) grub_malloc (sizeof (*tbl));
  134. if (! tbl)
  135. return grub_errno;
  136. tbl->guid = guid;
  137. tbl->get_table = get_table;
  138. tbl->unload = unload;
  139. tbl->data = data;
  140. tbl->next = efiemu_config_tables;
  141. efiemu_config_tables = tbl;
  142. return GRUB_ERR_NONE;
  143. }
  144. static grub_err_t
  145. grub_cmd_efiemu_unload (grub_command_t cmd __attribute__ ((unused)),
  146. int argc __attribute__ ((unused)),
  147. char *args[] __attribute__ ((unused)))
  148. {
  149. return grub_efiemu_unload ();
  150. }
  151. static grub_err_t
  152. grub_cmd_efiemu_prepare (grub_command_t cmd __attribute__ ((unused)),
  153. int argc __attribute__ ((unused)),
  154. char *args[] __attribute__ ((unused)))
  155. {
  156. return grub_efiemu_prepare ();
  157. }
  158. /* Load the runtime from the file FILENAME. */
  159. static grub_err_t
  160. grub_efiemu_load_file (const char *filename)
  161. {
  162. grub_file_t file;
  163. grub_err_t err;
  164. file = grub_file_open (filename, GRUB_FILE_TYPE_GRUB_MODULE);
  165. if (! file)
  166. return grub_errno;
  167. err = grub_efiemu_mm_init ();
  168. if (err)
  169. {
  170. grub_file_close (file);
  171. grub_efiemu_unload ();
  172. return err;
  173. }
  174. grub_dprintf ("efiemu", "mm initialized\n");
  175. err = grub_efiemu_loadcore_init (file, filename);
  176. if (err)
  177. {
  178. grub_file_close (file);
  179. grub_efiemu_unload ();
  180. return err;
  181. }
  182. grub_file_close (file);
  183. /* For configuration tables entry in system table. */
  184. grub_efiemu_request_symbols (1);
  185. return GRUB_ERR_NONE;
  186. }
  187. grub_err_t
  188. grub_efiemu_autocore (void)
  189. {
  190. const char *prefix;
  191. char *filename;
  192. const char *suffix;
  193. grub_err_t err;
  194. if (grub_efiemu_sizeof_uintn_t () != 0)
  195. return GRUB_ERR_NONE;
  196. prefix = grub_env_get ("prefix");
  197. if (! prefix)
  198. return grub_error (GRUB_ERR_FILE_NOT_FOUND,
  199. N_("variable `%s' isn't set"), "prefix");
  200. suffix = grub_efiemu_get_default_core_name ();
  201. filename = grub_xasprintf ("%s/" GRUB_TARGET_CPU "-" GRUB_PLATFORM "/%s",
  202. prefix, suffix);
  203. if (! filename)
  204. return grub_errno;
  205. err = grub_efiemu_load_file (filename);
  206. grub_free (filename);
  207. if (err)
  208. return err;
  209. #ifndef GRUB_MACHINE_EMU
  210. err = grub_machine_efiemu_init_tables ();
  211. if (err)
  212. return err;
  213. #endif
  214. return GRUB_ERR_NONE;
  215. }
  216. grub_err_t
  217. grub_efiemu_prepare (void)
  218. {
  219. grub_err_t err;
  220. if (prepared)
  221. return GRUB_ERR_NONE;
  222. err = grub_efiemu_autocore ();
  223. if (err)
  224. return err;
  225. grub_dprintf ("efiemu", "Preparing %d-bit efiemu\n",
  226. 8 * grub_efiemu_sizeof_uintn_t ());
  227. /* Create NVRAM. */
  228. grub_efiemu_pnvram ();
  229. prepared = 1;
  230. if (grub_efiemu_sizeof_uintn_t () == 4)
  231. return grub_efiemu_prepare32 (efiemu_prepare_hooks, efiemu_config_tables);
  232. else
  233. return grub_efiemu_prepare64 (efiemu_prepare_hooks, efiemu_config_tables);
  234. }
  235. static grub_err_t
  236. grub_cmd_efiemu_load (grub_command_t cmd __attribute__ ((unused)),
  237. int argc, char *args[])
  238. {
  239. grub_err_t err;
  240. grub_efiemu_unload ();
  241. if (argc != 1)
  242. return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
  243. err = grub_efiemu_load_file (args[0]);
  244. if (err)
  245. return err;
  246. #ifndef GRUB_MACHINE_EMU
  247. err = grub_machine_efiemu_init_tables ();
  248. if (err)
  249. return err;
  250. #endif
  251. return GRUB_ERR_NONE;
  252. }
  253. static grub_command_t cmd_loadcore, cmd_prepare, cmd_unload;
  254. GRUB_MOD_INIT(efiemu)
  255. {
  256. cmd_loadcore = grub_register_command ("efiemu_loadcore",
  257. grub_cmd_efiemu_load,
  258. N_("FILE"),
  259. N_("Load and initialize EFI emulator."));
  260. cmd_prepare = grub_register_command ("efiemu_prepare",
  261. grub_cmd_efiemu_prepare,
  262. 0,
  263. N_("Finalize loading of EFI emulator."));
  264. cmd_unload = grub_register_command ("efiemu_unload", grub_cmd_efiemu_unload,
  265. 0,
  266. N_("Unload EFI emulator."));
  267. }
  268. GRUB_MOD_FINI(efiemu)
  269. {
  270. grub_unregister_command (cmd_loadcore);
  271. grub_unregister_command (cmd_prepare);
  272. grub_unregister_command (cmd_unload);
  273. }