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