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