]> git.proxmox.com Git - efi-boot-shim.git/blob - fallback.c
Update copyright file
[efi-boot-shim.git] / fallback.c
1 // SPDX-License-Identifier: BSD-2-Clause-Patent
2 /*
3 * Copyright Red Hat, Inc.
4 * Copyright Peter Jones <pjones@redhat.com>
5 */
6
7 #include <efi.h>
8 #include <efilib.h>
9
10 #include "shim.h"
11
12 #define NO_REBOOT L"FB_NO_REBOOT"
13
14 EFI_LOADED_IMAGE *this_image = NULL;
15
16 int
17 get_fallback_verbose(void)
18 {
19 UINT8 *data = NULL;
20 UINTN dataSize = 0;
21 EFI_STATUS efi_status;
22 unsigned int i;
23 static int state = -1;
24
25 if (state != -1)
26 return state;
27
28 efi_status = get_variable(L"FALLBACK_VERBOSE",
29 &data, &dataSize, SHIM_LOCK_GUID);
30 if (EFI_ERROR(efi_status)) {
31 state = 0;
32 return state;
33 }
34
35 state = 0;
36 for (i = 0; i < dataSize; i++) {
37 if (data[i]) {
38 state = 1;
39 break;
40 }
41 }
42
43 if (data)
44 FreePool(data);
45 return state;
46 }
47
48 #define VerbosePrintUnprefixed(fmt, ...) \
49 ({ \
50 UINTN ret_ = 0; \
51 if (get_fallback_verbose()) \
52 ret_ = console_print((fmt), ##__VA_ARGS__); \
53 ret_; \
54 })
55
56 #define VerbosePrint(fmt, ...) \
57 ({ \
58 UINTN line_ = __LINE__ - 2; \
59 UINTN ret_ = 0; \
60 if (get_fallback_verbose()) { \
61 console_print(L"%a:%d: ", __func__, line_); \
62 ret_ = console_print((fmt), ##__VA_ARGS__); \
63 } \
64 ret_; \
65 })
66
67 static EFI_STATUS
68 FindSubDevicePath(EFI_DEVICE_PATH *In, UINT8 Type, UINT8 SubType,
69 EFI_DEVICE_PATH **Out)
70 {
71 EFI_DEVICE_PATH *dp = In;
72 if (!In || !Out)
73 return EFI_INVALID_PARAMETER;
74
75 CHAR16 *dps = DevicePathToStr(In);
76 VerbosePrint(L"input device path: \"%s\"\n", dps);
77 FreePool(dps);
78
79 for (dp = In; !IsDevicePathEnd(dp); dp = NextDevicePathNode(dp)) {
80 if (DevicePathType(dp) == Type &&
81 DevicePathSubType(dp) == SubType) {
82 dps = DevicePathToStr(dp);
83 VerbosePrint(L"sub-path (%hhd,%hhd): \"%s\"\n",
84 Type, SubType, dps);
85 FreePool(dps);
86
87 *Out = DuplicateDevicePath(dp);
88 if (!*Out)
89 return EFI_OUT_OF_RESOURCES;
90 return EFI_SUCCESS;
91 }
92 }
93 *Out = NULL;
94 return EFI_NOT_FOUND;
95 }
96
97 static EFI_STATUS
98 get_file_size(EFI_FILE_HANDLE fh, UINTN *retsize)
99 {
100 EFI_STATUS efi_status;
101 void *buffer = NULL;
102 UINTN bs = 0;
103
104 /* The API here is "Call it once with bs=0, it fills in bs,
105 * then allocate a buffer and ask again to get it filled. */
106 efi_status = fh->GetInfo(fh, &EFI_FILE_INFO_GUID, &bs, NULL);
107 if (EFI_ERROR(efi_status) && efi_status != EFI_BUFFER_TOO_SMALL)
108 return efi_status;
109 if (bs == 0)
110 return EFI_SUCCESS;
111
112 buffer = AllocateZeroPool(bs);
113 if (!buffer) {
114 console_print(L"Could not allocate memory\n");
115 return EFI_OUT_OF_RESOURCES;
116 }
117 efi_status = fh->GetInfo(fh, &EFI_FILE_INFO_GUID, &bs, buffer);
118 /* This checks *either* the error from the first GetInfo, if it isn't
119 * the EFI_BUFFER_TOO_SMALL we're expecting, or the second GetInfo
120 * call in *any* case. */
121 if (EFI_ERROR(efi_status)) {
122 console_print(L"Could not get file info: %r\n", efi_status);
123 if (buffer)
124 FreePool(buffer);
125 return efi_status;
126 }
127 EFI_FILE_INFO *fi = buffer;
128 *retsize = fi->FileSize;
129 FreePool(buffer);
130 return EFI_SUCCESS;
131 }
132
133 EFI_STATUS
134 read_file(EFI_FILE_HANDLE fh, CHAR16 *fullpath, CHAR16 **buffer, UINT64 *bs)
135 {
136 EFI_FILE_HANDLE fh2;
137 EFI_STATUS efi_status;
138
139 efi_status = fh->Open(fh, &fh2, fullpath, EFI_FILE_READ_ONLY, 0);
140 if (EFI_ERROR(efi_status)) {
141 console_print(L"Couldn't open \"%s\": %r\n", fullpath, efi_status);
142 return efi_status;
143 }
144
145 UINTN len = 0;
146 CHAR16 *b = NULL;
147 efi_status = get_file_size(fh2, &len);
148 if (EFI_ERROR(efi_status)) {
149 console_print(L"Could not get file size for \"%s\": %r\n",
150 fullpath, efi_status);
151 fh2->Close(fh2);
152 return efi_status;
153 }
154
155 if (len > 1024 * PAGE_SIZE) {
156 fh2->Close(fh2);
157 return EFI_BAD_BUFFER_SIZE;
158 }
159
160 b = AllocateZeroPool(len + 2);
161 if (!buffer) {
162 console_print(L"Could not allocate memory\n");
163 fh2->Close(fh2);
164 return EFI_OUT_OF_RESOURCES;
165 }
166
167 efi_status = fh->Read(fh, &len, b);
168 if (EFI_ERROR(efi_status)) {
169 FreePool(buffer);
170 fh2->Close(fh2);
171 console_print(L"Could not read file: %r\n", efi_status);
172 return efi_status;
173 }
174 *buffer = b;
175 *bs = len;
176 fh2->Close(fh2);
177 return EFI_SUCCESS;
178 }
179
180 EFI_STATUS
181 make_full_path(CHAR16 *dirname, CHAR16 *filename, CHAR16 **out, UINT64 *outlen)
182 {
183 UINT64 len;
184
185 len = StrLen(L"\\EFI\\") + StrLen(dirname)
186 + StrLen(L"\\") + StrLen(filename)
187 + 2;
188
189 CHAR16 *fullpath = AllocateZeroPool(len*sizeof(CHAR16));
190 if (!fullpath) {
191 console_print(L"Could not allocate memory\n");
192 return EFI_OUT_OF_RESOURCES;
193 }
194
195 StrCat(fullpath, L"\\EFI\\");
196 StrCat(fullpath, dirname);
197 StrCat(fullpath, L"\\");
198 StrCat(fullpath, filename);
199
200 *out = fullpath;
201 *outlen = len;
202 return EFI_SUCCESS;
203 }
204
205 CHAR16 *bootorder = NULL;
206 int nbootorder = 0;
207
208 EFI_DEVICE_PATH *first_new_option = NULL;
209 VOID *first_new_option_args = NULL;
210 UINTN first_new_option_size = 0;
211
212 EFI_STATUS
213 add_boot_option(EFI_DEVICE_PATH *hddp, EFI_DEVICE_PATH *fulldp,
214 CHAR16 *filename, CHAR16 *label, CHAR16 *arguments)
215 {
216 static int i = 0;
217 CHAR16 varname[] = L"Boot0000";
218 CHAR16 hexmap[] = L"0123456789ABCDEF";
219 EFI_STATUS efi_status;
220
221 for(; i <= 0xffff; i++) {
222 varname[4] = hexmap[(i & 0xf000) >> 12];
223 varname[5] = hexmap[(i & 0x0f00) >> 8];
224 varname[6] = hexmap[(i & 0x00f0) >> 4];
225 varname[7] = hexmap[(i & 0x000f) >> 0];
226
227 void *var = LibGetVariable(varname, &GV_GUID);
228 if (!var) {
229 int size = sizeof(UINT32) + sizeof (UINT16) +
230 StrLen(label)*2 + 2 + DevicePathSize(hddp) +
231 StrLen(arguments) * 2;
232
233 CHAR8 *data = AllocateZeroPool(size + 2);
234 CHAR8 *cursor = data;
235 *(UINT32 *)cursor = LOAD_OPTION_ACTIVE;
236 cursor += sizeof (UINT32);
237 *(UINT16 *)cursor = DevicePathSize(hddp);
238 cursor += sizeof (UINT16);
239 StrCpy((CHAR16 *)cursor, label);
240 cursor += StrLen(label)*2 + 2;
241 CopyMem(cursor, hddp, DevicePathSize(hddp));
242 cursor += DevicePathSize(hddp);
243 StrCpy((CHAR16 *)cursor, arguments);
244
245 console_print(L"Creating boot entry \"%s\" with label \"%s\" "
246 L"for file \"%s\"\n",
247 varname, label, filename);
248
249 if (!first_new_option) {
250 first_new_option = DuplicateDevicePath(fulldp);
251 first_new_option_args = arguments;
252 first_new_option_size = StrLen(arguments) * sizeof (CHAR16);
253 }
254
255 efi_status = gRT->SetVariable(varname, &GV_GUID,
256 EFI_VARIABLE_NON_VOLATILE |
257 EFI_VARIABLE_BOOTSERVICE_ACCESS |
258 EFI_VARIABLE_RUNTIME_ACCESS,
259 size, data);
260
261 FreePool(data);
262
263 if (EFI_ERROR(efi_status)) {
264 console_print(L"Could not create variable: %r\n",
265 efi_status);
266 return efi_status;
267 }
268
269 CHAR16 *newbootorder = AllocateZeroPool(sizeof (CHAR16)
270 * (nbootorder + 1));
271 if (!newbootorder)
272 return EFI_OUT_OF_RESOURCES;
273
274 int j = 0;
275 newbootorder[0] = i & 0xffff;
276 if (nbootorder) {
277 for (j = 0; j < nbootorder; j++)
278 newbootorder[j+1] = bootorder[j];
279 FreePool(bootorder);
280 }
281 bootorder = newbootorder;
282 nbootorder += 1;
283 #ifdef DEBUG_FALLBACK
284 console_print(L"nbootorder: %d\nBootOrder: ",
285 nbootorder);
286 for (j = 0 ; j < nbootorder ; j++)
287 console_print(L"%04x ", bootorder[j]);
288 console_print(L"\n");
289 #endif
290
291 return EFI_SUCCESS;
292 }
293 }
294 return EFI_OUT_OF_RESOURCES;
295 }
296
297 /*
298 * AMI BIOS (e.g, Intel NUC5i3MYHE) may automatically hide and patch BootXXXX
299 * variables with ami_masked_device_path_guid. We can get the valid device path
300 * if just skipping it and its next end path.
301 */
302
303 static EFI_GUID ami_masked_device_path_guid = {
304 0x99e275e7, 0x75a0, 0x4b37,
305 { 0xa2, 0xe6, 0xc5, 0x38, 0x5e, 0x6c, 0x0, 0xcb }
306 };
307
308 static unsigned int
309 calc_masked_boot_option_size(unsigned int size)
310 {
311 return size + sizeof(EFI_DEVICE_PATH) +
312 sizeof(ami_masked_device_path_guid) + sizeof(EFI_DEVICE_PATH);
313 }
314
315 static int
316 check_masked_boot_option(CHAR8 *candidate, unsigned int candidate_size,
317 CHAR8 *data, unsigned int data_size)
318 {
319 /*
320 * The patched BootXXXX variables contain a hardware device path and
321 * an end path, preceding the real device path.
322 */
323 if (calc_masked_boot_option_size(data_size) != candidate_size)
324 return 1;
325
326 CHAR8 *cursor = candidate;
327
328 /* Check whether the BootXXXX is patched */
329 cursor += sizeof(UINT32) + sizeof(UINT16);
330 cursor += StrSize((CHAR16 *)cursor);
331
332 unsigned int min_valid_size = cursor - candidate + sizeof(EFI_DEVICE_PATH);
333
334 if (candidate_size <= min_valid_size)
335 return 1;
336
337 EFI_DEVICE_PATH *dp = (EFI_DEVICE_PATH *)cursor;
338 unsigned int node_size = DevicePathNodeLength(dp) - sizeof(EFI_DEVICE_PATH);
339
340 min_valid_size += node_size;
341 if (candidate_size <= min_valid_size ||
342 DevicePathType(dp) != HARDWARE_DEVICE_PATH ||
343 DevicePathSubType(dp) != HW_VENDOR_DP ||
344 node_size != sizeof(ami_masked_device_path_guid) ||
345 CompareGuid((EFI_GUID *)(cursor + sizeof(EFI_DEVICE_PATH)),
346 &ami_masked_device_path_guid))
347 return 1;
348
349 /* Check whether the patched guid is followed by an end path */
350 min_valid_size += sizeof(EFI_DEVICE_PATH);
351 if (candidate_size <= min_valid_size)
352 return 1;
353
354 dp = NextDevicePathNode(dp);
355 if (!IsDevicePathEnd(dp))
356 return 1;
357
358 /*
359 * OK. We may really get a masked BootXXXX variable. The next
360 * step is to test whether it is hidden.
361 */
362 UINT32 attrs = *(UINT32 *)candidate;
363 #ifndef LOAD_OPTION_HIDDEN
364 # define LOAD_OPTION_HIDDEN 0x00000008
365 #endif
366 if (!(attrs & LOAD_OPTION_HIDDEN))
367 return 1;
368
369 attrs &= ~LOAD_OPTION_HIDDEN;
370
371 /* Compare the field Attributes */
372 if (attrs != *(UINT32 *)data)
373 return 1;
374
375 /* Compare the field FilePathListLength */
376 data += sizeof(UINT32);
377 candidate += sizeof(UINT32);
378 if (calc_masked_boot_option_size(*(UINT16 *)data) !=
379 *(UINT16 *)candidate)
380 return 1;
381
382 /* Compare the field Description */
383 data += sizeof(UINT16);
384 candidate += sizeof(UINT16);
385 if (CompareMem(candidate, data, cursor - candidate))
386 return 1;
387
388 /* Compare the filed FilePathList */
389 cursor = (CHAR8 *)NextDevicePathNode(dp);
390 data += sizeof(UINT16);
391 data += StrSize((CHAR16 *)data);
392
393 return CompareMem(cursor, data, candidate_size - min_valid_size);
394 }
395
396 EFI_STATUS
397 find_boot_option(EFI_DEVICE_PATH *dp, EFI_DEVICE_PATH *fulldp,
398 CHAR16 *filename, CHAR16 *label, CHAR16 *arguments,
399 UINT16 *optnum)
400 {
401 unsigned int size = sizeof(UINT32) + sizeof (UINT16) +
402 StrLen(label)*2 + 2 + DevicePathSize(dp) +
403 StrLen(arguments) * 2;
404
405 CHAR8 *data = AllocateZeroPool(size + 2);
406 if (!data)
407 return EFI_OUT_OF_RESOURCES;
408 CHAR8 *cursor = data;
409 *(UINT32 *)cursor = LOAD_OPTION_ACTIVE;
410 cursor += sizeof (UINT32);
411 *(UINT16 *)cursor = DevicePathSize(dp);
412 cursor += sizeof (UINT16);
413 StrCpy((CHAR16 *)cursor, label);
414 cursor += StrLen(label)*2 + 2;
415 CopyMem(cursor, dp, DevicePathSize(dp));
416 cursor += DevicePathSize(dp);
417 StrCpy((CHAR16 *)cursor, arguments);
418
419 int i = 0;
420 CHAR16 varname[] = L"Boot0000";
421 CHAR16 hexmap[] = L"0123456789ABCDEF";
422 EFI_STATUS efi_status;
423
424 UINTN max_candidate_size = calc_masked_boot_option_size(size);
425 CHAR8 *candidate = AllocateZeroPool(max_candidate_size);
426 if (!candidate) {
427 FreePool(data);
428 return EFI_OUT_OF_RESOURCES;
429 }
430
431 for(i = 0; i < nbootorder && i < 0x10000; i++) {
432 varname[4] = hexmap[(bootorder[i] & 0xf000) >> 12];
433 varname[5] = hexmap[(bootorder[i] & 0x0f00) >> 8];
434 varname[6] = hexmap[(bootorder[i] & 0x00f0) >> 4];
435 varname[7] = hexmap[(bootorder[i] & 0x000f) >> 0];
436
437 UINTN candidate_size = max_candidate_size;
438 efi_status = gRT->GetVariable(varname, &GV_GUID, NULL,
439 &candidate_size, candidate);
440 if (EFI_ERROR(efi_status))
441 continue;
442
443 if (candidate_size != size) {
444 if (check_masked_boot_option(candidate, candidate_size,
445 data, size))
446 continue;
447 } else if (CompareMem(candidate, data, size))
448 continue;
449
450 VerbosePrint(L"Found boot entry \"%s\" with label \"%s\" "
451 L"for file \"%s\"\n", varname, label, filename);
452
453 /* at this point, we have duplicate data. */
454 if (!first_new_option) {
455 first_new_option = DuplicateDevicePath(fulldp);
456 first_new_option_args = arguments;
457 first_new_option_size = StrLen(arguments) * sizeof (CHAR16);
458 }
459
460 *optnum = i;
461 FreePool(candidate);
462 FreePool(data);
463 return EFI_SUCCESS;
464 }
465 FreePool(candidate);
466 FreePool(data);
467 return EFI_NOT_FOUND;
468 }
469
470 EFI_STATUS
471 set_boot_order(void)
472 {
473 CHAR16 *oldbootorder;
474 UINTN size;
475
476 oldbootorder = LibGetVariableAndSize(L"BootOrder", &GV_GUID, &size);
477 if (oldbootorder) {
478 nbootorder = size / sizeof (CHAR16);
479 bootorder = oldbootorder;
480 }
481 return EFI_SUCCESS;
482
483 }
484
485 EFI_STATUS
486 update_boot_order(void)
487 {
488 UINTN size;
489 UINTN len = 0;
490 CHAR16 *newbootorder = NULL;
491 EFI_STATUS efi_status;
492
493 size = nbootorder * sizeof(CHAR16);
494 newbootorder = AllocateZeroPool(size);
495 if (!newbootorder)
496 return EFI_OUT_OF_RESOURCES;
497 CopyMem(newbootorder, bootorder, size);
498
499 VerbosePrint(L"nbootorder: %d\nBootOrder: ", size / sizeof (CHAR16));
500 UINTN j;
501 for (j = 0 ; j < size / sizeof (CHAR16); j++)
502 VerbosePrintUnprefixed(L"%04x ", newbootorder[j]);
503 console_print(L"\n");
504 efi_status = gRT->GetVariable(L"BootOrder", &GV_GUID, NULL, &len, NULL);
505 if (efi_status == EFI_BUFFER_TOO_SMALL)
506 LibDeleteVariable(L"BootOrder", &GV_GUID);
507
508 efi_status = gRT->SetVariable(L"BootOrder", &GV_GUID,
509 EFI_VARIABLE_NON_VOLATILE |
510 EFI_VARIABLE_BOOTSERVICE_ACCESS |
511 EFI_VARIABLE_RUNTIME_ACCESS,
512 size, newbootorder);
513 FreePool(newbootorder);
514 return efi_status;
515 }
516
517 EFI_STATUS
518 add_to_boot_list(CHAR16 *dirname, CHAR16 *filename, CHAR16 *label, CHAR16 *arguments)
519 {
520 CHAR16 *fullpath = NULL;
521 UINT64 pathlen = 0;
522 EFI_STATUS efi_status;
523
524 efi_status = make_full_path(dirname, filename, &fullpath, &pathlen);
525 if (EFI_ERROR(efi_status))
526 return efi_status;
527
528 EFI_DEVICE_PATH *full_device_path = NULL;
529 EFI_DEVICE_PATH *dp = NULL;
530 CHAR16 *dps;
531
532 full_device_path = FileDevicePath(this_image->DeviceHandle, fullpath);
533 if (!full_device_path) {
534 efi_status = EFI_OUT_OF_RESOURCES;
535 goto err;
536 }
537 dps = DevicePathToStr(full_device_path);
538 VerbosePrint(L"file DP: %s\n", dps);
539 FreePool(dps);
540
541 efi_status = FindSubDevicePath(full_device_path,
542 MEDIA_DEVICE_PATH, MEDIA_HARDDRIVE_DP,
543 &dp);
544 if (EFI_ERROR(efi_status)) {
545 if (efi_status == EFI_NOT_FOUND) {
546 dp = full_device_path;
547 } else {
548 efi_status = EFI_OUT_OF_RESOURCES;
549 goto err;
550 }
551 }
552
553 {
554 UINTN s = DevicePathSize(dp);
555 UINTN i;
556 UINT8 *dpv = (void *)dp;
557 for (i = 0; i < s; i++) {
558 if (i % 16 == 0) {
559 if (i > 0)
560 VerbosePrintUnprefixed(L"\n");
561 VerbosePrint(L"");
562 }
563 VerbosePrintUnprefixed(L"%02x ", dpv[i]);
564 }
565 VerbosePrintUnprefixed(L"\n");
566
567 CHAR16 *dps = DevicePathToStr(dp);
568 VerbosePrint(L"device path: \"%s\"\n", dps);
569 FreePool(dps);
570 }
571
572 UINT16 option;
573 efi_status = find_boot_option(dp, full_device_path, fullpath, label,
574 arguments, &option);
575 if (EFI_ERROR(efi_status)) {
576 add_boot_option(dp, full_device_path, fullpath, label,
577 arguments);
578 } else if (option != 0) {
579 CHAR16 *newbootorder;
580 newbootorder = AllocateZeroPool(sizeof (CHAR16) * nbootorder);
581 if (!newbootorder)
582 return EFI_OUT_OF_RESOURCES;
583
584 newbootorder[0] = bootorder[option];
585 CopyMem(newbootorder + 1, bootorder, sizeof (CHAR16) * option);
586 CopyMem(newbootorder + option + 1, bootorder + option + 1,
587 sizeof (CHAR16) * (nbootorder - option - 1));
588 FreePool(bootorder);
589 bootorder = newbootorder;
590 }
591
592 err:
593 if (full_device_path)
594 FreePool(full_device_path);
595 if (dp && dp != full_device_path)
596 FreePool(dp);
597 if (fullpath)
598 FreePool(fullpath);
599 return efi_status;
600 }
601
602 EFI_STATUS
603 populate_stanza(CHAR16 *dirname, CHAR16 *filename, CHAR16 *csv)
604 {
605 CHAR16 *file = csv;
606 VerbosePrint(L"CSV data: \"%s\"\n", csv);
607
608 UINTN comma0 = StrCSpn(csv, L",");
609 if (comma0 == 0)
610 return EFI_INVALID_PARAMETER;
611 file[comma0] = L'\0';
612 VerbosePrint(L"filename: \"%s\"\n", file);
613
614 CHAR16 *label = csv + comma0 + 1;
615 UINTN comma1 = StrCSpn(label, L",");
616 if (comma1 == 0)
617 return EFI_INVALID_PARAMETER;
618 label[comma1] = L'\0';
619 VerbosePrint(L"label: \"%s\"\n", label);
620
621 CHAR16 *arguments = csv + comma0 +1 + comma1 +1;
622 UINTN comma2 = StrCSpn(arguments, L",");
623 arguments[comma2] = L'\0';
624 /* This one is optional, so don't check if comma2 is 0 */
625 VerbosePrint(L"arguments: \"%s\"\n", arguments);
626
627 add_to_boot_list(dirname, file, label, arguments);
628
629 return EFI_SUCCESS;
630 }
631
632 EFI_STATUS
633 try_boot_csv(EFI_FILE_HANDLE fh, CHAR16 *dirname, CHAR16 *filename)
634 {
635 CHAR16 *fullpath = NULL;
636 UINT64 pathlen = 0;
637 EFI_STATUS efi_status;
638
639 efi_status = make_full_path(dirname, filename, &fullpath, &pathlen);
640 if (EFI_ERROR(efi_status))
641 return efi_status;
642
643 VerbosePrint(L"Found file \"%s\"\n", fullpath);
644
645 CHAR16 *buffer;
646 UINT64 bs;
647 efi_status = read_file(fh, fullpath, &buffer, &bs);
648 if (EFI_ERROR(efi_status)) {
649 console_print(L"Could not read file \"%s\": %r\n",
650 fullpath, efi_status);
651 FreePool(fullpath);
652 return efi_status;
653 }
654 FreePool(fullpath);
655
656 VerbosePrint(L"File looks like:\n%s\n", buffer);
657
658 CHAR16 *start = buffer;
659 /* The file may or may not start with the Unicode byte order marker.
660 * Sadness ensues. Since UEFI is defined as LE, I'm going to decree
661 * that these files must also be LE.
662 *
663 * IT IS THUS SO.
664 *
665 * But if we find the LE byte order marker, just skip it.
666 */
667 if (*start == 0xfeff)
668 start++;
669 while (*start) {
670 while (*start == L'\r' || *start == L'\n')
671 start++;
672 UINTN l = StrCSpn(start, L"\r\n");
673 if (l == 0) {
674 if (start[l] == L'\0')
675 break;
676 start++;
677 continue;
678 }
679 CHAR16 c = start[l];
680 start[l] = L'\0';
681
682 populate_stanza(dirname, filename, start);
683
684 start[l] = c;
685 start += l;
686 }
687
688 FreePool(buffer);
689 return EFI_SUCCESS;
690 }
691
692 EFI_STATUS
693 find_boot_csv(EFI_FILE_HANDLE fh, CHAR16 *dirname)
694 {
695 EFI_STATUS efi_status;
696 void *buffer = NULL;
697 UINTN bs = 0;
698
699 /* The API here is "Call it once with bs=0, it fills in bs,
700 * then allocate a buffer and ask again to get it filled. */
701 efi_status = fh->GetInfo(fh, &EFI_FILE_INFO_GUID, &bs, NULL);
702 if (EFI_ERROR(efi_status) && efi_status != EFI_BUFFER_TOO_SMALL) {
703 console_print(L"Could not get directory info for \\EFI\\%s\\: %r\n",
704 dirname, efi_status);
705 return efi_status;
706 }
707 if (bs == 0)
708 return EFI_SUCCESS;
709
710 buffer = AllocateZeroPool(bs);
711 if (!buffer) {
712 console_print(L"Could not allocate memory\n");
713 return EFI_OUT_OF_RESOURCES;
714 }
715
716 efi_status = fh->GetInfo(fh, &EFI_FILE_INFO_GUID, &bs, buffer);
717 /* This checks *either* the error from the first GetInfo, if it isn't
718 * the EFI_BUFFER_TOO_SMALL we're expecting, or the second GetInfo
719 * call in *any* case. */
720 if (EFI_ERROR(efi_status)) {
721 console_print(L"Could not get info for \"%s\": %r\n", dirname,
722 efi_status);
723 if (buffer)
724 FreePool(buffer);
725 return efi_status;
726 }
727
728 EFI_FILE_INFO *fi = buffer;
729 if (!(fi->Attribute & EFI_FILE_DIRECTORY)) {
730 FreePool(buffer);
731 return EFI_SUCCESS;
732 }
733 FreePool(buffer);
734 buffer = NULL;
735
736 CHAR16 *bootcsv=NULL, *bootarchcsv=NULL;
737
738 bs = 0;
739 do {
740 bs = 0;
741 efi_status = fh->Read(fh, &bs, NULL);
742 if (EFI_ERROR(efi_status) &&
743 efi_status != EFI_BUFFER_TOO_SMALL) {
744 console_print(L"Could not read \\EFI\\%s\\: %r\n",
745 dirname, efi_status);
746 return efi_status;
747 }
748 /* If there's no data to read, don't try to allocate 0 bytes
749 * and read the data... */
750 if (bs == 0)
751 break;
752
753 buffer = AllocateZeroPool(bs);
754 if (!buffer) {
755 console_print(L"Could not allocate memory\n");
756 return EFI_OUT_OF_RESOURCES;
757 }
758
759 efi_status = fh->Read(fh, &bs, buffer);
760 if (EFI_ERROR(efi_status)) {
761 console_print(L"Could not read \\EFI\\%s\\: %r\n",
762 dirname, efi_status);
763 FreePool(buffer);
764 return efi_status;
765 }
766
767 if (bs == 0)
768 break;
769
770 fi = buffer;
771
772 if (!bootcsv && !StrCaseCmp(fi->FileName, L"boot.csv"))
773 bootcsv = StrDuplicate(fi->FileName);
774
775 if (!bootarchcsv &&
776 !StrCaseCmp(fi->FileName, L"boot" EFI_ARCH L".csv"))
777 bootarchcsv = StrDuplicate(fi->FileName);
778
779 FreePool(buffer);
780 buffer = NULL;
781 } while (bs != 0);
782
783 efi_status = EFI_SUCCESS;
784 if (bootarchcsv) {
785 EFI_FILE_HANDLE fh2;
786 efi_status = fh->Open(fh, &fh2, bootarchcsv,
787 EFI_FILE_READ_ONLY, 0);
788 if (EFI_ERROR(efi_status) || fh2 == NULL) {
789 console_print(L"Couldn't open \\EFI\\%s\\%s: %r\n",
790 dirname, bootarchcsv, efi_status);
791 } else {
792 efi_status = try_boot_csv(fh2, dirname, bootarchcsv);
793 fh2->Close(fh2);
794 if (EFI_ERROR(efi_status))
795 console_print(L"Could not process \\EFI\\%s\\%s: %r\n",
796 dirname, bootarchcsv, efi_status);
797 }
798 }
799 if ((EFI_ERROR(efi_status) || !bootarchcsv) && bootcsv) {
800 EFI_FILE_HANDLE fh2;
801 efi_status = fh->Open(fh, &fh2, bootcsv,
802 EFI_FILE_READ_ONLY, 0);
803 if (EFI_ERROR(efi_status) || fh2 == NULL) {
804 console_print(L"Couldn't open \\EFI\\%s\\%s: %r\n",
805 dirname, bootcsv, efi_status);
806 } else {
807 efi_status = try_boot_csv(fh2, dirname, bootcsv);
808 fh2->Close(fh2);
809 if (EFI_ERROR(efi_status))
810 console_print(L"Could not process \\EFI\\%s\\%s: %r\n",
811 dirname, bootarchcsv, efi_status);
812 }
813 }
814 return EFI_SUCCESS;
815 }
816
817 EFI_STATUS
818 find_boot_options(EFI_HANDLE device)
819 {
820 EFI_STATUS efi_status;
821 EFI_FILE_IO_INTERFACE *fio = NULL;
822
823 efi_status = gBS->HandleProtocol(device, &FileSystemProtocol,
824 (void **) &fio);
825 if (EFI_ERROR(efi_status)) {
826 console_print(L"Couldn't find file system: %r\n", efi_status);
827 return efi_status;
828 }
829
830 /* EFI_FILE_HANDLE is a pointer to an EFI_FILE, and I have
831 * *no idea* what frees the memory allocated here. Hopefully
832 * Close() does. */
833 EFI_FILE_HANDLE fh = NULL;
834 efi_status = fio->OpenVolume(fio, &fh);
835 if (EFI_ERROR(efi_status) || fh == NULL) {
836 console_print(L"Couldn't open file system: %r\n", efi_status);
837 return efi_status;
838 }
839
840 EFI_FILE_HANDLE fh2 = NULL;
841 efi_status = fh->Open(fh, &fh2, L"EFI", EFI_FILE_READ_ONLY, 0);
842 if (EFI_ERROR(efi_status) || fh2 == NULL) {
843 console_print(L"Couldn't open EFI: %r\n", efi_status);
844 fh->Close(fh);
845 return efi_status;
846 }
847 efi_status = fh2->SetPosition(fh2, 0);
848 if (EFI_ERROR(efi_status)) {
849 console_print(L"Couldn't set file position: %r\n", efi_status);
850 fh2->Close(fh2);
851 fh->Close(fh);
852 return efi_status;
853 }
854
855 void *buffer;
856 UINTN bs;
857 do {
858 bs = 0;
859 efi_status = fh2->Read(fh2, &bs, NULL);
860 if (EFI_ERROR(efi_status) && efi_status != EFI_BUFFER_TOO_SMALL) {
861 console_print(L"Could not read \\EFI\\: %r\n", efi_status);
862 return efi_status;
863 }
864 if (bs == 0)
865 break;
866
867 buffer = AllocateZeroPool(bs);
868 if (!buffer) {
869 console_print(L"Could not allocate memory\n");
870 /* sure, this might work, why not? */
871 fh2->Close(fh2);
872 fh->Close(fh);
873 return EFI_OUT_OF_RESOURCES;
874 }
875
876 efi_status = fh2->Read(fh2, &bs, buffer);
877 if (EFI_ERROR(efi_status)) {
878 if (buffer) {
879 FreePool(buffer);
880 buffer = NULL;
881 }
882 fh2->Close(fh2);
883 fh->Close(fh);
884 return efi_status;
885 }
886 EFI_FILE_INFO *fi = buffer;
887
888 if (!(fi->Attribute & EFI_FILE_DIRECTORY)) {
889 FreePool(buffer);
890 buffer = NULL;
891 continue;
892 }
893 if (!StrCmp(fi->FileName, L".") ||
894 !StrCmp(fi->FileName, L"..") ||
895 !StrCaseCmp(fi->FileName, L"BOOT")) {
896 FreePool(buffer);
897 buffer = NULL;
898 continue;
899 }
900 VerbosePrint(L"Found directory named \"%s\"\n", fi->FileName);
901
902 EFI_FILE_HANDLE fh3;
903 efi_status = fh2->Open(fh2, &fh3, fi->FileName,
904 EFI_FILE_READ_ONLY, 0);
905 if (EFI_ERROR(efi_status)) {
906 console_print(L"%d Couldn't open %s: %r\n", __LINE__,
907 fi->FileName, efi_status);
908 FreePool(buffer);
909 buffer = NULL;
910 continue;
911 }
912
913 efi_status = find_boot_csv(fh3, fi->FileName);
914 fh3->Close(fh3);
915 FreePool(buffer);
916 buffer = NULL;
917 if (efi_status == EFI_OUT_OF_RESOURCES)
918 break;
919
920 } while (1);
921
922 if (!EFI_ERROR(efi_status) && nbootorder > 0)
923 efi_status = update_boot_order();
924
925 fh2->Close(fh2);
926 fh->Close(fh);
927 return efi_status;
928 }
929
930 static EFI_STATUS
931 try_start_first_option(EFI_HANDLE parent_image_handle)
932 {
933 EFI_STATUS efi_status;
934 EFI_HANDLE image_handle;
935
936 if (!first_new_option) {
937 return EFI_SUCCESS;
938 }
939
940 efi_status = gBS->LoadImage(0, parent_image_handle, first_new_option,
941 NULL, 0, &image_handle);
942 if (EFI_ERROR(efi_status)) {
943 CHAR16 *dps = DevicePathToStr(first_new_option);
944 UINTN s = DevicePathSize(first_new_option);
945 unsigned int i;
946 UINT8 *dpv = (void *)first_new_option;
947 console_print(L"LoadImage failed: %r\nDevice path: \"%s\"\n",
948 efi_status, dps);
949 for (i = 0; i < s; i++) {
950 if (i > 0 && i % 16 == 0)
951 console_print(L"\n");
952 console_print(L"%02x ", dpv[i]);
953 }
954 console_print(L"\n");
955
956 msleep(500000000);
957 return efi_status;
958 }
959
960 EFI_LOADED_IMAGE *image;
961 efi_status = gBS->HandleProtocol(image_handle, &LoadedImageProtocol,
962 (void *) &image);
963 if (!EFI_ERROR(efi_status)) {
964 image->LoadOptions = first_new_option_args;
965 image->LoadOptionsSize = first_new_option_size;
966 }
967
968 efi_status = gBS->StartImage(image_handle, NULL, NULL);
969 if (EFI_ERROR(efi_status)) {
970 console_print(L"StartImage failed: %r\n", efi_status);
971 msleep(500000000);
972 }
973 return efi_status;
974 }
975
976 static UINT32
977 get_fallback_no_reboot(void)
978 {
979 EFI_STATUS efi_status;
980 UINT32 no_reboot;
981 UINTN size = sizeof(UINT32);
982
983 efi_status = gRT->GetVariable(NO_REBOOT, &SHIM_LOCK_GUID,
984 NULL, &size, &no_reboot);
985 if (!EFI_ERROR(efi_status)) {
986 return no_reboot;
987 }
988 return 0;
989 }
990
991 static EFI_STATUS
992 set_fallback_no_reboot(void)
993 {
994 EFI_STATUS efi_status;
995 UINT32 no_reboot = 1;
996 efi_status = gRT->SetVariable(NO_REBOOT, &SHIM_LOCK_GUID,
997 EFI_VARIABLE_NON_VOLATILE
998 | EFI_VARIABLE_BOOTSERVICE_ACCESS
999 | EFI_VARIABLE_RUNTIME_ACCESS,
1000 sizeof(UINT32), &no_reboot);
1001 return efi_status;
1002 }
1003
1004 static int
1005 draw_countdown(void)
1006 {
1007 CHAR16 *title = L"Boot Option Restoration";
1008 CHAR16 *message = L"Press any key to stop system reset";
1009 int timeout;
1010
1011 timeout = console_countdown(title, message, 5);
1012
1013 return timeout;
1014 }
1015
1016 static int
1017 get_user_choice(void)
1018 {
1019 int choice;
1020 CHAR16 *title[] = {L"Boot Option Restored", NULL};
1021 CHAR16 *menu_strings[] = {
1022 L"Reset system",
1023 L"Continue boot",
1024 L"Always continue boot",
1025 NULL
1026 };
1027
1028 do {
1029 choice = console_select(title, menu_strings, 0);
1030 } while (choice < 0 || choice > 2);
1031
1032 return choice;
1033 }
1034
1035 extern EFI_STATUS
1036 efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab);
1037
1038 static void
1039 __attribute__((__optimize__("0")))
1040 debug_hook(void)
1041 {
1042 UINT8 *data = NULL;
1043 UINTN dataSize = 0;
1044 EFI_STATUS efi_status;
1045 register volatile int x = 0;
1046 extern char _etext, _edata;
1047
1048 efi_status = get_variable(L"SHIM_DEBUG", &data, &dataSize,
1049 SHIM_LOCK_GUID);
1050 if (EFI_ERROR(efi_status)) {
1051 return;
1052 }
1053
1054 if (data)
1055 FreePool(data);
1056 if (x)
1057 return;
1058
1059 x = 1;
1060 console_print(L"add-symbol-file "DEBUGDIR
1061 L"fb" EFI_ARCH L".efi.debug %p -s .data %p\n",
1062 &_etext, &_edata);
1063 }
1064
1065 EFI_STATUS
1066 efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
1067 {
1068 EFI_STATUS efi_status;
1069
1070 InitializeLib(image, systab);
1071
1072 /*
1073 * if SHIM_DEBUG is set, wait for a debugger to attach.
1074 */
1075 debug_hook();
1076
1077 efi_status = gBS->HandleProtocol(image, &LoadedImageProtocol,
1078 (void *) &this_image);
1079 if (EFI_ERROR(efi_status)) {
1080 console_print(L"Error: could not find loaded image: %r\n",
1081 efi_status);
1082 return efi_status;
1083 }
1084
1085 console_print(L"System BootOrder not found. Initializing defaults.\n");
1086
1087 set_boot_order();
1088
1089 efi_status = find_boot_options(this_image->DeviceHandle);
1090 if (EFI_ERROR(efi_status)) {
1091 console_print(L"Error: could not find boot options: %r\n",
1092 efi_status);
1093 return efi_status;
1094 }
1095
1096 efi_status = fallback_should_prefer_reset();
1097 if (EFI_ERROR(efi_status)) {
1098 VerbosePrint(L"tpm not present, starting the first image\n");
1099 try_start_first_option(image);
1100 } else {
1101 if (get_fallback_no_reboot() == 1) {
1102 VerbosePrint(L"NO_REBOOT is set, starting the first image\n");
1103 try_start_first_option(image);
1104 }
1105
1106 int timeout = draw_countdown();
1107 if (timeout == 0)
1108 goto reset;
1109
1110 int choice = get_user_choice();
1111 if (choice == 0) {
1112 goto reset;
1113 } else if (choice == 2) {
1114 efi_status = set_fallback_no_reboot();
1115 if (EFI_ERROR(efi_status))
1116 goto reset;
1117 }
1118 VerbosePrint(L"tpm present, starting the first image\n");
1119 try_start_first_option(image);
1120 reset:
1121 VerbosePrint(L"tpm present, resetting system\n");
1122 }
1123
1124 console_print(L"Reset System\n");
1125
1126 if (get_fallback_verbose()) {
1127 console_print(L"Verbose enabled, sleeping for half a second\n");
1128 msleep(500000);
1129 }
1130
1131 gRT->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL);
1132
1133 return EFI_SUCCESS;
1134 }