helper.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. #include "efidef.h"
  2. #include <efi.h>
  3. #include <efilib.h>
  4. #include <lib.h>
  5. #include <dragonstub/dragonstub.h>
  6. bool efi_nochunk;
  7. bool efi_nokaslr = true;
  8. // bool efi_nokaslr = !IS_ENABLED(CONFIG_RANDOMIZE_BASE);
  9. bool efi_novamap = false;
  10. static bool efi_noinitrd;
  11. static bool efi_nosoftreserve;
  12. static bool efi_disable_pci_dma = false;
  13. // static bool efi_disable_pci_dma = IS_ENABLED(CONFIG_EFI_DISABLE_PCI_DMA);
  14. enum efistub_event {
  15. EFISTUB_EVT_INITRD,
  16. EFISTUB_EVT_LOAD_OPTIONS,
  17. EFISTUB_EVT_COUNT,
  18. };
  19. #define STR_WITH_SIZE(s) sizeof(s), s
  20. static const struct {
  21. u32 pcr_index;
  22. u32 event_id;
  23. u32 event_data_len;
  24. u8 event_data[52];
  25. } events[] = {
  26. [EFISTUB_EVT_INITRD] = { 9, INITRD_EVENT_TAG_ID,
  27. STR_WITH_SIZE("Linux initrd") },
  28. [EFISTUB_EVT_LOAD_OPTIONS] = { 9, LOAD_OPTIONS_EVENT_TAG_ID,
  29. STR_WITH_SIZE(
  30. "LOADED_IMAGE::LoadOptions") },
  31. };
  32. static efi_status_t efi_measure_tagged_event(unsigned long load_addr,
  33. unsigned long load_size,
  34. enum efistub_event event)
  35. {
  36. efi_guid_t tcg2_guid = EFI_TCG2_PROTOCOL_GUID;
  37. efi_tcg2_protocol_t *tcg2 = NULL;
  38. efi_status_t status;
  39. efi_bs_call(LocateProtocol, &tcg2_guid, NULL, (void **)&tcg2);
  40. if (tcg2) {
  41. struct efi_measured_event {
  42. efi_tcg2_event_t event_data;
  43. efi_tcg2_tagged_event_t tagged_event;
  44. u8 tagged_event_data[];
  45. } * evt;
  46. int size = sizeof(*evt) + events[event].event_data_len;
  47. status = efi_bs_call(AllocatePool, EfiLoaderData, size,
  48. (void **)&evt);
  49. if (status != EFI_SUCCESS)
  50. goto fail;
  51. evt->event_data = (struct efi_tcg2_event){
  52. .event_size = size,
  53. .event_header.header_size =
  54. sizeof(evt->event_data.event_header),
  55. .event_header.header_version =
  56. EFI_TCG2_EVENT_HEADER_VERSION,
  57. .event_header.pcr_index = events[event].pcr_index,
  58. .event_header.event_type = EV_EVENT_TAG,
  59. };
  60. evt->tagged_event = (struct efi_tcg2_tagged_event){
  61. .tagged_event_id = events[event].event_id,
  62. .tagged_event_data_size = events[event].event_data_len,
  63. };
  64. memcpy(evt->tagged_event_data, events[event].event_data,
  65. events[event].event_data_len);
  66. status = efi_call_proto(tcg2, hash_log_extend_event, 0,
  67. load_addr, load_size, &evt->event_data);
  68. efi_bs_call(FreePool, evt);
  69. if (status != EFI_SUCCESS)
  70. goto fail;
  71. return EFI_SUCCESS;
  72. }
  73. return EFI_UNSUPPORTED;
  74. fail:
  75. efi_warn("Failed to measure data for event %d: 0x%lx\n", event, status);
  76. return status;
  77. }
  78. /*
  79. * At least some versions of Dell firmware pass the entire contents of the
  80. * Boot#### variable, i.e. the EFI_LOAD_OPTION descriptor, rather than just the
  81. * OptionalData field.
  82. *
  83. * Detect this case and extract OptionalData.
  84. */
  85. void efi_apply_loadoptions_quirk(const void **load_options,
  86. u32 *load_options_size)
  87. {
  88. #ifndef CONFIG_X86
  89. return;
  90. #else
  91. const efi_load_option_t *load_option = *load_options;
  92. efi_load_option_unpacked_t load_option_unpacked;
  93. if (!load_option)
  94. return;
  95. if (*load_options_size < sizeof(*load_option))
  96. return;
  97. if ((load_option->attributes & ~EFI_LOAD_OPTION_BOOT_MASK) != 0)
  98. return;
  99. if (!efi_load_option_unpack(&load_option_unpacked, load_option,
  100. *load_options_size))
  101. return;
  102. efi_warn_once(FW_BUG "LoadOptions is an EFI_LOAD_OPTION descriptor\n");
  103. efi_warn_once(FW_BUG "Using OptionalData as a workaround\n");
  104. *load_options = load_option_unpacked.optional_data;
  105. *load_options_size = load_option_unpacked.optional_data_size;
  106. #endif
  107. }
  108. /*
  109. * Convert the unicode UEFI command line to ASCII to pass to kernel.
  110. * Size of memory allocated return in *cmd_line_len.
  111. * Returns NULL on error.
  112. */
  113. char *efi_convert_cmdline(EFI_LOADED_IMAGE *image, int *cmd_line_len)
  114. {
  115. const efi_char16_t *options = efi_table_attr(image, LoadOptions);
  116. u32 options_size = efi_table_attr(image, LoadOptionsSize);
  117. int options_bytes = 0, safe_options_bytes = 0; /* UTF-8 bytes */
  118. unsigned long cmdline_addr = 0;
  119. const efi_char16_t *s2;
  120. bool in_quote = false;
  121. efi_status_t status;
  122. u32 options_chars;
  123. if (options_size > 0)
  124. efi_measure_tagged_event((unsigned long)options, options_size,
  125. EFISTUB_EVT_LOAD_OPTIONS);
  126. efi_apply_loadoptions_quirk((const void **)&options, &options_size);
  127. options_chars = options_size / sizeof(efi_char16_t);
  128. if (options) {
  129. s2 = options;
  130. while (options_bytes < COMMAND_LINE_SIZE && options_chars--) {
  131. efi_char16_t c = *s2++;
  132. if (c < 0x80) {
  133. if (c == L'\0' || c == L'\n')
  134. break;
  135. if (c == L'"')
  136. in_quote = !in_quote;
  137. else if (!in_quote && isspace((char)c))
  138. safe_options_bytes = options_bytes;
  139. options_bytes++;
  140. continue;
  141. }
  142. /*
  143. * Get the number of UTF-8 bytes corresponding to a
  144. * UTF-16 character.
  145. * The first part handles everything in the BMP.
  146. */
  147. options_bytes += 2 + (c >= 0x800);
  148. /*
  149. * Add one more byte for valid surrogate pairs. Invalid
  150. * surrogates will be replaced with 0xfffd and take up
  151. * only 3 bytes.
  152. */
  153. if ((c & 0xfc00) == 0xd800) {
  154. /*
  155. * If the very last word is a high surrogate,
  156. * we must ignore it since we can't access the
  157. * low surrogate.
  158. */
  159. if (!options_chars) {
  160. options_bytes -= 3;
  161. } else if ((*s2 & 0xfc00) == 0xdc00) {
  162. options_bytes++;
  163. options_chars--;
  164. s2++;
  165. }
  166. }
  167. }
  168. if (options_bytes >= COMMAND_LINE_SIZE) {
  169. options_bytes = safe_options_bytes;
  170. efi_err("Command line is too long: truncated to %d bytes\n",
  171. options_bytes);
  172. }
  173. }
  174. options_bytes++; /* NUL termination */
  175. status = efi_bs_call(AllocatePool, EfiLoaderData, options_bytes,
  176. (void **)&cmdline_addr);
  177. if (status != EFI_SUCCESS)
  178. return NULL;
  179. snprintf((char *)cmdline_addr, options_bytes, "%.*ls",
  180. options_bytes - 1, options);
  181. *cmd_line_len = options_bytes;
  182. return (char *)cmdline_addr;
  183. }
  184. /**
  185. * parse_option_str - Parse a string and check an option is set or not
  186. * @str: String to be parsed
  187. * @option: option name
  188. *
  189. * This function parses a string containing a comma-separated list of
  190. * strings like a=b,c.
  191. *
  192. * Return true if there's such option in the string, or return false.
  193. */
  194. bool parse_option_str(const char *str, const char *option)
  195. {
  196. while (*str) {
  197. if (!strncmp(str, option, strlen(option))) {
  198. str += strlen(option);
  199. if (!*str || *str == ',')
  200. return true;
  201. }
  202. while (*str && *str != ',')
  203. str++;
  204. if (*str == ',')
  205. str++;
  206. }
  207. return false;
  208. }
  209. /**
  210. * efi_parse_options() - Parse EFI command line options
  211. * @cmdline: kernel command line
  212. *
  213. * Parse the ASCII string @cmdline for EFI options, denoted by the efi=
  214. * option, e.g. efi=nochunk.
  215. *
  216. * It should be noted that efi= is parsed in two very different
  217. * environments, first in the early boot environment of the EFI boot
  218. * stub, and subsequently during the kernel boot.
  219. *
  220. * Return: status code
  221. */
  222. efi_status_t efi_parse_options(char const *cmdline)
  223. {
  224. size_t len;
  225. efi_status_t status;
  226. char *str, *buf;
  227. if (!cmdline)
  228. return EFI_SUCCESS;
  229. len = strnlen(cmdline, COMMAND_LINE_SIZE - 1) + 1;
  230. status = efi_bs_call(AllocatePool, EfiLoaderData, len, (void **)&buf);
  231. if (status != EFI_SUCCESS)
  232. return status;
  233. memcpy(buf, cmdline, len - 1);
  234. buf[len - 1] = '\0';
  235. str = skip_spaces(buf);
  236. while (*str) {
  237. char *param, *val;
  238. str = next_arg(str, &param, &val);
  239. if (!val && !strcmp(param, "--"))
  240. break;
  241. if (!strcmp(param, "nokaslr")) {
  242. efi_nokaslr = true;
  243. } else if (!strcmp(param, "quiet")) {
  244. // efi_loglevel = CONSOLE_LOGLEVEL_QUIET;
  245. } else if (!strcmp(param, "noinitrd")) {
  246. efi_noinitrd = true;
  247. }
  248. #ifdef CONFIG_X86_64
  249. else if (IS_ENABLED(CONFIG_X86_64) &&
  250. !strcmp(param, "no5lvl")) {
  251. efi_no5lvl = true;
  252. }
  253. #endif
  254. else if (!strcmp(param, "efi") && val) {
  255. efi_nochunk = parse_option_str(val, "nochunk");
  256. efi_novamap |= parse_option_str(val, "novamap");
  257. // efi_nosoftreserve =
  258. // IS_ENABLED(CONFIG_EFI_SOFT_RESERVE) &&
  259. // parse_option_str(val, "nosoftreserve");
  260. efi_nosoftreserve = false;
  261. if (parse_option_str(val, "disable_early_pci_dma"))
  262. efi_disable_pci_dma = true;
  263. if (parse_option_str(val, "no_disable_early_pci_dma"))
  264. efi_disable_pci_dma = false;
  265. if (parse_option_str(val, "debug")) {
  266. // efi_loglevel = CONSOLE_LOGLEVEL_DEBUG;
  267. }
  268. } else if (!strcmp(param, "video") && val &&
  269. strstarts(val, "efifb:")) {
  270. // efi_parse_option_graphics(val + strlen("efifb:"));
  271. }
  272. }
  273. efi_bs_call(FreePool, buf);
  274. return EFI_SUCCESS;
  275. }
  276. /**
  277. * get_efi_config_table() - retrieve UEFI configuration table
  278. * @guid: GUID of the configuration table to be retrieved
  279. * Return: pointer to the configuration table or NULL
  280. */
  281. void *get_efi_config_table(efi_guid_t guid)
  282. {
  283. efi_config_table_t *tables = efi_table_attr(ST, ConfigurationTable);
  284. int nr_tables = efi_table_attr(ST, NumberOfTableEntries);
  285. int i;
  286. for (i = 0; i < nr_tables; i++) {
  287. efi_config_table_t *t = (void *)tables;
  288. // print_efi_guid(&t->VendorGuid);
  289. if (efi_guidcmp(t->VendorGuid, guid) == 0)
  290. return efi_table_attr(t, VendorTable);
  291. tables++;
  292. }
  293. return NULL;
  294. }
  295. /**
  296. * efi_exit_boot_services() - Exit boot services
  297. * @handle: handle of the exiting image
  298. * @priv: argument to be passed to @priv_func
  299. * @priv_func: function to process the memory map before exiting boot services
  300. *
  301. * Handle calling ExitBootServices according to the requirements set out by the
  302. * spec. Obtains the current memory map, and returns that info after calling
  303. * ExitBootServices. The client must specify a function to perform any
  304. * processing of the memory map data prior to ExitBootServices. A client
  305. * specific structure may be passed to the function via priv. The client
  306. * function may be called multiple times.
  307. *
  308. * Return: status code
  309. */
  310. efi_status_t efi_exit_boot_services(void *handle, void *priv,
  311. efi_exit_boot_map_processing priv_func)
  312. {
  313. struct efi_boot_memmap *map;
  314. efi_status_t status;
  315. if (efi_disable_pci_dma) {
  316. efi_todo("efi_exit_boot_services:: efi_disable_pci_dma: efi_pci_disable_bridge_busmaster");
  317. // efi_pci_disable_bridge_busmaster();
  318. }
  319. status = efi_get_memory_map(&map, true);
  320. if (status != EFI_SUCCESS)
  321. return status;
  322. efi_debug("before priv_func\n");
  323. status = priv_func(map, priv);
  324. if (status != EFI_SUCCESS) {
  325. efi_bs_call(FreePool, map);
  326. return status;
  327. }
  328. efi_debug("before ExitBootServices, handle=%p, map_key=%p\n", handle, map->map_key);
  329. status = efi_bs_call(ExitBootServices, handle, map->map_key);
  330. efi_debug("after ExitBootServices, status: %d\n", status);
  331. if (status == EFI_INVALID_PARAMETER) {
  332. /*
  333. * The memory map changed between efi_get_memory_map() and
  334. * exit_boot_services(). Per the UEFI Spec v2.6, Section 6.4:
  335. * EFI_BOOT_SERVICES.ExitBootServices we need to get the
  336. * updated map, and try again. The spec implies one retry
  337. * should be sufficent, which is confirmed against the EDK2
  338. * implementation. Per the spec, we can only invoke
  339. * get_memory_map() and exit_boot_services() - we cannot alloc
  340. * so efi_get_memory_map() cannot be used, and we must reuse
  341. * the buffer. For all practical purposes, the headroom in the
  342. * buffer should account for any changes in the map so the call
  343. * to get_memory_map() is expected to succeed here.
  344. */
  345. map->map_size = map->buff_size;
  346. status = efi_bs_call(GetMemoryMap, &map->map_size, &map->map,
  347. &map->map_key, &map->desc_size,
  348. &map->desc_ver);
  349. /* exit_boot_services() was called, thus cannot free */
  350. if (status != EFI_SUCCESS)
  351. return status;
  352. status = priv_func(map, priv);
  353. /* exit_boot_services() was called, thus cannot free */
  354. if (status != EFI_SUCCESS)
  355. return status;
  356. status = efi_bs_call(ExitBootServices, handle, map->map_key);
  357. }
  358. return status;
  359. }