]> git.proxmox.com Git - efi-boot-shim.git/blob - fallback.c
fallback: Minor whitespace cleanup
[efi-boot-shim.git] / fallback.c
1 /*
2 * Copyright 2012-2013 Red Hat, Inc.
3 * All rights reserved.
4 *
5 * See "COPYING" for license terms.
6 *
7 * Author(s): Peter Jones <pjones@redhat.com>
8 */
9
10 #include <efi.h>
11 #include <efilib.h>
12
13 #include "ucs2.h"
14 #include "variables.h"
15
16 EFI_LOADED_IMAGE *this_image = NULL;
17
18 static EFI_STATUS
19 FindSubDevicePath(EFI_DEVICE_PATH *In, UINT8 Type, UINT8 SubType,
20 EFI_DEVICE_PATH **Out)
21 {
22 EFI_DEVICE_PATH *dp = In;
23 if (!In || !Out)
24 return EFI_INVALID_PARAMETER;
25
26 for (dp = In; !IsDevicePathEnd(dp); dp = NextDevicePathNode(dp)) {
27 if (DevicePathType(dp) == Type &&
28 DevicePathSubType(dp) == SubType) {
29 *Out = DuplicateDevicePath(dp);
30 if (!*Out)
31 return EFI_OUT_OF_RESOURCES;
32 return EFI_SUCCESS;
33 }
34 }
35 *Out = NULL;
36 return EFI_NOT_FOUND;
37 }
38
39 static EFI_STATUS
40 get_file_size(EFI_FILE_HANDLE fh, UINTN *retsize)
41 {
42 EFI_STATUS rc;
43 void *buffer = NULL;
44 UINTN bs = 0;
45 EFI_GUID finfo = EFI_FILE_INFO_ID;
46
47 /* The API here is "Call it once with bs=0, it fills in bs,
48 * then allocate a buffer and ask again to get it filled. */
49 rc = uefi_call_wrapper(fh->GetInfo, 4, fh, &finfo, &bs, NULL);
50 if (rc == EFI_BUFFER_TOO_SMALL) {
51 buffer = AllocateZeroPool(bs);
52 if (!buffer) {
53 Print(L"Could not allocate memory\n");
54 return EFI_OUT_OF_RESOURCES;
55 }
56 rc = uefi_call_wrapper(fh->GetInfo, 4, fh, &finfo,
57 &bs, buffer);
58 }
59 /* This checks *either* the error from the first GetInfo, if it isn't
60 * the EFI_BUFFER_TOO_SMALL we're expecting, or the second GetInfo call
61 * in *any* case. */
62 if (EFI_ERROR(rc)) {
63 Print(L"Could not get file info: %d\n", rc);
64 if (buffer)
65 FreePool(buffer);
66 return rc;
67 }
68 EFI_FILE_INFO *fi = buffer;
69 *retsize = fi->FileSize;
70 FreePool(buffer);
71 return EFI_SUCCESS;
72 }
73
74 EFI_STATUS
75 read_file(EFI_FILE_HANDLE fh, CHAR16 *fullpath, CHAR16 **buffer, UINT64 *bs)
76 {
77 EFI_FILE_HANDLE fh2;
78 EFI_STATUS rc = uefi_call_wrapper(fh->Open, 5, fh, &fh2, fullpath,
79 EFI_FILE_READ_ONLY, 0);
80 if (EFI_ERROR(rc)) {
81 Print(L"Couldn't open \"%s\": %d\n", fullpath, rc);
82 return rc;
83 }
84
85 UINTN len = 0;
86 CHAR16 *b = NULL;
87 rc = get_file_size(fh2, &len);
88 if (EFI_ERROR(rc)) {
89 uefi_call_wrapper(fh2->Close, 1, fh2);
90 return rc;
91 }
92
93 b = AllocateZeroPool(len + 2);
94 if (!buffer) {
95 Print(L"Could not allocate memory\n");
96 uefi_call_wrapper(fh2->Close, 1, fh2);
97 return EFI_OUT_OF_RESOURCES;
98 }
99
100 rc = uefi_call_wrapper(fh->Read, 3, fh, &len, b);
101 if (EFI_ERROR(rc)) {
102 FreePool(buffer);
103 uefi_call_wrapper(fh2->Close, 1, fh2);
104 Print(L"Could not read file: %d\n", rc);
105 return rc;
106 }
107 *buffer = b;
108 *bs = len;
109 uefi_call_wrapper(fh2->Close, 1, fh2);
110 return EFI_SUCCESS;
111 }
112
113 EFI_STATUS
114 make_full_path(CHAR16 *dirname, CHAR16 *filename, CHAR16 **out, UINT64 *outlen)
115 {
116 UINT64 len;
117
118 len = StrLen(L"\\EFI\\") + StrLen(dirname)
119 + StrLen(L"\\") + StrLen(filename)
120 + 2;
121
122 CHAR16 *fullpath = AllocateZeroPool(len*sizeof(CHAR16));
123 if (!fullpath) {
124 Print(L"Could not allocate memory\n");
125 return EFI_OUT_OF_RESOURCES;
126 }
127
128 StrCat(fullpath, L"\\EFI\\");
129 StrCat(fullpath, dirname);
130 StrCat(fullpath, L"\\");
131 StrCat(fullpath, filename);
132
133 *out = fullpath;
134 *outlen = len;
135 return EFI_SUCCESS;
136 }
137
138 CHAR16 *bootorder = NULL;
139 int nbootorder = 0;
140
141 EFI_DEVICE_PATH *first_new_option = NULL;
142 VOID *first_new_option_args = NULL;
143 UINTN first_new_option_size = 0;
144
145 EFI_STATUS
146 add_boot_option(EFI_DEVICE_PATH *hddp, EFI_DEVICE_PATH *fulldp,
147 CHAR16 *filename, CHAR16 *label, CHAR16 *arguments)
148 {
149 static int i = 0;
150 CHAR16 varname[] = L"Boot0000";
151 CHAR16 hexmap[] = L"0123456789ABCDEF";
152 EFI_GUID global = EFI_GLOBAL_VARIABLE;
153 EFI_STATUS rc;
154
155 for(; i <= 0xffff; i++) {
156 varname[4] = hexmap[(i & 0xf000) >> 12];
157 varname[5] = hexmap[(i & 0x0f00) >> 8];
158 varname[6] = hexmap[(i & 0x00f0) >> 4];
159 varname[7] = hexmap[(i & 0x000f) >> 0];
160
161 void *var = LibGetVariable(varname, &global);
162 if (!var) {
163 int size = sizeof(UINT32) + sizeof (UINT16) +
164 StrLen(label)*2 + 2 + DevicePathSize(hddp) +
165 StrLen(arguments) * 2;
166
167 CHAR8 *data = AllocateZeroPool(size + 2);
168 CHAR8 *cursor = data;
169 *(UINT32 *)cursor = LOAD_OPTION_ACTIVE;
170 cursor += sizeof (UINT32);
171 *(UINT16 *)cursor = DevicePathSize(hddp);
172 cursor += sizeof (UINT16);
173 StrCpy((CHAR16 *)cursor, label);
174 cursor += StrLen(label)*2 + 2;
175 CopyMem(cursor, hddp, DevicePathSize(hddp));
176 cursor += DevicePathSize(hddp);
177 StrCpy((CHAR16 *)cursor, arguments);
178
179 Print(L"Creating boot entry \"%s\" with label \"%s\" "
180 L"for file \"%s\"\n",
181 varname, label, filename);
182
183 if (!first_new_option) {
184 first_new_option = DuplicateDevicePath(fulldp);
185 first_new_option_args = arguments;
186 first_new_option_size = StrLen(arguments) * sizeof (CHAR16);
187 }
188
189 rc = uefi_call_wrapper(RT->SetVariable, 5, varname,
190 &global, EFI_VARIABLE_NON_VOLATILE |
191 EFI_VARIABLE_BOOTSERVICE_ACCESS |
192 EFI_VARIABLE_RUNTIME_ACCESS,
193 size, data);
194
195 FreePool(data);
196
197 if (EFI_ERROR(rc)) {
198 Print(L"Could not create variable: %d\n", rc);
199 return rc;
200 }
201
202 CHAR16 *newbootorder = AllocateZeroPool(sizeof (CHAR16)
203 * (nbootorder + 1));
204 if (!newbootorder)
205 return EFI_OUT_OF_RESOURCES;
206
207 int j = 0;
208 newbootorder[0] = i & 0xffff;
209 if (nbootorder) {
210 for (j = 0; j < nbootorder; j++)
211 newbootorder[j+1] = bootorder[j];
212 FreePool(bootorder);
213 }
214 bootorder = newbootorder;
215 nbootorder += 1;
216 #ifdef DEBUG_FALLBACK
217 Print(L"nbootorder: %d\nBootOrder: ", nbootorder);
218 for (j = 0 ; j < nbootorder ; j++)
219 Print(L"%04x ", bootorder[j]);
220 Print(L"\n");
221 #endif
222
223 return EFI_SUCCESS;
224 }
225 }
226 return EFI_OUT_OF_RESOURCES;
227 }
228
229 EFI_STATUS
230 find_boot_option(EFI_DEVICE_PATH *dp, EFI_DEVICE_PATH *fulldp,
231 CHAR16 *filename, CHAR16 *label, CHAR16 *arguments,
232 UINT16 *optnum)
233 {
234 unsigned int size = sizeof(UINT32) + sizeof (UINT16) +
235 StrLen(label)*2 + 2 + DevicePathSize(dp) +
236 StrLen(arguments) * 2;
237
238 CHAR8 *data = AllocateZeroPool(size + 2);
239 if (!data)
240 return EFI_OUT_OF_RESOURCES;
241 CHAR8 *cursor = data;
242 *(UINT32 *)cursor = LOAD_OPTION_ACTIVE;
243 cursor += sizeof (UINT32);
244 *(UINT16 *)cursor = DevicePathSize(dp);
245 cursor += sizeof (UINT16);
246 StrCpy((CHAR16 *)cursor, label);
247 cursor += StrLen(label)*2 + 2;
248 CopyMem(cursor, dp, DevicePathSize(dp));
249 cursor += DevicePathSize(dp);
250 StrCpy((CHAR16 *)cursor, arguments);
251
252 int i = 0;
253 CHAR16 varname[] = L"Boot0000";
254 CHAR16 hexmap[] = L"0123456789ABCDEF";
255 EFI_GUID global = EFI_GLOBAL_VARIABLE;
256 EFI_STATUS rc;
257
258 CHAR8 *candidate = AllocateZeroPool(size);
259 if (!candidate) {
260 FreePool(data);
261 return EFI_OUT_OF_RESOURCES;
262 }
263
264 for(i = 0; i < nbootorder && i < 0x10000; i++) {
265 varname[4] = hexmap[(bootorder[i] & 0xf000) >> 12];
266 varname[5] = hexmap[(bootorder[i] & 0x0f00) >> 8];
267 varname[6] = hexmap[(bootorder[i] & 0x00f0) >> 4];
268 varname[7] = hexmap[(bootorder[i] & 0x000f) >> 0];
269
270 UINTN candidate_size = size;
271 rc = uefi_call_wrapper(RT->GetVariable, 5, varname, &global,
272 NULL, &candidate_size, candidate);
273 if (EFI_ERROR(rc))
274 continue;
275
276 if (candidate_size != size)
277 continue;
278
279 if (CompareMem(candidate, data, size))
280 continue;
281
282 /* at this point, we have duplicate data. */
283 if (!first_new_option) {
284 first_new_option = DuplicateDevicePath(fulldp);
285 first_new_option_args = arguments;
286 first_new_option_size = StrLen(arguments) * sizeof (CHAR16);
287 }
288
289 *optnum = i;
290 FreePool(candidate);
291 FreePool(data);
292 return EFI_SUCCESS;
293 }
294 FreePool(candidate);
295 FreePool(data);
296 return EFI_NOT_FOUND;
297 }
298
299 EFI_STATUS
300 set_boot_order(void)
301 {
302 CHAR16 *oldbootorder;
303 UINTN size;
304 EFI_GUID global = EFI_GLOBAL_VARIABLE;
305
306 oldbootorder = LibGetVariableAndSize(L"BootOrder", &global, &size);
307 if (oldbootorder) {
308 nbootorder = size / sizeof (CHAR16);
309 bootorder = oldbootorder;
310 }
311 return EFI_SUCCESS;
312
313 }
314
315 EFI_STATUS
316 update_boot_order(void)
317 {
318 UINTN size;
319 UINTN len = 0;
320 EFI_GUID global = EFI_GLOBAL_VARIABLE;
321 CHAR16 *newbootorder = NULL;
322 EFI_STATUS rc;
323
324 size = nbootorder * sizeof(CHAR16);
325 newbootorder = AllocateZeroPool(size);
326 if (!newbootorder)
327 return EFI_OUT_OF_RESOURCES;
328 CopyMem(newbootorder, bootorder, size);
329
330 #ifdef DEBUG_FALLBACK
331 Print(L"nbootorder: %d\nBootOrder: ", size / sizeof (CHAR16));
332 UINTN j;
333 for (j = 0 ; j < size / sizeof (CHAR16); j++)
334 Print(L"%04x ", newbootorder[j]);
335 Print(L"\n");
336 #endif
337 rc = uefi_call_wrapper(RT->GetVariable, 5, L"BootOrder", &global,
338 NULL, &len, NULL);
339 if (rc == EFI_BUFFER_TOO_SMALL)
340 LibDeleteVariable(L"BootOrder", &global);
341
342 rc = uefi_call_wrapper(RT->SetVariable, 5, L"BootOrder", &global,
343 EFI_VARIABLE_NON_VOLATILE |
344 EFI_VARIABLE_BOOTSERVICE_ACCESS |
345 EFI_VARIABLE_RUNTIME_ACCESS,
346 size, newbootorder);
347 FreePool(newbootorder);
348 return rc;
349 }
350
351 EFI_STATUS
352 add_to_boot_list(EFI_FILE_HANDLE fh, CHAR16 *dirname, CHAR16 *filename, CHAR16 *label, CHAR16 *arguments)
353 {
354 CHAR16 *fullpath = NULL;
355 UINT64 pathlen = 0;
356 EFI_STATUS rc = EFI_SUCCESS;
357
358 rc = make_full_path(dirname, filename, &fullpath, &pathlen);
359 if (EFI_ERROR(rc))
360 return rc;
361
362 EFI_DEVICE_PATH *dph = NULL;
363 EFI_DEVICE_PATH *file = NULL;
364 EFI_DEVICE_PATH *full_device_path = NULL;
365 EFI_DEVICE_PATH *dp = NULL;
366
367 dph = DevicePathFromHandle(this_image->DeviceHandle);
368 if (!dph) {
369 rc = EFI_OUT_OF_RESOURCES;
370 goto err;
371 }
372
373 file = FileDevicePath(fh, fullpath);
374 if (!file) {
375 rc = EFI_OUT_OF_RESOURCES;
376 goto err;
377 }
378
379 full_device_path = AppendDevicePath(dph, file);
380 if (!full_device_path) {
381 rc = EFI_OUT_OF_RESOURCES;
382 goto err;
383 }
384
385 rc = FindSubDevicePath(full_device_path,
386 MEDIA_DEVICE_PATH, MEDIA_HARDDRIVE_DP, &dp);
387 if (EFI_ERROR(rc)) {
388 if (rc == EFI_NOT_FOUND) {
389 dp = full_device_path;
390 } else {
391 rc = EFI_OUT_OF_RESOURCES;
392 goto err;
393 }
394 }
395
396 #ifdef DEBUG_FALLBACK
397 {
398 UINTN s = DevicePathSize(dp);
399 UINTN i;
400 UINT8 *dpv = (void *)dp;
401 for (i = 0; i < s; i++) {
402 if (i > 0 && i % 16 == 0)
403 Print(L"\n");
404 Print(L"%02x ", dpv[i]);
405 }
406 Print(L"\n");
407
408 CHAR16 *dps = DevicePathToStr(dp);
409 Print(L"device path: \"%s\"\n", dps);
410 }
411 #endif
412
413 UINT16 option;
414 rc = find_boot_option(dp, full_device_path, fullpath, label, arguments, &option);
415 if (EFI_ERROR(rc)) {
416 add_boot_option(dp, full_device_path, fullpath, label, arguments);
417 } else if (option != 0) {
418 CHAR16 *newbootorder;
419 newbootorder = AllocateZeroPool(sizeof (CHAR16) * nbootorder);
420 if (!newbootorder)
421 return EFI_OUT_OF_RESOURCES;
422
423 newbootorder[0] = bootorder[option];
424 CopyMem(newbootorder + 1, bootorder, sizeof (CHAR16) * option);
425 CopyMem(newbootorder + option + 1, bootorder + option + 1,
426 sizeof (CHAR16) * (nbootorder - option - 1));
427 FreePool(bootorder);
428 bootorder = newbootorder;
429 }
430
431 err:
432 if (file)
433 FreePool(file);
434 if (full_device_path)
435 FreePool(full_device_path);
436 if (dp)
437 FreePool(dp);
438 if (fullpath)
439 FreePool(fullpath);
440 return rc;
441 }
442
443 EFI_STATUS
444 populate_stanza(EFI_FILE_HANDLE fh, CHAR16 *dirname, CHAR16 *filename, CHAR16 *csv)
445 {
446 #ifdef DEBUG_FALLBACK
447 Print(L"CSV data: \"%s\"\n", csv);
448 #endif
449 CHAR16 *file = csv;
450
451 UINTN comma0 = StrCSpn(csv, L",");
452 if (comma0 == 0)
453 return EFI_INVALID_PARAMETER;
454 file[comma0] = L'\0';
455 #ifdef DEBUG_FALLBACK
456 Print(L"filename: \"%s\"\n", file);
457 #endif
458
459 CHAR16 *label = csv + comma0 + 1;
460 UINTN comma1 = StrCSpn(label, L",");
461 if (comma1 == 0)
462 return EFI_INVALID_PARAMETER;
463 label[comma1] = L'\0';
464 #ifdef DEBUG_FALLBACK
465 Print(L"label: \"%s\"\n", label);
466 #endif
467
468 CHAR16 *arguments = csv + comma0 +1 + comma1 +1;
469 UINTN comma2 = StrCSpn(arguments, L",");
470 arguments[comma2] = L'\0';
471 /* This one is optional, so don't check if comma2 is 0 */
472 #ifdef DEBUG_FALLBACK
473 Print(L"arguments: \"%s\"\n", arguments);
474 #endif
475
476 add_to_boot_list(fh, dirname, file, label, arguments);
477
478 return EFI_SUCCESS;
479 }
480
481 EFI_STATUS
482 try_boot_csv(EFI_FILE_HANDLE fh, CHAR16 *dirname, CHAR16 *filename)
483 {
484 CHAR16 *fullpath = NULL;
485 UINT64 pathlen = 0;
486 EFI_STATUS rc;
487
488 rc = make_full_path(dirname, filename, &fullpath, &pathlen);
489 if (EFI_ERROR(rc))
490 return rc;
491
492 #ifdef DEBUG_FALLBACK
493 Print(L"Found file \"%s\"\n", fullpath);
494 #endif
495
496 CHAR16 *buffer;
497 UINT64 bs;
498 rc = read_file(fh, fullpath, &buffer, &bs);
499 if (EFI_ERROR(rc)) {
500 Print(L"Could not read file \"%s\": %d\n", fullpath, rc);
501 FreePool(fullpath);
502 return rc;
503 }
504 FreePool(fullpath);
505
506 #ifdef DEBUG_FALLBACK
507 Print(L"File looks like:\n%s\n", buffer);
508 #endif
509
510 CHAR16 *start = buffer;
511 /* The file may or may not start with the Unicode byte order marker.
512 * Sadness ensues. Since UEFI is defined as LE, I'm going to decree
513 * that these files must also be LE.
514 *
515 * IT IS THUS SO.
516 *
517 * But if we find the LE byte order marker, just skip it.
518 */
519 if (*start == 0xfeff)
520 start++;
521 while (*start) {
522 while (*start == L'\r' || *start == L'\n')
523 start++;
524 UINTN l = StrCSpn(start, L"\r\n");
525 if (l == 0) {
526 if (start[l] == L'\0')
527 break;
528 start++;
529 continue;
530 }
531 CHAR16 c = start[l];
532 start[l] = L'\0';
533
534 populate_stanza(fh, dirname, filename, start);
535
536 start[l] = c;
537 start += l;
538 }
539
540 FreePool(buffer);
541 return EFI_SUCCESS;
542 }
543
544 EFI_STATUS
545 find_boot_csv(EFI_FILE_HANDLE fh, CHAR16 *dirname)
546 {
547 EFI_STATUS rc;
548 void *buffer = NULL;
549 UINTN bs = 0;
550 EFI_GUID finfo = EFI_FILE_INFO_ID;
551
552 /* The API here is "Call it once with bs=0, it fills in bs,
553 * then allocate a buffer and ask again to get it filled. */
554 rc = uefi_call_wrapper(fh->GetInfo, 4, fh, &finfo, &bs, NULL);
555 if (rc == EFI_BUFFER_TOO_SMALL) {
556 buffer = AllocateZeroPool(bs);
557 if (!buffer) {
558 Print(L"Could not allocate memory\n");
559 return EFI_OUT_OF_RESOURCES;
560 }
561 rc = uefi_call_wrapper(fh->GetInfo, 4, fh, &finfo,
562 &bs, buffer);
563 }
564 /* This checks *either* the error from the first GetInfo, if it isn't
565 * the EFI_BUFFER_TOO_SMALL we're expecting, or the second GetInfo call
566 * in *any* case. */
567 if (EFI_ERROR(rc)) {
568 Print(L"Could not get info for \"%s\": %d\n", dirname, rc);
569 if (buffer)
570 FreePool(buffer);
571 return rc;
572 }
573
574 EFI_FILE_INFO *fi = buffer;
575 if (!(fi->Attribute & EFI_FILE_DIRECTORY)) {
576 FreePool(buffer);
577 return EFI_SUCCESS;
578 }
579 FreePool(buffer);
580 buffer = NULL;
581
582 CHAR16 *bootcsv=NULL, *bootarchcsv=NULL;
583
584 bs = 0;
585 do {
586 bs = 0;
587 rc = uefi_call_wrapper(fh->Read, 3, fh, &bs, NULL);
588 if (EFI_ERROR(rc) && rc != EFI_BUFFER_TOO_SMALL) {
589 Print(L"Could not read \\EFI\\%s\\: %d\n", dirname, rc);
590 if (buffer)
591 FreePool(buffer);
592 return rc;
593 }
594 /* If there's no data to read, don't try to allocate 0 bytes
595 * and read the data... */
596 if (bs == 0)
597 break;
598
599 buffer = AllocateZeroPool(bs);
600 if (!buffer) {
601 Print(L"Could not allocate memory\n");
602 return EFI_OUT_OF_RESOURCES;
603 }
604
605 rc = uefi_call_wrapper(fh->Read, 3, fh, &bs, buffer);
606 if (EFI_ERROR(rc)) {
607 Print(L"Could not read \\EFI\\%s\\: %d\n", dirname, rc);
608 FreePool(buffer);
609 return rc;
610 }
611
612 if (bs == 0)
613 break;
614
615 fi = buffer;
616
617 if (!bootcsv && !StrCaseCmp(fi->FileName, L"boot.csv"))
618 bootcsv = StrDuplicate(fi->FileName);
619
620 if (!bootarchcsv &&
621 !StrCaseCmp(fi->FileName, L"boot" EFI_ARCH L".csv"))
622 bootarchcsv = StrDuplicate(fi->FileName);
623
624 FreePool(buffer);
625 buffer = NULL;
626 } while (bs != 0);
627
628 rc = EFI_SUCCESS;
629 if (bootarchcsv) {
630 EFI_FILE_HANDLE fh2;
631 rc = uefi_call_wrapper(fh->Open, 5, fh, &fh2,
632 bootarchcsv, EFI_FILE_READ_ONLY, 0);
633 if (EFI_ERROR(rc) || fh2 == NULL) {
634 Print(L"Couldn't open \\EFI\\%s\\%s: %d\n",
635 dirname, bootarchcsv, rc);
636 } else {
637 rc = try_boot_csv(fh2, dirname, bootarchcsv);
638 uefi_call_wrapper(fh2->Close, 1, fh2);
639 }
640 }
641 if ((EFI_ERROR(rc) || !bootarchcsv) && bootcsv) {
642 EFI_FILE_HANDLE fh2;
643 rc = uefi_call_wrapper(fh->Open, 5, fh, &fh2,
644 bootcsv, EFI_FILE_READ_ONLY, 0);
645 if (EFI_ERROR(rc) || fh2 == NULL) {
646 Print(L"Couldn't open \\EFI\\%s\\%s: %d\n",
647 dirname, bootcsv, rc);
648 } else {
649 rc = try_boot_csv(fh2, dirname, bootcsv);
650 uefi_call_wrapper(fh2->Close, 1, fh2);
651 }
652 }
653 rc = EFI_SUCCESS;
654
655 return rc;
656 }
657
658 EFI_STATUS
659 find_boot_options(EFI_HANDLE device)
660 {
661 EFI_STATUS rc = EFI_SUCCESS;
662
663 EFI_FILE_IO_INTERFACE *fio = NULL;
664 rc = uefi_call_wrapper(BS->HandleProtocol, 3, device,
665 &FileSystemProtocol, (void **)&fio);
666 if (EFI_ERROR(rc)) {
667 Print(L"Couldn't find file system: %d\n", rc);
668 return rc;
669 }
670
671 /* EFI_FILE_HANDLE is a pointer to an EFI_FILE, and I have
672 * *no idea* what frees the memory allocated here. Hopefully
673 * Close() does. */
674 EFI_FILE_HANDLE fh = NULL;
675 rc = uefi_call_wrapper(fio->OpenVolume, 2, fio, &fh);
676 if (EFI_ERROR(rc) || fh == NULL) {
677 Print(L"Couldn't open file system: %d\n", rc);
678 return rc;
679 }
680
681 EFI_FILE_HANDLE fh2 = NULL;
682 rc = uefi_call_wrapper(fh->Open, 5, fh, &fh2, L"EFI",
683 EFI_FILE_READ_ONLY, 0);
684 if (EFI_ERROR(rc) || fh2 == NULL) {
685 Print(L"Couldn't open EFI: %d\n", rc);
686 uefi_call_wrapper(fh->Close, 1, fh);
687 return rc;
688 }
689 rc = uefi_call_wrapper(fh2->SetPosition, 2, fh2, 0);
690 if (EFI_ERROR(rc)) {
691 Print(L"Couldn't set file position: %d\n", rc);
692 uefi_call_wrapper(fh2->Close, 1, fh2);
693 uefi_call_wrapper(fh->Close, 1, fh);
694 return rc;
695 }
696
697 void *buffer;
698 UINTN bs;
699 do {
700 bs = 0;
701 rc = uefi_call_wrapper(fh2->Read, 3, fh2, &bs, NULL);
702 if (rc == EFI_BUFFER_TOO_SMALL ||
703 (rc == EFI_SUCCESS && bs != 0)) {
704 buffer = AllocateZeroPool(bs);
705 if (!buffer) {
706 Print(L"Could not allocate memory\n");
707 /* sure, this might work, why not? */
708 uefi_call_wrapper(fh2->Close, 1, fh2);
709 uefi_call_wrapper(fh->Close, 1, fh);
710 return EFI_OUT_OF_RESOURCES;
711 }
712
713 rc = uefi_call_wrapper(fh2->Read, 3, fh2, &bs, buffer);
714 }
715 if (bs == 0)
716 break;
717
718 if (EFI_ERROR(rc)) {
719 Print(L"Could not read \\EFI\\: %d\n", rc);
720 if (buffer) {
721 FreePool(buffer);
722 buffer = NULL;
723 }
724 uefi_call_wrapper(fh2->Close, 1, fh2);
725 uefi_call_wrapper(fh->Close, 1, fh);
726 return rc;
727 }
728 EFI_FILE_INFO *fi = buffer;
729
730 if (!(fi->Attribute & EFI_FILE_DIRECTORY)) {
731 FreePool(buffer);
732 buffer = NULL;
733 continue;
734 }
735 if (!StrCmp(fi->FileName, L".") ||
736 !StrCmp(fi->FileName, L"..") ||
737 !StrCaseCmp(fi->FileName, L"BOOT")) {
738 FreePool(buffer);
739 buffer = NULL;
740 continue;
741 }
742 #ifdef DEBUG_FALLBACK
743 Print(L"Found directory named \"%s\"\n", fi->FileName);
744 #endif
745
746 EFI_FILE_HANDLE fh3;
747 rc = uefi_call_wrapper(fh->Open, 5, fh2, &fh3, fi->FileName,
748 EFI_FILE_READ_ONLY, 0);
749 if (EFI_ERROR(rc)) {
750 Print(L"%d Couldn't open %s: %d\n", __LINE__, fi->FileName, rc);
751 FreePool(buffer);
752 buffer = NULL;
753 continue;
754 }
755
756 rc = find_boot_csv(fh3, fi->FileName);
757 FreePool(buffer);
758 buffer = NULL;
759 if (rc == EFI_OUT_OF_RESOURCES)
760 break;
761
762 } while (1);
763
764 if (rc == EFI_SUCCESS && nbootorder > 0)
765 rc = update_boot_order();
766
767 uefi_call_wrapper(fh2->Close, 1, fh2);
768 uefi_call_wrapper(fh->Close, 1, fh);
769 return rc;
770 }
771
772 static EFI_STATUS
773 try_start_first_option(EFI_HANDLE parent_image_handle)
774 {
775 EFI_STATUS rc;
776 EFI_HANDLE image_handle;
777
778 if (!first_new_option) {
779 return EFI_SUCCESS;
780 }
781
782 rc = uefi_call_wrapper(BS->LoadImage, 6, 0, parent_image_handle,
783 first_new_option, NULL, 0,
784 &image_handle);
785 if (EFI_ERROR(rc)) {
786 CHAR16 *dps = DevicePathToStr(first_new_option);
787 UINTN s = DevicePathSize(first_new_option);
788 unsigned int i;
789 UINT8 *dpv = (void *)first_new_option;
790 Print(L"LoadImage failed: %d\nDevice path: \"%s\"\n", rc, dps);
791 for (i = 0; i < s; i++) {
792 if (i > 0 && i % 16 == 0)
793 Print(L"\n");
794 Print(L"%02x ", dpv[i]);
795 }
796 Print(L"\n");
797
798 uefi_call_wrapper(BS->Stall, 1, 500000000);
799 return rc;
800 }
801
802 EFI_LOADED_IMAGE *image;
803 rc = uefi_call_wrapper(BS->HandleProtocol, 3, image_handle, &LoadedImageProtocol, (void *)&image);
804 if (!EFI_ERROR(rc)) {
805 image->LoadOptions = first_new_option_args;
806 image->LoadOptionsSize = first_new_option_size;
807 }
808
809 rc = uefi_call_wrapper(BS->StartImage, 3, image_handle, NULL, NULL);
810 if (EFI_ERROR(rc)) {
811 Print(L"StartImage failed: %d\n", rc);
812 uefi_call_wrapper(BS->Stall, 1, 500000000);
813 }
814 return rc;
815 }
816
817 EFI_GUID SHIM_LOCK_GUID = { 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23} };
818 extern EFI_STATUS
819 efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab);
820
821 static void
822 __attribute__((__optimize__("0")))
823 debug_hook(void)
824 {
825 EFI_GUID guid = SHIM_LOCK_GUID;
826 UINT8 *data = NULL;
827 UINTN dataSize = 0;
828 EFI_STATUS efi_status;
829 volatile register int x = 0;
830 extern char _etext, _edata;
831
832 efi_status = get_variable(L"SHIM_DEBUG", &data, &dataSize, guid);
833 if (EFI_ERROR(efi_status)) {
834 return;
835 }
836
837 if (x)
838 return;
839
840 x = 1;
841 Print(L"add-symbol-file "DEBUGDIR
842 L"fb" EFI_ARCH L".efi.debug %p -s .data %p\n", &_etext,
843 &_edata);
844 }
845
846 EFI_STATUS
847 efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
848 {
849 EFI_STATUS rc;
850
851 InitializeLib(image, systab);
852
853 /*
854 * if SHIM_DEBUG is set, wait for a debugger to attach.
855 */
856 debug_hook();
857
858 rc = uefi_call_wrapper(BS->HandleProtocol, 3, image, &LoadedImageProtocol, (void *)&this_image);
859 if (EFI_ERROR(rc)) {
860 Print(L"Error: could not find loaded image: %d\n", rc);
861 return rc;
862 }
863
864 Print(L"System BootOrder not found. Initializing defaults.\n");
865
866 set_boot_order();
867
868 rc = find_boot_options(this_image->DeviceHandle);
869 if (EFI_ERROR(rc)) {
870 Print(L"Error: could not find boot options: %d\n", rc);
871 return rc;
872 }
873
874 try_start_first_option(image);
875
876 Print(L"Reset System\n");
877 uefi_call_wrapper(RT->ResetSystem, 4, EfiResetCold,
878 EFI_SUCCESS, 0, NULL);
879
880 return EFI_SUCCESS;
881 }