]> git.proxmox.com Git - mirror_edk2.git/blob - ShellPkg/Library/UefiShellBcfgCommandLib/UefiShellBcfgCommandLib.c
dc3714d236d20dae1569421acac982208af3ee57
[mirror_edk2.git] / ShellPkg / Library / UefiShellBcfgCommandLib / UefiShellBcfgCommandLib.c
1 /** @file
2 Main file for BCFG command.
3
4 (C) Copyright 2014-2015 Hewlett-Packard Development Company, L.P.<BR>
5 Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14 **/
15
16
17 #include <Uefi.h>
18 #include <ShellBase.h>
19
20 #include <Guid/GlobalVariable.h>
21 #include <Guid/ShellLibHiiGuid.h>
22
23 #include <Protocol/EfiShell.h>
24 #include <Protocol/EfiShellParameters.h>
25 #include <Protocol/DevicePath.h>
26 #include <Protocol/LoadedImage.h>
27 #include <Protocol/UnicodeCollation.h>
28
29 #include <Library/BaseLib.h>
30 #include <Library/BaseMemoryLib.h>
31 #include <Library/DebugLib.h>
32 #include <Library/MemoryAllocationLib.h>
33 #include <Library/PcdLib.h>
34 #include <Library/ShellCommandLib.h>
35 #include <Library/ShellLib.h>
36 #include <Library/SortLib.h>
37 #include <Library/UefiLib.h>
38 #include <Library/UefiRuntimeServicesTableLib.h>
39 #include <Library/UefiBootServicesTableLib.h>
40 #include <Library/HiiLib.h>
41 #include <Library/FileHandleLib.h>
42 #include <Library/PrintLib.h>
43 #include <Library/HandleParsingLib.h>
44 #include <Library/DevicePathLib.h>
45
46 STATIC CONST CHAR16 mFileName[] = L"ShellCommands";
47 STATIC EFI_HANDLE gShellBcfgHiiHandle = NULL;
48
49 typedef enum {
50 BcfgTargetBootOrder = 0,
51 BcfgTargetDriverOrder = 1,
52 BcfgTargetMax = 2
53 } BCFG_OPERATION_TARGET;
54
55 typedef enum {
56 BcfgTypeDump = 0,
57 BcfgTypeAdd = 1,
58 BcfgTypeAddp = 2,
59 BcfgTypeAddh = 3,
60 BcfgTypeRm = 4,
61 BcfgTypeMv = 5,
62 BcfgTypeOpt = 6,
63 BcfgTypeMax = 7
64 } BCFG_OPERATION_TYPE;
65
66 typedef struct {
67 BCFG_OPERATION_TARGET Target;
68 BCFG_OPERATION_TYPE Type;
69 UINT16 Number1;
70 UINT16 Number2;
71 UINTN HandleIndex;
72 CHAR16 *FileName;
73 CHAR16 *Description;
74 UINT16 *Order;
75 CONST CHAR16 *OptData;
76 } BGFG_OPERATION;
77
78 /**
79 Update the optional data for a boot or driver option.
80
81 If optional data exists it will be changed.
82
83 @param[in] Index The boot or driver option index update.
84 @param[in] DataSize The size in bytes of Data.
85 @param[in] Data The buffer for the optioanl data.
86 @param[in] Target The target of the operation.
87
88 @retval EFI_SUCCESS The data was sucessfully updated.
89 @retval other A error occured.
90 **/
91 EFI_STATUS
92 UpdateOptionalData(
93 UINT16 Index,
94 UINTN DataSize,
95 UINT8 *Data,
96 IN CONST BCFG_OPERATION_TARGET Target
97 )
98 {
99 EFI_STATUS Status;
100 CHAR16 VariableName[12];
101 UINTN OriginalSize;
102 UINT8 *OriginalData;
103 UINTN NewSize;
104 UINT8 *NewData;
105 UINTN OriginalOptionDataSize;
106
107 UnicodeSPrint(VariableName, sizeof(VariableName), L"%s%04x", Target == BcfgTargetBootOrder?L"Boot":L"Driver", Index);
108
109 OriginalSize = 0;
110 OriginalData = NULL;
111 NewData = NULL;
112 NewSize = 0;
113
114 Status = gRT->GetVariable(
115 VariableName,
116 (EFI_GUID*)&gEfiGlobalVariableGuid,
117 NULL,
118 &OriginalSize,
119 OriginalData);
120 if (Status == EFI_BUFFER_TOO_SMALL) {
121 OriginalData = AllocateZeroPool(OriginalSize);
122 if (OriginalData == NULL) {
123 return (EFI_OUT_OF_RESOURCES);
124 }
125 Status = gRT->GetVariable(
126 VariableName,
127 (EFI_GUID*)&gEfiGlobalVariableGuid,
128 NULL,
129 &OriginalSize,
130 OriginalData);
131 }
132
133 if (!EFI_ERROR(Status)) {
134 //
135 // Allocate new struct and discard old optional data.
136 //
137 ASSERT (OriginalData != NULL);
138 OriginalOptionDataSize = sizeof(UINT32) + sizeof(UINT16) + StrSize(((CHAR16*)(OriginalData + sizeof(UINT32) + sizeof(UINT16))));
139 OriginalOptionDataSize += (*(UINT16*)(OriginalData + sizeof(UINT32)));
140 OriginalOptionDataSize -= OriginalSize;
141 NewSize = OriginalSize - OriginalOptionDataSize + DataSize;
142 NewData = AllocateCopyPool(NewSize, OriginalData);
143 if (NewData == NULL) {
144 Status = EFI_OUT_OF_RESOURCES;
145 } else {
146 CopyMem(NewData + OriginalSize - OriginalOptionDataSize, Data, DataSize);
147 }
148 }
149
150 if (!EFI_ERROR(Status)) {
151 //
152 // put the data back under the variable
153 //
154 Status = gRT->SetVariable(
155 VariableName,
156 (EFI_GUID*)&gEfiGlobalVariableGuid,
157 EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS,
158 NewSize,
159 NewData);
160 }
161
162 SHELL_FREE_NON_NULL(OriginalData);
163 SHELL_FREE_NON_NULL(NewData);
164 return (Status);
165 }
166
167 /**
168 This function will get a CRC for a boot option.
169
170 @param[in, out] Crc The CRC value to return.
171 @param[in] BootIndex The boot option index to CRC.
172
173 @retval EFI_SUCCESS The CRC was sucessfully returned.
174 @retval other A error occured.
175 **/
176 EFI_STATUS
177 GetBootOptionCrc(
178 UINT32 *Crc,
179 UINT16 BootIndex
180 )
181 {
182 CHAR16 VariableName[12];
183 EFI_STATUS Status;
184 UINT8 *Buffer;
185 UINTN BufferSize;
186
187 Buffer = NULL;
188 BufferSize = 0;
189
190 //
191 // Get the data Buffer
192 //
193 UnicodeSPrint(VariableName, sizeof(VariableName), L"%Boot%04x", BootIndex);
194 Status = gRT->GetVariable(
195 VariableName,
196 (EFI_GUID*)&gEfiGlobalVariableGuid,
197 NULL,
198 &BufferSize,
199 NULL);
200 if (Status == EFI_BUFFER_TOO_SMALL) {
201 Buffer = AllocateZeroPool(BufferSize);
202 Status = gRT->GetVariable(
203 VariableName,
204 (EFI_GUID*)&gEfiGlobalVariableGuid,
205 NULL,
206 &BufferSize,
207 Buffer);
208 }
209
210 //
211 // Get the CRC computed
212 //
213 if (!EFI_ERROR(Status)) {
214 Status = gBS->CalculateCrc32 (Buffer, BufferSize, Crc);
215 }
216
217 SHELL_FREE_NON_NULL(Buffer);
218 return EFI_SUCCESS;
219 }
220
221 /**
222 This function will populate the device path protocol parameter based on TheHandle.
223
224 @param[in] TheHandle Driver handle.
225 @param[in, out] FilePath On a sucessful return the device path to the handle.
226
227 @retval EFI_SUCCESS The device path was sucessfully returned.
228 @retval other A error from gBS->HandleProtocol.
229
230 @sa HandleProtocol
231 **/
232 EFI_STATUS
233 GetDevicePathForDriverHandle (
234 IN EFI_HANDLE TheHandle,
235 IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath
236 )
237 {
238 EFI_STATUS Status;
239 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
240 EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath;
241
242 Status = gBS->OpenProtocol (
243 TheHandle,
244 &gEfiLoadedImageProtocolGuid,
245 (VOID**)&LoadedImage,
246 gImageHandle,
247 NULL,
248 EFI_OPEN_PROTOCOL_GET_PROTOCOL
249 );
250 if (!EFI_ERROR (Status)) {
251 Status = gBS->OpenProtocol (
252 LoadedImage->DeviceHandle,
253 &gEfiDevicePathProtocolGuid,
254 (VOID**)&ImageDevicePath,
255 gImageHandle,
256 NULL,
257 EFI_OPEN_PROTOCOL_GET_PROTOCOL
258 );
259 if (!EFI_ERROR (Status)) {
260 // *DevPath = DuplicateDevicePath (ImageDevicePath);
261 // *FilePath = DuplicateDevicePath (LoadedImage->FilePath);
262 *FilePath = AppendDevicePath(ImageDevicePath,LoadedImage->FilePath);
263 gBS->CloseProtocol(
264 LoadedImage->DeviceHandle,
265 &gEfiDevicePathProtocolGuid,
266 gImageHandle,
267 NULL);
268 }
269 gBS->CloseProtocol(
270 TheHandle,
271 &gEfiLoadedImageProtocolGuid,
272 gImageHandle,
273 NULL);
274 }
275 return (Status);
276 }
277
278 /**
279 Function to add a option.
280
281 @param[in] Position The position to add Target at.
282 @param[in] File The file to make the target.
283 @param[in] Desc The description text.
284 @param[in] CurrentOrder The pointer to the current order of items.
285 @param[in] OrderCount The number if items in CurrentOrder.
286 @param[in] Target The info on the option to add.
287 @param[in] UseHandle TRUE to use HandleNumber, FALSE to use File and Desc.
288 @param[in] UsePath TRUE to convert to devicepath.
289 @param[in] HandleNumber The handle number to add.
290
291 @retval SHELL_SUCCESS The operation was successful.
292 @retval SHELL_INVALID_PARAMETER A parameter was invalid.
293 **/
294 SHELL_STATUS
295 BcfgAdd(
296 IN UINTN Position,
297 IN CONST CHAR16 *File,
298 IN CONST CHAR16 *Desc,
299 IN CONST UINT16 *CurrentOrder,
300 IN CONST UINTN OrderCount,
301 IN CONST BCFG_OPERATION_TARGET Target,
302 IN CONST BOOLEAN UseHandle,
303 IN CONST BOOLEAN UsePath,
304 IN CONST UINTN HandleNumber
305 )
306 {
307 EFI_STATUS Status;
308 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
309 EFI_DEVICE_PATH_PROTOCOL *DevPath;
310 EFI_DEVICE_PATH_PROTOCOL *FilePath;
311 CHAR16 *Str;
312 UINT8 *TempByteBuffer;
313 UINT8 *TempByteStart;
314 EFI_SHELL_FILE_INFO *Arg;
315 EFI_SHELL_FILE_INFO *FileList;
316 CHAR16 OptionStr[40];
317 UINTN DescSize, FilePathSize;
318 BOOLEAN Found;
319 UINTN TargetLocation;
320 UINTN Index;
321 EFI_HANDLE *Handles;
322 EFI_HANDLE CurHandle;
323 UINTN DriverBindingHandleCount;
324 UINTN ParentControllerHandleCount;
325 UINTN ChildControllerHandleCount;
326 SHELL_STATUS ShellStatus;
327 UINT16 *NewOrder;
328
329 if (!UseHandle) {
330 if (File == NULL || Desc == NULL) {
331 return (SHELL_INVALID_PARAMETER);
332 }
333 } else {
334 if (HandleNumber == 0) {
335 return (SHELL_INVALID_PARAMETER);
336 }
337 }
338
339 if (Position > OrderCount) {
340 Position = OrderCount;
341 }
342
343 Str = NULL;
344 FilePath = NULL;
345 FileList = NULL;
346 Handles = NULL;
347 ShellStatus = SHELL_SUCCESS;
348 TargetLocation = 0xFFFF;
349
350 if (UseHandle) {
351 CurHandle = ConvertHandleIndexToHandle(HandleNumber);
352 if (CurHandle == NULL) {
353 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", L"Handle Number");
354 ShellStatus = SHELL_INVALID_PARAMETER;
355 } else {
356 if (Target == BcfgTargetBootOrder) {
357 //
358 //Make sure that the handle should point to a real controller
359 //
360 Status = PARSE_HANDLE_DATABASE_UEFI_DRIVERS (
361 CurHandle,
362 &DriverBindingHandleCount,
363 NULL);
364
365 Status = PARSE_HANDLE_DATABASE_PARENTS (
366 CurHandle,
367 &ParentControllerHandleCount,
368 NULL);
369
370 Status = ParseHandleDatabaseForChildControllers (
371 CurHandle,
372 &ChildControllerHandleCount,
373 NULL);
374
375 if (DriverBindingHandleCount > 0
376 || ParentControllerHandleCount > 0
377 || ChildControllerHandleCount > 0) {
378 FilePath = NULL;
379 Status = gBS->HandleProtocol (
380 CurHandle,
381 &gEfiDevicePathProtocolGuid,
382 (VOID**)&FilePath);
383 }
384 if (EFI_ERROR (Status)) {
385 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_HANDLE), gShellBcfgHiiHandle, L"bcfg", HandleNumber);
386 ShellStatus = SHELL_INVALID_PARAMETER;
387 }
388 } else {
389 //
390 //Make sure that the handle should point to driver, not a controller.
391 //
392 Status = PARSE_HANDLE_DATABASE_UEFI_DRIVERS (
393 CurHandle,
394 &DriverBindingHandleCount,
395 NULL);
396
397 Status = PARSE_HANDLE_DATABASE_PARENTS (
398 CurHandle,
399 &ParentControllerHandleCount,
400 NULL);
401
402 Status = ParseHandleDatabaseForChildControllers (
403 CurHandle,
404 &ChildControllerHandleCount,
405 NULL);
406
407 Status = gBS->HandleProtocol (
408 CurHandle,
409 &gEfiDevicePathProtocolGuid,
410 (VOID**)&FilePath);
411
412 if (DriverBindingHandleCount > 0
413 || ParentControllerHandleCount > 0
414 || ChildControllerHandleCount > 0
415 || !EFI_ERROR(Status) ) {
416 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", L"Handle Number");
417 ShellStatus = SHELL_INVALID_PARAMETER;
418 } else {
419 //
420 // Get the DevicePath from the loaded image information.
421 //
422 Status = GetDevicePathForDriverHandle(CurHandle, &FilePath);
423 }
424 }
425 }
426 } else {
427 //
428 // Get file info
429 //
430 ShellOpenFileMetaArg ((CHAR16*)File, EFI_FILE_MODE_READ, &FileList);
431
432 if (FileList == NULL) {
433 //
434 // If filename matched nothing fail
435 //
436 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellBcfgHiiHandle, L"bcfg", File);
437 ShellStatus = SHELL_INVALID_PARAMETER;
438 } else if (FileList->Link.ForwardLink != FileList->Link.BackLink) {
439 //
440 // If filename expanded to multiple names, fail
441 //
442 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_FILE), gShellBcfgHiiHandle, L"bcfg", File);
443 ShellStatus = SHELL_INVALID_PARAMETER;
444 } else {
445 Arg = (EFI_SHELL_FILE_INFO*)GetFirstNode(&FileList->Link);
446 if (EFI_ERROR(Arg->Status)) {
447 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_FILE_OPEN), gShellBcfgHiiHandle, L"bcfg", File);
448 ShellStatus = SHELL_INVALID_PARAMETER;
449 } else {
450 //
451 // Build FilePath to the filename
452 //
453
454 //
455 // get the device path
456 //
457 DevicePath = gEfiShellProtocol->GetDevicePathFromFilePath(Arg->FullName);
458 if (DevicePath == NULL) {
459 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_FILE_DP), gShellBcfgHiiHandle, L"bcfg", Arg->FullName);
460 ShellStatus = SHELL_UNSUPPORTED;
461 } else {
462 if (UsePath) {
463 DevPath = DevicePath;
464 ShellStatus = SHELL_INVALID_PARAMETER;
465 while (!IsDevicePathEnd(DevPath)) {
466 if ((DevicePathType(DevPath) == MEDIA_DEVICE_PATH) &&
467 (DevicePathSubType(DevPath) == MEDIA_HARDDRIVE_DP)) {
468
469 //
470 // If we find it use it instead
471 //
472 ShellStatus = SHELL_SUCCESS;
473 FilePath = DuplicateDevicePath (DevPath);
474 break;
475 }
476 DevPath = NextDevicePathNode(DevPath);
477 }
478 } else {
479 FilePath = DuplicateDevicePath(DevicePath);
480 }
481 FreePool(DevicePath);
482 }
483 }
484 }
485 }
486
487
488 if (ShellStatus == SHELL_SUCCESS) {
489 //
490 // Find a free target ,a brute force implementation
491 //
492 Found = FALSE;
493 for (TargetLocation=0; TargetLocation < 0xFFFF; TargetLocation++) {
494 Found = TRUE;
495 for (Index=0; Index < OrderCount; Index++) {
496 if (CurrentOrder[Index] == TargetLocation) {
497 Found = FALSE;
498 break;
499 }
500 }
501
502 if (Found) {
503 break;
504 }
505 }
506
507 if (TargetLocation == 0xFFFF) {
508 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_TARGET_NF), gShellBcfgHiiHandle, L"bcfg");
509 } else {
510 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_TARGET), gShellBcfgHiiHandle, TargetLocation);
511 }
512 }
513
514 if (ShellStatus == SHELL_SUCCESS) {
515 //
516 // Add the option
517 //
518 DescSize = StrSize(Desc);
519 FilePathSize = GetDevicePathSize (FilePath);
520
521 TempByteBuffer = AllocateZeroPool(sizeof(UINT32) + sizeof(UINT16) + DescSize + FilePathSize);
522 if (TempByteBuffer != NULL) {
523 TempByteStart = TempByteBuffer;
524 *((UINT32 *) TempByteBuffer) = LOAD_OPTION_ACTIVE; // Attributes
525 TempByteBuffer += sizeof (UINT32);
526
527 *((UINT16 *) TempByteBuffer) = (UINT16)FilePathSize; // FilePathListLength
528 TempByteBuffer += sizeof (UINT16);
529
530 CopyMem (TempByteBuffer, Desc, DescSize);
531 TempByteBuffer += DescSize;
532 ASSERT (FilePath != NULL);
533 CopyMem (TempByteBuffer, FilePath, FilePathSize);
534
535 UnicodeSPrint (OptionStr, sizeof(OptionStr), L"%s%04x", Target == BcfgTargetBootOrder?L"Boot":L"Driver", TargetLocation);
536 Status = gRT->SetVariable (
537 OptionStr,
538 &gEfiGlobalVariableGuid,
539 EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS,
540 sizeof(UINT32) + sizeof(UINT16) + DescSize + FilePathSize,
541 TempByteStart
542 );
543
544 FreePool(TempByteStart);
545 } else {
546 Status = EFI_OUT_OF_RESOURCES;
547 }
548
549 if (EFI_ERROR(Status)) {
550 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_SET_VAR_FAIL), gShellBcfgHiiHandle, L"bcfg", OptionStr);
551 } else {
552 NewOrder = AllocateZeroPool ((OrderCount + 1) * sizeof (NewOrder[0]));
553 if (NewOrder != NULL) {
554 CopyMem (NewOrder, CurrentOrder, (OrderCount) * sizeof (NewOrder[0]));
555
556 //
557 // Insert target into order list
558 //
559 for (Index = OrderCount; Index > Position; Index--) {
560 NewOrder[Index] = NewOrder[Index - 1];
561 }
562
563 NewOrder[Position] = (UINT16) TargetLocation;
564 Status = gRT->SetVariable (
565 Target == BcfgTargetBootOrder ? L"BootOrder" : L"DriverOrder",
566 &gEfiGlobalVariableGuid,
567 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
568 (OrderCount + 1) * sizeof (UINT16),
569 NewOrder
570 );
571
572 FreePool (NewOrder);
573
574 if (EFI_ERROR (Status)) {
575 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_BCFG_WRITE_FAIL), gShellBcfgHiiHandle, L"bcfg", Target == BcfgTargetBootOrder ? L"BootOrder" : L"DriverOrder");
576 ShellStatus = SHELL_INVALID_PARAMETER;
577 } else {
578 Print (L"bcfg: Add %s as %x\n", OptionStr, Position);
579 }
580 }
581 }
582 }
583
584 //
585 //If always Free FilePath, will free devicepath in system when use "addh"
586 //
587 if (FilePath!=NULL && !UseHandle) {
588 FreePool (FilePath);
589 }
590
591 if (Str != NULL) {
592 FreePool(Str);
593 }
594
595 if (Handles != NULL) {
596 FreePool (Handles);
597 }
598
599 if (FileList != NULL) {
600 ShellCloseFileMetaArg (&FileList);
601 }
602
603 return (ShellStatus);
604 }
605
606 /**
607 Funciton to remove an item.
608
609 @param[in] Target The target item to move.
610 @param[in] CurrentOrder The pointer to the current order of items.
611 @param[in] OrderCount The number if items in CurrentOrder.
612 @param[in] Location The current location of the Target.
613
614 @retval SHELL_SUCCESS The operation was successful.
615 @retval SHELL_INVALID_PARAMETER A parameter was invalid.
616 **/
617 SHELL_STATUS
618 BcfgRemove(
619 IN CONST BCFG_OPERATION_TARGET Target,
620 IN CONST UINT16 *CurrentOrder,
621 IN CONST UINTN OrderCount,
622 IN CONST UINT16 Location
623 )
624 {
625 CHAR16 VariableName[12];
626 UINT16 *NewOrder;
627 EFI_STATUS Status;
628 UINTN NewCount;
629
630 UnicodeSPrint(VariableName, sizeof(VariableName), L"%s%04x", Target == BcfgTargetBootOrder?L"Boot":L"Driver", CurrentOrder[Location]);
631 Status = gRT->SetVariable(
632 VariableName,
633 (EFI_GUID*)&gEfiGlobalVariableGuid,
634 EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS,
635 0,
636 NULL);
637 if (EFI_ERROR(Status)) {
638 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_WRITE_FAIL), gShellBcfgHiiHandle, L"bcfg", VariableName);
639 return (SHELL_INVALID_PARAMETER);
640 }
641 NewOrder = AllocateZeroPool(OrderCount*sizeof(CurrentOrder[0]));
642 if (NewOrder != NULL) {
643 NewCount = OrderCount;
644 CopyMem(NewOrder, CurrentOrder, OrderCount*sizeof(CurrentOrder[0]));
645 CopyMem(NewOrder+Location, NewOrder+Location+1, (OrderCount - Location - 1)*sizeof(CurrentOrder[0]));
646 NewCount--;
647
648 Status = gRT->SetVariable(
649 Target == BcfgTargetBootOrder?(CHAR16*)L"BootOrder":(CHAR16*)L"DriverOrder",
650 (EFI_GUID*)&gEfiGlobalVariableGuid,
651 EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS,
652 NewCount*sizeof(NewOrder[0]),
653 NewOrder);
654 FreePool(NewOrder);
655 } else {
656 Status = EFI_OUT_OF_RESOURCES;
657 }
658 if (EFI_ERROR(Status)) {
659 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_WRITE_FAIL), gShellBcfgHiiHandle, L"bcfg", Target == BcfgTargetBootOrder?(CHAR16*)L"BootOrder":(CHAR16*)L"DriverOrder");
660 return (SHELL_INVALID_PARAMETER);
661 }
662 return (SHELL_SUCCESS);
663 }
664
665 /**
666 Funciton to move a item to another location.
667
668 @param[in] Target The target item to move.
669 @param[in] CurrentOrder The pointer to the current order of items.
670 @param[in] OrderCount The number if items in CurrentOrder.
671 @param[in] OldLocation The current location of the Target.
672 @param[in] NewLocation The desired location of the Target.
673
674 @retval SHELL_SUCCESS The operation was successful.
675 @retval SHELL_INVALID_PARAMETER A parameter was invalid.
676 **/
677 SHELL_STATUS
678 BcfgMove(
679 IN CONST BCFG_OPERATION_TARGET Target,
680 IN CONST UINT16 *CurrentOrder,
681 IN CONST UINTN OrderCount,
682 IN CONST UINT16 OldLocation,
683 IN UINT16 NewLocation
684 )
685 {
686 UINT16 *NewOrder;
687 EFI_STATUS Status;
688 UINT16 Temp;
689
690 NewOrder = AllocateCopyPool(OrderCount*sizeof(CurrentOrder[0]), CurrentOrder);
691 if (NewOrder == NULL) {
692 return (SHELL_OUT_OF_RESOURCES);
693 }
694
695 //
696 // correct the new location
697 //
698 if (NewLocation >= OrderCount) {
699 if (OrderCount > 0) {
700 NewLocation = (UINT16)OrderCount - 1;
701 } else {
702 NewLocation = 0;
703 }
704 }
705
706 Temp = CurrentOrder[OldLocation];
707 CopyMem(NewOrder+OldLocation, NewOrder+OldLocation+1, (OrderCount - OldLocation - 1)*sizeof(CurrentOrder[0]));
708 CopyMem(NewOrder+NewLocation+1, NewOrder+NewLocation, (OrderCount - NewLocation - 1)*sizeof(CurrentOrder[0]));
709 NewOrder[NewLocation] = Temp;
710
711 Status = gRT->SetVariable(
712 Target == BcfgTargetBootOrder?(CHAR16*)L"BootOrder":(CHAR16*)L"DriverOrder",
713 (EFI_GUID*)&gEfiGlobalVariableGuid,
714 EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS,
715 OrderCount*sizeof(CurrentOrder[0]),
716 NewOrder);
717
718 FreePool(NewOrder);
719
720 if (EFI_ERROR(Status)) {
721 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_WRITE_FAIL), gShellBcfgHiiHandle, L"bcfg", Target == BcfgTargetBootOrder?(CHAR16*)L"BootOrder":(CHAR16*)L"DriverOrder");
722 return (SHELL_INVALID_PARAMETER);
723 }
724 return (SHELL_SUCCESS);
725 }
726
727 /**
728 Function to add optional data to an option.
729
730 @param[in] OptData The optional data to add.
731 @param[in] CurrentOrder The pointer to the current order of items.
732 @param[in] OrderCount The number if items in CurrentOrder.
733 @param[in] Target The target of the operation.
734
735 @retval SHELL_SUCCESS The operation was succesful.
736 **/
737 SHELL_STATUS
738 BcfgAddOpt(
739 IN CONST CHAR16 *OptData,
740 IN CONST UINT16 *CurrentOrder,
741 IN CONST UINTN OrderCount,
742 IN CONST BCFG_OPERATION_TARGET Target
743 )
744 {
745 EFI_KEY_OPTION NewKeyOption;
746 EFI_KEY_OPTION *KeyOptionBuffer;
747 SHELL_STATUS ShellStatus;
748 EFI_STATUS Status;
749 UINT16 OptionIndex;
750 UINT16 LoopCounter;
751 UINT64 Intermediate;
752 CONST CHAR16 *Temp;
753 CONST CHAR16 *Walker;
754 CHAR16 *FileName;
755 CHAR16 *Temp2;
756 CHAR16 *Data;
757 UINT32 KeyIndex;
758 CHAR16 VariableName[12];
759 VOID *VariableData;
760
761 SHELL_FILE_HANDLE FileHandle;
762
763 Status = EFI_SUCCESS;
764 ShellStatus = SHELL_SUCCESS;
765 Walker = OptData;
766 FileName = NULL;
767 Data = NULL;
768 KeyOptionBuffer = NULL;
769 VariableData = NULL;
770
771 ZeroMem(&NewKeyOption, sizeof(EFI_KEY_OPTION));
772 ZeroMem(VariableName, sizeof(VariableName));
773
774 while(Walker[0] == L' ') {
775 Walker++;
776 }
777
778 //
779 // Get the index of the variable we are changing.
780 //
781 Status = ShellConvertStringToUint64(Walker, &Intermediate, FALSE, TRUE);
782 if (EFI_ERROR(Status) || (((UINT16)Intermediate) != Intermediate) || StrStr(Walker, L" ") == NULL || ((UINT16)Intermediate) > ((UINT16)OrderCount)) {
783 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", L"Option Index");
784 ShellStatus = SHELL_INVALID_PARAMETER;
785 return (ShellStatus);
786 }
787 OptionIndex = (UINT16)Intermediate;
788
789 Temp = StrStr(Walker, L" ");
790 if (Temp != NULL) {
791 Walker = Temp;
792 }
793 while(Walker[0] == L' ') {
794 Walker++;
795 }
796
797 //
798 // determine whether we have file with data, quote delimited information, or a hot-key
799 //
800 if (Walker[0] == L'\"') {
801 //
802 // quoted filename or quoted information.
803 //
804 Temp = StrStr(Walker+1, L"\"");
805 if (Temp == NULL || StrLen(Temp) != 1) {
806 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", Walker);
807 ShellStatus = SHELL_INVALID_PARAMETER;
808 } else {
809 FileName = StrnCatGrow(&FileName, NULL, Walker+1, 0);
810 if (FileName == NULL) {
811 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellBcfgHiiHandle, L"bcfg");
812 ShellStatus = SHELL_OUT_OF_RESOURCES;
813 return (ShellStatus);
814 }
815 Temp2 = StrStr(FileName, L"\"");
816 ASSERT(Temp2 != NULL);
817 Temp2[0] = CHAR_NULL;
818 Temp2++;
819 if (StrLen(Temp2)>0) {
820 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", Walker);
821 ShellStatus = SHELL_INVALID_PARAMETER;
822 }
823 if (EFI_ERROR(ShellFileExists(Walker))) {
824 //
825 // Not a file. must be misc information.
826 //
827 Data = FileName;
828 FileName = NULL;
829 } else {
830 FileName = StrnCatGrow(&FileName, NULL, Walker, 0);
831 }
832 }
833 } else {
834 //
835 // filename or hot key information.
836 //
837 if (StrStr(Walker, L" ") == NULL) {
838 //
839 // filename
840 //
841 if (EFI_ERROR(ShellFileExists(Walker))) {
842 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FIND_FAIL), gShellBcfgHiiHandle, L"bcfg", Walker);
843 ShellStatus = SHELL_INVALID_PARAMETER;
844 } else {
845 FileName = StrnCatGrow(&FileName, NULL, Walker, 0);
846 }
847 } else {
848 if (Target != BcfgTargetBootOrder) {
849 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_BOOT_ONLY), gShellBcfgHiiHandle, L"bcfg");
850 ShellStatus = SHELL_INVALID_PARAMETER;
851 }
852
853 if (ShellStatus == SHELL_SUCCESS) {
854 //
855 // Get hot key information
856 //
857 Status = ShellConvertStringToUint64(Walker, &Intermediate, FALSE, TRUE);
858 if (EFI_ERROR(Status) || (((UINT32)Intermediate) != Intermediate) || StrStr(Walker, L" ") == NULL) {
859 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", Walker);
860 ShellStatus = SHELL_INVALID_PARAMETER;
861 }
862 NewKeyOption.KeyData.PackedValue = (UINT32)Intermediate;
863 Temp = StrStr(Walker, L" ");
864 if (Temp != NULL) {
865 Walker = Temp;
866 }
867 while(Walker[0] == L' ') {
868 Walker++;
869 }
870 }
871
872 if (ShellStatus == SHELL_SUCCESS) {
873 //
874 // Now we know how many EFI_INPUT_KEY structs we need to attach to the end of the EFI_KEY_OPTION struct.
875 // Re-allocate with the added information.
876 //
877 KeyOptionBuffer = AllocateCopyPool(sizeof(EFI_KEY_OPTION) + (sizeof(EFI_INPUT_KEY) * NewKeyOption.KeyData.Options.InputKeyCount), &NewKeyOption);
878 if (KeyOptionBuffer == NULL) {
879 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_MEM), gShellBcfgHiiHandle, L"bcfg");
880 ShellStatus = SHELL_OUT_OF_RESOURCES;
881 }
882 }
883 for (LoopCounter = 0 ; ShellStatus == SHELL_SUCCESS && LoopCounter < NewKeyOption.KeyData.Options.InputKeyCount; LoopCounter++) {
884 //
885 // ScanCode
886 //
887 Status = ShellConvertStringToUint64(Walker, &Intermediate, FALSE, TRUE);
888 if (EFI_ERROR(Status) || (((UINT16)Intermediate) != Intermediate) || StrStr(Walker, L" ") == NULL) {
889 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", Walker);
890 ShellStatus = SHELL_INVALID_PARAMETER;
891 }
892 ((EFI_INPUT_KEY*)(((UINT8*)KeyOptionBuffer) + sizeof(EFI_KEY_OPTION)))[LoopCounter].ScanCode = (UINT16)Intermediate;
893 Temp = StrStr(Walker, L" ");
894 if (Temp != NULL) {
895 Walker = Temp;
896 }
897 while(Walker[0] == L' ') {
898 Walker++;
899 }
900
901 //
902 // UnicodeChar
903 //
904 Status = ShellConvertStringToUint64(Walker, &Intermediate, FALSE, TRUE);
905 if (EFI_ERROR(Status) || (((UINT16)Intermediate) != Intermediate)) {
906 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", Walker);
907 ShellStatus = SHELL_INVALID_PARAMETER;
908 }
909 ((EFI_INPUT_KEY*)(((UINT8*)KeyOptionBuffer) + sizeof(EFI_KEY_OPTION)))[LoopCounter].UnicodeChar = (UINT16)Intermediate;
910 Temp = StrStr(Walker, L" ");
911 if (Temp != NULL) {
912 Walker = Temp;
913 }
914 while(Walker[0] == L' ') {
915 Walker++;
916 }
917 }
918
919 if (ShellStatus == SHELL_SUCCESS) {
920 //
921 // Now do the BootOption / BootOptionCrc
922 //
923 ASSERT (OptionIndex <= OrderCount);
924 KeyOptionBuffer->BootOption = CurrentOrder[OptionIndex];
925 Status = GetBootOptionCrc(&(KeyOptionBuffer->BootOptionCrc), KeyOptionBuffer->BootOption);
926 if (EFI_ERROR(Status)) {
927 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", L"Option Index");
928 ShellStatus = SHELL_INVALID_PARAMETER;
929 }
930 }
931
932 if (ShellStatus == SHELL_SUCCESS) {
933 for (Temp2 = NULL, KeyIndex = 0 ; KeyIndex <= 0xFFFF ; KeyIndex++) {
934 UnicodeSPrint(VariableName, sizeof(VariableName), L"Key%04x", KeyIndex);
935 Status = GetEfiGlobalVariable2 (VariableName, &VariableData, NULL);
936 if (Status == EFI_NOT_FOUND) {
937 break;
938 }
939 if (!EFI_ERROR(Status)) {
940 SHELL_FREE_NON_NULL(VariableData);
941 }
942 }
943 if (KeyIndex <= 0xFFFF) {
944 Status = gRT->SetVariable(
945 VariableName,
946 (EFI_GUID*)&gEfiGlobalVariableGuid,
947 EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS,
948 sizeof(EFI_KEY_OPTION) + (sizeof(EFI_INPUT_KEY) * NewKeyOption.KeyData.Options.InputKeyCount),
949 KeyOptionBuffer);
950 if (EFI_ERROR(Status)) {
951 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_SET_VAR_FAIL), gShellBcfgHiiHandle, L"bcfg", VariableName);
952 ShellStatus = SHELL_INVALID_PARAMETER;
953 }
954 } else {
955 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_VAR_NO_NUM), gShellBcfgHiiHandle, L"bcfg");
956 ShellStatus = SHELL_INVALID_PARAMETER;
957 }
958 ASSERT(FileName == NULL && Data == NULL);
959 }
960 }
961 }
962
963 //
964 // Shouldn't be possible to have have both. Neither is ok though.
965 //
966 ASSERT(FileName == NULL || Data == NULL);
967
968 if (ShellStatus == SHELL_SUCCESS && (FileName != NULL || Data != NULL)) {
969 if (FileName != NULL) {
970 //
971 // Open the file and populate the data buffer.
972 //
973 Status = ShellOpenFileByName(
974 FileName,
975 &FileHandle,
976 EFI_FILE_MODE_READ,
977 0);
978 if (!EFI_ERROR(Status)) {
979 Status = ShellGetFileSize(FileHandle, &Intermediate);
980 }
981 Data = AllocateZeroPool((UINTN)Intermediate);
982 if (Data == NULL) {
983 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_MEM), gShellBcfgHiiHandle, L"bcfg");
984 ShellStatus = SHELL_OUT_OF_RESOURCES;
985 }
986 if (!EFI_ERROR(Status)) {
987 Status = ShellReadFile(FileHandle, (UINTN *)&Intermediate, Data);
988 }
989 } else {
990 Intermediate = StrSize(Data);
991 }
992
993 if (!EFI_ERROR(Status) && ShellStatus == SHELL_SUCCESS && Data != NULL) {
994 Status = UpdateOptionalData(CurrentOrder[OptionIndex], (UINTN)Intermediate, (UINT8*)Data, Target);
995 if (EFI_ERROR(Status)) {
996 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_SET_VAR_FAIL), gShellBcfgHiiHandle, L"bcfg", VariableName);
997 ShellStatus = SHELL_INVALID_PARAMETER;
998 }
999 }
1000 if (EFI_ERROR(Status) && ShellStatus == SHELL_SUCCESS) {
1001 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_SET_VAR_FAIL), gShellBcfgHiiHandle, L"bcfg", VariableName);
1002 ShellStatus = SHELL_INVALID_PARAMETER;
1003 }
1004 }
1005
1006 SHELL_FREE_NON_NULL(Data);
1007 SHELL_FREE_NON_NULL(KeyOptionBuffer);
1008 SHELL_FREE_NON_NULL(FileName);
1009 return ShellStatus;
1010 }
1011
1012 /**
1013 Function to dump the Bcfg information.
1014
1015 @param[in] Op The operation.
1016 @param[in] OrderCount How many to dump.
1017 @param[in] CurrentOrder The pointer to the current order of items.
1018 @param[in] VerboseOutput TRUE for extra output. FALSE otherwise.
1019
1020 @retval SHELL_SUCCESS The dump was successful.
1021 @retval SHELL_INVALID_PARAMETER A parameter was invalid.
1022 **/
1023 SHELL_STATUS
1024 BcfgDisplayDump(
1025 IN CONST CHAR16 *Op,
1026 IN CONST UINTN OrderCount,
1027 IN CONST UINT16 *CurrentOrder,
1028 IN CONST BOOLEAN VerboseOutput
1029 )
1030 {
1031 EFI_STATUS Status;
1032 UINT8 *Buffer;
1033 UINTN BufferSize;
1034 CHAR16 VariableName[12];
1035 UINTN LoopVar;
1036 CHAR16 *DevPathString;
1037 VOID *FilePathList;
1038 UINTN Errors;
1039 EFI_LOAD_OPTION *LoadOption;
1040 CHAR16 *Description;
1041 UINTN DescriptionSize;
1042 UINTN OptionalDataOffset;
1043
1044 if (OrderCount == 0) {
1045 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_BCFG_NONE), gShellBcfgHiiHandle, L"bcfg");
1046 return (SHELL_SUCCESS);
1047 }
1048
1049 Errors = 0;
1050
1051 for (LoopVar = 0 ; LoopVar < OrderCount ; LoopVar++) {
1052 Buffer = NULL;
1053 BufferSize = 0;
1054 DevPathString = NULL;
1055
1056 UnicodeSPrint(VariableName, sizeof(VariableName), L"%s%04x", Op, CurrentOrder[LoopVar]);
1057
1058 Status = gRT->GetVariable(
1059 VariableName,
1060 (EFI_GUID*)&gEfiGlobalVariableGuid,
1061 NULL,
1062 &BufferSize,
1063 Buffer);
1064 if (Status == EFI_BUFFER_TOO_SMALL) {
1065 Buffer = AllocateZeroPool(BufferSize);
1066 Status = gRT->GetVariable(
1067 VariableName,
1068 (EFI_GUID*)&gEfiGlobalVariableGuid,
1069 NULL,
1070 &BufferSize,
1071 Buffer);
1072 }
1073
1074 if (EFI_ERROR(Status) || Buffer == NULL) {
1075 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_READ_FAIL), gShellBcfgHiiHandle, L"bcfg", VariableName);
1076 ++Errors;
1077 goto Cleanup;
1078 }
1079
1080 //
1081 // We expect the Attributes, FilePathListLength, and L'\0'-terminated
1082 // Description fields to be present.
1083 //
1084 if (BufferSize < sizeof *LoadOption + sizeof (CHAR16)) {
1085 ShellPrintHiiEx (
1086 -1,
1087 -1,
1088 NULL,
1089 STRING_TOKEN (STR_BCFG_VAR_CORRUPT),
1090 gShellBcfgHiiHandle,
1091 L"bcfg",
1092 VariableName
1093 );
1094 ++Errors;
1095 goto Cleanup;
1096 }
1097
1098 LoadOption = (EFI_LOAD_OPTION *)Buffer;
1099 Description = (CHAR16*)(Buffer + sizeof (EFI_LOAD_OPTION));
1100 DescriptionSize = StrSize (Description);
1101
1102 if (LoadOption->FilePathListLength != 0) {
1103 FilePathList = (UINT8 *)Description + DescriptionSize;
1104 DevPathString = ConvertDevicePathToText(FilePathList, TRUE, FALSE);
1105 }
1106
1107 OptionalDataOffset = sizeof *LoadOption + DescriptionSize +
1108 LoadOption->FilePathListLength;
1109
1110 ShellPrintHiiEx(
1111 -1,
1112 -1,
1113 NULL,
1114 STRING_TOKEN(STR_BCFG_LOAD_OPTIONS),
1115 gShellBcfgHiiHandle,
1116 LoopVar,
1117 VariableName,
1118 Description,
1119 DevPathString,
1120 OptionalDataOffset >= BufferSize ? L'N' : L'Y'
1121 );
1122 if (VerboseOutput && (OptionalDataOffset < BufferSize)) {
1123 DumpHex (
1124 2, // Indent
1125 0, // Offset (displayed)
1126 BufferSize - OptionalDataOffset, // DataSize
1127 Buffer + OptionalDataOffset // UserData
1128 );
1129 }
1130
1131 Cleanup:
1132 if (Buffer != NULL) {
1133 FreePool(Buffer);
1134 }
1135 if (DevPathString != NULL) {
1136 FreePool(DevPathString);
1137 }
1138 }
1139 return (Errors > 0) ? SHELL_INVALID_PARAMETER : SHELL_SUCCESS;
1140 }
1141
1142 /**
1143 Function to initialize the BCFG operation structure.
1144
1145 @param[in] Struct The stuct to initialize.
1146 **/
1147 VOID
1148 InitBcfgStruct(
1149 IN BGFG_OPERATION *Struct
1150 )
1151 {
1152 ASSERT(Struct != NULL);
1153 Struct->Target = BcfgTargetMax;
1154 Struct->Type = BcfgTypeMax;
1155 Struct->Number1 = 0;
1156 Struct->Number2 = 0;
1157 Struct->HandleIndex = 0;
1158 Struct->FileName = NULL;
1159 Struct->Description = NULL;
1160 Struct->Order = NULL;
1161 Struct->OptData = NULL;
1162 }
1163
1164
1165 STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
1166 {L"-v", TypeFlag},
1167 {L"-opt", TypeMaxValue},
1168 {NULL, TypeMax}
1169 };
1170
1171 /**
1172 Function for 'bcfg' command.
1173
1174 @param[in] ImageHandle Handle to the Image (NULL if Internal).
1175 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
1176 **/
1177 SHELL_STATUS
1178 EFIAPI
1179 ShellCommandRunBcfg (
1180 IN EFI_HANDLE ImageHandle,
1181 IN EFI_SYSTEM_TABLE *SystemTable
1182 )
1183 {
1184 EFI_STATUS Status;
1185 LIST_ENTRY *Package;
1186 CHAR16 *ProblemParam;
1187 SHELL_STATUS ShellStatus;
1188 UINTN ParamNumber;
1189 CONST CHAR16 *CurrentParam;
1190 BGFG_OPERATION CurrentOperation;
1191 UINTN Length;
1192 UINT64 Intermediate;
1193 UINT16 Count;
1194
1195 Length = 0;
1196 ProblemParam = NULL;
1197 Package = NULL;
1198 ShellStatus = SHELL_SUCCESS;
1199
1200 InitBcfgStruct(&CurrentOperation);
1201
1202 //
1203 // initialize the shell lib (we must be in non-auto-init...)
1204 //
1205 Status = ShellInitialize();
1206 ASSERT_EFI_ERROR(Status);
1207
1208 Status = CommandInit();
1209 ASSERT_EFI_ERROR(Status);
1210
1211 //
1212 // parse the command line
1213 //
1214 Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE);
1215 if (EFI_ERROR(Status)) {
1216 if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {
1217 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellBcfgHiiHandle, L"bcfg", ProblemParam);
1218 FreePool(ProblemParam);
1219 ShellStatus = SHELL_INVALID_PARAMETER;
1220 } else {
1221 ASSERT(FALSE);
1222 }
1223 } else {
1224 //
1225 // Read in if we are doing -OPT
1226 //
1227 if (ShellCommandLineGetFlag(Package, L"-opt")) {
1228 CurrentOperation.OptData = ShellCommandLineGetValue(Package, L"-opt");
1229 if (CurrentOperation.OptData == NULL) {
1230 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_VALUE), gShellBcfgHiiHandle, L"bcfg", L"-opt");
1231 ShellStatus = SHELL_INVALID_PARAMETER;
1232 }
1233 CurrentOperation.Type = BcfgTypeOpt;
1234 }
1235
1236 //
1237 // small block to read the target of the operation
1238 //
1239 if ((ShellCommandLineGetCount(Package) < 3 && CurrentOperation.Type != BcfgTypeOpt) ||
1240 (ShellCommandLineGetCount(Package) < 2 && CurrentOperation.Type == BcfgTypeOpt)
1241 ){
1242 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellBcfgHiiHandle, L"bcfg");
1243 ShellStatus = SHELL_INVALID_PARAMETER;
1244 } else if (gUnicodeCollation->StriColl(gUnicodeCollation, (CHAR16*)ShellCommandLineGetRawValue(Package, 1), L"driver") == 0) {
1245 CurrentOperation.Target = BcfgTargetDriverOrder;
1246 } else if (gUnicodeCollation->StriColl(gUnicodeCollation, (CHAR16*)ShellCommandLineGetRawValue(Package, 1), L"boot") == 0) {
1247 CurrentOperation.Target = BcfgTargetBootOrder;
1248 } else {
1249 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_DRIVER_BOOT), gShellBcfgHiiHandle, L"bcfg");
1250 ShellStatus = SHELL_INVALID_PARAMETER;
1251 }
1252
1253
1254 //
1255 // Read in the boot or driver order environment variable (not needed for opt)
1256 //
1257 if (ShellStatus == SHELL_SUCCESS && CurrentOperation.Target < BcfgTargetMax) {
1258 Length = 0;
1259 Status = gRT->GetVariable(
1260 CurrentOperation.Target == BcfgTargetBootOrder?(CHAR16*)L"BootOrder":(CHAR16*)L"DriverOrder",
1261 (EFI_GUID*)&gEfiGlobalVariableGuid,
1262 NULL,
1263 &Length,
1264 CurrentOperation.Order);
1265 if (Status == EFI_BUFFER_TOO_SMALL) {
1266 CurrentOperation.Order = AllocateZeroPool(Length+(4*sizeof(CurrentOperation.Order[0])));
1267 if (CurrentOperation.Order == NULL) {
1268 ShellStatus = SHELL_OUT_OF_RESOURCES;
1269 } else {
1270 Status = gRT->GetVariable(
1271 CurrentOperation.Target == BcfgTargetBootOrder?(CHAR16*)L"BootOrder":(CHAR16*)L"DriverOrder",
1272 (EFI_GUID*)&gEfiGlobalVariableGuid,
1273 NULL,
1274 &Length,
1275 CurrentOperation.Order);
1276 }
1277 }
1278 }
1279
1280 Count = (UINT16) (Length / sizeof(CurrentOperation.Order[0]));
1281
1282 //
1283 // large block to read the type of operation and verify parameter types for the info.
1284 //
1285 if (ShellStatus == SHELL_SUCCESS && CurrentOperation.Target < BcfgTargetMax) {
1286 for (ParamNumber = 2 ; ParamNumber < ShellCommandLineGetCount(Package) && ShellStatus == SHELL_SUCCESS; ParamNumber++) {
1287 CurrentParam = ShellCommandLineGetRawValue(Package, ParamNumber);
1288 if (gUnicodeCollation->StriColl(gUnicodeCollation, (CHAR16*)CurrentParam, L"dump") == 0) {
1289 CurrentOperation.Type = BcfgTypeDump;
1290 if (ShellCommandLineGetCount(Package) > 3) {
1291 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellBcfgHiiHandle, L"bcfg");
1292 ShellStatus = SHELL_INVALID_PARAMETER;
1293 }
1294 } else if (ShellCommandLineGetFlag(Package, L"-v")) {
1295 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", L"-v (without dump)");
1296 ShellStatus = SHELL_INVALID_PARAMETER;
1297 } else if (gUnicodeCollation->StriColl(gUnicodeCollation, (CHAR16*)CurrentParam, L"add") == 0) {
1298 if ((ParamNumber + 3) >= ShellCommandLineGetCount(Package)) {
1299 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellBcfgHiiHandle, L"bcfg");
1300 ShellStatus = SHELL_INVALID_PARAMETER;
1301 }
1302 CurrentOperation.Type = BcfgTypeAdd;
1303 CurrentParam = ShellCommandLineGetRawValue(Package, ++ParamNumber);
1304 if (CurrentParam == NULL || !ShellIsHexOrDecimalNumber(CurrentParam, TRUE, FALSE)) {
1305 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", CurrentParam);
1306 ShellStatus = SHELL_INVALID_PARAMETER;
1307 } else {
1308 Status = ShellConvertStringToUint64(CurrentParam, &Intermediate, TRUE, FALSE);
1309 CurrentOperation.Number1 = (UINT16)Intermediate;
1310 ASSERT(CurrentOperation.FileName == NULL);
1311 CurrentOperation.FileName = StrnCatGrow(&CurrentOperation.FileName , NULL, ShellCommandLineGetRawValue(Package, ++ParamNumber), 0);
1312 ASSERT(CurrentOperation.Description == NULL);
1313 CurrentOperation.Description = StrnCatGrow(&CurrentOperation.Description, NULL, ShellCommandLineGetRawValue(Package, ++ParamNumber), 0);
1314 }
1315 } else if (gUnicodeCollation->StriColl(gUnicodeCollation, (CHAR16*)CurrentParam, L"addp") == 0) {
1316 if ((ParamNumber + 3) >= ShellCommandLineGetCount(Package)) {
1317 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellBcfgHiiHandle, L"bcfg");
1318 ShellStatus = SHELL_INVALID_PARAMETER;
1319 }
1320 CurrentOperation.Type = BcfgTypeAddp;
1321 CurrentParam = ShellCommandLineGetRawValue(Package, ++ParamNumber);
1322 if (CurrentParam == NULL || !ShellIsHexOrDecimalNumber(CurrentParam, TRUE, FALSE)) {
1323 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", CurrentParam);
1324 ShellStatus = SHELL_INVALID_PARAMETER;
1325 } else {
1326 Status = ShellConvertStringToUint64(CurrentParam, &Intermediate, TRUE, FALSE);
1327 CurrentOperation.Number1 = (UINT16)Intermediate;
1328 ASSERT(CurrentOperation.FileName == NULL);
1329 CurrentOperation.FileName = StrnCatGrow(&CurrentOperation.FileName , NULL, ShellCommandLineGetRawValue(Package, ++ParamNumber), 0);
1330 ASSERT(CurrentOperation.Description == NULL);
1331 CurrentOperation.Description = StrnCatGrow(&CurrentOperation.Description, NULL, ShellCommandLineGetRawValue(Package, ++ParamNumber), 0);
1332 }
1333 } else if (gUnicodeCollation->StriColl(gUnicodeCollation, (CHAR16*)CurrentParam, L"addh") == 0) {
1334 if ((ParamNumber + 3) >= ShellCommandLineGetCount(Package)) {
1335 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellBcfgHiiHandle, L"bcfg");
1336 ShellStatus = SHELL_INVALID_PARAMETER;
1337 }
1338 CurrentOperation.Type = BcfgTypeAddh;
1339 CurrentParam = ShellCommandLineGetRawValue(Package, ++ParamNumber);
1340 if (CurrentParam == NULL || !ShellIsHexOrDecimalNumber(CurrentParam, TRUE, FALSE)) {
1341 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", CurrentParam);
1342 ShellStatus = SHELL_INVALID_PARAMETER;
1343 } else {
1344 Status = ShellConvertStringToUint64(CurrentParam, &Intermediate, TRUE, FALSE);
1345 CurrentOperation.Number1 = (UINT16)Intermediate;
1346 CurrentParam = ShellCommandLineGetRawValue(Package, ++ParamNumber);
1347 if (CurrentParam == NULL || !ShellIsHexOrDecimalNumber(CurrentParam, TRUE, FALSE)) {
1348 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", CurrentParam);
1349 ShellStatus = SHELL_INVALID_PARAMETER;
1350 } else {
1351 Status = ShellConvertStringToUint64(CurrentParam, &Intermediate, TRUE, FALSE);
1352 CurrentOperation.HandleIndex = (UINT16)Intermediate;
1353 ASSERT(CurrentOperation.Description == NULL);
1354 CurrentOperation.Description = StrnCatGrow(&CurrentOperation.Description, NULL, ShellCommandLineGetRawValue(Package, ++ParamNumber), 0);
1355 }
1356 }
1357 } else if (gUnicodeCollation->StriColl(gUnicodeCollation, (CHAR16*)CurrentParam, L"rm") == 0) {
1358 if ((ParamNumber + 1) >= ShellCommandLineGetCount(Package)) {
1359 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellBcfgHiiHandle, L"bcfg");
1360 ShellStatus = SHELL_INVALID_PARAMETER;
1361 }
1362 CurrentOperation.Type = BcfgTypeRm;
1363 CurrentParam = ShellCommandLineGetRawValue(Package, ++ParamNumber);
1364 if (CurrentParam == NULL || !ShellIsHexOrDecimalNumber(CurrentParam, TRUE, FALSE)) {
1365 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", CurrentParam);
1366 ShellStatus = SHELL_INVALID_PARAMETER;
1367 } else {
1368 Status = ShellConvertStringToUint64(CurrentParam, &Intermediate, TRUE, FALSE);
1369 CurrentOperation.Number1 = (UINT16)Intermediate;
1370 if (CurrentOperation.Number1 >= Count){
1371 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_NUMB_RANGE), gShellBcfgHiiHandle, L"bcfg", Count);
1372 ShellStatus = SHELL_INVALID_PARAMETER;
1373 }
1374 }
1375 } else if (gUnicodeCollation->StriColl(gUnicodeCollation, (CHAR16*)CurrentParam, L"mv") == 0) {
1376 if ((ParamNumber + 2) >= ShellCommandLineGetCount(Package)) {
1377 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellBcfgHiiHandle, L"bcfg");
1378 ShellStatus = SHELL_INVALID_PARAMETER;
1379 }
1380 CurrentOperation.Type = BcfgTypeMv;
1381 CurrentParam = ShellCommandLineGetRawValue(Package, ++ParamNumber);
1382 if (CurrentParam == NULL || !ShellIsHexOrDecimalNumber(CurrentParam, TRUE, FALSE)) {
1383 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", CurrentParam);
1384 ShellStatus = SHELL_INVALID_PARAMETER;
1385 } else {
1386 Status = ShellConvertStringToUint64(CurrentParam, &Intermediate, TRUE, FALSE);
1387 CurrentOperation.Number1 = (UINT16)Intermediate;
1388 if (CurrentOperation.Number1 >= Count){
1389 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_NUMB_RANGE), gShellBcfgHiiHandle, L"bcfg", Count);
1390 ShellStatus = SHELL_INVALID_PARAMETER;
1391 } else {
1392 CurrentParam = ShellCommandLineGetRawValue(Package, ++ParamNumber);
1393 if (CurrentParam == NULL || !ShellIsHexOrDecimalNumber(CurrentParam, TRUE, FALSE)) {
1394 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", CurrentParam);
1395 ShellStatus = SHELL_INVALID_PARAMETER;
1396 } else {
1397 Status = ShellConvertStringToUint64(CurrentParam, &Intermediate, TRUE, FALSE);
1398 CurrentOperation.Number2 = (UINT16)Intermediate;
1399 }
1400 if (CurrentOperation.Number2 == CurrentOperation.Number1
1401 ||CurrentOperation.Number2 >= Count
1402 ){
1403 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_NUMB_RANGE), gShellBcfgHiiHandle, L"bcfg", Count);
1404 ShellStatus = SHELL_INVALID_PARAMETER;
1405 }
1406 }
1407 }
1408 } else {
1409 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", CurrentParam);
1410 ShellStatus = SHELL_INVALID_PARAMETER;
1411 }
1412 }
1413 }
1414 if (ShellStatus == SHELL_SUCCESS && CurrentOperation.Target < BcfgTargetMax && CurrentOperation.Type < BcfgTypeMax) {
1415 //
1416 // we have all the info. Do the work
1417 //
1418 switch (CurrentOperation.Type) {
1419 case BcfgTypeDump:
1420 ShellStatus = BcfgDisplayDump(
1421 CurrentOperation.Target == BcfgTargetBootOrder?L"Boot":L"Driver",
1422 Count,
1423 CurrentOperation.Order,
1424 ShellCommandLineGetFlag(Package, L"-v"));
1425 break;
1426 case BcfgTypeMv:
1427 ShellStatus = BcfgMove(
1428 CurrentOperation.Target,
1429 CurrentOperation.Order,
1430 Count,
1431 CurrentOperation.Number1,
1432 CurrentOperation.Number2);
1433 break;
1434 case BcfgTypeRm:
1435 ShellStatus = BcfgRemove(
1436 CurrentOperation.Target,
1437 CurrentOperation.Order,
1438 Count,
1439 CurrentOperation.Number1);
1440 break;
1441 case BcfgTypeAdd:
1442 case BcfgTypeAddp:
1443 case BcfgTypeAddh:
1444 ShellStatus = BcfgAdd(
1445 CurrentOperation.Number1,
1446 CurrentOperation.FileName,
1447 CurrentOperation.Description==NULL?L"":CurrentOperation.Description,
1448 CurrentOperation.Order,
1449 Count,
1450 CurrentOperation.Target,
1451 (BOOLEAN)(CurrentOperation.Type == BcfgTypeAddh),
1452 (BOOLEAN)(CurrentOperation.Type == BcfgTypeAddp),
1453 CurrentOperation.HandleIndex);
1454 break;
1455 case BcfgTypeOpt:
1456 ShellStatus = BcfgAddOpt(
1457 CurrentOperation.OptData,
1458 CurrentOperation.Order,
1459 Count,
1460 CurrentOperation.Target);
1461 break;
1462 default:
1463 ASSERT(FALSE);
1464 }
1465 }
1466 }
1467
1468 if (Package != NULL) {
1469 ShellCommandLineFreeVarList (Package);
1470 }
1471 if (CurrentOperation.FileName != NULL) {
1472 FreePool(CurrentOperation.FileName);
1473 }
1474 if (CurrentOperation.Description != NULL) {
1475 FreePool(CurrentOperation.Description);
1476 }
1477 if (CurrentOperation.Order != NULL) {
1478 FreePool(CurrentOperation.Order);
1479 }
1480
1481 return (ShellStatus);
1482 }
1483
1484
1485 /**
1486 Function to get the filename with help context if HII will not be used.
1487
1488 @return The filename with help text in it.
1489 **/
1490 CONST CHAR16*
1491 EFIAPI
1492 ShellCommandGetManFileNameBcfg (
1493 VOID
1494 )
1495 {
1496 return (mFileName);
1497 }
1498
1499 /**
1500 "Constructor" for the library.
1501
1502 This will register the handler for the bcfg command.
1503
1504 @param[in] ImageHandle the image handle of the process
1505 @param[in] SystemTable the EFI System Table pointer
1506 @param[in] Name the profile name to use
1507
1508 @retval EFI_SUCCESS the shell command handlers were installed sucessfully
1509 @retval EFI_UNSUPPORTED the shell level required was not found.
1510 **/
1511 EFI_STATUS
1512 EFIAPI
1513 BcfgLibraryRegisterBcfgCommand (
1514 IN EFI_HANDLE ImageHandle,
1515 IN EFI_SYSTEM_TABLE *SystemTable,
1516 IN CONST CHAR16 *Name
1517 )
1518 {
1519 if (gShellBcfgHiiHandle != NULL) {
1520 return (EFI_SUCCESS);
1521 }
1522
1523 gShellBcfgHiiHandle = HiiAddPackages (&gShellBcfgHiiGuid, gImageHandle, UefiShellBcfgCommandLibStrings, NULL);
1524 if (gShellBcfgHiiHandle == NULL) {
1525 return (EFI_DEVICE_ERROR);
1526 }
1527
1528 //
1529 // install our shell command handler
1530 //
1531 ShellCommandRegisterCommandName(L"bcfg", ShellCommandRunBcfg , ShellCommandGetManFileNameBcfg, 0, Name, FALSE, gShellBcfgHiiHandle, STRING_TOKEN(STR_GET_HELP_BCFG));
1532
1533 return (EFI_SUCCESS);
1534 }
1535
1536 /**
1537 Destructor for the library. free any resources.
1538
1539 @param ImageHandle The image handle of the process.
1540 @param SystemTable The EFI System Table pointer.
1541 **/
1542 EFI_STATUS
1543 EFIAPI
1544 BcfgLibraryUnregisterBcfgCommand (
1545 IN EFI_HANDLE ImageHandle,
1546 IN EFI_SYSTEM_TABLE *SystemTable
1547 )
1548 {
1549 if (gShellBcfgHiiHandle != NULL) {
1550 HiiRemovePackages(gShellBcfgHiiHandle);
1551 }
1552 gShellBcfgHiiHandle = NULL;
1553 return (EFI_SUCCESS);
1554 }
1555