]> git.proxmox.com Git - efi-boot-shim.git/blame - fallback.c
Cryptlib: Update to the latest edk2 commit
[efi-boot-shim.git] / fallback.c
CommitLineData
3ce517fd
PJ
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"
a0319607 14#include "variables.h"
3ce517fd
PJ
15
16EFI_LOADED_IMAGE *this_image = NULL;
17
dfd6c73a
PJ
18static EFI_STATUS
19FindSubDevicePath(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
3ce517fd 39static EFI_STATUS
d74ab697 40get_file_size(EFI_FILE_HANDLE fh, UINTN *retsize)
3ce517fd
PJ
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
74EFI_STATUS
75read_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
d74ab697 85 UINTN len = 0;
3ce517fd
PJ
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
113EFI_STATUS
114make_full_path(CHAR16 *dirname, CHAR16 *filename, CHAR16 **out, UINT64 *outlen)
115{
116 UINT64 len;
117
dfd6c73a
PJ
118 len = StrLen(L"\\EFI\\") + StrLen(dirname)
119 + StrLen(L"\\") + StrLen(filename)
120 + 2;
3ce517fd 121
4665fcab 122 CHAR16 *fullpath = AllocateZeroPool(len*sizeof(CHAR16));
3ce517fd
PJ
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
138CHAR16 *bootorder = NULL;
139int nbootorder = 0;
140
3fa9a534
PJ
141EFI_DEVICE_PATH *first_new_option = NULL;
142VOID *first_new_option_args = NULL;
143UINTN first_new_option_size = 0;
144
3ce517fd 145EFI_STATUS
dfd6c73a
PJ
146add_boot_option(EFI_DEVICE_PATH *hddp, EFI_DEVICE_PATH *fulldp,
147 CHAR16 *filename, CHAR16 *label, CHAR16 *arguments)
3ce517fd
PJ
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) +
dfd6c73a
PJ
164 StrLen(label)*2 + 2 + DevicePathSize(hddp) +
165 StrLen(arguments) * 2;
3ce517fd 166
6b251052 167 CHAR8 *data = AllocateZeroPool(size + 2);
3ce517fd
PJ
168 CHAR8 *cursor = data;
169 *(UINT32 *)cursor = LOAD_OPTION_ACTIVE;
170 cursor += sizeof (UINT32);
dfd6c73a 171 *(UINT16 *)cursor = DevicePathSize(hddp);
3ce517fd
PJ
172 cursor += sizeof (UINT16);
173 StrCpy((CHAR16 *)cursor, label);
174 cursor += StrLen(label)*2 + 2;
dfd6c73a
PJ
175 CopyMem(cursor, hddp, DevicePathSize(hddp));
176 cursor += DevicePathSize(hddp);
3ce517fd
PJ
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);
dfd6c73a
PJ
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
3ce517fd
PJ
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;
382a0b66 208 newbootorder[0] = i & 0xffff;
3ce517fd
PJ
209 if (nbootorder) {
210 for (j = 0; j < nbootorder; j++)
382a0b66 211 newbootorder[j+1] = bootorder[j];
3ce517fd
PJ
212 FreePool(bootorder);
213 }
3ce517fd
PJ
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
894a2738 229EFI_STATUS
0ba09477
GCPL
230find_boot_option(EFI_DEVICE_PATH *dp, EFI_DEVICE_PATH *fulldp,
231 CHAR16 *filename, CHAR16 *label, CHAR16 *arguments,
232 UINT16 *optnum)
894a2738 233{
5495694c 234 unsigned int size = sizeof(UINT32) + sizeof (UINT16) +
894a2738 235 StrLen(label)*2 + 2 + DevicePathSize(dp) +
4aac8a11 236 StrLen(arguments) * 2;
894a2738 237
6b251052 238 CHAR8 *data = AllocateZeroPool(size + 2);
894a2738
PJ
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. */
0ba09477
GCPL
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
894a2738
PJ
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
299EFI_STATUS
300set_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
3ce517fd
PJ
315EFI_STATUS
316update_boot_order(void)
317{
3ce517fd 318 UINTN size;
382a0b66 319 UINTN len = 0;
3ce517fd
PJ
320 EFI_GUID global = EFI_GLOBAL_VARIABLE;
321 CHAR16 *newbootorder = NULL;
382a0b66 322 EFI_STATUS rc;
3ce517fd 323
382a0b66
GCPL
324 size = nbootorder * sizeof(CHAR16);
325 newbootorder = AllocateZeroPool(size);
326 if (!newbootorder)
327 return EFI_OUT_OF_RESOURCES;
328 CopyMem(newbootorder, bootorder, size);
3ce517fd
PJ
329
330#ifdef DEBUG_FALLBACK
331 Print(L"nbootorder: %d\nBootOrder: ", size / sizeof (CHAR16));
90c65f72 332 UINTN j;
3ce517fd
PJ
333 for (j = 0 ; j < size / sizeof (CHAR16); j++)
334 Print(L"%04x ", newbootorder[j]);
335 Print(L"\n");
336#endif
382a0b66
GCPL
337 rc = uefi_call_wrapper(RT->GetVariable, 5, L"BootOrder", &global,
338 NULL, &len, NULL);
339 if (rc == EFI_BUFFER_TOO_SMALL)
3ce517fd 340 LibDeleteVariable(L"BootOrder", &global);
3ce517fd 341
3ce517fd
PJ
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
351EFI_STATUS
352add_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
dfd6c73a
PJ
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;
3ce517fd
PJ
366
367 dph = DevicePathFromHandle(this_image->DeviceHandle);
368 if (!dph) {
369 rc = EFI_OUT_OF_RESOURCES;
370 goto err;
371 }
372
dfd6c73a
PJ
373 file = FileDevicePath(fh, fullpath);
374 if (!file) {
3ce517fd
PJ
375 rc = EFI_OUT_OF_RESOURCES;
376 goto err;
377 }
378
dfd6c73a
PJ
379 full_device_path = AppendDevicePath(dph, file);
380 if (!full_device_path) {
3ce517fd
PJ
381 rc = EFI_OUT_OF_RESOURCES;
382 goto err;
383 }
384
dfd6c73a
PJ
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
3ce517fd 396#ifdef DEBUG_FALLBACK
dfd6c73a 397 {
3ce517fd 398 UINTN s = DevicePathSize(dp);
90c65f72 399 UINTN i;
3ce517fd
PJ
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);
3fa9a534 410 }
dfd6c73a 411#endif
3ce517fd 412
894a2738 413 UINT16 option;
0ba09477 414 rc = find_boot_option(dp, full_device_path, fullpath, label, arguments, &option);
894a2738
PJ
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 }
3ce517fd
PJ
430
431err:
dfd6c73a
PJ
432 if (file)
433 FreePool(file);
434 if (full_device_path)
435 FreePool(full_device_path);
3ce517fd
PJ
436 if (dp)
437 FreePool(dp);
438 if (fullpath)
439 FreePool(fullpath);
440 return rc;
441}
442
443EFI_STATUS
444populate_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
481EFI_STATUS
482try_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;
f0e4df7d
PJ
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.
3ce517fd
PJ
518 */
519 if (*start == 0xfeff)
520 start++;
521 while (*start) {
82a9c9fd 522 while (*start == L'\r' || *start == L'\n')
3ce517fd 523 start++;
3ce517fd
PJ
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
544EFI_STATUS
545find_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);
3a7feeff 580 buffer = NULL;
3ce517fd 581
47f3a65e
PJ
582 CHAR16 *bootcsv=NULL, *bootarchcsv=NULL;
583
3ce517fd
PJ
584 bs = 0;
585 do {
586 bs = 0;
587 rc = uefi_call_wrapper(fh->Read, 3, fh, &bs, NULL);
3a7feeff
PJ
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 }
3ce517fd 594
3a7feeff
PJ
595 buffer = AllocateZeroPool(bs);
596 if (!buffer) {
597 Print(L"Could not allocate memory\n");
598 return EFI_OUT_OF_RESOURCES;
3ce517fd 599 }
3a7feeff
PJ
600
601 rc = uefi_call_wrapper(fh->Read, 3, fh, &bs, buffer);
3ce517fd
PJ
602 if (EFI_ERROR(rc)) {
603 Print(L"Could not read \\EFI\\%s\\: %d\n", dirname, rc);
604 FreePool(buffer);
605 return rc;
606 }
3a7feeff 607
3ce517fd
PJ
608 if (bs == 0)
609 break;
610
611 fi = buffer;
612
47f3a65e
PJ
613 if (!bootcsv && !StrCaseCmp(fi->FileName, L"boot.csv"))
614 bootcsv = StrDuplicate(fi->FileName);
615
616 if (!bootarchcsv &&
617 !StrCaseCmp(fi->FileName, L"boot" EFI_ARCH L".csv"))
618 bootarchcsv = StrDuplicate(fi->FileName);
3ce517fd
PJ
619
620 FreePool(buffer);
621 buffer = NULL;
622 } while (bs != 0);
623
47f3a65e
PJ
624 rc = EFI_SUCCESS;
625 if (bootarchcsv) {
626 EFI_FILE_HANDLE fh2;
627 rc = uefi_call_wrapper(fh->Open, 5, fh, &fh2,
628 bootarchcsv, EFI_FILE_READ_ONLY, 0);
629 if (EFI_ERROR(rc) || fh2 == NULL) {
630 Print(L"Couldn't open \\EFI\\%s\\%s: %d\n",
631 dirname, bootarchcsv, rc);
632 } else {
633 rc = try_boot_csv(fh2, dirname, bootarchcsv);
634 uefi_call_wrapper(fh2->Close, 1, fh2);
635 }
636 }
637 if ((EFI_ERROR(rc) || !bootarchcsv) && bootcsv) {
638 EFI_FILE_HANDLE fh2;
639 rc = uefi_call_wrapper(fh->Open, 5, fh, &fh2,
640 bootcsv, EFI_FILE_READ_ONLY, 0);
641 if (EFI_ERROR(rc) || fh2 == NULL) {
642 Print(L"Couldn't open \\EFI\\%s\\%s: %d\n",
643 dirname, bootcsv, rc);
644 } else {
645 rc = try_boot_csv(fh2, dirname, bootcsv);
646 uefi_call_wrapper(fh2->Close, 1, fh2);
647 }
648 }
3ce517fd 649 rc = EFI_SUCCESS;
3ce517fd
PJ
650
651 return rc;
652}
653
654EFI_STATUS
655find_boot_options(EFI_HANDLE device)
656{
657 EFI_STATUS rc = EFI_SUCCESS;
658
659 EFI_FILE_IO_INTERFACE *fio = NULL;
660 rc = uefi_call_wrapper(BS->HandleProtocol, 3, device,
073f3b3c 661 &FileSystemProtocol, (void **)&fio);
3ce517fd
PJ
662 if (EFI_ERROR(rc)) {
663 Print(L"Couldn't find file system: %d\n", rc);
664 return rc;
665 }
666
667 /* EFI_FILE_HANDLE is a pointer to an EFI_FILE, and I have
668 * *no idea* what frees the memory allocated here. Hopefully
669 * Close() does. */
670 EFI_FILE_HANDLE fh = NULL;
671 rc = uefi_call_wrapper(fio->OpenVolume, 2, fio, &fh);
672 if (EFI_ERROR(rc) || fh == NULL) {
673 Print(L"Couldn't open file system: %d\n", rc);
674 return rc;
675 }
676
677 EFI_FILE_HANDLE fh2 = NULL;
678 rc = uefi_call_wrapper(fh->Open, 5, fh, &fh2, L"EFI",
679 EFI_FILE_READ_ONLY, 0);
680 if (EFI_ERROR(rc) || fh2 == NULL) {
681 Print(L"Couldn't open EFI: %d\n", rc);
682 uefi_call_wrapper(fh->Close, 1, fh);
683 return rc;
684 }
685 rc = uefi_call_wrapper(fh2->SetPosition, 2, fh2, 0);
686 if (EFI_ERROR(rc)) {
687 Print(L"Couldn't set file position: %d\n", rc);
688 uefi_call_wrapper(fh2->Close, 1, fh2);
689 uefi_call_wrapper(fh->Close, 1, fh);
690 return rc;
691 }
692
693 void *buffer;
694 UINTN bs;
695 do {
696 bs = 0;
697 rc = uefi_call_wrapper(fh2->Read, 3, fh2, &bs, NULL);
698 if (rc == EFI_BUFFER_TOO_SMALL ||
699 (rc == EFI_SUCCESS && bs != 0)) {
700 buffer = AllocateZeroPool(bs);
701 if (!buffer) {
702 Print(L"Could not allocate memory\n");
703 /* sure, this might work, why not? */
704 uefi_call_wrapper(fh2->Close, 1, fh2);
705 uefi_call_wrapper(fh->Close, 1, fh);
706 return EFI_OUT_OF_RESOURCES;
707 }
708
709 rc = uefi_call_wrapper(fh2->Read, 3, fh2, &bs, buffer);
710 }
711 if (bs == 0)
712 break;
713
714 if (EFI_ERROR(rc)) {
715 Print(L"Could not read \\EFI\\: %d\n", rc);
716 if (buffer) {
717 FreePool(buffer);
718 buffer = NULL;
719 }
720 uefi_call_wrapper(fh2->Close, 1, fh2);
721 uefi_call_wrapper(fh->Close, 1, fh);
722 return rc;
723 }
724 EFI_FILE_INFO *fi = buffer;
725
726 if (!(fi->Attribute & EFI_FILE_DIRECTORY)) {
727 FreePool(buffer);
728 buffer = NULL;
729 continue;
730 }
731 if (!StrCmp(fi->FileName, L".") ||
732 !StrCmp(fi->FileName, L"..") ||
733 !StrCaseCmp(fi->FileName, L"BOOT")) {
734 FreePool(buffer);
735 buffer = NULL;
736 continue;
737 }
738#ifdef DEBUG_FALLBACK
739 Print(L"Found directory named \"%s\"\n", fi->FileName);
740#endif
741
742 EFI_FILE_HANDLE fh3;
743 rc = uefi_call_wrapper(fh->Open, 5, fh2, &fh3, fi->FileName,
744 EFI_FILE_READ_ONLY, 0);
745 if (EFI_ERROR(rc)) {
746 Print(L"%d Couldn't open %s: %d\n", __LINE__, fi->FileName, rc);
747 FreePool(buffer);
748 buffer = NULL;
749 continue;
750 }
751
752 rc = find_boot_csv(fh3, fi->FileName);
753 FreePool(buffer);
754 buffer = NULL;
755 if (rc == EFI_OUT_OF_RESOURCES)
756 break;
757
758 } while (1);
759
8adfd201
GCPL
760 if (rc == EFI_SUCCESS && nbootorder > 0)
761 rc = update_boot_order();
762
3ce517fd
PJ
763 uefi_call_wrapper(fh2->Close, 1, fh2);
764 uefi_call_wrapper(fh->Close, 1, fh);
8adfd201 765 return rc;
3ce517fd 766}
3fa9a534
PJ
767
768static EFI_STATUS
769try_start_first_option(EFI_HANDLE parent_image_handle)
770{
771 EFI_STATUS rc;
772 EFI_HANDLE image_handle;
773
774 if (!first_new_option) {
775 return EFI_SUCCESS;
776 }
777
778 rc = uefi_call_wrapper(BS->LoadImage, 6, 0, parent_image_handle,
779 first_new_option, NULL, 0,
780 &image_handle);
781 if (EFI_ERROR(rc)) {
dfd6c73a
PJ
782 CHAR16 *dps = DevicePathToStr(first_new_option);
783 UINTN s = DevicePathSize(first_new_option);
5495694c 784 unsigned int i;
dfd6c73a
PJ
785 UINT8 *dpv = (void *)first_new_option;
786 Print(L"LoadImage failed: %d\nDevice path: \"%s\"\n", rc, dps);
787 for (i = 0; i < s; i++) {
788 if (i > 0 && i % 16 == 0)
789 Print(L"\n");
790 Print(L"%02x ", dpv[i]);
791 }
792 Print(L"\n");
793
794 uefi_call_wrapper(BS->Stall, 1, 500000000);
3fa9a534
PJ
795 return rc;
796 }
a41306e8
PJ
797
798 EFI_LOADED_IMAGE *image;
799 rc = uefi_call_wrapper(BS->HandleProtocol, 3, image_handle, &LoadedImageProtocol, (void *)&image);
800 if (!EFI_ERROR(rc)) {
801 image->LoadOptions = first_new_option_args;
802 image->LoadOptionsSize = first_new_option_size;
803 }
804
3fa9a534
PJ
805 rc = uefi_call_wrapper(BS->StartImage, 3, image_handle, NULL, NULL);
806 if (EFI_ERROR(rc)) {
807 Print(L"StartImage failed: %d\n", rc);
dfd6c73a 808 uefi_call_wrapper(BS->Stall, 1, 500000000);
3fa9a534
PJ
809 }
810 return rc;
811}
812
a0319607
PJ
813EFI_GUID SHIM_LOCK_GUID = { 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23} };
814extern EFI_STATUS
815efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab);
816
817static void
818__attribute__((__optimize__("0")))
819debug_hook(void)
820{
821 EFI_GUID guid = SHIM_LOCK_GUID;
822 UINT8 *data = NULL;
823 UINTN dataSize = 0;
824 EFI_STATUS efi_status;
825 volatile register int x = 0;
826 extern char _etext, _edata;
827
828 efi_status = get_variable(L"SHIM_DEBUG", &data, &dataSize, guid);
829 if (EFI_ERROR(efi_status)) {
830 return;
831 }
832
833 if (x)
834 return;
835
836 x = 1;
70ce2c42 837 Print(L"add-symbol-file "DEBUGDIR
6f040920 838 L"fb" EFI_ARCH L".efi.debug %p -s .data %p\n", &_etext,
a0319607
PJ
839 &_edata);
840}
841
3ce517fd
PJ
842EFI_STATUS
843efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
844{
845 EFI_STATUS rc;
846
847 InitializeLib(image, systab);
848
a0319607
PJ
849 /*
850 * if SHIM_DEBUG is set, wait for a debugger to attach.
851 */
852 debug_hook();
853
3ce517fd
PJ
854 rc = uefi_call_wrapper(BS->HandleProtocol, 3, image, &LoadedImageProtocol, (void *)&this_image);
855 if (EFI_ERROR(rc)) {
856 Print(L"Error: could not find loaded image: %d\n", rc);
857 return rc;
858 }
859
860 Print(L"System BootOrder not found. Initializing defaults.\n");
861
894a2738
PJ
862 set_boot_order();
863
3ce517fd
PJ
864 rc = find_boot_options(this_image->DeviceHandle);
865 if (EFI_ERROR(rc)) {
866 Print(L"Error: could not find boot options: %d\n", rc);
867 return rc;
868 }
869
3fa9a534
PJ
870 try_start_first_option(image);
871
f7fbcdce 872 Print(L"Reset System\n");
3fa9a534 873 uefi_call_wrapper(RT->ResetSystem, 4, EfiResetCold,
f7fbcdce
GCPL
874 EFI_SUCCESS, 0, NULL);
875
3ce517fd
PJ
876 return EFI_SUCCESS;
877}