fallback.c 26 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12
/*
 * Copyright 2012-2013 Red Hat, Inc.
 * All rights reserved.
 *
 * See "COPYING" for license terms.
 *
 * Author(s): Peter Jones <pjones@redhat.com>
 */

#include <efi.h>
#include <efilib.h>

13
#include "shim.h"
14 15 16

EFI_LOADED_IMAGE *this_image = NULL;

17 18 19 20 21 22 23 24 25 26 27 28 29
int
get_fallback_verbose(void)
{
	UINT8 *data = NULL;
	UINTN dataSize = 0;
	EFI_STATUS efi_status;
	unsigned int i;
	static int state = -1;

	if (state != -1)
		return state;

	efi_status = get_variable(L"FALLBACK_VERBOSE",
30
				  &data, &dataSize, SHIM_LOCK_GUID);
31 32 33 34 35
	if (EFI_ERROR(efi_status)) {
		state = 0;
		return state;
	}

36
	state = 0;
37 38 39
	for (i = 0; i < dataSize; i++) {
		if (data[i]) {
			state = 1;
40
			break;
41 42 43
		}
	}

44 45
	if (data)
		FreePool(data);
46 47 48 49 50 51 52
	return state;
}

#define VerbosePrintUnprefixed(fmt, ...)				\
	({								\
		UINTN ret_ = 0;						\
		if (get_fallback_verbose())				\
53
			ret_ = console_print((fmt), ##__VA_ARGS__);	\
54 55 56 57 58 59 60
		ret_;							\
	})

#define VerbosePrint(fmt, ...)						\
	({	UINTN line_ = __LINE__;					\
		UINTN ret_ = 0;						\
		if (get_fallback_verbose()) {				\
61 62
			console_print(L"%a:%d: ", __func__, line_);	\
			ret_ = console_print((fmt), ##__VA_ARGS__);	\
63 64 65 66
		}							\
		ret_;							\
	})

67 68 69 70 71 72 73 74
static EFI_STATUS
FindSubDevicePath(EFI_DEVICE_PATH *In, UINT8 Type, UINT8 SubType,
		  EFI_DEVICE_PATH **Out)
{
	EFI_DEVICE_PATH *dp = In;
	if (!In || !Out)
		return EFI_INVALID_PARAMETER;

75 76 77 78
	CHAR16 *dps = DevicePathToStr(In);
	VerbosePrint(L"input device path: \"%s\"\n", dps);
	FreePool(dps);

79 80 81
	for (dp = In; !IsDevicePathEnd(dp); dp = NextDevicePathNode(dp)) {
		if (DevicePathType(dp) == Type &&
				DevicePathSubType(dp) == SubType) {
82 83 84 85 86
			dps = DevicePathToStr(dp);
			VerbosePrint(L"sub-path (%hhd,%hhd): \"%s\"\n",
				     Type, SubType, dps);
			FreePool(dps);

87 88 89 90 91 92 93 94 95 96
			*Out = DuplicateDevicePath(dp);
			if (!*Out)
				return EFI_OUT_OF_RESOURCES;
			return EFI_SUCCESS;
		}
	}
	*Out = NULL;
	return EFI_NOT_FOUND;
}

97
static EFI_STATUS
98
get_file_size(EFI_FILE_HANDLE fh, UINTN *retsize)
99
{
100
	EFI_STATUS efi_status;
101 102 103 104 105
	void *buffer = NULL;
	UINTN bs = 0;

	/* The API here is "Call it once with bs=0, it fills in bs,
	 * then allocate a buffer and ask again to get it filled. */
106 107 108 109 110 111 112 113 114 115
	efi_status = fh->GetInfo(fh, &EFI_FILE_INFO_GUID, &bs, NULL);
	if (EFI_ERROR(efi_status) && efi_status != EFI_BUFFER_TOO_SMALL)
		return efi_status;
	if (bs == 0)
		return EFI_SUCCESS;

	buffer = AllocateZeroPool(bs);
	if (!buffer) {
		console_print(L"Could not allocate memory\n");
		return EFI_OUT_OF_RESOURCES;
116
	}
117
	efi_status = fh->GetInfo(fh, &EFI_FILE_INFO_GUID, &bs, buffer);
118
	/* This checks *either* the error from the first GetInfo, if it isn't
119 120 121 122
	 * the EFI_BUFFER_TOO_SMALL we're expecting, or the second GetInfo
	 * call in *any* case. */
	if (EFI_ERROR(efi_status)) {
		console_print(L"Could not get file info: %r\n", efi_status);
123 124
		if (buffer)
			FreePool(buffer);
125
		return efi_status;
126 127 128 129 130 131 132 133 134 135 136
	}
	EFI_FILE_INFO *fi = buffer;
	*retsize = fi->FileSize;
	FreePool(buffer);
	return EFI_SUCCESS;
}

EFI_STATUS
read_file(EFI_FILE_HANDLE fh, CHAR16 *fullpath, CHAR16 **buffer, UINT64 *bs)
{
	EFI_FILE_HANDLE fh2;
137 138 139 140 141 142
	EFI_STATUS efi_status;

	efi_status = fh->Open(fh, &fh2, fullpath, EFI_FILE_READ_ONLY, 0);
	if (EFI_ERROR(efi_status)) {
		console_print(L"Couldn't open \"%s\": %r\n", fullpath, efi_status);
		return efi_status;
143 144
	}

145
	UINTN len = 0;
146
	CHAR16 *b = NULL;
147 148 149 150 151 152 153 154 155 156 157
	efi_status = get_file_size(fh2, &len);
	if (EFI_ERROR(efi_status)) {
		console_print(L"Could not get file size for \"%s\": %r\n",
			      fullpath, efi_status);
		fh2->Close(fh2);
		return efi_status;
	}

	if (len > 1024 * PAGE_SIZE) {
		fh2->Close(fh2);
		return EFI_BAD_BUFFER_SIZE;
158 159 160 161
	}

	b = AllocateZeroPool(len + 2);
	if (!buffer) {
162 163
		console_print(L"Could not allocate memory\n");
		fh2->Close(fh2);
164 165 166
		return EFI_OUT_OF_RESOURCES;
	}

167 168
	efi_status = fh->Read(fh, &len, b);
	if (EFI_ERROR(efi_status)) {
169
		FreePool(buffer);
170 171 172
		fh2->Close(fh2);
		console_print(L"Could not read file: %r\n", efi_status);
		return efi_status;
173 174 175
	}
	*buffer = b;
	*bs = len;
176
	fh2->Close(fh2);
177 178 179 180 181 182 183
	return EFI_SUCCESS;
}

EFI_STATUS
make_full_path(CHAR16 *dirname, CHAR16 *filename, CHAR16 **out, UINT64 *outlen)
{
	UINT64 len;
184

185 186 187
	len = StrLen(L"\\EFI\\") + StrLen(dirname)
	    + StrLen(L"\\") + StrLen(filename)
	    + 2;
188

189
	CHAR16 *fullpath = AllocateZeroPool(len*sizeof(CHAR16));
190
	if (!fullpath) {
191
		console_print(L"Could not allocate memory\n");
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
		return EFI_OUT_OF_RESOURCES;
	}

	StrCat(fullpath, L"\\EFI\\");
	StrCat(fullpath, dirname);
	StrCat(fullpath, L"\\");
	StrCat(fullpath, filename);

	*out = fullpath;
	*outlen = len;
	return EFI_SUCCESS;
}

CHAR16 *bootorder = NULL;
int nbootorder = 0;

208 209 210 211
EFI_DEVICE_PATH *first_new_option = NULL;
VOID *first_new_option_args = NULL;
UINTN first_new_option_size = 0;

212
EFI_STATUS
213 214
add_boot_option(EFI_DEVICE_PATH *hddp, EFI_DEVICE_PATH *fulldp,
		CHAR16 *filename, CHAR16 *label, CHAR16 *arguments)
215 216 217 218
{
	static int i = 0;
	CHAR16 varname[] = L"Boot0000";
	CHAR16 hexmap[] = L"0123456789ABCDEF";
219
	EFI_STATUS efi_status;
220 221 222 223 224 225 226

	for(; i <= 0xffff; i++) {
		varname[4] = hexmap[(i & 0xf000) >> 12];
		varname[5] = hexmap[(i & 0x0f00) >> 8];
		varname[6] = hexmap[(i & 0x00f0) >> 4];
		varname[7] = hexmap[(i & 0x000f) >> 0];

227
		void *var = LibGetVariable(varname, &GV_GUID);
228 229
		if (!var) {
			int size = sizeof(UINT32) + sizeof (UINT16) +
230 231
				StrLen(label)*2 + 2 + DevicePathSize(hddp) +
				StrLen(arguments) * 2;
232

233
			CHAR8 *data = AllocateZeroPool(size + 2);
234 235 236
			CHAR8 *cursor = data;
			*(UINT32 *)cursor = LOAD_OPTION_ACTIVE;
			cursor += sizeof (UINT32);
237
			*(UINT16 *)cursor = DevicePathSize(hddp);
238 239 240
			cursor += sizeof (UINT16);
			StrCpy((CHAR16 *)cursor, label);
			cursor += StrLen(label)*2 + 2;
241 242
			CopyMem(cursor, hddp, DevicePathSize(hddp));
			cursor += DevicePathSize(hddp);
243 244
			StrCpy((CHAR16 *)cursor, arguments);

245 246 247
			console_print(L"Creating boot entry \"%s\" with label \"%s\" "
				      L"for file \"%s\"\n",
				      varname, label, filename);
248 249 250 251 252 253 254

			if (!first_new_option) {
				first_new_option = DuplicateDevicePath(fulldp);
				first_new_option_args = arguments;
				first_new_option_size = StrLen(arguments) * sizeof (CHAR16);
			}

255 256 257 258 259
			efi_status = gRT->SetVariable(varname, &GV_GUID,
						EFI_VARIABLE_NON_VOLATILE |
						EFI_VARIABLE_BOOTSERVICE_ACCESS |
						EFI_VARIABLE_RUNTIME_ACCESS,
						size, data);
260 261 262

			FreePool(data);

263 264 265 266
			if (EFI_ERROR(efi_status)) {
				console_print(L"Could not create variable: %r\n",
					      efi_status);
				return efi_status;
267 268 269 270 271 272 273 274
			}

			CHAR16 *newbootorder = AllocateZeroPool(sizeof (CHAR16)
							* (nbootorder + 1));
			if (!newbootorder)
				return EFI_OUT_OF_RESOURCES;

			int j = 0;
275
			newbootorder[0] = i & 0xffff;
276 277
			if (nbootorder) {
				for (j = 0; j < nbootorder; j++)
278
					newbootorder[j+1] = bootorder[j];
279 280 281 282 283
				FreePool(bootorder);
			}
			bootorder = newbootorder;
			nbootorder += 1;
#ifdef DEBUG_FALLBACK
284 285
			console_print(L"nbootorder: %d\nBootOrder: ",
				      nbootorder);
286
			for (j = 0 ; j < nbootorder ; j++)
287 288
				console_print(L"%04x ", bootorder[j]);
			console_print(L"\n");
289 290 291 292 293 294 295 296
#endif

			return EFI_SUCCESS;
		}
	}
	return EFI_OUT_OF_RESOURCES;
}

297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395
/*
 * AMI BIOS (e.g, Intel NUC5i3MYHE) may automatically hide and patch BootXXXX
 * variables with ami_masked_device_path_guid. We can get the valid device path
 * if just skipping it and its next end path.
 */

static EFI_GUID ami_masked_device_path_guid = {
	0x99e275e7, 0x75a0, 0x4b37,
	{ 0xa2, 0xe6, 0xc5, 0x38, 0x5e, 0x6c, 0x0, 0xcb }
};

static unsigned int
calc_masked_boot_option_size(unsigned int size)
{
	return size + sizeof(EFI_DEVICE_PATH) +
	       sizeof(ami_masked_device_path_guid) + sizeof(EFI_DEVICE_PATH);
}

static int
check_masked_boot_option(CHAR8 *candidate, unsigned int candidate_size,
			 CHAR8 *data, unsigned int data_size)
{
	/*
	 * The patched BootXXXX variables contain a hardware device path and
	 * an end path, preceding the real device path.
	 */
	if (calc_masked_boot_option_size(data_size) != candidate_size)
		return 1;

	CHAR8 *cursor = candidate;

	/* Check whether the BootXXXX is patched */
	cursor += sizeof(UINT32) + sizeof(UINT16);
	cursor += StrSize((CHAR16 *)cursor);

	unsigned int min_valid_size = cursor - candidate + sizeof(EFI_DEVICE_PATH);

	if (candidate_size <= min_valid_size)
		return 1;

	EFI_DEVICE_PATH *dp = (EFI_DEVICE_PATH *)cursor;
	unsigned int node_size = DevicePathNodeLength(dp) - sizeof(EFI_DEVICE_PATH);

	min_valid_size += node_size;
	if (candidate_size <= min_valid_size ||
	    DevicePathType(dp) != HARDWARE_DEVICE_PATH ||
	    DevicePathSubType(dp) != HW_VENDOR_DP ||
	    node_size != sizeof(ami_masked_device_path_guid) ||
	    CompareGuid((EFI_GUID *)(cursor + sizeof(EFI_DEVICE_PATH)),
		        &ami_masked_device_path_guid))
		return 1;

	/* Check whether the patched guid is followed by an end path */
	min_valid_size += sizeof(EFI_DEVICE_PATH);
	if (candidate_size <= min_valid_size)
		return 1;

	dp = NextDevicePathNode(dp);
	if (!IsDevicePathEnd(dp))
		return 1;

	/*
	 * OK. We may really get a masked BootXXXX variable. The next
	 * step is to test whether it is hidden.
	 */
	UINT32 attrs = *(UINT32 *)candidate;
#ifndef LOAD_OPTION_HIDDEN
#  define LOAD_OPTION_HIDDEN	0x00000008
#endif
        if (!(attrs & LOAD_OPTION_HIDDEN))
		return 1;

	attrs &= ~LOAD_OPTION_HIDDEN;

	/* Compare the field Attributes */
	if (attrs != *(UINT32 *)data)
		return 1;

	/* Compare the field FilePathListLength */
	data += sizeof(UINT32);
	candidate += sizeof(UINT32);
	if (calc_masked_boot_option_size(*(UINT16 *)data) !=
					 *(UINT16 *)candidate)
		return 1;

	/* Compare the field Description */
	data += sizeof(UINT16);
	candidate += sizeof(UINT16);
	if (CompareMem(candidate, data, cursor - candidate))
		return 1;

	/* Compare the filed FilePathList */
	cursor = (CHAR8 *)NextDevicePathNode(dp);
	data += sizeof(UINT16);
	data += StrSize((CHAR16 *)data);

	return CompareMem(cursor, data, candidate_size - min_valid_size);
}

396
EFI_STATUS
397 398 399
find_boot_option(EFI_DEVICE_PATH *dp, EFI_DEVICE_PATH *fulldp,
                 CHAR16 *filename, CHAR16 *label, CHAR16 *arguments,
                 UINT16 *optnum)
400
{
401
	unsigned int size = sizeof(UINT32) + sizeof (UINT16) +
402
		StrLen(label)*2 + 2 + DevicePathSize(dp) +
403
		StrLen(arguments) * 2;
404

405
	CHAR8 *data = AllocateZeroPool(size + 2);
406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421
	if (!data)
		return EFI_OUT_OF_RESOURCES;
	CHAR8 *cursor = data;
	*(UINT32 *)cursor = LOAD_OPTION_ACTIVE;
	cursor += sizeof (UINT32);
	*(UINT16 *)cursor = DevicePathSize(dp);
	cursor += sizeof (UINT16);
	StrCpy((CHAR16 *)cursor, label);
	cursor += StrLen(label)*2 + 2;
	CopyMem(cursor, dp, DevicePathSize(dp));
	cursor += DevicePathSize(dp);
	StrCpy((CHAR16 *)cursor, arguments);

	int i = 0;
	CHAR16 varname[] = L"Boot0000";
	CHAR16 hexmap[] = L"0123456789ABCDEF";
422
	EFI_STATUS efi_status;
423

424 425
	UINTN max_candidate_size = calc_masked_boot_option_size(size);
	CHAR8 *candidate = AllocateZeroPool(max_candidate_size);
426 427 428 429 430 431 432 433 434 435 436
	if (!candidate) {
		FreePool(data);
		return EFI_OUT_OF_RESOURCES;
	}

	for(i = 0; i < nbootorder && i < 0x10000; i++) {
		varname[4] = hexmap[(bootorder[i] & 0xf000) >> 12];
		varname[5] = hexmap[(bootorder[i] & 0x0f00) >> 8];
		varname[6] = hexmap[(bootorder[i] & 0x00f0) >> 4];
		varname[7] = hexmap[(bootorder[i] & 0x000f) >> 0];

437
		UINTN candidate_size = max_candidate_size;
438 439 440
		efi_status = gRT->GetVariable(varname, &GV_GUID, NULL,
					      &candidate_size, candidate);
		if (EFI_ERROR(efi_status))
441 442
			continue;

443 444 445 446 447
		if (candidate_size != size) {
			if (check_masked_boot_option(candidate, candidate_size,
						     data, size))
				continue;
		} else if (CompareMem(candidate, data, size))
448 449
			continue;

450 451
		VerbosePrint(L"Found boot entry \"%s\" with label \"%s\" "
			     L"for file \"%s\"\n", varname, label, filename);
452 453

		/* at this point, we have duplicate data. */
454 455 456 457 458 459
		if (!first_new_option) {
			first_new_option = DuplicateDevicePath(fulldp);
			first_new_option_args = arguments;
			first_new_option_size = StrLen(arguments) * sizeof (CHAR16);
		}

460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475
		*optnum = i;
		FreePool(candidate);
		FreePool(data);
		return EFI_SUCCESS;
	}
	FreePool(candidate);
	FreePool(data);
	return EFI_NOT_FOUND;
}

EFI_STATUS
set_boot_order(void)
{
	CHAR16 *oldbootorder;
	UINTN size;

476
	oldbootorder = LibGetVariableAndSize(L"BootOrder", &GV_GUID, &size);
477 478 479 480 481 482 483 484
	if (oldbootorder) {
		nbootorder = size / sizeof (CHAR16);
		bootorder = oldbootorder;
	}
	return EFI_SUCCESS;

}

485 486 487 488
EFI_STATUS
update_boot_order(void)
{
	UINTN size;
489
	UINTN len = 0;
490
	CHAR16 *newbootorder = NULL;
491
	EFI_STATUS efi_status;
492

493 494 495 496 497
	size = nbootorder * sizeof(CHAR16);
	newbootorder = AllocateZeroPool(size);
	if (!newbootorder)
		return EFI_OUT_OF_RESOURCES;
	CopyMem(newbootorder, bootorder, size);
498

499
	VerbosePrint(L"nbootorder: %d\nBootOrder: ", size / sizeof (CHAR16));
500
	UINTN j;
501
	for (j = 0 ; j < size / sizeof (CHAR16); j++)
502
		VerbosePrintUnprefixed(L"%04x ", newbootorder[j]);
503 504 505 506 507 508 509 510 511 512
	console_print(L"\n");
	efi_status = gRT->GetVariable(L"BootOrder", &GV_GUID, NULL, &len, NULL);
	if (efi_status == EFI_BUFFER_TOO_SMALL)
		LibDeleteVariable(L"BootOrder", &GV_GUID);

	efi_status = gRT->SetVariable(L"BootOrder", &GV_GUID,
				      EFI_VARIABLE_NON_VOLATILE |
				      EFI_VARIABLE_BOOTSERVICE_ACCESS |
				      EFI_VARIABLE_RUNTIME_ACCESS,
				      size, newbootorder);
513
	FreePool(newbootorder);
514
	return efi_status;
515 516 517
}

EFI_STATUS
518
add_to_boot_list(CHAR16 *dirname, CHAR16 *filename, CHAR16 *label, CHAR16 *arguments)
519 520 521
{
	CHAR16 *fullpath = NULL;
	UINT64 pathlen = 0;
522
	EFI_STATUS efi_status;
523

524 525 526
	efi_status = make_full_path(dirname, filename, &fullpath, &pathlen);
	if (EFI_ERROR(efi_status))
		return efi_status;
527

528 529
	EFI_DEVICE_PATH *full_device_path = NULL;
	EFI_DEVICE_PATH *dp = NULL;
530
	CHAR16 *dps;
531

532
	full_device_path = FileDevicePath(this_image->DeviceHandle, fullpath);
533
	if (!full_device_path) {
534
		efi_status = EFI_OUT_OF_RESOURCES;
535 536
		goto err;
	}
537 538 539
	dps = DevicePathToStr(full_device_path);
	VerbosePrint(L"file DP: %s\n", dps);
	FreePool(dps);
540

541 542 543 544 545
	efi_status = FindSubDevicePath(full_device_path,
				       MEDIA_DEVICE_PATH, MEDIA_HARDDRIVE_DP,
				       &dp);
	if (EFI_ERROR(efi_status)) {
		if (efi_status == EFI_NOT_FOUND) {
546 547
			dp = full_device_path;
		} else {
548
			efi_status = EFI_OUT_OF_RESOURCES;
549 550 551 552 553
			goto err;
		}
	}

	{
554 555 556 557 558 559 560 561 562 563 564 565
		UINTN s = DevicePathSize(dp);
		UINTN i;
		UINT8 *dpv = (void *)dp;
		for (i = 0; i < s; i++) {
			if (i % 16 == 0) {
				if (i > 0)
					VerbosePrintUnprefixed(L"\n");
				VerbosePrint(L"");
			}
			VerbosePrintUnprefixed(L"%02x ", dpv[i]);
		}
		VerbosePrintUnprefixed(L"\n");
566

567 568 569
		CHAR16 *dps = DevicePathToStr(dp);
		VerbosePrint(L"device path: \"%s\"\n", dps);
		FreePool(dps);
570
	}
571

572
	UINT16 option;
573 574 575 576 577
	efi_status = find_boot_option(dp, full_device_path, fullpath, label,
				      arguments, &option);
	if (EFI_ERROR(efi_status)) {
		add_boot_option(dp, full_device_path, fullpath, label,
				arguments);
578 579 580 581 582 583 584 585 586 587 588 589 590
	} else if (option != 0) {
		CHAR16 *newbootorder;
		newbootorder = AllocateZeroPool(sizeof (CHAR16) * nbootorder);
		if (!newbootorder)
			return EFI_OUT_OF_RESOURCES;

		newbootorder[0] = bootorder[option];
		CopyMem(newbootorder + 1, bootorder, sizeof (CHAR16) * option);
		CopyMem(newbootorder + option + 1, bootorder + option + 1,
			sizeof (CHAR16) * (nbootorder - option - 1));
		FreePool(bootorder);
		bootorder = newbootorder;
	}
591 592

err:
593 594
	if (full_device_path)
		FreePool(full_device_path);
595
	if (dp && dp != full_device_path)
596 597 598
		FreePool(dp);
	if (fullpath)
		FreePool(fullpath);
599
	return efi_status;
600 601 602
}

EFI_STATUS
603
populate_stanza(CHAR16 *dirname, CHAR16 *filename, CHAR16 *csv)
604 605
{
	CHAR16 *file = csv;
606
	VerbosePrint(L"CSV data: \"%s\"\n", csv);
607 608 609 610 611

	UINTN comma0 = StrCSpn(csv, L",");
	if (comma0 == 0)
		return EFI_INVALID_PARAMETER;
	file[comma0] = L'\0';
612
	VerbosePrint(L"filename: \"%s\"\n", file);
613 614 615 616 617 618

	CHAR16 *label = csv + comma0 + 1;
	UINTN comma1 = StrCSpn(label, L",");
	if (comma1 == 0)
		return EFI_INVALID_PARAMETER;
	label[comma1] = L'\0';
619
	VerbosePrint(L"label: \"%s\"\n", label);
620 621 622 623 624

	CHAR16 *arguments = csv + comma0 +1 + comma1 +1;
	UINTN comma2 = StrCSpn(arguments, L",");
	arguments[comma2] = L'\0';
	/* This one is optional, so don't check if comma2 is 0 */
625
	VerbosePrint(L"arguments: \"%s\"\n", arguments);
626

627
	add_to_boot_list(dirname, file, label, arguments);
628 629 630 631 632 633 634 635 636

	return EFI_SUCCESS;
}

EFI_STATUS
try_boot_csv(EFI_FILE_HANDLE fh, CHAR16 *dirname, CHAR16 *filename)
{
	CHAR16 *fullpath = NULL;
	UINT64 pathlen = 0;
637
	EFI_STATUS efi_status;
638

639 640 641
	efi_status = make_full_path(dirname, filename, &fullpath, &pathlen);
	if (EFI_ERROR(efi_status))
		return efi_status;
642

643
	VerbosePrint(L"Found file \"%s\"\n", fullpath);
644 645 646

	CHAR16 *buffer;
	UINT64 bs;
647 648 649 650
	efi_status = read_file(fh, fullpath, &buffer, &bs);
	if (EFI_ERROR(efi_status)) {
		console_print(L"Could not read file \"%s\": %r\n",
			      fullpath, efi_status);
651
		FreePool(fullpath);
652
		return efi_status;
653 654 655
	}
	FreePool(fullpath);

656
	VerbosePrint(L"File looks like:\n%s\n", buffer);
657 658

	CHAR16 *start = buffer;
659 660 661 662 663 664 665
	/* The file may or may not start with the Unicode byte order marker.
	 * Sadness ensues.  Since UEFI is defined as LE, I'm going to decree
	 * that these files must also be LE.
	 *
	 * IT IS THUS SO.
	 *
	 * But if we find the LE byte order marker, just skip it.
666 667 668 669
	 */
	if (*start == 0xfeff)
		start++;
	while (*start) {
670
		while (*start == L'\r' || *start == L'\n')
671 672 673 674 675 676 677 678 679 680 681
			start++;
		UINTN l = StrCSpn(start, L"\r\n");
		if (l == 0) {
			if (start[l] == L'\0')
				break;
			start++;
			continue;
		}
		CHAR16 c = start[l];
		start[l] = L'\0';

682
		populate_stanza(dirname, filename, start);
683 684 685 686 687 688 689 690 691 692 693 694

		start[l] = c;
		start += l;
	}

	FreePool(buffer);
	return EFI_SUCCESS;
}

EFI_STATUS
find_boot_csv(EFI_FILE_HANDLE fh, CHAR16 *dirname)
{
695
	EFI_STATUS efi_status;
696 697 698 699 700
	void *buffer = NULL;
	UINTN bs = 0;

	/* The API here is "Call it once with bs=0, it fills in bs,
	 * then allocate a buffer and ask again to get it filled. */
701 702 703 704 705
	efi_status = fh->GetInfo(fh, &EFI_FILE_INFO_GUID, &bs, NULL);
	if (EFI_ERROR(efi_status) && efi_status != EFI_BUFFER_TOO_SMALL) {
		console_print(L"Could not get directory info for \\EFI\\%s\\: %r\n",
			      dirname, efi_status);
		return efi_status;
706
	}
707 708 709 710 711 712 713 714 715 716
	if (bs == 0)
		return EFI_SUCCESS;

	buffer = AllocateZeroPool(bs);
	if (!buffer) {
		console_print(L"Could not allocate memory\n");
		return EFI_OUT_OF_RESOURCES;
	}

	efi_status = fh->GetInfo(fh, &EFI_FILE_INFO_GUID, &bs, buffer);
717
	/* This checks *either* the error from the first GetInfo, if it isn't
718 719 720 721 722
	 * the EFI_BUFFER_TOO_SMALL we're expecting, or the second GetInfo
	 * call in *any* case. */
	if (EFI_ERROR(efi_status)) {
		console_print(L"Could not get info for \"%s\": %r\n", dirname,
			      efi_status);
723 724
		if (buffer)
			FreePool(buffer);
725
		return efi_status;
726 727 728 729 730 731 732 733
	}

	EFI_FILE_INFO *fi = buffer;
	if (!(fi->Attribute & EFI_FILE_DIRECTORY)) {
		FreePool(buffer);
		return EFI_SUCCESS;
	}
	FreePool(buffer);
734
	buffer = NULL;
735

736 737
	CHAR16 *bootcsv=NULL, *bootarchcsv=NULL;

738 739 740
	bs = 0;
	do {
		bs = 0;
741 742 743 744 745 746
		efi_status = fh->Read(fh, &bs, NULL);
		if (EFI_ERROR(efi_status) &&
		    efi_status != EFI_BUFFER_TOO_SMALL) {
			console_print(L"Could not read \\EFI\\%s\\: %r\n",
				      dirname, efi_status);
			return efi_status;
747
		}
748 749 750 751
		/* If there's no data to read, don't try to allocate 0 bytes
		 * and read the data... */
		if (bs == 0)
			break;
752

753 754
		buffer = AllocateZeroPool(bs);
		if (!buffer) {
755
			console_print(L"Could not allocate memory\n");
756
			return EFI_OUT_OF_RESOURCES;
757
		}
758

759 760 761 762
		efi_status = fh->Read(fh, &bs, buffer);
		if (EFI_ERROR(efi_status)) {
			console_print(L"Could not read \\EFI\\%s\\: %r\n",
				      dirname, efi_status);
763
			FreePool(buffer);
764
			return efi_status;
765
		}
766

767 768 769 770 771
		if (bs == 0)
			break;

		fi = buffer;

772 773 774 775 776 777
		if (!bootcsv && !StrCaseCmp(fi->FileName, L"boot.csv"))
			bootcsv = StrDuplicate(fi->FileName);

		if (!bootarchcsv &&
		    !StrCaseCmp(fi->FileName, L"boot" EFI_ARCH L".csv"))
			bootarchcsv = StrDuplicate(fi->FileName);
778 779 780 781 782

		FreePool(buffer);
		buffer = NULL;
	} while (bs != 0);

783
	efi_status = EFI_SUCCESS;
784 785
	if (bootarchcsv) {
		EFI_FILE_HANDLE fh2;
786 787 788 789 790
		efi_status = fh->Open(fh, &fh2, bootarchcsv,
				      EFI_FILE_READ_ONLY, 0);
		if (EFI_ERROR(efi_status) || fh2 == NULL) {
			console_print(L"Couldn't open \\EFI\\%s\\%s: %r\n",
				      dirname, bootarchcsv, efi_status);
791
		} else {
792 793 794 795 796
			efi_status = try_boot_csv(fh2, dirname, bootarchcsv);
			fh2->Close(fh2);
			if (EFI_ERROR(efi_status))
				console_print(L"Could not process \\EFI\\%s\\%s: %r\n",
					      dirname, bootarchcsv, efi_status);
797 798
		}
	}
799
	if ((EFI_ERROR(efi_status) || !bootarchcsv) && bootcsv) {
800
		EFI_FILE_HANDLE fh2;
801 802 803 804 805
		efi_status = fh->Open(fh, &fh2, bootcsv,
				      EFI_FILE_READ_ONLY, 0);
		if (EFI_ERROR(efi_status) || fh2 == NULL) {
			console_print(L"Couldn't open \\EFI\\%s\\%s: %r\n",
				      dirname, bootcsv, efi_status);
806
		} else {
807 808 809 810 811
			efi_status = try_boot_csv(fh2, dirname, bootcsv);
			fh2->Close(fh2);
			if (EFI_ERROR(efi_status))
				console_print(L"Could not process \\EFI\\%s\\%s: %r\n",
					      dirname, bootarchcsv, efi_status);
812 813
		}
	}
814
	return EFI_SUCCESS;
815 816 817 818 819
}

EFI_STATUS
find_boot_options(EFI_HANDLE device)
{
820
	EFI_STATUS efi_status;
821
	EFI_FILE_IO_INTERFACE *fio = NULL;
822 823 824 825 826 827

	efi_status = gBS->HandleProtocol(device, &FileSystemProtocol,
					 (void **) &fio);
	if (EFI_ERROR(efi_status)) {
		console_print(L"Couldn't find file system: %r\n", efi_status);
		return efi_status;
828 829 830 831 832 833
	}

	/* EFI_FILE_HANDLE is a pointer to an EFI_FILE, and I have
	 * *no idea* what frees the memory allocated here. Hopefully
	 * Close() does. */
	EFI_FILE_HANDLE fh = NULL;
834 835 836 837
	efi_status = fio->OpenVolume(fio, &fh);
	if (EFI_ERROR(efi_status) || fh == NULL) {
		console_print(L"Couldn't open file system: %r\n", efi_status);
		return efi_status;
838 839 840
	}

	EFI_FILE_HANDLE fh2 = NULL;
841 842 843 844 845
	efi_status = fh->Open(fh, &fh2, L"EFI", EFI_FILE_READ_ONLY, 0);
	if (EFI_ERROR(efi_status) || fh2 == NULL) {
		console_print(L"Couldn't open EFI: %r\n", efi_status);
		fh->Close(fh);
		return efi_status;
846
	}
847 848 849 850 851 852
	efi_status = fh2->SetPosition(fh2, 0);
	if (EFI_ERROR(efi_status)) {
		console_print(L"Couldn't set file position: %r\n", efi_status);
		fh2->Close(fh2);
		fh->Close(fh);
		return efi_status;
853 854 855 856 857 858
	}

	void *buffer;
	UINTN bs;
	do {
		bs = 0;
859 860 861 862
		efi_status = fh2->Read(fh2, &bs, NULL);
		if (EFI_ERROR(efi_status) && efi_status != EFI_BUFFER_TOO_SMALL) {
			console_print(L"Could not read \\EFI\\: %r\n", efi_status);
			return efi_status;
863 864 865 866
		}
		if (bs == 0)
			break;

867 868 869 870 871 872 873 874 875 876 877
		buffer = AllocateZeroPool(bs);
		if (!buffer) {
			console_print(L"Could not allocate memory\n");
			/* sure, this might work, why not? */
			fh2->Close(fh2);
			fh->Close(fh);
			return EFI_OUT_OF_RESOURCES;
		}

		efi_status = fh2->Read(fh2, &bs, buffer);
		if (EFI_ERROR(efi_status)) {
878 879 880 881
			if (buffer) {
				FreePool(buffer);
				buffer = NULL;
			}
882 883 884
			fh2->Close(fh2);
			fh->Close(fh);
			return efi_status;
885 886 887 888 889 890 891 892 893 894 895 896 897 898 899
		}
		EFI_FILE_INFO *fi = buffer;

		if (!(fi->Attribute & EFI_FILE_DIRECTORY)) {
			FreePool(buffer);
			buffer = NULL;
			continue;
		}
		if (!StrCmp(fi->FileName, L".") ||
				!StrCmp(fi->FileName, L"..") ||
				!StrCaseCmp(fi->FileName, L"BOOT")) {
			FreePool(buffer);
			buffer = NULL;
			continue;
		}
900
		VerbosePrint(L"Found directory named \"%s\"\n", fi->FileName);
901 902

		EFI_FILE_HANDLE fh3;
903 904 905 906 907
		efi_status = fh2->Open(fh2, &fh3, fi->FileName,
				      EFI_FILE_READ_ONLY, 0);
		if (EFI_ERROR(efi_status)) {
			console_print(L"%d Couldn't open %s: %r\n", __LINE__,
				      fi->FileName, efi_status);
908 909 910 911 912
			FreePool(buffer);
			buffer = NULL;
			continue;
		}

913 914
		efi_status = find_boot_csv(fh3, fi->FileName);
		fh3->Close(fh3);
915 916
		FreePool(buffer);
		buffer = NULL;
917
		if (efi_status == EFI_OUT_OF_RESOURCES)
918 919 920 921
			break;

	} while (1);

922 923
	if (!EFI_ERROR(efi_status) && nbootorder > 0)
		efi_status = update_boot_order();
924

925 926 927
	fh2->Close(fh2);
	fh->Close(fh);
	return efi_status;
928
}
929 930 931 932

static EFI_STATUS
try_start_first_option(EFI_HANDLE parent_image_handle)
{
933
	EFI_STATUS efi_status;
934 935 936 937 938 939
	EFI_HANDLE image_handle;

	if (!first_new_option) {
		return EFI_SUCCESS;
	}

940 941 942
	efi_status = gBS->LoadImage(0, parent_image_handle, first_new_option,
				    NULL, 0, &image_handle);
	if (EFI_ERROR(efi_status)) {
943 944
		CHAR16 *dps = DevicePathToStr(first_new_option);
		UINTN s = DevicePathSize(first_new_option);
945
		unsigned int i;
946
		UINT8 *dpv = (void *)first_new_option;
947 948
		console_print(L"LoadImage failed: %r\nDevice path: \"%s\"\n",
			      efi_status, dps);
949 950
		for (i = 0; i < s; i++) {
			if (i > 0 && i % 16 == 0)
951 952
				console_print(L"\n");
			console_print(L"%02x ", dpv[i]);
953
		}
954
		console_print(L"\n");
955

956 957
		msleep(500000000);
		return efi_status;
958
	}
959 960

	EFI_LOADED_IMAGE *image;
961 962 963
	efi_status = gBS->HandleProtocol(image_handle, &LoadedImageProtocol,
					 (void *) &image);
	if (!EFI_ERROR(efi_status)) {
964 965 966 967
		image->LoadOptions = first_new_option_args;
		image->LoadOptionsSize = first_new_option_size;
	}

968 969 970 971
	efi_status = gBS->StartImage(image_handle, NULL, NULL);
	if (EFI_ERROR(efi_status)) {
		console_print(L"StartImage failed: %r\n", efi_status);
		msleep(500000000);
972
	}
973
	return efi_status;
974 975
}

976 977 978 979 980 981 982 983 984 985 986 987 988
extern EFI_STATUS
efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab);

static void
__attribute__((__optimize__("0")))
debug_hook(void)
{
	UINT8 *data = NULL;
	UINTN dataSize = 0;
	EFI_STATUS efi_status;
	volatile register int x = 0;
	extern char _etext, _edata;

989 990
	efi_status = get_variable(L"SHIM_DEBUG", &data, &dataSize,
				  SHIM_LOCK_GUID);
991 992 993 994
	if (EFI_ERROR(efi_status)) {
		return;
	}

995 996
	if (data)
		FreePool(data);
997 998 999 1000
	if (x)
		return;

	x = 1;
1001 1002 1003
	console_print(L"add-symbol-file "DEBUGDIR
		      L"fb" EFI_ARCH L".efi.debug %p -s .data %p\n",
		      &_etext, &_edata);
1004 1005
}

1006 1007 1008
EFI_STATUS
efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
{
1009
	EFI_STATUS efi_status;
1010 1011 1012

	InitializeLib(image, systab);

1013 1014 1015 1016 1017
	/*
	 * if SHIM_DEBUG is set, wait for a debugger to attach.
	 */
	debug_hook();

1018 1019 1020 1021 1022 1023
	efi_status = gBS->HandleProtocol(image, &LoadedImageProtocol,
					 (void *) &this_image);
	if (EFI_ERROR(efi_status)) {
		console_print(L"Error: could not find loaded image: %r\n",
			      efi_status);
		return efi_status;
1024 1025
	}

1026
	console_print(L"System BootOrder not found.  Initializing defaults.\n");
1027

1028 1029
	set_boot_order();

1030 1031 1032 1033 1034
	efi_status = find_boot_options(this_image->DeviceHandle);
	if (EFI_ERROR(efi_status)) {
		console_print(L"Error: could not find boot options: %r\n",
			      efi_status);
		return efi_status;
1035 1036
	}

1037 1038
	efi_status = fallback_should_prefer_reset();
	if (EFI_ERROR(efi_status)) {
1039 1040 1041 1042 1043
		VerbosePrint(L"tpm not present, starting the first image\n");
		try_start_first_option(image);
	} else {
		VerbosePrint(L"tpm present, resetting system\n");
	}
1044

1045
	console_print(L"Reset System\n");
1046 1047

	if (get_fallback_verbose()) {
1048 1049
		console_print(L"Verbose enabled, sleeping for half a second\n");
		msleep(500000);
1050 1051
	}

1052
	gRT->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL);
1053

1054 1055
	return EFI_SUCCESS;
}