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
FindSubDevicePath(EFI_DEVICE_PATH * In,UINT8 Type,UINT8 SubType,EFI_DEVICE_PATH ** Out)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
get_file_size(EFI_FILE_HANDLE fh,UINTN * retsize)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
read_file(EFI_FILE_HANDLE fh,CHAR16 * fullpath,CHAR16 ** buffer,UINT64 * bs)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
make_full_path(CHAR16 * dirname,CHAR16 * filename,CHAR16 ** out,UINT64 * outlen)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
add_boot_option(EFI_DEVICE_PATH * hddp,EFI_DEVICE_PATH * fulldp,CHAR16 * filename,CHAR16 * label,CHAR16 * arguments)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
find_boot_option(EFI_DEVICE_PATH * dp,EFI_DEVICE_PATH * fulldp,CHAR16 * filename,CHAR16 * label,CHAR16 * arguments,UINT16 * optnum)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
set_boot_order(void)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
update_boot_order(void)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
add_to_boot_list(EFI_FILE_HANDLE fh,CHAR16 * dirname,CHAR16 * filename,CHAR16 * label,CHAR16 * arguments)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
populate_stanza(EFI_FILE_HANDLE fh,CHAR16 * dirname,CHAR16 * filename,CHAR16 * csv)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
try_boot_csv(EFI_FILE_HANDLE fh,CHAR16 * dirname,CHAR16 * filename)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
find_boot_csv(EFI_FILE_HANDLE fh,CHAR16 * dirname)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 bs = 0;
583 do {
584 bs = 0;
585 rc = uefi_call_wrapper(fh->Read, 3, fh, &bs, NULL);
586 if (EFI_ERROR(rc) && rc != EFI_BUFFER_TOO_SMALL) {
587 Print(L"Could not read \\EFI\\%s\\: %d\n", dirname, rc);
588 if (buffer)
589 FreePool(buffer);
590 return rc;
591 }
592
593 buffer = AllocateZeroPool(bs);
594 if (!buffer) {
595 Print(L"Could not allocate memory\n");
596 return EFI_OUT_OF_RESOURCES;
597 }
598
599 rc = uefi_call_wrapper(fh->Read, 3, fh, &bs, buffer);
600 if (EFI_ERROR(rc)) {
601 Print(L"Could not read \\EFI\\%s\\: %d\n", dirname, rc);
602 FreePool(buffer);
603 return rc;
604 }
605
606 if (bs == 0)
607 break;
608
609 fi = buffer;
610
611 if (!StrCaseCmp(fi->FileName, L"boot.csv")) {
612 EFI_FILE_HANDLE fh2;
613 rc = uefi_call_wrapper(fh->Open, 5, fh, &fh2,
614 fi->FileName,
615 EFI_FILE_READ_ONLY, 0);
616 if (EFI_ERROR(rc) || fh2 == NULL) {
617 Print(L"Couldn't open \\EFI\\%s\\%s: %d\n",
618 dirname, fi->FileName, rc);
619 FreePool(buffer);
620 buffer = NULL;
621 continue;
622 }
623 rc = try_boot_csv(fh2, dirname, fi->FileName);
624 uefi_call_wrapper(fh2->Close, 1, fh2);
625 }
626
627 FreePool(buffer);
628 buffer = NULL;
629 } while (bs != 0);
630
631 rc = EFI_SUCCESS;
632
633 return rc;
634 }
635
636 EFI_STATUS
find_boot_options(EFI_HANDLE device)637 find_boot_options(EFI_HANDLE device)
638 {
639 EFI_STATUS rc = EFI_SUCCESS;
640
641 EFI_FILE_IO_INTERFACE *fio = NULL;
642 rc = uefi_call_wrapper(BS->HandleProtocol, 3, device,
643 &FileSystemProtocol, (void **)&fio);
644 if (EFI_ERROR(rc)) {
645 Print(L"Couldn't find file system: %d\n", rc);
646 return rc;
647 }
648
649 /* EFI_FILE_HANDLE is a pointer to an EFI_FILE, and I have
650 * *no idea* what frees the memory allocated here. Hopefully
651 * Close() does. */
652 EFI_FILE_HANDLE fh = NULL;
653 rc = uefi_call_wrapper(fio->OpenVolume, 2, fio, &fh);
654 if (EFI_ERROR(rc) || fh == NULL) {
655 Print(L"Couldn't open file system: %d\n", rc);
656 return rc;
657 }
658
659 EFI_FILE_HANDLE fh2 = NULL;
660 rc = uefi_call_wrapper(fh->Open, 5, fh, &fh2, L"EFI",
661 EFI_FILE_READ_ONLY, 0);
662 if (EFI_ERROR(rc) || fh2 == NULL) {
663 Print(L"Couldn't open EFI: %d\n", rc);
664 uefi_call_wrapper(fh->Close, 1, fh);
665 return rc;
666 }
667 rc = uefi_call_wrapper(fh2->SetPosition, 2, fh2, 0);
668 if (EFI_ERROR(rc)) {
669 Print(L"Couldn't set file position: %d\n", rc);
670 uefi_call_wrapper(fh2->Close, 1, fh2);
671 uefi_call_wrapper(fh->Close, 1, fh);
672 return rc;
673 }
674
675 void *buffer;
676 UINTN bs;
677 do {
678 bs = 0;
679 rc = uefi_call_wrapper(fh2->Read, 3, fh2, &bs, NULL);
680 if (rc == EFI_BUFFER_TOO_SMALL ||
681 (rc == EFI_SUCCESS && bs != 0)) {
682 buffer = AllocateZeroPool(bs);
683 if (!buffer) {
684 Print(L"Could not allocate memory\n");
685 /* sure, this might work, why not? */
686 uefi_call_wrapper(fh2->Close, 1, fh2);
687 uefi_call_wrapper(fh->Close, 1, fh);
688 return EFI_OUT_OF_RESOURCES;
689 }
690
691 rc = uefi_call_wrapper(fh2->Read, 3, fh2, &bs, buffer);
692 }
693 if (bs == 0)
694 break;
695
696 if (EFI_ERROR(rc)) {
697 Print(L"Could not read \\EFI\\: %d\n", rc);
698 if (buffer) {
699 FreePool(buffer);
700 buffer = NULL;
701 }
702 uefi_call_wrapper(fh2->Close, 1, fh2);
703 uefi_call_wrapper(fh->Close, 1, fh);
704 return rc;
705 }
706 EFI_FILE_INFO *fi = buffer;
707
708 if (!(fi->Attribute & EFI_FILE_DIRECTORY)) {
709 FreePool(buffer);
710 buffer = NULL;
711 continue;
712 }
713 if (!StrCmp(fi->FileName, L".") ||
714 !StrCmp(fi->FileName, L"..") ||
715 !StrCaseCmp(fi->FileName, L"BOOT")) {
716 FreePool(buffer);
717 buffer = NULL;
718 continue;
719 }
720 #ifdef DEBUG_FALLBACK
721 Print(L"Found directory named \"%s\"\n", fi->FileName);
722 #endif
723
724 EFI_FILE_HANDLE fh3;
725 rc = uefi_call_wrapper(fh->Open, 5, fh2, &fh3, fi->FileName,
726 EFI_FILE_READ_ONLY, 0);
727 if (EFI_ERROR(rc)) {
728 Print(L"%d Couldn't open %s: %d\n", __LINE__, fi->FileName, rc);
729 FreePool(buffer);
730 buffer = NULL;
731 continue;
732 }
733
734 rc = find_boot_csv(fh3, fi->FileName);
735 FreePool(buffer);
736 buffer = NULL;
737 if (rc == EFI_OUT_OF_RESOURCES)
738 break;
739
740 } while (1);
741
742 if (rc == EFI_SUCCESS && nbootorder > 0)
743 rc = update_boot_order();
744
745 uefi_call_wrapper(fh2->Close, 1, fh2);
746 uefi_call_wrapper(fh->Close, 1, fh);
747 return rc;
748 }
749
750 static EFI_STATUS
try_start_first_option(EFI_HANDLE parent_image_handle)751 try_start_first_option(EFI_HANDLE parent_image_handle)
752 {
753 EFI_STATUS rc;
754 EFI_HANDLE image_handle;
755
756 if (!first_new_option) {
757 return EFI_SUCCESS;
758 }
759
760 rc = uefi_call_wrapper(BS->LoadImage, 6, 0, parent_image_handle,
761 first_new_option, NULL, 0,
762 &image_handle);
763 if (EFI_ERROR(rc)) {
764 CHAR16 *dps = DevicePathToStr(first_new_option);
765 UINTN s = DevicePathSize(first_new_option);
766 unsigned int i;
767 UINT8 *dpv = (void *)first_new_option;
768 Print(L"LoadImage failed: %d\nDevice path: \"%s\"\n", rc, dps);
769 for (i = 0; i < s; i++) {
770 if (i > 0 && i % 16 == 0)
771 Print(L"\n");
772 Print(L"%02x ", dpv[i]);
773 }
774 Print(L"\n");
775
776 uefi_call_wrapper(BS->Stall, 1, 500000000);
777 return rc;
778 }
779
780 EFI_LOADED_IMAGE *image;
781 rc = uefi_call_wrapper(BS->HandleProtocol, 3, image_handle, &LoadedImageProtocol, (void *)&image);
782 if (!EFI_ERROR(rc)) {
783 image->LoadOptions = first_new_option_args;
784 image->LoadOptionsSize = first_new_option_size;
785 }
786
787 rc = uefi_call_wrapper(BS->StartImage, 3, image_handle, NULL, NULL);
788 if (EFI_ERROR(rc)) {
789 Print(L"StartImage failed: %d\n", rc);
790 uefi_call_wrapper(BS->Stall, 1, 500000000);
791 }
792 return rc;
793 }
794
795 EFI_GUID SHIM_LOCK_GUID = { 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23} };
796 extern EFI_STATUS
797 efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab);
798
799 static void
800 __attribute__((__optimize__("0")))
debug_hook(void)801 debug_hook(void)
802 {
803 EFI_GUID guid = SHIM_LOCK_GUID;
804 UINT8 *data = NULL;
805 UINTN dataSize = 0;
806 EFI_STATUS efi_status;
807 volatile register int x = 0;
808 extern char _etext, _edata;
809
810 efi_status = get_variable(L"SHIM_DEBUG", &data, &dataSize, guid);
811 if (EFI_ERROR(efi_status)) {
812 return;
813 }
814
815 if (x)
816 return;
817
818 x = 1;
819 Print(L"add-symbol-file "DEBUGDIR
820 L"fallback.debug %p -s .data %p\n", &_etext,
821 &_edata);
822 }
823
824 EFI_STATUS
efi_main(EFI_HANDLE image,EFI_SYSTEM_TABLE * systab)825 efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
826 {
827 EFI_STATUS rc;
828
829 InitializeLib(image, systab);
830
831 /*
832 * if SHIM_DEBUG is set, wait for a debugger to attach.
833 */
834 debug_hook();
835
836 rc = uefi_call_wrapper(BS->HandleProtocol, 3, image, &LoadedImageProtocol, (void *)&this_image);
837 if (EFI_ERROR(rc)) {
838 Print(L"Error: could not find loaded image: %d\n", rc);
839 return rc;
840 }
841
842 Print(L"System BootOrder not found. Initializing defaults.\n");
843
844 set_boot_order();
845
846 rc = find_boot_options(this_image->DeviceHandle);
847 if (EFI_ERROR(rc)) {
848 Print(L"Error: could not find boot options: %d\n", rc);
849 return rc;
850 }
851
852 try_start_first_option(image);
853
854 Print(L"Reset System\n");
855 uefi_call_wrapper(RT->ResetSystem, 4, EfiResetCold,
856 EFI_SUCCESS, 0, NULL);
857
858 return EFI_SUCCESS;
859 }
860