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