1 
2 #include <efi.h>
3 #include <efilib.h>
4 
5 #include "shelliface.h"
6 #include "sb.h"
7 
8 /* XXX probably shouldn't ship defaulting to this */
9 EFI_GUID rh_guid = {0x0abba7dc, 0xe516, 0x4167, {0xbb,0xf5,0x4d,0x9d,0x1c,0x73,0x94,0x16}};
10 
11 /* XXX this needs to be moved into gnu-efi */
12 EFI_GUID gEfiShellInterfaceGuid = EFI_SHELL_INTERFACE_GUID;
13 
14 /* XXX this needs to be moved into gnu-efi */
15 #define EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS			0x00000010
16 #define EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS	0x00000020
17 #define EFI_VARIABLE_APPEND_WRITE				0x00000040
18 
19 /* XXX this needs to be moved into gnu-efi */
20 #define EFI_SHELL_DEVICE_PATH_MAP \
21  {0x47c7b225, 0xc42a, 0x11d2, {0x8e,0x57,0x0,0xa0,0xc9,0x69,0x72,0x3b}}
22 EFI_GUID gEfiShellDevPathMap = EFI_SHELL_DEVICE_PATH_MAP;
23 
24 static void
25 __attribute__((unused))
dumphex(UINT8 * data,UINTN data_size)26 dumphex(UINT8 *data, UINTN data_size)
27 {
28 	int i, j;
29 	for (i = 0, j = 0; i < data_size; i++, j++) {
30 		Print(L"%02x ", data[i]);
31 		if (j == 15) {
32 			j = -1;
33 			Print(L"\n");
34 		}
35 	}
36 	if (j != -1)
37 		Print(L"\n");
38 }
39 
40 static void
41 __attribute__((unused))
dumphex_str(CHAR16 * data,UINTN data_size)42 dumphex_str(CHAR16 *data, UINTN data_size)
43 {
44 	int i, j;
45 	for (i = 0, j = 0; i < data_size; i+=2, j++) {
46 		Print(L"%c%c ", data[i], data[i+1]);
47 		if (j == 15) {
48 			j = -1;
49 			Print(L"\n");
50 		}
51 	}
52 	if (j != -1)
53 		Print(L"\n");
54 }
55 
56 static EFI_STATUS
get_args(EFI_HANDLE image,UINTN * argc,CHAR16 *** argv)57 get_args(EFI_HANDLE image, UINTN *argc, CHAR16 ***argv)
58 {
59 	EFI_STATUS rc;
60 	EFI_SHELL_INTERFACE *shell;
61 
62 	rc = uefi_call_wrapper(BS->OpenProtocol, 6,
63 				image,
64 				&gEfiShellInterfaceGuid,
65 				(VOID **)&shell, image, NULL,
66 				EFI_OPEN_PROTOCOL_GET_PROTOCOL);
67 
68 	if (EFI_ERROR(rc))
69 		return rc;
70 
71 	*argc = shell->Argc;
72 	*argv = shell->Argv;
73 	uefi_call_wrapper(BS->CloseProtocol, 4, image,
74 			&gEfiShellInterfaceGuid,
75 			image, NULL);
76 	return EFI_SUCCESS;
77 }
78 
79 static int
pk_is_populated(void)80 pk_is_populated(void)
81 {
82 	char *data = NULL;
83 	UINTN data_size = 0;
84 
85 	data = LibGetVariableAndSize(EFI_PLATFORM_KEY_NAME, &EfiGlobalVariable,
86 		&data_size);
87 	FreePool(data);
88 	if (!data || data_size == 0)
89 		return 0;
90 	return 1;
91 }
92 
93 static int
kek_is_populated(void)94 kek_is_populated(void)
95 {
96 	char *data = NULL;
97 	UINTN data_size = 0;
98 
99 	data = LibGetVariableAndSize(EFI_KEY_EXCHANGE_KEY_NAME,
100 		&EfiGlobalVariable, &data_size);
101 	FreePool(data);
102 	if (!data || data_size == 0)
103 		return 0;
104 	return 1;
105 }
106 
107 static int
db_is_populated(void)108 db_is_populated(void)
109 {
110 	char *data = NULL;
111 	UINTN data_size = 0;
112 
113 	data = LibGetVariableAndSize(EFI_IMAGE_SECURITY_DATABASE,
114 		&gEfiImageSecurityDatabaseGuid, &data_size);
115 	FreePool(data);
116 	if (!data || data_size == 0)
117 		return 0;
118 	return 1;
119 }
120 
121 #if 0 /* doesn't appear necessary */
122 static int
123 dbx_is_populated(void)
124 {
125 	char *data = NULL;
126 	UINTN data_size = 0;
127 
128 	data = LibGetVariableAndSize(EFI_IMAGE_SECURITY_DATABASE1,
129 		&gEfiImageSecurityDatabaseGuid, &data_size);
130 	FreePool(data);
131 	if (!data || data_size == 0)
132 		return 0;
133 	return 1;
134 }
135 #endif
136 
137 static EFI_STATUS
make_variable(UINT8 * hash,UINTN hash_size,EFI_GUID owner,EFI_GUID signature_type,VOID ** data,UINTN * data_size)138 make_variable(UINT8 *hash, UINTN hash_size,
139 		EFI_GUID owner, EFI_GUID signature_type,
140 		VOID **data, UINTN *data_size)
141 {
142 	if (!data || !data_size)
143 		return EFI_INVALID_PARAMETER;
144 
145 	struct {
146 		EFI_SIGNATURE_LIST sl;
147 		EFI_SIGNATURE_DATA sd;
148 		UINT8 cert[hash_size];
149 	} __attribute__((aligned (1))) __attribute__((packed)) *var;
150 
151 	var = AllocatePool(sizeof(*var));
152 	if (!var)
153 		return EFI_OUT_OF_RESOURCES;
154 
155 	var->sl.SignatureType = signature_type;
156 	var->sl.SignatureListSize = sizeof(*var);
157 	var->sl.SignatureHeaderSize = 0;
158 	var->sl.SignatureSize = sizeof(EFI_SIGNATURE_DATA) + hash_size;
159 
160 	var->sd.SignatureOwner = owner;
161 	CopyMem(var->cert, hash, hash_size);
162 
163 	*data = var;
164 	*data_size = sizeof(*var);
165 
166 	return EFI_SUCCESS;
167 }
168 
169 static void
usage(void)170 usage(void)
171 {
172 	Print(L"Usage: setupbs COMMAND \n");
173 	Print(L"  COMMAND := { set KEY SET_OPTIONS |\n"
174 	      L"               append KEY SET_OPTIONS |\n"
175 	      L"               clear KEY CLEAR_OPTIONS |\n"
176 	      L"               help }\n");
177 	Print(L"  KEY := { pk | kek | db | dbx }\n");
178 	Print(L"  SET_OPTIONS := [ --force ] { HASH | FILE }\n");
179 	Print(L"  HASH := --hash SIG_TYPE <hash>\n");
180 	Print(L"  FILE := --file SIG_TYPE <filename>\n");
181 	Print(L"  SIG_TYPE := sha1 sha256 rsa2048 x509\n");
182 	Print(L"  CLEAR_OPTIONS := [ --force ]\n");
183 }
184 
185 static int
has_force(UINTN argc,CHAR16 ** argv)186 has_force(UINTN argc, CHAR16 **argv)
187 {
188 	int i;
189 	for (i = 0; i < argc; i++) {
190 		if (!StrCmp(argv[i], L"--force"))
191 			return 1;
192 	}
193 	return 0;
194 }
195 
196 static inline int
hex_to_ord(CHAR16 x)197 hex_to_ord(CHAR16 x)
198 {
199 	char y = x & 0xff;
200 	int c = y >= 'a' ? 'a'-0xa
201 			 : y >= 'A' ? 'A'-0xa
202 			 	    : '0';
203 	y -= c;
204 
205 	if (y < 0 && y > 0xf)
206 		return -1;
207 	return y;
208 }
209 
210 static struct {
211 	CHAR16 *name;
212 	EFI_GUID guid;
213 	UINTN size;
214 } hashes[] = {
215 	{ L"SHA1", EFI_CERT_SHA1_GUID, 20 },
216 	{ L"SHA256", EFI_CERT_SHA256_GUID, 32 },
217 	{ L"RSA2048", EFI_CERT_RSA2048_GUID, 256 },
218 	{ L"X509", EFI_CERT_X509_GUID, -1 },
219 	{ NULL, }
220 };
221 
222 static EFI_STATUS
get_hash(UINTN argc,CHAR16 ** argv,EFI_GUID * sig_type_guid,UINT8 ** hashp,UINTN * hash_sizep)223 get_hash(UINTN argc, CHAR16 **argv, EFI_GUID *sig_type_guid,
224 	UINT8 **hashp, UINTN *hash_sizep)
225 {
226 	int i;
227 
228 	UINT8 *hash = NULL;
229 	UINTN hash_size = 0;
230 
231 	EFI_GUID hash_guid;
232 	UINTN expected_hash_size = 0;
233 
234 	if (!hashp || !hash_sizep)
235 		return EFI_INVALID_PARAMETER;
236 
237 	for (i = 1; i < argc; i++) {
238 		if (!StrCmp(argv[i], L"--hash")) {
239 			if (argc <= i+2) {
240 				Print(L"argc is %d and we need %d\n",
241 					argc, i+2);
242 				return EFI_INVALID_PARAMETER;
243 			}
244 
245 			StrUpr(argv[i+1]);
246 			int j;
247 			for (j = 0; hashes[j].name != NULL; j++) {
248 				if (!StrCmp(hashes[j].name, argv[i+1])) {
249 					hash_guid = hashes[j].guid;
250 					expected_hash_size = hashes[j].size;
251 					break;
252 				}
253 			}
254 
255 			if (!expected_hash_size) {
256 				Print(L"Unknown hash %s\n", argv[i+1]);
257 				return EFI_UNSUPPORTED;
258 			}
259 
260 			CHAR16 *text = argv[i+2];
261 			int text_len = StrLen(text);
262 
263 			hash_size = text_len / 2;
264 			if (hash_size != expected_hash_size) {
265 				Print(L"Hash size was expected to be %d, but was actually %d\n", expected_hash_size, hash_size);
266 				return EFI_INVALID_PARAMETER;
267 			}
268 
269 
270 			hash = AllocatePool(hash_size);
271 			int k;
272 			for (j = 0, k = 0; j < hash_size; j++, k+=2) {
273 				int x = hex_to_ord(text[k]);
274 				int y = hex_to_ord(text[k+1]);
275 
276 				if (x < 0 || y < 0) {
277 					Print(L"Coding error: {%d,%d} should both be positive\n", x, y);
278 					FreePool(hash);
279 					return EFI_INVALID_PARAMETER;
280 				}
281 				hash[j] = (x << 4) | y;
282 			}
283 
284 			*sig_type_guid = hash_guid;
285 			*hashp = hash;
286 			*hash_sizep = hash_size;
287 			return EFI_SUCCESS;
288 		}
289 	}
290 	return EFI_NOT_FOUND;
291 }
292 
293 static EFI_STATUS
get_file(UINTN argc,CHAR16 ** argv,EFI_GUID * sig_type_guid,UINT8 ** hashp,UINTN * hash_sizep)294 get_file(UINTN argc, CHAR16 **argv, EFI_GUID *sig_type_guid,
295 		UINT8 **hashp, UINTN *hash_sizep)
296 {
297 	return EFI_UNSUPPORTED;
298 }
299 
300 static EFI_STATUS
set_pk(EFI_SYSTEM_TABLE * systab,EFI_HANDLE image,UINTN argc,CHAR16 ** argv)301 set_pk(EFI_SYSTEM_TABLE *systab, EFI_HANDLE image, UINTN argc, CHAR16 **argv)
302 {
303 	EFI_STATUS rc;
304 	UINT8 *hash = NULL;
305 	UINTN hash_size = 0;
306 	EFI_GUID sig_type_guid;
307 
308 	rc = get_hash(argc, argv, &sig_type_guid, &hash, &hash_size);
309 	if (rc == EFI_NOT_FOUND) {
310 		rc = get_file(argc, argv, &sig_type_guid, &hash, &hash_size);
311 		if (rc == EFI_NOT_FOUND)
312 			return EFI_INVALID_PARAMETER;
313 	}
314 	if (EFI_ERROR(rc))
315 		return rc;
316 
317 	if (!CompareMem(&sig_type_guid, &gEfiCertRsa2048Guid,
318 			sizeof(sig_type_guid))) {
319 		Print(L"PK must be an RSA2048 Modulus.\n");
320 		return EFI_INVALID_PARAMETER;
321 	}
322 
323 	UINTN flags = EFI_VARIABLE_NON_VOLATILE |
324 				EFI_VARIABLE_RUNTIME_ACCESS |
325 				EFI_VARIABLE_BOOTSERVICE_ACCESS;
326 
327 #if 0 /* this is what you'd expect */
328 	VOID *data = NULL;
329 	UINTN data_size = 0;
330 
331 	rc = make_variable(hash, hash_size, rh_guid,
332 		sig_type_guid, &data, &data_size);
333 
334 	rc = uefi_call_wrapper(systab->RuntimeServices->SetVariable, 5,
335 			EFI_PLATFORM_KEY_NAME, &EfiGlobalVariable,
336 			flags, data_size, data);
337 	FreePool(data);
338 #else /* this is what you get */
339 	rc = uefi_call_wrapper(systab->RuntimeServices->SetVariable, 5,
340 			EFI_PLATFORM_KEY_NAME, &EfiGlobalVariable,
341 			flags, hash_size, hash);
342 #endif
343 
344 	FreePool(hash);
345 
346 	return rc;
347 }
348 
349 static EFI_STATUS
set_db_helper(EFI_SYSTEM_TABLE * systab,EFI_HANDLE image,UINTN argc,CHAR16 ** argv,EFI_GUID * vendor_guid,CHAR16 * dbname,int append)350 set_db_helper(EFI_SYSTEM_TABLE *systab, EFI_HANDLE image,
351 		UINTN argc, CHAR16 **argv,
352 		EFI_GUID *vendor_guid, CHAR16 *dbname,
353 		int append)
354 {
355 	EFI_STATUS rc;
356 	UINT8 *hash = NULL;
357 	UINTN hash_size = 0;
358 	EFI_GUID sig_type_guid;
359 
360 	rc = get_hash(argc, argv, &sig_type_guid, &hash, &hash_size);
361 	if (rc == EFI_NOT_FOUND) {
362 		rc = get_file(argc, argv, &sig_type_guid, &hash, &hash_size);
363 		if (rc == EFI_NOT_FOUND)
364 			return EFI_INVALID_PARAMETER;
365 	}
366 	if (EFI_ERROR(rc))
367 		return rc;
368 
369 	VOID *data = NULL;
370 	UINTN data_size = 0;
371 
372 	rc = make_variable(hash, hash_size, rh_guid,
373 		sig_type_guid, &data, &data_size);
374 
375 	UINTN flags = EFI_VARIABLE_NON_VOLATILE |
376 				EFI_VARIABLE_RUNTIME_ACCESS |
377 				EFI_VARIABLE_BOOTSERVICE_ACCESS;
378 	if (append)
379 		flags |= EFI_VARIABLE_APPEND_WRITE;
380 
381 	rc = uefi_call_wrapper(systab->RuntimeServices->SetVariable, 5,
382 			dbname, vendor_guid, flags, data_size, data);
383 	FreePool(data);
384 	FreePool(hash);
385 
386 	return rc;
387 }
388 
389 static EFI_STATUS
set_db(EFI_SYSTEM_TABLE * systab,EFI_HANDLE image,UINTN argc,CHAR16 ** argv)390 set_db(EFI_SYSTEM_TABLE *systab, EFI_HANDLE image, UINTN argc, CHAR16 **argv)
391 {
392 	return set_db_helper(systab, image, argc, argv,
393 				&gEfiImageSecurityDatabaseGuid,
394 				EFI_IMAGE_SECURITY_DATABASE, 0);
395 }
396 
397 static EFI_STATUS
set_dbx(EFI_SYSTEM_TABLE * systab,EFI_HANDLE image,UINTN argc,CHAR16 ** argv)398 set_dbx(EFI_SYSTEM_TABLE *systab, EFI_HANDLE image, UINTN argc, CHAR16 **argv)
399 {
400 	return set_db_helper(systab, image, argc, argv,
401 				&gEfiImageSecurityDatabaseGuid,
402 				EFI_IMAGE_SECURITY_DATABASE1, 0);
403 }
404 
405 static EFI_STATUS
set_kek(EFI_SYSTEM_TABLE * systab,EFI_HANDLE image,UINTN argc,CHAR16 ** argv)406 set_kek(EFI_SYSTEM_TABLE *systab, EFI_HANDLE image, UINTN argc, CHAR16 **argv)
407 {
408 	return set_db_helper(systab, image, argc, argv,
409 				&EfiGlobalVariable,
410 				EFI_KEY_EXCHANGE_KEY_NAME, 0);
411 }
412 
413 static EFI_STATUS
append_db(EFI_SYSTEM_TABLE * systab,EFI_HANDLE image,UINTN argc,CHAR16 ** argv)414 append_db(EFI_SYSTEM_TABLE *systab, EFI_HANDLE image, UINTN argc, CHAR16 **argv)
415 {
416 
417 	return set_db_helper(systab, image, argc, argv,
418 				&gEfiImageSecurityDatabaseGuid,
419 				EFI_IMAGE_SECURITY_DATABASE, 1);
420 }
421 
422 static EFI_STATUS
append_dbx(EFI_SYSTEM_TABLE * systab,EFI_HANDLE image,UINTN argc,CHAR16 ** argv)423 append_dbx(EFI_SYSTEM_TABLE *systab, EFI_HANDLE image, UINTN argc, CHAR16 **argv)
424 {
425 	return set_db_helper(systab, image, argc, argv,
426 				&gEfiImageSecurityDatabaseGuid,
427 				EFI_IMAGE_SECURITY_DATABASE1, 1);
428 }
429 
430 static EFI_STATUS
append_kek(EFI_SYSTEM_TABLE * systab,EFI_HANDLE image,UINTN argc,CHAR16 ** argv)431 append_kek(EFI_SYSTEM_TABLE *systab, EFI_HANDLE image, UINTN argc, CHAR16 **argv)
432 {
433 	return set_db_helper(systab, image, argc, argv,
434 				&EfiGlobalVariable,
435 				EFI_KEY_EXCHANGE_KEY_NAME, 1);
436 }
437 
438 static EFI_STATUS
append_pk(EFI_SYSTEM_TABLE * systab,EFI_HANDLE image,UINTN argc,CHAR16 ** argv)439 append_pk(EFI_SYSTEM_TABLE *systab, EFI_HANDLE image, UINTN argc, CHAR16 **argv)
440 {
441 	Print(L"PK Can only be one entry.\n");
442 	return EFI_UNSUPPORTED;
443 }
444 
445 static EFI_STATUS
clear_pk(EFI_SYSTEM_TABLE * systab,EFI_HANDLE image,UINTN argc,CHAR16 ** argv)446 clear_pk(EFI_SYSTEM_TABLE *systab, EFI_HANDLE image, UINTN argc, CHAR16 **argv)
447 {
448 	EFI_STATUS rc;
449 	rc = uefi_call_wrapper(systab->RuntimeServices->SetVariable, 5,
450 		EFI_PLATFORM_KEY_NAME, &EfiGlobalVariable,
451 		EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_RUNTIME_ACCESS|
452 			EFI_VARIABLE_BOOTSERVICE_ACCESS,
453 		0, NULL);
454 	if (rc == EFI_NOT_FOUND)
455 		rc = EFI_SUCCESS;
456 	return rc;
457 }
458 
459 static EFI_STATUS
clear_db(EFI_SYSTEM_TABLE * systab,EFI_HANDLE image,UINTN argc,CHAR16 ** argv)460 clear_db(EFI_SYSTEM_TABLE *systab, EFI_HANDLE image, UINTN argc, CHAR16 **argv)
461 {
462 	EFI_STATUS rc;
463 
464 	if (pk_is_populated() && !kek_is_populated() && !has_force(argc,argv)) {
465 		Print(L"Cowardly refusing to clear db with PK set "
466 			L"and no KEK\n");
467 		return EFI_UNSUPPORTED;
468 	}
469 	rc = uefi_call_wrapper(systab->RuntimeServices->SetVariable, 5,
470 		EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid,
471 		EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_RUNTIME_ACCESS|
472 			EFI_VARIABLE_BOOTSERVICE_ACCESS,
473 		0, NULL);
474 	if (rc == EFI_NOT_FOUND)
475 		rc = EFI_SUCCESS;
476 	return rc;
477 }
478 
479 static EFI_STATUS
clear_dbx(EFI_SYSTEM_TABLE * systab,EFI_HANDLE image,UINTN argc,CHAR16 ** argv)480 clear_dbx(EFI_SYSTEM_TABLE *systab, EFI_HANDLE image, UINTN argc, CHAR16 **argv)
481 {
482 	EFI_STATUS rc;
483 	rc = uefi_call_wrapper(systab->RuntimeServices->SetVariable, 5,
484 		EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid,
485 		EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_RUNTIME_ACCESS|
486 			EFI_VARIABLE_BOOTSERVICE_ACCESS,
487 		0, NULL);
488 	if (rc == EFI_NOT_FOUND)
489 		rc = EFI_SUCCESS;
490 	return rc;
491 }
492 
493 static EFI_STATUS
clear_kek(EFI_SYSTEM_TABLE * systab,EFI_HANDLE image,UINTN argc,CHAR16 ** argv)494 clear_kek(EFI_SYSTEM_TABLE *systab, EFI_HANDLE image, UINTN argc, CHAR16 **argv)
495 {
496 	EFI_STATUS rc;
497 	if (pk_is_populated() && !db_is_populated() && !has_force(argc,argv)) {
498 		Print(L"Cowardly refusing to clear KEK with PK set "
499 			L"and no DB entries\n");
500 		return EFI_UNSUPPORTED;
501 	}
502 	rc = uefi_call_wrapper(systab->RuntimeServices->SetVariable, 5,
503 		EFI_KEY_EXCHANGE_KEY_NAME, &EfiGlobalVariable,
504 		EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_RUNTIME_ACCESS|
505 			EFI_VARIABLE_BOOTSERVICE_ACCESS,
506 		0, NULL);
507 	if (rc == EFI_NOT_FOUND)
508 		rc = EFI_SUCCESS;
509 	return rc;
510 }
511 
512 struct {
513 	CHAR16 *name;
514 	CHAR16 *db;
515 	EFI_STATUS (*handler)(EFI_SYSTEM_TABLE *systab, EFI_HANDLE image, UINTN argc, CHAR16 **argv);
516 } actions[] = {
517 	{ L"set", L"pk", set_pk},
518 	{ L"set", L"kek", set_kek},
519 	{ L"set", L"db", set_db},
520 	{ L"set", L"dbx", set_dbx},
521 	{ L"append", L"PK", append_pk},
522 	{ L"append", L"kek", append_kek},
523 	{ L"append", L"db", append_db},
524 	{ L"append", L"dbx", append_dbx},
525 	{ L"clear", L"pk", clear_pk},
526 	{ L"clear", L"kek", clear_kek},
527 	{ L"clear", L"db", clear_db},
528 	{ L"clear", L"dbx", clear_dbx},
529 	{ NULL, NULL, NULL},
530 };
531 
532 typedef EFI_STATUS (*handler)(EFI_SYSTEM_TABLE *systab, EFI_HANDLE image, UINTN argc, CHAR16 **argv);
533 
534 EFI_STATUS
efi_main(EFI_HANDLE image,EFI_SYSTEM_TABLE * systab)535 efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
536 {
537 	UINTN argc;
538 	CHAR16 **argv;
539 	EFI_STATUS rc = EFI_SUCCESS;
540 
541 	InitializeLib(image, systab);
542 
543 	rc = get_args(image, &argc, &argv);
544 	if (EFI_ERROR(rc)) {
545 		Print(L"Error: %d\n", rc);
546 		return rc;
547 	}
548 
549 	if (argc == 1) {
550 		Print(L"Too few arguments.\n");
551 show_usage:
552 		usage();
553 		return EFI_INVALID_PARAMETER;
554 	}
555 
556 	if (argc == 2) {
557 		if (!StrCmp(argv[1], L"help") ||
558 				!StrCmp(argv[1], L"/help") ||
559 				!StrCmp(argv[1], L"--help") ||
560 				!StrCmp(argv[1], L"-?")) {
561 			usage();
562 			return EFI_SUCCESS;
563 		}
564 		goto show_usage;
565 	}
566 
567 	int i = 1;
568 
569 	rc = EFI_INVALID_PARAMETER;
570 	int j;
571 
572 	for(j = 0; actions[j].name != NULL; j++ ) {
573 		if (!StrCmp(actions[j].name, argv[i]) &&
574 				!StrCmp(actions[j].db, argv[i+1])) {
575 			rc = actions[j].handler(systab, image, argc-i, argv+i);
576 			break;
577 		}
578 	}
579 	if (rc == EFI_UNSUPPORTED || rc == EFI_INVALID_PARAMETER)
580 		goto show_usage;
581 
582 	if (EFI_ERROR(rc))
583 		Print(L"Error: %d\n", rc);
584 	return rc;
585 }
586