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