1 /** @file 2 Provide boot option support for Application "BootMaint" 3 4 Include file system navigation, system handle selection 5 6 Boot option manipulation 7 8 Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR> 9 This program and the accompanying materials 10 are licensed and made available under the terms and conditions of the BSD License 11 which accompanies this distribution. The full text of the license may be found at 12 http://opensource.org/licenses/bsd-license.php 13 14 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 15 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 16 17 **/ 18 19 #include "BootMaint.h" 20 #include "BBSsupport.h" 21 22 /** 23 Create a menu entry by given menu type. 24 25 @param MenuType The Menu type to be created. 26 27 @retval NULL If failed to create the menu. 28 @return the new menu entry. 29 30 **/ 31 BM_MENU_ENTRY * 32 BOpt_CreateMenuEntry ( 33 UINTN MenuType 34 ) 35 { 36 BM_MENU_ENTRY *MenuEntry; 37 UINTN ContextSize; 38 39 // 40 // Get context size according to menu type 41 // 42 switch (MenuType) { 43 case BM_LOAD_CONTEXT_SELECT: 44 ContextSize = sizeof (BM_LOAD_CONTEXT); 45 break; 46 47 case BM_FILE_CONTEXT_SELECT: 48 ContextSize = sizeof (BM_FILE_CONTEXT); 49 break; 50 51 case BM_CONSOLE_CONTEXT_SELECT: 52 ContextSize = sizeof (BM_CONSOLE_CONTEXT); 53 break; 54 55 case BM_TERMINAL_CONTEXT_SELECT: 56 ContextSize = sizeof (BM_TERMINAL_CONTEXT); 57 break; 58 59 case BM_HANDLE_CONTEXT_SELECT: 60 ContextSize = sizeof (BM_HANDLE_CONTEXT); 61 break; 62 63 case BM_LEGACY_DEV_CONTEXT_SELECT: 64 ContextSize = sizeof (BM_LEGACY_DEVICE_CONTEXT); 65 break; 66 67 default: 68 ContextSize = 0; 69 break; 70 } 71 72 if (ContextSize == 0) { 73 return NULL; 74 } 75 76 // 77 // Create new menu entry 78 // 79 MenuEntry = AllocateZeroPool (sizeof (BM_MENU_ENTRY)); 80 if (MenuEntry == NULL) { 81 return NULL; 82 } 83 84 MenuEntry->VariableContext = AllocateZeroPool (ContextSize); 85 if (MenuEntry->VariableContext == NULL) { 86 FreePool (MenuEntry); 87 return NULL; 88 } 89 90 MenuEntry->Signature = BM_MENU_ENTRY_SIGNATURE; 91 MenuEntry->ContextSelection = MenuType; 92 return MenuEntry; 93 } 94 95 /** 96 Free up all resource allocated for a BM_MENU_ENTRY. 97 98 @param MenuEntry A pointer to BM_MENU_ENTRY. 99 100 **/ 101 VOID 102 BOpt_DestroyMenuEntry ( 103 BM_MENU_ENTRY *MenuEntry 104 ) 105 { 106 BM_LOAD_CONTEXT *LoadContext; 107 BM_FILE_CONTEXT *FileContext; 108 BM_CONSOLE_CONTEXT *ConsoleContext; 109 BM_TERMINAL_CONTEXT *TerminalContext; 110 BM_HANDLE_CONTEXT *HandleContext; 111 BM_LEGACY_DEVICE_CONTEXT *LegacyDevContext; 112 113 // 114 // Select by the type in Menu entry for current context type 115 // 116 switch (MenuEntry->ContextSelection) { 117 case BM_LOAD_CONTEXT_SELECT: 118 LoadContext = (BM_LOAD_CONTEXT *) MenuEntry->VariableContext; 119 FreePool (LoadContext->FilePathList); 120 FreePool (LoadContext->LoadOption); 121 if (LoadContext->OptionalData != NULL) { 122 FreePool (LoadContext->OptionalData); 123 } 124 FreePool (LoadContext); 125 break; 126 127 case BM_FILE_CONTEXT_SELECT: 128 FileContext = (BM_FILE_CONTEXT *) MenuEntry->VariableContext; 129 130 if (!FileContext->IsRoot) { 131 FreePool (FileContext->DevicePath); 132 } else { 133 if (FileContext->FHandle != NULL) { 134 FileContext->FHandle->Close (FileContext->FHandle); 135 } 136 } 137 138 if (FileContext->FileName != NULL) { 139 FreePool (FileContext->FileName); 140 } 141 if (FileContext->Info != NULL) { 142 FreePool (FileContext->Info); 143 } 144 FreePool (FileContext); 145 break; 146 147 case BM_CONSOLE_CONTEXT_SELECT: 148 ConsoleContext = (BM_CONSOLE_CONTEXT *) MenuEntry->VariableContext; 149 FreePool (ConsoleContext->DevicePath); 150 FreePool (ConsoleContext); 151 break; 152 153 case BM_TERMINAL_CONTEXT_SELECT: 154 TerminalContext = (BM_TERMINAL_CONTEXT *) MenuEntry->VariableContext; 155 FreePool (TerminalContext->DevicePath); 156 FreePool (TerminalContext); 157 break; 158 159 case BM_HANDLE_CONTEXT_SELECT: 160 HandleContext = (BM_HANDLE_CONTEXT *) MenuEntry->VariableContext; 161 FreePool (HandleContext); 162 break; 163 164 case BM_LEGACY_DEV_CONTEXT_SELECT: 165 LegacyDevContext = (BM_LEGACY_DEVICE_CONTEXT *) MenuEntry->VariableContext; 166 FreePool (LegacyDevContext); 167 168 default: 169 break; 170 } 171 172 FreePool (MenuEntry->DisplayString); 173 if (MenuEntry->HelpString != NULL) { 174 FreePool (MenuEntry->HelpString); 175 } 176 177 FreePool (MenuEntry); 178 } 179 180 /** 181 Get the Menu Entry from the list in Menu Entry List. 182 183 If MenuNumber is great or equal to the number of Menu 184 Entry in the list, then ASSERT. 185 186 @param MenuOption The Menu Entry List to read the menu entry. 187 @param MenuNumber The index of Menu Entry. 188 189 @return The Menu Entry. 190 191 **/ 192 BM_MENU_ENTRY * 193 BOpt_GetMenuEntry ( 194 BM_MENU_OPTION *MenuOption, 195 UINTN MenuNumber 196 ) 197 { 198 BM_MENU_ENTRY *NewMenuEntry; 199 UINTN Index; 200 LIST_ENTRY *List; 201 202 ASSERT (MenuNumber < MenuOption->MenuNumber); 203 204 List = MenuOption->Head.ForwardLink; 205 for (Index = 0; Index < MenuNumber; Index++) { 206 List = List->ForwardLink; 207 } 208 209 NewMenuEntry = CR (List, BM_MENU_ENTRY, Link, BM_MENU_ENTRY_SIGNATURE); 210 211 return NewMenuEntry; 212 } 213 214 /** 215 This function build the FsOptionMenu list which records all 216 available file system in the system. They includes all instances 217 of EFI_SIMPLE_FILE_SYSTEM_PROTOCOL, all instances of EFI_LOAD_FILE_SYSTEM 218 and all type of legacy boot device. 219 220 @param CallbackData BMM context data 221 222 @retval EFI_SUCCESS Success find the file system 223 @retval EFI_OUT_OF_RESOURCES Can not create menu entry 224 225 **/ 226 EFI_STATUS 227 BOpt_FindFileSystem ( 228 IN BMM_CALLBACK_DATA *CallbackData 229 ) 230 { 231 UINTN NoBlkIoHandles; 232 UINTN NoSimpleFsHandles; 233 UINTN NoLoadFileHandles; 234 EFI_HANDLE *BlkIoHandle; 235 EFI_HANDLE *SimpleFsHandle; 236 EFI_HANDLE *LoadFileHandle; 237 UINT16 *VolumeLabel; 238 EFI_BLOCK_IO_PROTOCOL *BlkIo; 239 UINTN Index; 240 EFI_STATUS Status; 241 BM_MENU_ENTRY *MenuEntry; 242 BM_FILE_CONTEXT *FileContext; 243 UINT16 *TempStr; 244 UINTN OptionNumber; 245 VOID *Buffer; 246 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; 247 UINT16 DeviceType; 248 BBS_BBS_DEVICE_PATH BbsDevicePathNode; 249 EFI_DEVICE_PATH_PROTOCOL *DevicePath; 250 BOOLEAN RemovableMedia; 251 252 253 NoSimpleFsHandles = 0; 254 NoLoadFileHandles = 0; 255 OptionNumber = 0; 256 InitializeListHead (&FsOptionMenu.Head); 257 258 // 259 // Locate Handles that support BlockIo protocol 260 // 261 Status = gBS->LocateHandleBuffer ( 262 ByProtocol, 263 &gEfiBlockIoProtocolGuid, 264 NULL, 265 &NoBlkIoHandles, 266 &BlkIoHandle 267 ); 268 if (!EFI_ERROR (Status)) { 269 270 for (Index = 0; Index < NoBlkIoHandles; Index++) { 271 Status = gBS->HandleProtocol ( 272 BlkIoHandle[Index], 273 &gEfiBlockIoProtocolGuid, 274 (VOID **) &BlkIo 275 ); 276 277 if (EFI_ERROR (Status)) { 278 continue; 279 } 280 281 // 282 // Issue a dummy read to trigger reinstall of BlockIo protocol for removable media 283 // 284 if (BlkIo->Media->RemovableMedia) { 285 Buffer = AllocateZeroPool (BlkIo->Media->BlockSize); 286 if (NULL == Buffer) { 287 FreePool (BlkIoHandle); 288 return EFI_OUT_OF_RESOURCES; 289 } 290 291 BlkIo->ReadBlocks ( 292 BlkIo, 293 BlkIo->Media->MediaId, 294 0, 295 BlkIo->Media->BlockSize, 296 Buffer 297 ); 298 FreePool (Buffer); 299 } 300 } 301 FreePool (BlkIoHandle); 302 } 303 304 // 305 // Locate Handles that support Simple File System protocol 306 // 307 Status = gBS->LocateHandleBuffer ( 308 ByProtocol, 309 &gEfiSimpleFileSystemProtocolGuid, 310 NULL, 311 &NoSimpleFsHandles, 312 &SimpleFsHandle 313 ); 314 if (!EFI_ERROR (Status)) { 315 // 316 // Find all the instances of the File System prototocol 317 // 318 for (Index = 0; Index < NoSimpleFsHandles; Index++) { 319 Status = gBS->HandleProtocol ( 320 SimpleFsHandle[Index], 321 &gEfiBlockIoProtocolGuid, 322 (VOID **) &BlkIo 323 ); 324 if (EFI_ERROR (Status)) { 325 // 326 // If no block IO exists assume it's NOT a removable media 327 // 328 RemovableMedia = FALSE; 329 } else { 330 // 331 // If block IO exists check to see if it's remobable media 332 // 333 RemovableMedia = BlkIo->Media->RemovableMedia; 334 } 335 336 // 337 // Allocate pool for this load option 338 // 339 MenuEntry = BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT); 340 if (NULL == MenuEntry) { 341 FreePool (SimpleFsHandle); 342 return EFI_OUT_OF_RESOURCES; 343 } 344 345 FileContext = (BM_FILE_CONTEXT *) MenuEntry->VariableContext; 346 347 FileContext->Handle = SimpleFsHandle[Index]; 348 MenuEntry->OptionNumber = Index; 349 FileContext->FHandle = EfiLibOpenRoot (FileContext->Handle); 350 if (FileContext->FHandle == NULL) { 351 BOpt_DestroyMenuEntry (MenuEntry); 352 continue; 353 } 354 355 MenuEntry->HelpString = DevicePathToStr (DevicePathFromHandle (FileContext->Handle)); 356 FileContext->Info = EfiLibFileSystemVolumeLabelInfo (FileContext->FHandle); 357 FileContext->FileName = EfiStrDuplicate (L"\\"); 358 FileContext->DevicePath = FileDevicePath ( 359 FileContext->Handle, 360 FileContext->FileName 361 ); 362 FileContext->IsDir = TRUE; 363 FileContext->IsRoot = TRUE; 364 FileContext->IsRemovableMedia = RemovableMedia; 365 FileContext->IsLoadFile = FALSE; 366 367 // 368 // Get current file system's Volume Label 369 // 370 if (FileContext->Info == NULL) { 371 VolumeLabel = L"NO FILE SYSTEM INFO"; 372 } else { 373 VolumeLabel = FileContext->Info->VolumeLabel; 374 if (*VolumeLabel == 0x0000) { 375 VolumeLabel = L"NO VOLUME LABEL"; 376 } 377 } 378 379 TempStr = MenuEntry->HelpString; 380 MenuEntry->DisplayString = AllocateZeroPool (MAX_CHAR); 381 ASSERT (MenuEntry->DisplayString != NULL); 382 UnicodeSPrint ( 383 MenuEntry->DisplayString, 384 MAX_CHAR, 385 L"%s, [%s]", 386 VolumeLabel, 387 TempStr 388 ); 389 OptionNumber++; 390 InsertTailList (&FsOptionMenu.Head, &MenuEntry->Link); 391 } 392 } 393 394 if (NoSimpleFsHandles != 0) { 395 FreePool (SimpleFsHandle); 396 } 397 // 398 // Searching for handles that support Load File protocol 399 // 400 Status = gBS->LocateHandleBuffer ( 401 ByProtocol, 402 &gEfiLoadFileProtocolGuid, 403 NULL, 404 &NoLoadFileHandles, 405 &LoadFileHandle 406 ); 407 408 if (!EFI_ERROR (Status)) { 409 for (Index = 0; Index < NoLoadFileHandles; Index++) { 410 MenuEntry = BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT); 411 if (NULL == MenuEntry) { 412 FreePool (LoadFileHandle); 413 return EFI_OUT_OF_RESOURCES; 414 } 415 416 FileContext = (BM_FILE_CONTEXT *) MenuEntry->VariableContext; 417 FileContext->IsRemovableMedia = FALSE; 418 FileContext->IsLoadFile = TRUE; 419 FileContext->Handle = LoadFileHandle[Index]; 420 FileContext->IsRoot = TRUE; 421 422 FileContext->DevicePath = DevicePathFromHandle (FileContext->Handle); 423 FileContext->FileName = DevicePathToStr (FileContext->DevicePath); 424 425 MenuEntry->HelpString = DevicePathToStr (FileContext->DevicePath); 426 427 TempStr = MenuEntry->HelpString; 428 MenuEntry->DisplayString = AllocateZeroPool (MAX_CHAR); 429 ASSERT (MenuEntry->DisplayString != NULL); 430 UnicodeSPrint ( 431 MenuEntry->DisplayString, 432 MAX_CHAR, 433 L"Load File [%s]", 434 TempStr 435 ); 436 437 MenuEntry->OptionNumber = OptionNumber; 438 OptionNumber++; 439 InsertTailList (&FsOptionMenu.Head, &MenuEntry->Link); 440 } 441 } 442 443 if (NoLoadFileHandles != 0) { 444 FreePool (LoadFileHandle); 445 } 446 447 // 448 // Add Legacy Boot Option Support Here 449 // 450 Status = gBS->LocateProtocol ( 451 &gEfiLegacyBiosProtocolGuid, 452 NULL, 453 (VOID **) &LegacyBios 454 ); 455 if (!EFI_ERROR (Status)) { 456 457 for (Index = BBS_TYPE_FLOPPY; Index <= BBS_TYPE_EMBEDDED_NETWORK; Index++) { 458 MenuEntry = BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT); 459 if (NULL == MenuEntry) { 460 return EFI_OUT_OF_RESOURCES; 461 } 462 463 FileContext = (BM_FILE_CONTEXT *) MenuEntry->VariableContext; 464 465 FileContext->IsRemovableMedia = FALSE; 466 FileContext->IsLoadFile = TRUE; 467 FileContext->IsBootLegacy = TRUE; 468 DeviceType = (UINT16) Index; 469 BbsDevicePathNode.Header.Type = BBS_DEVICE_PATH; 470 BbsDevicePathNode.Header.SubType = BBS_BBS_DP; 471 SetDevicePathNodeLength ( 472 &BbsDevicePathNode.Header, 473 sizeof (BBS_BBS_DEVICE_PATH) 474 ); 475 BbsDevicePathNode.DeviceType = DeviceType; 476 BbsDevicePathNode.StatusFlag = 0; 477 BbsDevicePathNode.String[0] = 0; 478 DevicePath = AppendDevicePathNode ( 479 EndDevicePath, 480 (EFI_DEVICE_PATH_PROTOCOL *) &BbsDevicePathNode 481 ); 482 483 FileContext->DevicePath = DevicePath; 484 MenuEntry->HelpString = DevicePathToStr (FileContext->DevicePath); 485 486 TempStr = MenuEntry->HelpString; 487 MenuEntry->DisplayString = AllocateZeroPool (MAX_CHAR); 488 ASSERT (MenuEntry->DisplayString != NULL); 489 UnicodeSPrint ( 490 MenuEntry->DisplayString, 491 MAX_CHAR, 492 L"Boot Legacy [%s]", 493 TempStr 494 ); 495 MenuEntry->OptionNumber = OptionNumber; 496 OptionNumber++; 497 InsertTailList (&FsOptionMenu.Head, &MenuEntry->Link); 498 } 499 } 500 // 501 // Remember how many file system options are here 502 // 503 FsOptionMenu.MenuNumber = OptionNumber; 504 return EFI_SUCCESS; 505 } 506 507 /** 508 Free resources allocated in Allocate Rountine. 509 510 @param FreeMenu Menu to be freed 511 **/ 512 VOID 513 BOpt_FreeMenu ( 514 BM_MENU_OPTION *FreeMenu 515 ) 516 { 517 BM_MENU_ENTRY *MenuEntry; 518 while (!IsListEmpty (&FreeMenu->Head)) { 519 MenuEntry = CR ( 520 FreeMenu->Head.ForwardLink, 521 BM_MENU_ENTRY, 522 Link, 523 BM_MENU_ENTRY_SIGNATURE 524 ); 525 RemoveEntryList (&MenuEntry->Link); 526 BOpt_DestroyMenuEntry (MenuEntry); 527 } 528 FreeMenu->MenuNumber = 0; 529 } 530 531 /** 532 Find files under current directory 533 All files and sub-directories in current directory 534 will be stored in DirectoryMenu for future use. 535 536 @param CallbackData The BMM context data. 537 @param MenuEntry The Menu Entry. 538 539 @retval EFI_SUCCESS Get files from current dir successfully. 540 @return Other value if can't get files from current dir. 541 542 **/ 543 EFI_STATUS 544 BOpt_FindFiles ( 545 IN BMM_CALLBACK_DATA *CallbackData, 546 IN BM_MENU_ENTRY *MenuEntry 547 ) 548 { 549 EFI_FILE_HANDLE NewDir; 550 EFI_FILE_HANDLE Dir; 551 EFI_FILE_INFO *DirInfo; 552 UINTN BufferSize; 553 UINTN DirBufferSize; 554 BM_MENU_ENTRY *NewMenuEntry; 555 BM_FILE_CONTEXT *FileContext; 556 BM_FILE_CONTEXT *NewFileContext; 557 UINTN Pass; 558 EFI_STATUS Status; 559 UINTN OptionNumber; 560 561 FileContext = (BM_FILE_CONTEXT *) MenuEntry->VariableContext; 562 Dir = FileContext->FHandle; 563 OptionNumber = 0; 564 // 565 // Open current directory to get files from it 566 // 567 Status = Dir->Open ( 568 Dir, 569 &NewDir, 570 FileContext->FileName, 571 EFI_FILE_READ_ONLY, 572 0 573 ); 574 if (!FileContext->IsRoot) { 575 Dir->Close (Dir); 576 } 577 578 if (EFI_ERROR (Status)) { 579 return Status; 580 } 581 582 DirInfo = EfiLibFileInfo (NewDir); 583 if (DirInfo == NULL) { 584 return EFI_NOT_FOUND; 585 } 586 587 if ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == 0) { 588 return EFI_INVALID_PARAMETER; 589 } 590 591 FileContext->DevicePath = FileDevicePath ( 592 FileContext->Handle, 593 FileContext->FileName 594 ); 595 596 DirBufferSize = sizeof (EFI_FILE_INFO) + 1024; 597 DirInfo = AllocateZeroPool (DirBufferSize); 598 if (DirInfo == NULL) { 599 return EFI_OUT_OF_RESOURCES; 600 } 601 // 602 // Get all files in current directory 603 // Pass 1 to get Directories 604 // Pass 2 to get files that are EFI images 605 // 606 for (Pass = 1; Pass <= 2; Pass++) { 607 NewDir->SetPosition (NewDir, 0); 608 for (;;) { 609 BufferSize = DirBufferSize; 610 Status = NewDir->Read (NewDir, &BufferSize, DirInfo); 611 if (EFI_ERROR (Status) || BufferSize == 0) { 612 break; 613 } 614 615 if (((DirInfo->Attribute & EFI_FILE_DIRECTORY) != 0 && Pass == 2) || 616 ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == 0 && Pass == 1) 617 ) { 618 // 619 // Pass 1 is for Directories 620 // Pass 2 is for file names 621 // 622 continue; 623 } 624 625 if (!(BOpt_IsEfiImageName (DirInfo->FileName) || (DirInfo->Attribute & EFI_FILE_DIRECTORY) != 0)) { 626 // 627 // Slip file unless it is a directory entry or a .EFI file 628 // 629 continue; 630 } 631 632 NewMenuEntry = BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT); 633 if (NULL == NewMenuEntry) { 634 return EFI_OUT_OF_RESOURCES; 635 } 636 637 NewFileContext = (BM_FILE_CONTEXT *) NewMenuEntry->VariableContext; 638 NewFileContext->Handle = FileContext->Handle; 639 NewFileContext->FileName = BOpt_AppendFileName ( 640 FileContext->FileName, 641 DirInfo->FileName 642 ); 643 NewFileContext->FHandle = NewDir; 644 NewFileContext->DevicePath = FileDevicePath ( 645 NewFileContext->Handle, 646 NewFileContext->FileName 647 ); 648 NewMenuEntry->HelpString = NULL; 649 650 MenuEntry->DisplayStringToken = GetStringTokenFromDepository ( 651 CallbackData, 652 FileOptionStrDepository 653 ); 654 655 NewFileContext->IsDir = (BOOLEAN) ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY); 656 657 if (NewFileContext->IsDir) { 658 BufferSize = StrLen (DirInfo->FileName) * 2 + 6; 659 NewMenuEntry->DisplayString = AllocateZeroPool (BufferSize); 660 661 UnicodeSPrint ( 662 NewMenuEntry->DisplayString, 663 BufferSize, 664 L"<%s>", 665 DirInfo->FileName 666 ); 667 668 } else { 669 NewMenuEntry->DisplayString = EfiStrDuplicate (DirInfo->FileName); 670 } 671 672 NewFileContext->IsRoot = FALSE; 673 NewFileContext->IsLoadFile = FALSE; 674 NewFileContext->IsRemovableMedia = FALSE; 675 676 NewMenuEntry->OptionNumber = OptionNumber; 677 OptionNumber++; 678 InsertTailList (&DirectoryMenu.Head, &NewMenuEntry->Link); 679 } 680 } 681 682 DirectoryMenu.MenuNumber = OptionNumber; 683 FreePool (DirInfo); 684 return EFI_SUCCESS; 685 } 686 687 /** 688 Build the LegacyFDMenu LegacyHDMenu LegacyCDMenu according to LegacyBios.GetBbsInfo(). 689 690 @retval EFI_SUCCESS The function complete successfully. 691 @retval EFI_OUT_OF_RESOURCES No enough memory to complete this function. 692 693 **/ 694 EFI_STATUS 695 BOpt_GetLegacyOptions ( 696 VOID 697 ) 698 { 699 BM_MENU_ENTRY *NewMenuEntry; 700 BM_LEGACY_DEVICE_CONTEXT *NewLegacyDevContext; 701 EFI_STATUS Status; 702 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; 703 UINT16 HddCount; 704 HDD_INFO *HddInfo; 705 UINT16 BbsCount; 706 BBS_TABLE *BbsTable; 707 UINT16 Index; 708 CHAR16 DescString[100]; 709 UINTN FDNum; 710 UINTN HDNum; 711 UINTN CDNum; 712 UINTN NETNum; 713 UINTN BEVNum; 714 715 NewMenuEntry = NULL; 716 HddInfo = NULL; 717 BbsTable = NULL; 718 BbsCount = 0; 719 720 // 721 // Initialize Bbs Table Context from BBS info data 722 // 723 InitializeListHead (&LegacyFDMenu.Head); 724 InitializeListHead (&LegacyHDMenu.Head); 725 InitializeListHead (&LegacyCDMenu.Head); 726 InitializeListHead (&LegacyNETMenu.Head); 727 InitializeListHead (&LegacyBEVMenu.Head); 728 729 Status = gBS->LocateProtocol ( 730 &gEfiLegacyBiosProtocolGuid, 731 NULL, 732 (VOID **) &LegacyBios 733 ); 734 if (!EFI_ERROR (Status)) { 735 Status = LegacyBios->GetBbsInfo ( 736 LegacyBios, 737 &HddCount, 738 &HddInfo, 739 &BbsCount, 740 &BbsTable 741 ); 742 if (EFI_ERROR (Status)) { 743 return Status; 744 } 745 } 746 747 FDNum = 0; 748 HDNum = 0; 749 CDNum = 0; 750 NETNum = 0; 751 BEVNum = 0; 752 753 for (Index = 0; Index < BbsCount; Index++) { 754 if ((BBS_IGNORE_ENTRY == BbsTable[Index].BootPriority) || 755 (BBS_DO_NOT_BOOT_FROM == BbsTable[Index].BootPriority) 756 ) { 757 continue; 758 } 759 760 NewMenuEntry = BOpt_CreateMenuEntry (BM_LEGACY_DEV_CONTEXT_SELECT); 761 if (NULL == NewMenuEntry) { 762 break; 763 } 764 765 NewLegacyDevContext = (BM_LEGACY_DEVICE_CONTEXT *) NewMenuEntry->VariableContext; 766 NewLegacyDevContext->BbsEntry = &BbsTable[Index]; 767 NewLegacyDevContext->BbsIndex = Index; 768 NewLegacyDevContext->BbsCount = BbsCount; 769 BdsBuildLegacyDevNameString ( 770 &BbsTable[Index], 771 Index, 772 sizeof (DescString), 773 DescString 774 ); 775 NewLegacyDevContext->Description = AllocateCopyPool (StrSize (DescString), DescString); 776 if (NULL == NewLegacyDevContext->Description) { 777 break; 778 } 779 780 NewMenuEntry->DisplayString = NewLegacyDevContext->Description; 781 NewMenuEntry->HelpString = NULL; 782 783 switch (BbsTable[Index].DeviceType) { 784 case BBS_FLOPPY: 785 InsertTailList (&LegacyFDMenu.Head, &NewMenuEntry->Link); 786 FDNum++; 787 break; 788 789 case BBS_HARDDISK: 790 InsertTailList (&LegacyHDMenu.Head, &NewMenuEntry->Link); 791 HDNum++; 792 break; 793 794 case BBS_CDROM: 795 InsertTailList (&LegacyCDMenu.Head, &NewMenuEntry->Link); 796 CDNum++; 797 break; 798 799 case BBS_EMBED_NETWORK: 800 InsertTailList (&LegacyNETMenu.Head, &NewMenuEntry->Link); 801 NETNum++; 802 break; 803 804 case BBS_BEV_DEVICE: 805 InsertTailList (&LegacyBEVMenu.Head, &NewMenuEntry->Link); 806 BEVNum++; 807 break; 808 } 809 } 810 811 if (Index != BbsCount) { 812 BOpt_FreeLegacyOptions (); 813 return EFI_OUT_OF_RESOURCES; 814 } 815 816 LegacyFDMenu.MenuNumber = FDNum; 817 LegacyHDMenu.MenuNumber = HDNum; 818 LegacyCDMenu.MenuNumber = CDNum; 819 LegacyNETMenu.MenuNumber = NETNum; 820 LegacyBEVMenu.MenuNumber = BEVNum; 821 return EFI_SUCCESS; 822 } 823 824 /** 825 Free out resouce allocated from Legacy Boot Options. 826 827 **/ 828 VOID 829 BOpt_FreeLegacyOptions ( 830 VOID 831 ) 832 { 833 BOpt_FreeMenu (&LegacyFDMenu); 834 BOpt_FreeMenu (&LegacyHDMenu); 835 BOpt_FreeMenu (&LegacyCDMenu); 836 BOpt_FreeMenu (&LegacyNETMenu); 837 BOpt_FreeMenu (&LegacyBEVMenu); 838 } 839 840 /** 841 842 Build the BootOptionMenu according to BootOrder Variable. 843 This Routine will access the Boot#### to get EFI_LOAD_OPTION. 844 845 @param CallbackData The BMM context data. 846 847 @return EFI_NOT_FOUND Fail to find "BootOrder" variable. 848 @return EFI_SUCESS Success build boot option menu. 849 850 **/ 851 EFI_STATUS 852 BOpt_GetBootOptions ( 853 IN BMM_CALLBACK_DATA *CallbackData 854 ) 855 { 856 UINTN Index; 857 UINT16 BootString[10]; 858 UINT8 *LoadOptionFromVar; 859 UINT8 *LoadOption; 860 UINTN BootOptionSize; 861 BOOLEAN BootNextFlag; 862 UINT16 *BootOrderList; 863 UINTN BootOrderListSize; 864 UINT16 *BootNext; 865 UINTN BootNextSize; 866 BM_MENU_ENTRY *NewMenuEntry; 867 BM_LOAD_CONTEXT *NewLoadContext; 868 UINT8 *LoadOptionPtr; 869 UINTN StringSize; 870 UINTN OptionalDataSize; 871 UINT8 *LoadOptionEnd; 872 EFI_DEVICE_PATH_PROTOCOL *DevicePath; 873 UINTN MenuCount; 874 UINT8 *Ptr; 875 876 MenuCount = 0; 877 BootOrderListSize = 0; 878 BootNextSize = 0; 879 BootOrderList = NULL; 880 BootNext = NULL; 881 LoadOptionFromVar = NULL; 882 BOpt_FreeMenu (&BootOptionMenu); 883 InitializeListHead (&BootOptionMenu.Head); 884 885 // 886 // Get the BootOrder from the Var 887 // 888 BootOrderList = BdsLibGetVariableAndSize ( 889 L"BootOrder", 890 &gEfiGlobalVariableGuid, 891 &BootOrderListSize 892 ); 893 if (BootOrderList == NULL) { 894 return EFI_NOT_FOUND; 895 } 896 897 // 898 // Get the BootNext from the Var 899 // 900 BootNext = BdsLibGetVariableAndSize ( 901 L"BootNext", 902 &gEfiGlobalVariableGuid, 903 &BootNextSize 904 ); 905 906 if (BootNext != NULL) { 907 if (BootNextSize != sizeof (UINT16)) { 908 FreePool (BootNext); 909 BootNext = NULL; 910 } 911 } 912 913 for (Index = 0; Index < BootOrderListSize / sizeof (UINT16); Index++) { 914 UnicodeSPrint (BootString, sizeof (BootString), L"Boot%04x", BootOrderList[Index]); 915 // 916 // Get all loadoptions from the VAR 917 // 918 LoadOptionFromVar = BdsLibGetVariableAndSize ( 919 BootString, 920 &gEfiGlobalVariableGuid, 921 &BootOptionSize 922 ); 923 if (LoadOptionFromVar == NULL) { 924 continue; 925 } 926 927 LoadOption = AllocateZeroPool (BootOptionSize); 928 if (LoadOption == NULL) { 929 continue; 930 } 931 932 CopyMem (LoadOption, LoadOptionFromVar, BootOptionSize); 933 FreePool (LoadOptionFromVar); 934 935 if (BootNext != NULL) { 936 BootNextFlag = (BOOLEAN) (*BootNext == BootOrderList[Index]); 937 } else { 938 BootNextFlag = FALSE; 939 } 940 941 if (0 == (*((UINT32 *) LoadOption) & LOAD_OPTION_ACTIVE)) { 942 FreePool (LoadOption); 943 continue; 944 } 945 // 946 // BUGBUG: could not return EFI_OUT_OF_RESOURCES here directly. 947 // the buffer allocated already should be freed before returning. 948 // 949 NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT); 950 if (NULL == NewMenuEntry) { 951 return EFI_OUT_OF_RESOURCES; 952 } 953 954 NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext; 955 956 LoadOptionPtr = LoadOption; 957 LoadOptionEnd = LoadOption + BootOptionSize; 958 959 NewMenuEntry->OptionNumber = BootOrderList[Index]; 960 NewLoadContext->LoadOptionModified = FALSE; 961 NewLoadContext->Deleted = FALSE; 962 NewLoadContext->IsBootNext = BootNextFlag; 963 964 // 965 // Is a Legacy Device? 966 // 967 Ptr = (UINT8 *) LoadOption; 968 969 // 970 // Attribute = *(UINT32 *)Ptr; 971 // 972 Ptr += sizeof (UINT32); 973 974 // 975 // FilePathSize = *(UINT16 *)Ptr; 976 // 977 Ptr += sizeof (UINT16); 978 979 // 980 // Description = (CHAR16 *)Ptr; 981 // 982 Ptr += StrSize ((CHAR16 *) Ptr); 983 984 // 985 // Now Ptr point to Device Path 986 // 987 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Ptr; 988 if ((BBS_DEVICE_PATH == DevicePath->Type) && (BBS_BBS_DP == DevicePath->SubType)) { 989 NewLoadContext->IsLegacy = TRUE; 990 } else { 991 NewLoadContext->IsLegacy = FALSE; 992 } 993 // 994 // LoadOption is a pointer type of UINT8 995 // for easy use with following LOAD_OPTION 996 // embedded in this struct 997 // 998 NewLoadContext->LoadOption = LoadOption; 999 NewLoadContext->LoadOptionSize = BootOptionSize; 1000 1001 NewLoadContext->Attributes = *(UINT32 *) LoadOptionPtr; 1002 NewLoadContext->IsActive = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_ACTIVE); 1003 1004 NewLoadContext->ForceReconnect = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_FORCE_RECONNECT); 1005 1006 LoadOptionPtr += sizeof (UINT32); 1007 1008 NewLoadContext->FilePathListLength = *(UINT16 *) LoadOptionPtr; 1009 LoadOptionPtr += sizeof (UINT16); 1010 1011 StringSize = StrSize((UINT16*)LoadOptionPtr); 1012 1013 NewLoadContext->Description = AllocateCopyPool (StrSize((UINT16*)LoadOptionPtr), LoadOptionPtr); 1014 ASSERT (NewLoadContext->Description != NULL); 1015 1016 NewMenuEntry->DisplayString = NewLoadContext->Description; 1017 1018 LoadOptionPtr += StringSize; 1019 1020 NewLoadContext->FilePathList = AllocateZeroPool (NewLoadContext->FilePathListLength); 1021 ASSERT (NewLoadContext->FilePathList != NULL); 1022 CopyMem ( 1023 NewLoadContext->FilePathList, 1024 (EFI_DEVICE_PATH_PROTOCOL *) LoadOptionPtr, 1025 NewLoadContext->FilePathListLength 1026 ); 1027 1028 NewMenuEntry->HelpString = DevicePathToStr (NewLoadContext->FilePathList); 1029 NewMenuEntry->DisplayStringToken = GetStringTokenFromDepository ( 1030 CallbackData, 1031 BootOptionStrDepository 1032 ); 1033 NewMenuEntry->HelpStringToken = GetStringTokenFromDepository ( 1034 CallbackData, 1035 BootOptionHelpStrDepository 1036 ); 1037 LoadOptionPtr += NewLoadContext->FilePathListLength; 1038 1039 if (LoadOptionPtr < LoadOptionEnd) { 1040 OptionalDataSize = BootOptionSize - 1041 sizeof (UINT32) - 1042 sizeof (UINT16) - 1043 StringSize - 1044 NewLoadContext->FilePathListLength; 1045 1046 NewLoadContext->OptionalData = AllocateZeroPool (OptionalDataSize); 1047 ASSERT (NewLoadContext->OptionalData != NULL); 1048 CopyMem ( 1049 NewLoadContext->OptionalData, 1050 LoadOptionPtr, 1051 OptionalDataSize 1052 ); 1053 1054 NewLoadContext->OptionalDataSize = OptionalDataSize; 1055 } 1056 1057 InsertTailList (&BootOptionMenu.Head, &NewMenuEntry->Link); 1058 MenuCount++; 1059 } 1060 1061 if (BootNext != NULL) { 1062 FreePool (BootNext); 1063 } 1064 if (BootOrderList != NULL) { 1065 FreePool (BootOrderList); 1066 } 1067 BootOptionMenu.MenuNumber = MenuCount; 1068 return EFI_SUCCESS; 1069 } 1070 1071 /** 1072 1073 Append file name to existing file name. 1074 1075 @param Str1 The existing file name 1076 @param Str2 The file name to be appended 1077 1078 @return Allocate a new string to hold the appended result. 1079 Caller is responsible to free the returned string. 1080 1081 **/ 1082 CHAR16 * 1083 BOpt_AppendFileName ( 1084 IN CHAR16 *Str1, 1085 IN CHAR16 *Str2 1086 ) 1087 { 1088 UINTN Size1; 1089 UINTN Size2; 1090 UINTN MaxLen; 1091 CHAR16 *Str; 1092 CHAR16 *TmpStr; 1093 CHAR16 *Ptr; 1094 CHAR16 *LastSlash; 1095 1096 Size1 = StrSize (Str1); 1097 Size2 = StrSize (Str2); 1098 MaxLen = (Size1 + Size2 + sizeof (CHAR16)) / sizeof (CHAR16); 1099 Str = AllocateZeroPool (MaxLen * sizeof (CHAR16)); 1100 ASSERT (Str != NULL); 1101 1102 TmpStr = AllocateZeroPool (MaxLen * sizeof (CHAR16)); 1103 ASSERT (TmpStr != NULL); 1104 1105 StrCatS (Str, MaxLen, Str1); 1106 if (!((*Str == '\\') && (*(Str + 1) == 0))) { 1107 StrCatS (Str, MaxLen, L"\\"); 1108 } 1109 1110 StrCatS (Str, MaxLen, Str2); 1111 1112 Ptr = Str; 1113 LastSlash = Str; 1114 while (*Ptr != 0) { 1115 if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '.' && *(Ptr + 3) == L'\\') { 1116 // 1117 // Convert "\Name\..\" to "\" 1118 // DO NOT convert the .. if it is at the end of the string. This will 1119 // break the .. behavior in changing directories. 1120 // 1121 1122 // 1123 // Use TmpStr as a backup, as StrCpyS in BaseLib does not handle copy of two strings 1124 // that overlap. 1125 // 1126 StrCpyS (TmpStr, MaxLen, Ptr + 3); 1127 StrCpyS (LastSlash, MaxLen - (UINTN) (LastSlash - Str), TmpStr); 1128 Ptr = LastSlash; 1129 } else if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '\\') { 1130 // 1131 // Convert a "\.\" to a "\" 1132 // 1133 1134 // 1135 // Use TmpStr as a backup, as StrCpyS in BaseLib does not handle copy of two strings 1136 // that overlap. 1137 // 1138 StrCpyS (TmpStr, MaxLen, Ptr + 2); 1139 StrCpyS (Ptr, MaxLen - (UINTN) (Ptr - Str), TmpStr); 1140 Ptr = LastSlash; 1141 } else if (*Ptr == '\\') { 1142 LastSlash = Ptr; 1143 } 1144 1145 Ptr++; 1146 } 1147 1148 FreePool (TmpStr); 1149 1150 return Str; 1151 } 1152 1153 /** 1154 1155 Check whether current FileName point to a valid 1156 Efi Image File. 1157 1158 @param FileName File need to be checked. 1159 1160 @retval TRUE Is Efi Image 1161 @retval FALSE Not a valid Efi Image 1162 1163 **/ 1164 BOOLEAN 1165 BOpt_IsEfiImageName ( 1166 IN UINT16 *FileName 1167 ) 1168 { 1169 // 1170 // Search for ".efi" extension 1171 // 1172 while (*FileName != L'\0') { 1173 if (FileName[0] == '.') { 1174 if (FileName[1] == 'e' || FileName[1] == 'E') { 1175 if (FileName[2] == 'f' || FileName[2] == 'F') { 1176 if (FileName[3] == 'i' || FileName[3] == 'I') { 1177 return TRUE; 1178 } else if (FileName[3] == 0x0000) { 1179 return FALSE; 1180 } 1181 } else if (FileName[2] == 0x0000) { 1182 return FALSE; 1183 } 1184 } else if (FileName[1] == 0x0000) { 1185 return FALSE; 1186 } 1187 } 1188 1189 FileName += 1; 1190 } 1191 1192 return FALSE; 1193 } 1194 1195 /** 1196 1197 Check whether current FileName point to a valid Efi Application 1198 1199 @param Dir Pointer to current Directory 1200 @param FileName Pointer to current File name. 1201 1202 @retval TRUE Is a valid Efi Application 1203 @retval FALSE not a valid Efi Application 1204 1205 **/ 1206 BOOLEAN 1207 BOpt_IsEfiApp ( 1208 IN EFI_FILE_HANDLE Dir, 1209 IN UINT16 *FileName 1210 ) 1211 { 1212 UINTN BufferSize; 1213 EFI_IMAGE_DOS_HEADER DosHdr; 1214 UINT16 Subsystem; 1215 EFI_FILE_HANDLE File; 1216 EFI_STATUS Status; 1217 EFI_IMAGE_OPTIONAL_HEADER_UNION PeHdr; 1218 1219 Status = Dir->Open (Dir, &File, FileName, EFI_FILE_MODE_READ, 0); 1220 1221 if (EFI_ERROR (Status)) { 1222 return FALSE; 1223 } 1224 1225 BufferSize = sizeof (EFI_IMAGE_DOS_HEADER); 1226 File->Read (File, &BufferSize, &DosHdr); 1227 if (DosHdr.e_magic != EFI_IMAGE_DOS_SIGNATURE) { 1228 File->Close (File); 1229 return FALSE; 1230 } 1231 1232 File->SetPosition (File, DosHdr.e_lfanew); 1233 BufferSize = sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION); 1234 File->Read (File, &BufferSize, &PeHdr); 1235 if (PeHdr.Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) { 1236 File->Close (File); 1237 return FALSE; 1238 } 1239 // 1240 // Determine PE type and read subsytem 1241 // 1242 if (PeHdr.Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { 1243 Subsystem = PeHdr.Pe32.OptionalHeader.Subsystem; 1244 } else if (PeHdr.Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) { 1245 Subsystem = PeHdr.Pe32Plus.OptionalHeader.Subsystem; 1246 } else { 1247 return FALSE; 1248 } 1249 1250 if (Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) { 1251 File->Close (File); 1252 return TRUE; 1253 } else { 1254 File->Close (File); 1255 return FALSE; 1256 } 1257 } 1258 1259 /** 1260 1261 Find drivers that will be added as Driver#### variables from handles 1262 in current system environment 1263 All valid handles in the system except those consume SimpleFs, LoadFile 1264 are stored in DriverMenu for future use. 1265 1266 @retval EFI_SUCCESS The function complets successfully. 1267 @return Other value if failed to build the DriverMenu. 1268 1269 **/ 1270 EFI_STATUS 1271 BOpt_FindDrivers ( 1272 VOID 1273 ) 1274 { 1275 UINTN NoDevicePathHandles; 1276 EFI_HANDLE *DevicePathHandle; 1277 UINTN Index; 1278 EFI_STATUS Status; 1279 BM_MENU_ENTRY *NewMenuEntry; 1280 BM_HANDLE_CONTEXT *NewHandleContext; 1281 EFI_HANDLE CurHandle; 1282 UINTN OptionNumber; 1283 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFs; 1284 EFI_LOAD_FILE_PROTOCOL *LoadFile; 1285 1286 SimpleFs = NULL; 1287 LoadFile = NULL; 1288 1289 InitializeListHead (&DriverMenu.Head); 1290 1291 // 1292 // At first, get all handles that support Device Path 1293 // protocol which is the basic requirement for 1294 // Driver#### 1295 // 1296 Status = gBS->LocateHandleBuffer ( 1297 ByProtocol, 1298 &gEfiDevicePathProtocolGuid, 1299 NULL, 1300 &NoDevicePathHandles, 1301 &DevicePathHandle 1302 ); 1303 if (EFI_ERROR (Status)) { 1304 return Status; 1305 } 1306 1307 OptionNumber = 0; 1308 for (Index = 0; Index < NoDevicePathHandles; Index++) { 1309 CurHandle = DevicePathHandle[Index]; 1310 1311 Status = gBS->HandleProtocol ( 1312 CurHandle, 1313 &gEfiSimpleFileSystemProtocolGuid, 1314 (VOID **) &SimpleFs 1315 ); 1316 if (Status == EFI_SUCCESS) { 1317 continue; 1318 } 1319 1320 Status = gBS->HandleProtocol ( 1321 CurHandle, 1322 &gEfiLoadFileProtocolGuid, 1323 (VOID **) &LoadFile 1324 ); 1325 if (Status == EFI_SUCCESS) { 1326 continue; 1327 } 1328 1329 NewMenuEntry = BOpt_CreateMenuEntry (BM_HANDLE_CONTEXT_SELECT); 1330 if (NULL == NewMenuEntry) { 1331 FreePool (DevicePathHandle); 1332 return EFI_OUT_OF_RESOURCES; 1333 } 1334 1335 NewHandleContext = (BM_HANDLE_CONTEXT *) NewMenuEntry->VariableContext; 1336 NewHandleContext->Handle = CurHandle; 1337 NewHandleContext->DevicePath = DevicePathFromHandle (CurHandle); 1338 NewMenuEntry->DisplayString = DevicePathToStr (NewHandleContext->DevicePath); 1339 NewMenuEntry->HelpString = NULL; 1340 NewMenuEntry->OptionNumber = OptionNumber; 1341 OptionNumber++; 1342 InsertTailList (&DriverMenu.Head, &NewMenuEntry->Link); 1343 1344 } 1345 1346 if (DevicePathHandle != NULL) { 1347 FreePool (DevicePathHandle); 1348 } 1349 1350 DriverMenu.MenuNumber = OptionNumber; 1351 return EFI_SUCCESS; 1352 } 1353 1354 /** 1355 1356 Get the Option Number that has not been allocated for use. 1357 1358 @param Type The type of Option. 1359 1360 @return The available Option Number. 1361 1362 **/ 1363 UINT16 1364 BOpt_GetOptionNumber ( 1365 CHAR16 *Type 1366 ) 1367 { 1368 UINT16 *OrderList; 1369 UINTN OrderListSize; 1370 UINTN Index; 1371 CHAR16 StrTemp[20]; 1372 UINT16 *OptionBuffer; 1373 UINT16 OptionNumber; 1374 UINTN OptionSize; 1375 1376 OrderListSize = 0; 1377 OrderList = NULL; 1378 OptionNumber = 0; 1379 Index = 0; 1380 1381 UnicodeSPrint (StrTemp, sizeof (StrTemp), L"%sOrder", Type); 1382 1383 OrderList = BdsLibGetVariableAndSize ( 1384 StrTemp, 1385 &gEfiGlobalVariableGuid, 1386 &OrderListSize 1387 ); 1388 1389 for (OptionNumber = 0; ; OptionNumber++) { 1390 if (OrderList != NULL) { 1391 for (Index = 0; Index < OrderListSize / sizeof (UINT16); Index++) { 1392 if (OptionNumber == OrderList[Index]) { 1393 break; 1394 } 1395 } 1396 } 1397 1398 if (Index < OrderListSize / sizeof (UINT16)) { 1399 // 1400 // The OptionNumber occurs in the OrderList, continue to use next one 1401 // 1402 continue; 1403 } 1404 UnicodeSPrint (StrTemp, sizeof (StrTemp), L"%s%04x", Type, (UINTN) OptionNumber); 1405 DEBUG((EFI_D_ERROR,"Option = %s\n", StrTemp)); 1406 OptionBuffer = BdsLibGetVariableAndSize ( 1407 StrTemp, 1408 &gEfiGlobalVariableGuid, 1409 &OptionSize 1410 ); 1411 if (NULL == OptionBuffer) { 1412 // 1413 // The Boot[OptionNumber] / Driver[OptionNumber] NOT occurs, we found it 1414 // 1415 break; 1416 } 1417 } 1418 1419 return OptionNumber; 1420 } 1421 1422 /** 1423 1424 Get the Option Number for Boot#### that does not used. 1425 1426 @return The available Option Number. 1427 1428 **/ 1429 UINT16 1430 BOpt_GetBootOptionNumber ( 1431 VOID 1432 ) 1433 { 1434 return BOpt_GetOptionNumber (L"Boot"); 1435 } 1436 1437 /** 1438 1439 Get the Option Number for Driver#### that does not used. 1440 1441 @return The unused Option Number. 1442 1443 **/ 1444 UINT16 1445 BOpt_GetDriverOptionNumber ( 1446 VOID 1447 ) 1448 { 1449 return BOpt_GetOptionNumber (L"Driver"); 1450 } 1451 1452 /** 1453 1454 Build up all DriverOptionMenu 1455 1456 @param CallbackData The BMM context data. 1457 1458 @retval EFI_SUCESS The functin completes successfully. 1459 @retval EFI_OUT_OF_RESOURCES Not enough memory to compete the operation. 1460 @retval EFI_NOT_FOUND Fail to get "DriverOrder" variable. 1461 1462 **/ 1463 EFI_STATUS 1464 BOpt_GetDriverOptions ( 1465 IN BMM_CALLBACK_DATA *CallbackData 1466 ) 1467 { 1468 UINTN Index; 1469 UINT16 DriverString[12]; 1470 UINT8 *LoadOptionFromVar; 1471 UINT8 *LoadOption; 1472 UINTN DriverOptionSize; 1473 1474 UINT16 *DriverOrderList; 1475 UINTN DriverOrderListSize; 1476 BM_MENU_ENTRY *NewMenuEntry; 1477 BM_LOAD_CONTEXT *NewLoadContext; 1478 UINT8 *LoadOptionPtr; 1479 UINTN StringSize; 1480 UINTN OptionalDataSize; 1481 UINT8 *LoadOptionEnd; 1482 1483 DriverOrderListSize = 0; 1484 DriverOrderList = NULL; 1485 DriverOptionSize = 0; 1486 LoadOptionFromVar = NULL; 1487 BOpt_FreeMenu (&DriverOptionMenu); 1488 InitializeListHead (&DriverOptionMenu.Head); 1489 // 1490 // Get the DriverOrder from the Var 1491 // 1492 DriverOrderList = BdsLibGetVariableAndSize ( 1493 L"DriverOrder", 1494 &gEfiGlobalVariableGuid, 1495 &DriverOrderListSize 1496 ); 1497 if (DriverOrderList == NULL) { 1498 return EFI_NOT_FOUND; 1499 } 1500 1501 for (Index = 0; Index < DriverOrderListSize / sizeof (UINT16); Index++) { 1502 UnicodeSPrint ( 1503 DriverString, 1504 sizeof (DriverString), 1505 L"Driver%04x", 1506 DriverOrderList[Index] 1507 ); 1508 // 1509 // Get all loadoptions from the VAR 1510 // 1511 LoadOptionFromVar = BdsLibGetVariableAndSize ( 1512 DriverString, 1513 &gEfiGlobalVariableGuid, 1514 &DriverOptionSize 1515 ); 1516 if (LoadOptionFromVar == NULL) { 1517 continue; 1518 } 1519 1520 LoadOption = AllocateZeroPool (DriverOptionSize); 1521 if (LoadOption == NULL) { 1522 continue; 1523 } 1524 1525 CopyMem (LoadOption, LoadOptionFromVar, DriverOptionSize); 1526 FreePool (LoadOptionFromVar); 1527 1528 NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT); 1529 if (NULL == NewMenuEntry) { 1530 return EFI_OUT_OF_RESOURCES; 1531 } 1532 1533 NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext; 1534 LoadOptionPtr = LoadOption; 1535 LoadOptionEnd = LoadOption + DriverOptionSize; 1536 NewMenuEntry->OptionNumber = DriverOrderList[Index]; 1537 NewLoadContext->LoadOptionModified = FALSE; 1538 NewLoadContext->Deleted = FALSE; 1539 NewLoadContext->IsLegacy = FALSE; 1540 1541 // 1542 // LoadOption is a pointer type of UINT8 1543 // for easy use with following LOAD_OPTION 1544 // embedded in this struct 1545 // 1546 NewLoadContext->LoadOption = LoadOption; 1547 NewLoadContext->LoadOptionSize = DriverOptionSize; 1548 1549 NewLoadContext->Attributes = *(UINT32 *) LoadOptionPtr; 1550 NewLoadContext->IsActive = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_ACTIVE); 1551 1552 NewLoadContext->ForceReconnect = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_FORCE_RECONNECT); 1553 1554 LoadOptionPtr += sizeof (UINT32); 1555 1556 NewLoadContext->FilePathListLength = *(UINT16 *) LoadOptionPtr; 1557 LoadOptionPtr += sizeof (UINT16); 1558 1559 StringSize = StrSize ((UINT16 *) LoadOptionPtr); 1560 NewLoadContext->Description = AllocateZeroPool (StringSize); 1561 ASSERT (NewLoadContext->Description != NULL); 1562 CopyMem ( 1563 NewLoadContext->Description, 1564 (UINT16 *) LoadOptionPtr, 1565 StringSize 1566 ); 1567 NewMenuEntry->DisplayString = NewLoadContext->Description; 1568 1569 LoadOptionPtr += StringSize; 1570 1571 NewLoadContext->FilePathList = AllocateZeroPool (NewLoadContext->FilePathListLength); 1572 ASSERT (NewLoadContext->FilePathList != NULL); 1573 CopyMem ( 1574 NewLoadContext->FilePathList, 1575 (EFI_DEVICE_PATH_PROTOCOL *) LoadOptionPtr, 1576 NewLoadContext->FilePathListLength 1577 ); 1578 1579 NewMenuEntry->HelpString = DevicePathToStr (NewLoadContext->FilePathList); 1580 NewMenuEntry->DisplayStringToken = GetStringTokenFromDepository ( 1581 CallbackData, 1582 DriverOptionStrDepository 1583 ); 1584 NewMenuEntry->HelpStringToken = GetStringTokenFromDepository ( 1585 CallbackData, 1586 DriverOptionHelpStrDepository 1587 ); 1588 LoadOptionPtr += NewLoadContext->FilePathListLength; 1589 1590 if (LoadOptionPtr < LoadOptionEnd) { 1591 OptionalDataSize = DriverOptionSize - 1592 sizeof (UINT32) - 1593 sizeof (UINT16) - 1594 StringSize - 1595 NewLoadContext->FilePathListLength; 1596 1597 NewLoadContext->OptionalData = AllocateZeroPool (OptionalDataSize); 1598 ASSERT (NewLoadContext->OptionalData != NULL); 1599 CopyMem ( 1600 NewLoadContext->OptionalData, 1601 LoadOptionPtr, 1602 OptionalDataSize 1603 ); 1604 1605 NewLoadContext->OptionalDataSize = OptionalDataSize; 1606 } 1607 1608 InsertTailList (&DriverOptionMenu.Head, &NewMenuEntry->Link); 1609 1610 } 1611 1612 if (DriverOrderList != NULL) { 1613 FreePool (DriverOrderList); 1614 } 1615 DriverOptionMenu.MenuNumber = Index; 1616 return EFI_SUCCESS; 1617 1618 } 1619 1620 /** 1621 Get option number according to Boot#### and BootOrder variable. 1622 The value is saved as #### + 1. 1623 1624 @param CallbackData The BMM context data. 1625 **/ 1626 VOID 1627 GetBootOrder ( 1628 IN BMM_CALLBACK_DATA *CallbackData 1629 ) 1630 { 1631 BMM_FAKE_NV_DATA *BmmConfig; 1632 UINT16 Index; 1633 UINT16 OptionOrderIndex; 1634 UINTN DeviceType; 1635 BM_MENU_ENTRY *NewMenuEntry; 1636 BM_LOAD_CONTEXT *NewLoadContext; 1637 1638 ASSERT (CallbackData != NULL); 1639 1640 DeviceType = (UINTN) -1; 1641 BmmConfig = &CallbackData->BmmFakeNvData; 1642 ZeroMem (BmmConfig->BootOptionOrder, sizeof (BmmConfig->BootOptionOrder)); 1643 1644 for (Index = 0, OptionOrderIndex = 0; ((Index < BootOptionMenu.MenuNumber) && 1645 (OptionOrderIndex < (sizeof (BmmConfig->BootOptionOrder) / sizeof (BmmConfig->BootOptionOrder[0])))); 1646 Index++) { 1647 NewMenuEntry = BOpt_GetMenuEntry (&BootOptionMenu, Index); 1648 NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext; 1649 1650 if (NewLoadContext->IsLegacy) { 1651 if (((BBS_BBS_DEVICE_PATH *) NewLoadContext->FilePathList)->DeviceType != DeviceType) { 1652 DeviceType = ((BBS_BBS_DEVICE_PATH *) NewLoadContext->FilePathList)->DeviceType; 1653 } else { 1654 // 1655 // Only show one legacy boot option for the same device type 1656 // assuming the boot options are grouped by the device type 1657 // 1658 continue; 1659 } 1660 } 1661 BmmConfig->BootOptionOrder[OptionOrderIndex++] = (UINT32) (NewMenuEntry->OptionNumber + 1); 1662 } 1663 } 1664 1665 /** 1666 According to LegacyDevOrder variable to get legacy FD\HD\CD\NET\BEV 1667 devices list . 1668 1669 @param CallbackData The BMM context data. 1670 **/ 1671 VOID 1672 GetLegacyDeviceOrder ( 1673 IN BMM_CALLBACK_DATA *CallbackData 1674 ) 1675 { 1676 UINTN Index; 1677 UINTN OptionIndex; 1678 UINT16 PageIdList[5]; 1679 UINTN PageNum; 1680 UINTN VarSize; 1681 UINT8 *VarData; 1682 UINT8 *WorkingVarData; 1683 LEGACY_DEV_ORDER_ENTRY *DevOrder; 1684 UINT16 VarDevOrder; 1685 UINT8 *DisMap; 1686 BM_MENU_OPTION *OptionMenu; 1687 BBS_TYPE BbsType; 1688 UINT8 *LegacyOrder; 1689 UINT8 *OldData; 1690 UINTN Pos; 1691 UINTN Bit; 1692 1693 ASSERT (CallbackData != NULL); 1694 1695 PageIdList[0] = FORM_SET_FD_ORDER_ID; 1696 PageIdList[1] = FORM_SET_HD_ORDER_ID; 1697 PageIdList[2] = FORM_SET_CD_ORDER_ID; 1698 PageIdList[3] = FORM_SET_NET_ORDER_ID; 1699 PageIdList[4] = FORM_SET_BEV_ORDER_ID; 1700 OptionMenu = NULL; 1701 BbsType = 0; 1702 LegacyOrder = NULL; 1703 OldData = NULL; 1704 DisMap = ZeroMem (CallbackData->BmmFakeNvData.DisableMap, sizeof (CallbackData->BmmFakeNvData.DisableMap)); 1705 PageNum = ARRAY_SIZE (PageIdList); 1706 VarData = BdsLibGetVariableAndSize ( 1707 VAR_LEGACY_DEV_ORDER, 1708 &gEfiLegacyDevOrderVariableGuid, 1709 &VarSize 1710 ); 1711 1712 for (Index = 0; Index < PageNum; Index++) { 1713 switch (PageIdList[Index]) { 1714 1715 case FORM_SET_FD_ORDER_ID: 1716 OptionMenu = (BM_MENU_OPTION *) &LegacyFDMenu; 1717 BbsType = BBS_FLOPPY; 1718 LegacyOrder = CallbackData->BmmFakeNvData.LegacyFD; 1719 OldData = CallbackData->BmmOldFakeNVData.LegacyFD; 1720 break; 1721 1722 case FORM_SET_HD_ORDER_ID: 1723 OptionMenu = (BM_MENU_OPTION *) &LegacyHDMenu; 1724 BbsType = BBS_HARDDISK; 1725 LegacyOrder = CallbackData->BmmFakeNvData.LegacyHD; 1726 OldData = CallbackData->BmmOldFakeNVData.LegacyHD; 1727 break; 1728 1729 case FORM_SET_CD_ORDER_ID: 1730 OptionMenu = (BM_MENU_OPTION *) &LegacyCDMenu; 1731 BbsType = BBS_CDROM; 1732 LegacyOrder = CallbackData->BmmFakeNvData.LegacyCD; 1733 OldData = CallbackData->BmmOldFakeNVData.LegacyCD; 1734 break; 1735 1736 case FORM_SET_NET_ORDER_ID: 1737 OptionMenu = (BM_MENU_OPTION *) &LegacyNETMenu; 1738 BbsType = BBS_EMBED_NETWORK; 1739 LegacyOrder = CallbackData->BmmFakeNvData.LegacyNET; 1740 OldData = CallbackData->BmmOldFakeNVData.LegacyNET; 1741 break; 1742 1743 default: 1744 ASSERT (PageIdList[Index] == FORM_SET_BEV_ORDER_ID); 1745 OptionMenu = (BM_MENU_OPTION *) &LegacyBEVMenu; 1746 BbsType = BBS_BEV_DEVICE; 1747 LegacyOrder = CallbackData->BmmFakeNvData.LegacyBEV; 1748 OldData = CallbackData->BmmOldFakeNVData.LegacyBEV; 1749 break; 1750 } 1751 1752 if (NULL != VarData) { 1753 WorkingVarData = VarData; 1754 DevOrder = (LEGACY_DEV_ORDER_ENTRY *) WorkingVarData; 1755 while (WorkingVarData < VarData + VarSize) { 1756 if (DevOrder->BbsType == BbsType) { 1757 break; 1758 } 1759 1760 WorkingVarData = (UINT8 *)((UINTN)WorkingVarData + sizeof (BBS_TYPE)); 1761 WorkingVarData += *(UINT16 *) WorkingVarData; 1762 DevOrder = (LEGACY_DEV_ORDER_ENTRY *) WorkingVarData; 1763 } 1764 for (OptionIndex = 0; OptionIndex < OptionMenu->MenuNumber; OptionIndex++) { 1765 VarDevOrder = *(UINT16 *) ((UINTN) DevOrder + sizeof (BBS_TYPE) + sizeof (UINT16) + OptionIndex * sizeof (UINT16)); 1766 if (0xFF00 == (VarDevOrder & 0xFF00)) { 1767 LegacyOrder[OptionIndex] = 0xFF; 1768 Pos = (VarDevOrder & 0xFF) / 8; 1769 Bit = 7 - ((VarDevOrder & 0xFF) % 8); 1770 DisMap[Pos] = (UINT8) (DisMap[Pos] | (UINT8) (1 << Bit)); 1771 } else { 1772 LegacyOrder[OptionIndex] = (UINT8) (VarDevOrder & 0xFF); 1773 } 1774 } 1775 CopyMem (OldData, LegacyOrder, 100); 1776 } 1777 } 1778 } 1779 1780 /** 1781 Get driver option order from globalc DriverOptionMenu. 1782 1783 @param CallbackData The BMM context data. 1784 1785 **/ 1786 VOID 1787 GetDriverOrder ( 1788 IN BMM_CALLBACK_DATA *CallbackData 1789 ) 1790 { 1791 BMM_FAKE_NV_DATA *BmmConfig; 1792 UINT16 Index; 1793 UINT16 OptionOrderIndex; 1794 UINTN DeviceType; 1795 BM_MENU_ENTRY *NewMenuEntry; 1796 BM_LOAD_CONTEXT *NewLoadContext; 1797 1798 ASSERT (CallbackData != NULL); 1799 1800 DeviceType = (UINTN) -1; 1801 BmmConfig = &CallbackData->BmmFakeNvData; 1802 ZeroMem (BmmConfig->DriverOptionOrder, sizeof (BmmConfig->DriverOptionOrder)); 1803 1804 for (Index = 0, OptionOrderIndex = 0; ((Index < DriverOptionMenu.MenuNumber) && 1805 (OptionOrderIndex < (sizeof (BmmConfig->DriverOptionOrder) / sizeof (BmmConfig->DriverOptionOrder[0])))); 1806 Index++) { 1807 NewMenuEntry = BOpt_GetMenuEntry (&DriverOptionMenu, Index); 1808 NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext; 1809 1810 if (NewLoadContext->IsLegacy) { 1811 if (((BBS_BBS_DEVICE_PATH *) NewLoadContext->FilePathList)->DeviceType != DeviceType) { 1812 DeviceType = ((BBS_BBS_DEVICE_PATH *) NewLoadContext->FilePathList)->DeviceType; 1813 } else { 1814 // 1815 // Only show one legacy boot option for the same device type 1816 // assuming the boot options are grouped by the device type 1817 // 1818 continue; 1819 } 1820 } 1821 BmmConfig->DriverOptionOrder[OptionOrderIndex++] = (UINT32) (NewMenuEntry->OptionNumber + 1); 1822 } 1823 } 1824