1 /** @file 2 Implementation for PlatformBootManagerLib library class interfaces. 3 4 Copyright (C) 2015-2016, Red Hat, Inc. 5 Copyright (c) 2014, ARM Ltd. All rights reserved.<BR> 6 Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR> 7 Copyright (c) 2016-2017, Linaro Ltd. All rights reserved.<BR> 8 9 This program and the accompanying materials are licensed and made available 10 under the terms and conditions of the BSD License which accompanies this 11 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, WITHOUT 15 WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 16 17 **/ 18 19 #include <Library/DevicePathLib.h> 20 #include <Library/PcdLib.h> 21 #include <Library/UefiBootManagerLib.h> 22 #include <Library/UefiLib.h> 23 #include <Protocol/BlockIo.h> 24 #include <Protocol/DevicePath.h> 25 #include <Protocol/DevicePathFromText.h> 26 #include <Protocol/DevicePathToText.h> 27 #include <Protocol/GraphicsOutput.h> 28 #include <Protocol/LoadedImage.h> 29 #include <Guid/EventGroup.h> 30 #include <Guid/TtyTerm.h> 31 32 #include "PlatformBm.h" 33 34 #define DP_NODE_LEN(Type) { (UINT8)sizeof (Type), (UINT8)(sizeof (Type) >> 8) } 35 36 #define GRUB_FILE_NAME L"\\EFI\\BOOT\\GRUBAA64.EFI" 37 #define SD_FILE_NAME L"\\EFI\\BOOT\\BOOTAA64.EFI" 38 39 40 #pragma pack (1) 41 typedef struct { 42 VENDOR_DEVICE_PATH SerialDxe; 43 UART_DEVICE_PATH Uart; 44 VENDOR_DEFINED_DEVICE_PATH TermType; 45 EFI_DEVICE_PATH_PROTOCOL End; 46 } PLATFORM_SERIAL_CONSOLE; 47 #pragma pack () 48 49 #define SERIAL_DXE_FILE_GUID { \ 50 0xD3987D4B, 0x971A, 0x435F, \ 51 { 0x8C, 0xAF, 0x49, 0x67, 0xEB, 0x62, 0x72, 0x41 } \ 52 } 53 54 STATIC PLATFORM_SERIAL_CONSOLE mSerialConsole = { 55 // 56 // VENDOR_DEVICE_PATH SerialDxe 57 // 58 { 59 { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, DP_NODE_LEN (VENDOR_DEVICE_PATH) }, 60 SERIAL_DXE_FILE_GUID 61 }, 62 63 // 64 // UART_DEVICE_PATH Uart 65 // 66 { 67 { MESSAGING_DEVICE_PATH, MSG_UART_DP, DP_NODE_LEN (UART_DEVICE_PATH) }, 68 0, // Reserved 69 FixedPcdGet64 (PcdUartDefaultBaudRate), // BaudRate 70 FixedPcdGet8 (PcdUartDefaultDataBits), // DataBits 71 FixedPcdGet8 (PcdUartDefaultParity), // Parity 72 FixedPcdGet8 (PcdUartDefaultStopBits) // StopBits 73 }, 74 75 // 76 // VENDOR_DEFINED_DEVICE_PATH TermType 77 // 78 { 79 { 80 MESSAGING_DEVICE_PATH, MSG_VENDOR_DP, 81 DP_NODE_LEN (VENDOR_DEFINED_DEVICE_PATH) 82 } 83 // 84 // Guid to be filled in dynamically 85 // 86 }, 87 88 // 89 // EFI_DEVICE_PATH_PROTOCOL End 90 // 91 { 92 END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, 93 DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL) 94 } 95 }; 96 97 98 #pragma pack (1) 99 typedef struct { 100 USB_CLASS_DEVICE_PATH Keyboard; 101 EFI_DEVICE_PATH_PROTOCOL End; 102 } PLATFORM_USB_KEYBOARD; 103 #pragma pack () 104 105 STATIC PLATFORM_USB_KEYBOARD mUsbKeyboard = { 106 // 107 // USB_CLASS_DEVICE_PATH Keyboard 108 // 109 { 110 { 111 MESSAGING_DEVICE_PATH, MSG_USB_CLASS_DP, 112 DP_NODE_LEN (USB_CLASS_DEVICE_PATH) 113 }, 114 0xFFFF, // VendorId: any 115 0xFFFF, // ProductId: any 116 3, // DeviceClass: HID 117 1, // DeviceSubClass: boot 118 1 // DeviceProtocol: keyboard 119 }, 120 121 // 122 // EFI_DEVICE_PATH_PROTOCOL End 123 // 124 { 125 END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, 126 DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL) 127 } 128 }; 129 130 131 /** 132 Check if the handle satisfies a particular condition. 133 134 @param[in] Handle The handle to check. 135 @param[in] ReportText A caller-allocated string passed in for reporting 136 purposes. It must never be NULL. 137 138 @retval TRUE The condition is satisfied. 139 @retval FALSE Otherwise. This includes the case when the condition could not 140 be fully evaluated due to an error. 141 **/ 142 typedef 143 BOOLEAN 144 (EFIAPI *FILTER_FUNCTION) ( 145 IN EFI_HANDLE Handle, 146 IN CONST CHAR16 *ReportText 147 ); 148 149 150 /** 151 Process a handle. 152 153 @param[in] Handle The handle to process. 154 @param[in] ReportText A caller-allocated string passed in for reporting 155 purposes. It must never be NULL. 156 **/ 157 typedef 158 VOID 159 (EFIAPI *CALLBACK_FUNCTION) ( 160 IN EFI_HANDLE Handle, 161 IN CONST CHAR16 *ReportText 162 ); 163 164 /** 165 Locate all handles that carry the specified protocol, filter them with a 166 callback function, and pass each handle that passes the filter to another 167 callback. 168 169 @param[in] ProtocolGuid The protocol to look for. 170 171 @param[in] Filter The filter function to pass each handle to. If this 172 parameter is NULL, then all handles are processed. 173 174 @param[in] Process The callback function to pass each handle to that 175 clears the filter. 176 **/ 177 STATIC 178 VOID 179 FilterAndProcess ( 180 IN EFI_GUID *ProtocolGuid, 181 IN FILTER_FUNCTION Filter OPTIONAL, 182 IN CALLBACK_FUNCTION Process 183 ) 184 { 185 EFI_STATUS Status; 186 EFI_HANDLE *Handles; 187 UINTN NoHandles; 188 UINTN Idx; 189 190 Status = gBS->LocateHandleBuffer (ByProtocol, ProtocolGuid, 191 NULL /* SearchKey */, &NoHandles, &Handles); 192 if (EFI_ERROR (Status)) { 193 // 194 // This is not an error, just an informative condition. 195 // 196 DEBUG ((DEBUG_VERBOSE, "%a: %g: %r\n", __FUNCTION__, ProtocolGuid, 197 Status)); 198 return; 199 } 200 201 ASSERT (NoHandles > 0); 202 for (Idx = 0; Idx < NoHandles; ++Idx) { 203 CHAR16 *DevicePathText; 204 STATIC CHAR16 Fallback[] = L"<device path unavailable>"; 205 206 // 207 // The ConvertDevicePathToText() function handles NULL input transparently. 208 // 209 DevicePathText = ConvertDevicePathToText ( 210 DevicePathFromHandle (Handles[Idx]), 211 FALSE, // DisplayOnly 212 FALSE // AllowShortcuts 213 ); 214 if (DevicePathText == NULL) { 215 DevicePathText = Fallback; 216 } 217 218 if (Filter == NULL || Filter (Handles[Idx], DevicePathText)) { 219 Process (Handles[Idx], DevicePathText); 220 } 221 222 if (DevicePathText != Fallback) { 223 FreePool (DevicePathText); 224 } 225 } 226 gBS->FreePool (Handles); 227 } 228 229 230 /** 231 This CALLBACK_FUNCTION retrieves the EFI_DEVICE_PATH_PROTOCOL from the 232 handle, and adds it to ConOut and ErrOut. 233 **/ 234 STATIC 235 VOID 236 EFIAPI 237 AddOutput ( 238 IN EFI_HANDLE Handle, 239 IN CONST CHAR16 *ReportText 240 ) 241 { 242 EFI_STATUS Status; 243 EFI_DEVICE_PATH_PROTOCOL *DevicePath; 244 245 DevicePath = DevicePathFromHandle (Handle); 246 if (DevicePath == NULL) { 247 DEBUG ((DEBUG_ERROR, "%a: %s: handle %p: device path not found\n", 248 __FUNCTION__, ReportText, Handle)); 249 return; 250 } 251 252 Status = EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL); 253 if (EFI_ERROR (Status)) { 254 DEBUG ((DEBUG_ERROR, "%a: %s: adding to ConOut: %r\n", __FUNCTION__, 255 ReportText, Status)); 256 return; 257 } 258 259 Status = EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL); 260 if (EFI_ERROR (Status)) { 261 DEBUG ((DEBUG_ERROR, "%a: %s: adding to ErrOut: %r\n", __FUNCTION__, 262 ReportText, Status)); 263 return; 264 } 265 266 DEBUG ((DEBUG_VERBOSE, "%a: %s: added to ConOut and ErrOut\n", __FUNCTION__, 267 ReportText)); 268 } 269 270 STATIC 271 VOID 272 PlatformRegisterFvBootOption ( 273 EFI_GUID *FileGuid, 274 CHAR16 *Description, 275 UINT32 Attributes 276 ) 277 { 278 EFI_STATUS Status; 279 INTN OptionIndex; 280 EFI_BOOT_MANAGER_LOAD_OPTION NewOption; 281 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions; 282 UINTN BootOptionCount; 283 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode; 284 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; 285 EFI_DEVICE_PATH_PROTOCOL *DevicePath; 286 287 Status = gBS->HandleProtocol ( 288 gImageHandle, 289 &gEfiLoadedImageProtocolGuid, 290 (VOID **) &LoadedImage 291 ); 292 ASSERT_EFI_ERROR (Status); 293 294 EfiInitializeFwVolDevicepathNode (&FileNode, FileGuid); 295 DevicePath = DevicePathFromHandle (LoadedImage->DeviceHandle); 296 ASSERT (DevicePath != NULL); 297 DevicePath = AppendDevicePathNode ( 298 DevicePath, 299 (EFI_DEVICE_PATH_PROTOCOL *) &FileNode 300 ); 301 ASSERT (DevicePath != NULL); 302 303 Status = EfiBootManagerInitializeLoadOption ( 304 &NewOption, 305 LoadOptionNumberUnassigned, 306 LoadOptionTypeBoot, 307 Attributes, 308 Description, 309 DevicePath, 310 NULL, 311 0 312 ); 313 ASSERT_EFI_ERROR (Status); 314 FreePool (DevicePath); 315 316 BootOptions = EfiBootManagerGetLoadOptions ( 317 &BootOptionCount, LoadOptionTypeBoot 318 ); 319 320 OptionIndex = EfiBootManagerFindLoadOption ( 321 &NewOption, BootOptions, BootOptionCount 322 ); 323 324 if (OptionIndex == -1) { 325 Status = EfiBootManagerAddLoadOptionVariable (&NewOption, MAX_UINTN); 326 ASSERT_EFI_ERROR (Status); 327 } 328 329 EfiBootManagerFreeLoadOption (&NewOption); 330 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount); 331 } 332 333 334 STATIC 335 VOID 336 PlatformRegisterBootSd ( 337 VOID 338 ) 339 { 340 EFI_STATUS Status; 341 CHAR16 *BootPathStr; 342 EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *EfiDevicePathFromTextProtocol; 343 EFI_DEVICE_PATH *DevicePath; 344 EFI_BOOT_MANAGER_LOAD_OPTION NewOption; 345 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions; 346 UINTN BootOptionCount; 347 INTN OptionIndex; 348 349 // 350 // Get PcdSdBootDevicePath 351 // 352 BootPathStr = (CHAR16 *)PcdGetPtr (PcdSdBootDevicePath); 353 ASSERT (BootPathStr != NULL); 354 Status = gBS->LocateProtocol (&gEfiDevicePathFromTextProtocolGuid, NULL, (VOID **)&EfiDevicePathFromTextProtocol); 355 ASSERT_EFI_ERROR(Status); 356 DevicePath = (EFI_DEVICE_PATH *)EfiDevicePathFromTextProtocol->ConvertTextToDevicePath (BootPathStr); 357 ASSERT (DevicePath != NULL); 358 359 Status = EfiBootManagerInitializeLoadOption ( 360 &NewOption, 361 LoadOptionNumberUnassigned, 362 LoadOptionTypeBoot, 363 LOAD_OPTION_ACTIVE, 364 L"Boot from SD", 365 DevicePath, 366 NULL, 367 0 368 ); 369 ASSERT_EFI_ERROR (Status); 370 FreePool (DevicePath); 371 372 BootOptions = EfiBootManagerGetLoadOptions ( 373 &BootOptionCount, LoadOptionTypeBoot 374 ); 375 376 OptionIndex = EfiBootManagerFindLoadOption ( 377 &NewOption, BootOptions, BootOptionCount 378 ); 379 380 if (OptionIndex == -1) { 381 Status = EfiBootManagerAddLoadOptionVariable (&NewOption, MAX_UINTN); 382 ASSERT_EFI_ERROR (Status); 383 } 384 385 EfiBootManagerFreeLoadOption (&NewOption); 386 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount); 387 } 388 389 STATIC 390 VOID 391 PlatformRegisterBootGrub ( 392 VOID 393 ) 394 { 395 EFI_STATUS Status; 396 CHAR16 *BootPathStr; 397 EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *EfiDevicePathFromTextProtocol; 398 EFI_DEVICE_PATH *DevicePath; 399 EFI_DEVICE_PATH *FileDevicePath; 400 FILEPATH_DEVICE_PATH *FilePath; 401 UINTN Size; 402 EFI_BOOT_MANAGER_LOAD_OPTION NewOption; 403 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions; 404 UINTN BootOptionCount; 405 INTN OptionIndex; 406 407 // 408 // Get PcdAndroidBootDevicePath 409 // 410 BootPathStr = (CHAR16 *)PcdGetPtr (PcdAndroidBootDevicePath); 411 ASSERT (BootPathStr != NULL); 412 Status = gBS->LocateProtocol (&gEfiDevicePathFromTextProtocolGuid, NULL, (VOID **)&EfiDevicePathFromTextProtocol); 413 ASSERT_EFI_ERROR(Status); 414 DevicePath = (EFI_DEVICE_PATH *)EfiDevicePathFromTextProtocol->ConvertTextToDevicePath (BootPathStr); 415 ASSERT (DevicePath != NULL); 416 417 Size = StrSize (GRUB_FILE_NAME); 418 FileDevicePath = AllocatePool (Size + SIZE_OF_FILEPATH_DEVICE_PATH + END_DEVICE_PATH_LENGTH); 419 if (FileDevicePath != NULL) { 420 FilePath = (FILEPATH_DEVICE_PATH *) FileDevicePath; 421 FilePath->Header.Type = MEDIA_DEVICE_PATH; 422 FilePath->Header.SubType = MEDIA_FILEPATH_DP; 423 CopyMem (&FilePath->PathName, GRUB_FILE_NAME, Size); 424 SetDevicePathNodeLength (&FilePath->Header, Size + SIZE_OF_FILEPATH_DEVICE_PATH); 425 SetDevicePathEndNode (NextDevicePathNode (&FilePath->Header)); 426 427 DevicePath = AppendDevicePath (DevicePath, FileDevicePath); 428 FreePool (FileDevicePath); 429 } 430 Status = EfiBootManagerInitializeLoadOption ( 431 &NewOption, 432 LoadOptionNumberUnassigned, 433 LoadOptionTypeBoot, 434 LOAD_OPTION_ACTIVE, 435 L"Grub", 436 DevicePath, 437 NULL, 438 0 439 ); 440 ASSERT_EFI_ERROR (Status); 441 FreePool (DevicePath); 442 443 BootOptions = EfiBootManagerGetLoadOptions ( 444 &BootOptionCount, LoadOptionTypeBoot 445 ); 446 447 OptionIndex = EfiBootManagerFindLoadOption ( 448 &NewOption, BootOptions, BootOptionCount 449 ); 450 451 if (OptionIndex == -1) { 452 Status = EfiBootManagerAddLoadOptionVariable (&NewOption, MAX_UINTN); 453 ASSERT_EFI_ERROR (Status); 454 } 455 456 EfiBootManagerFreeLoadOption (&NewOption); 457 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount); 458 459 } 460 461 STATIC 462 VOID 463 PlatformRegisterOptionsAndKeys ( 464 VOID 465 ) 466 { 467 EFI_STATUS Status; 468 EFI_INPUT_KEY Enter; 469 EFI_INPUT_KEY Esc; 470 EFI_INPUT_KEY KeyF; 471 EFI_BOOT_MANAGER_LOAD_OPTION BootOption; 472 473 // 474 // Register Boot on SD. OptionNumber is 1. 475 // 476 PlatformRegisterBootSd (); 477 478 // 479 // Register Boot. OptionNumber is 2. 480 // 481 PlatformRegisterBootGrub (); 482 483 // 484 // Register Android Boot. OptionNumber is 3. 485 // 486 PlatformRegisterFvBootOption ( 487 PcdGetPtr (PcdAndroidBootFile), L"Android Boot", LOAD_OPTION_ACTIVE 488 ); 489 490 // 491 // Register Android Fastboot. OptionNumber is 4. 492 // 493 PlatformRegisterFvBootOption ( 494 PcdGetPtr (PcdAndroidFastbootFile), L"Android Fastboot", LOAD_OPTION_ACTIVE 495 ); 496 497 // 498 // Register ENTER as CONTINUE key 499 // 500 Enter.ScanCode = SCAN_NULL; 501 Enter.UnicodeChar = CHAR_CARRIAGE_RETURN; 502 Status = EfiBootManagerRegisterContinueKeyOption (0, &Enter, NULL); 503 ASSERT_EFI_ERROR (Status); 504 505 // 506 // Map ESC to Boot Manager Menu 507 // 508 Esc.ScanCode = SCAN_ESC; 509 Esc.UnicodeChar = CHAR_NULL; 510 Status = EfiBootManagerGetBootManagerMenu (&BootOption); 511 ASSERT_EFI_ERROR (Status); 512 Status = EfiBootManagerAddKeyOptionVariable ( 513 NULL, (UINT16) BootOption.OptionNumber, 0, &Esc, NULL 514 ); 515 ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED); 516 517 // 518 // Map KeyF to Android Fastboot 519 // 520 KeyF.ScanCode = SCAN_NULL; 521 KeyF.UnicodeChar = 'f'; 522 Status = EfiBootManagerAddKeyOptionVariable ( 523 NULL, 4, 0, &KeyF, NULL 524 ); 525 ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED); 526 } 527 528 529 // 530 // BDS Platform Functions 531 // 532 /** 533 Do the platform init, can be customized by OEM/IBV 534 Possible things that can be done in PlatformBootManagerBeforeConsole: 535 > Update console variable: 1. include hot-plug devices; 536 > 2. Clear ConIn and add SOL for AMT 537 > Register new Driver#### or Boot#### 538 > Register new Key####: e.g.: F12 539 > Signal ReadyToLock event 540 > Authentication action: 1. connect Auth devices; 541 > 2. Identify auto logon user. 542 **/ 543 VOID 544 EFIAPI 545 PlatformBootManagerBeforeConsole ( 546 VOID 547 ) 548 { 549 // 550 // Signal EndOfDxe PI Event 551 // 552 EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid); 553 554 // 555 // Now add the device path of all handles with GOP on them to ConOut and 556 // ErrOut. 557 // 558 FilterAndProcess (&gEfiGraphicsOutputProtocolGuid, NULL, AddOutput); 559 560 // 561 // Add the hardcoded short-form USB keyboard device path to ConIn. 562 // 563 EfiBootManagerUpdateConsoleVariable (ConIn, 564 (EFI_DEVICE_PATH_PROTOCOL *)&mUsbKeyboard, NULL); 565 566 // 567 // Add the hardcoded serial console device path to ConIn, ConOut, ErrOut. 568 // 569 ASSERT (FixedPcdGet8 (PcdDefaultTerminalType) == 4); 570 CopyGuid (&mSerialConsole.TermType.Guid, &gEfiTtyTermGuid); 571 572 EfiBootManagerUpdateConsoleVariable (ConIn, 573 (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL); 574 EfiBootManagerUpdateConsoleVariable (ConOut, 575 (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL); 576 EfiBootManagerUpdateConsoleVariable (ErrOut, 577 (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL); 578 579 // 580 // Register platform-specific boot options and keyboard shortcuts. 581 // 582 PlatformRegisterOptionsAndKeys (); 583 } 584 585 /** 586 Do the platform specific action after the console is ready 587 Possible things that can be done in PlatformBootManagerAfterConsole: 588 > Console post action: 589 > Dynamically switch output mode from 100x31 to 80x25 for certain senarino 590 > Signal console ready platform customized event 591 > Run diagnostics like memory testing 592 > Connect certain devices 593 > Dispatch aditional option roms 594 > Special boot: e.g.: USB boot, enter UI 595 **/ 596 VOID 597 EFIAPI 598 PlatformBootManagerAfterConsole ( 599 VOID 600 ) 601 { 602 Print (L"Press ESCAPE for boot options "); 603 604 // 605 // Show the splash screen. 606 // 607 EnableQuietBoot (PcdGetPtr (PcdLogoFile)); 608 609 // 610 // Connect the rest of the devices. 611 // 612 EfiBootManagerConnectAll (); 613 614 // 615 // Enumerate all possible boot options. 616 // 617 EfiBootManagerRefreshAllBootOption (); 618 619 // 620 // Register UEFI Shell 621 // 622 PlatformRegisterFvBootOption ( 623 PcdGetPtr (PcdShellFile), L"UEFI Shell", LOAD_OPTION_ACTIVE 624 ); 625 } 626 627 /** 628 This function is called each second during the boot manager waits the 629 timeout. 630 631 @param TimeoutRemain The remaining timeout. 632 **/ 633 VOID 634 EFIAPI 635 PlatformBootManagerWaitCallback ( 636 UINT16 TimeoutRemain 637 ) 638 { 639 Print (L"."); 640 } 641