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 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 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 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 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 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 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 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 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 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 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 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 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 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