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