main.c 8.7 KB

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