1 /** @file 2 Implementation for PlatformBdsLib library class interfaces. 3 4 Copyright (C) 2015, Red Hat, Inc. 5 Copyright (c) 2014, ARM Ltd. All rights reserved.<BR> 6 Copyright (c) 2004 - 2008, Intel Corporation. All rights reserved.<BR> 7 8 This program and the accompanying materials are licensed and made available 9 under the terms and conditions of the BSD License which accompanies this 10 distribution. The full text of the license may be found at 11 http://opensource.org/licenses/bsd-license.php 12 13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT 14 WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 15 16 **/ 17 18 #include <IndustryStandard/Pci22.h> 19 #include <Library/DevicePathLib.h> 20 #include <Library/PcdLib.h> 21 #include <Library/PlatformBdsLib.h> 22 #include <Library/QemuBootOrderLib.h> 23 #include <Protocol/DevicePath.h> 24 #include <Protocol/GraphicsOutput.h> 25 #include <Protocol/PciIo.h> 26 #include <Protocol/PciRootBridgeIo.h> 27 #include <Guid/EventGroup.h> 28 29 #include "IntelBdsPlatform.h" 30 31 #define DP_NODE_LEN(Type) { (UINT8)sizeof (Type), (UINT8)(sizeof (Type) >> 8) } 32 33 34 #pragma pack (1) 35 typedef struct { 36 VENDOR_DEVICE_PATH SerialDxe; 37 UART_DEVICE_PATH Uart; 38 VENDOR_DEFINED_DEVICE_PATH TermType; 39 EFI_DEVICE_PATH_PROTOCOL End; 40 } PLATFORM_SERIAL_CONSOLE; 41 #pragma pack () 42 43 #define SERIAL_DXE_FILE_GUID { \ 44 0xD3987D4B, 0x971A, 0x435F, \ 45 { 0x8C, 0xAF, 0x49, 0x67, 0xEB, 0x62, 0x72, 0x41 } \ 46 } 47 48 STATIC PLATFORM_SERIAL_CONSOLE mSerialConsole = { 49 // 50 // VENDOR_DEVICE_PATH SerialDxe 51 // 52 { 53 { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, DP_NODE_LEN (VENDOR_DEVICE_PATH) }, 54 SERIAL_DXE_FILE_GUID 55 }, 56 57 // 58 // UART_DEVICE_PATH Uart 59 // 60 { 61 { MESSAGING_DEVICE_PATH, MSG_UART_DP, DP_NODE_LEN (UART_DEVICE_PATH) }, 62 0, // Reserved 63 FixedPcdGet64 (PcdUartDefaultBaudRate), // BaudRate 64 FixedPcdGet8 (PcdUartDefaultDataBits), // DataBits 65 FixedPcdGet8 (PcdUartDefaultParity), // Parity 66 FixedPcdGet8 (PcdUartDefaultStopBits) // StopBits 67 }, 68 69 // 70 // VENDOR_DEFINED_DEVICE_PATH TermType 71 // 72 { 73 { 74 MESSAGING_DEVICE_PATH, MSG_VENDOR_DP, 75 DP_NODE_LEN (VENDOR_DEFINED_DEVICE_PATH) 76 } 77 // 78 // Guid to be filled in dynamically 79 // 80 }, 81 82 // 83 // EFI_DEVICE_PATH_PROTOCOL End 84 // 85 { 86 END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, 87 DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL) 88 } 89 }; 90 91 92 #pragma pack (1) 93 typedef struct { 94 USB_CLASS_DEVICE_PATH Keyboard; 95 EFI_DEVICE_PATH_PROTOCOL End; 96 } PLATFORM_USB_KEYBOARD; 97 #pragma pack () 98 99 STATIC PLATFORM_USB_KEYBOARD mUsbKeyboard = { 100 // 101 // USB_CLASS_DEVICE_PATH Keyboard 102 // 103 { 104 { 105 MESSAGING_DEVICE_PATH, MSG_USB_CLASS_DP, 106 DP_NODE_LEN (USB_CLASS_DEVICE_PATH) 107 }, 108 0xFFFF, // VendorId: any 109 0xFFFF, // ProductId: any 110 3, // DeviceClass: HID 111 1, // DeviceSubClass: boot 112 1 // DeviceProtocol: keyboard 113 }, 114 115 // 116 // EFI_DEVICE_PATH_PROTOCOL End 117 // 118 { 119 END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, 120 DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL) 121 } 122 }; 123 124 /** 125 An empty function to pass error checking of CreateEventEx (). 126 127 @param Event Event whose notification function is being invoked. 128 @param Context Pointer to the notification function's context, 129 which is implementation-dependent. 130 131 **/ 132 STATIC 133 VOID 134 EFIAPI 135 EmptyCallbackFunction ( 136 IN EFI_EVENT Event, 137 IN VOID *Context 138 ) 139 { 140 } 141 142 // 143 // BDS Platform Functions 144 // 145 /** 146 Platform Bds init. Include the platform firmware vendor, revision 147 and so crc check. 148 149 **/ 150 VOID 151 EFIAPI 152 PlatformBdsInit ( 153 VOID 154 ) 155 { 156 EFI_EVENT EndOfDxeEvent; 157 EFI_STATUS Status; 158 159 // 160 // Signal EndOfDxe PI Event 161 // 162 Status = gBS->CreateEventEx ( 163 EVT_NOTIFY_SIGNAL, 164 TPL_CALLBACK, 165 EmptyCallbackFunction, 166 NULL, 167 &gEfiEndOfDxeEventGroupGuid, 168 &EndOfDxeEvent 169 ); 170 if (!EFI_ERROR (Status)) { 171 gBS->SignalEvent (EndOfDxeEvent); 172 gBS->CloseEvent (EndOfDxeEvent); 173 } 174 } 175 176 177 /** 178 Check if the handle satisfies a particular condition. 179 180 @param[in] Handle The handle to check. 181 @param[in] ReportText A caller-allocated string passed in for reporting 182 purposes. It must never be NULL. 183 184 @retval TRUE The condition is satisfied. 185 @retval FALSE Otherwise. This includes the case when the condition could not 186 be fully evaluated due to an error. 187 **/ 188 typedef 189 BOOLEAN 190 (EFIAPI *FILTER_FUNCTION) ( 191 IN EFI_HANDLE Handle, 192 IN CONST CHAR16 *ReportText 193 ); 194 195 196 /** 197 Process a handle. 198 199 @param[in] Handle The handle to process. 200 @param[in] ReportText A caller-allocated string passed in for reporting 201 purposes. It must never be NULL. 202 **/ 203 typedef 204 VOID 205 (EFIAPI *CALLBACK_FUNCTION) ( 206 IN EFI_HANDLE Handle, 207 IN CONST CHAR16 *ReportText 208 ); 209 210 /** 211 Locate all handles that carry the specified protocol, filter them with a 212 callback function, and pass each handle that passes the filter to another 213 callback. 214 215 @param[in] ProtocolGuid The protocol to look for. 216 217 @param[in] Filter The filter function to pass each handle to. If this 218 parameter is NULL, then all handles are processed. 219 220 @param[in] Process The callback function to pass each handle to that 221 clears the filter. 222 **/ 223 STATIC 224 VOID 225 FilterAndProcess ( 226 IN EFI_GUID *ProtocolGuid, 227 IN FILTER_FUNCTION Filter OPTIONAL, 228 IN CALLBACK_FUNCTION Process 229 ) 230 { 231 EFI_STATUS Status; 232 EFI_HANDLE *Handles; 233 UINTN NoHandles; 234 UINTN Idx; 235 236 Status = gBS->LocateHandleBuffer (ByProtocol, ProtocolGuid, 237 NULL /* SearchKey */, &NoHandles, &Handles); 238 if (EFI_ERROR (Status)) { 239 // 240 // This is not an error, just an informative condition. 241 // 242 DEBUG ((EFI_D_VERBOSE, "%a: %g: %r\n", __FUNCTION__, ProtocolGuid, 243 Status)); 244 return; 245 } 246 247 ASSERT (NoHandles > 0); 248 for (Idx = 0; Idx < NoHandles; ++Idx) { 249 CHAR16 *DevicePathText; 250 STATIC CHAR16 Fallback[] = L"<device path unavailable>"; 251 252 // 253 // The ConvertDevicePathToText() function handles NULL input transparently. 254 // 255 DevicePathText = ConvertDevicePathToText ( 256 DevicePathFromHandle (Handles[Idx]), 257 FALSE, // DisplayOnly 258 FALSE // AllowShortcuts 259 ); 260 if (DevicePathText == NULL) { 261 DevicePathText = Fallback; 262 } 263 264 if (Filter == NULL || Filter (Handles[Idx], DevicePathText)) { 265 Process (Handles[Idx], DevicePathText); 266 } 267 268 if (DevicePathText != Fallback) { 269 FreePool (DevicePathText); 270 } 271 } 272 gBS->FreePool (Handles); 273 } 274 275 276 /** 277 This FILTER_FUNCTION checks if a handle corresponds to a PCI display device. 278 **/ 279 STATIC 280 BOOLEAN 281 EFIAPI 282 IsPciDisplay ( 283 IN EFI_HANDLE Handle, 284 IN CONST CHAR16 *ReportText 285 ) 286 { 287 EFI_STATUS Status; 288 EFI_PCI_IO_PROTOCOL *PciIo; 289 PCI_TYPE00 Pci; 290 291 Status = gBS->HandleProtocol (Handle, &gEfiPciIoProtocolGuid, 292 (VOID**)&PciIo); 293 if (EFI_ERROR (Status)) { 294 // 295 // This is not an error worth reporting. 296 // 297 return FALSE; 298 } 299 300 Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, 0 /* Offset */, 301 sizeof Pci / sizeof (UINT32), &Pci); 302 if (EFI_ERROR (Status)) { 303 DEBUG ((EFI_D_ERROR, "%a: %s: %r\n", __FUNCTION__, ReportText, Status)); 304 return FALSE; 305 } 306 307 return IS_PCI_DISPLAY (&Pci); 308 } 309 310 311 /** 312 This CALLBACK_FUNCTION attempts to connect a handle non-recursively, asking 313 the matching driver to produce all first-level child handles. 314 **/ 315 STATIC 316 VOID 317 EFIAPI 318 Connect ( 319 IN EFI_HANDLE Handle, 320 IN CONST CHAR16 *ReportText 321 ) 322 { 323 EFI_STATUS Status; 324 325 Status = gBS->ConnectController ( 326 Handle, // ControllerHandle 327 NULL, // DriverImageHandle 328 NULL, // RemainingDevicePath -- produce all children 329 FALSE // Recursive 330 ); 331 DEBUG ((EFI_ERROR (Status) ? EFI_D_ERROR : EFI_D_VERBOSE, "%a: %s: %r\n", 332 __FUNCTION__, ReportText, Status)); 333 } 334 335 336 /** 337 This CALLBACK_FUNCTION retrieves the EFI_DEVICE_PATH_PROTOCOL from the 338 handle, and adds it to ConOut and ErrOut. 339 **/ 340 STATIC 341 VOID 342 EFIAPI 343 AddOutput ( 344 IN EFI_HANDLE Handle, 345 IN CONST CHAR16 *ReportText 346 ) 347 { 348 EFI_STATUS Status; 349 EFI_DEVICE_PATH_PROTOCOL *DevicePath; 350 351 DevicePath = DevicePathFromHandle (Handle); 352 if (DevicePath == NULL) { 353 DEBUG ((EFI_D_ERROR, "%a: %s: handle %p: device path not found\n", 354 __FUNCTION__, ReportText, Handle)); 355 return; 356 } 357 358 Status = BdsLibUpdateConsoleVariable (L"ConOut", DevicePath, NULL); 359 if (EFI_ERROR (Status)) { 360 DEBUG ((EFI_D_ERROR, "%a: %s: adding to ConOut: %r\n", __FUNCTION__, 361 ReportText, Status)); 362 return; 363 } 364 365 Status = BdsLibUpdateConsoleVariable (L"ErrOut", DevicePath, NULL); 366 if (EFI_ERROR (Status)) { 367 DEBUG ((EFI_D_ERROR, "%a: %s: adding to ErrOut: %r\n", __FUNCTION__, 368 ReportText, Status)); 369 return; 370 } 371 372 DEBUG ((EFI_D_VERBOSE, "%a: %s: added to ConOut and ErrOut\n", __FUNCTION__, 373 ReportText)); 374 } 375 376 377 /** 378 The function will execute with as the platform policy, current policy 379 is driven by boot mode. IBV/OEM can customize this code for their specific 380 policy action. 381 382 @param DriverOptionList The header of the driver option link list 383 @param BootOptionList The header of the boot option link list 384 @param ProcessCapsules A pointer to ProcessCapsules() 385 @param BaseMemoryTest A pointer to BaseMemoryTest() 386 387 **/ 388 VOID 389 EFIAPI 390 PlatformBdsPolicyBehavior ( 391 IN LIST_ENTRY *DriverOptionList, 392 IN LIST_ENTRY *BootOptionList, 393 IN PROCESS_CAPSULES ProcessCapsules, 394 IN BASEM_MEMORY_TEST BaseMemoryTest 395 ) 396 { 397 // 398 // Locate the PCI root bridges and make the PCI bus driver connect each, 399 // non-recursively. This will produce a number of child handles with PciIo on 400 // them. 401 // 402 FilterAndProcess (&gEfiPciRootBridgeIoProtocolGuid, NULL, Connect); 403 404 // 405 // Find all display class PCI devices (using the handles from the previous 406 // step), and connect them non-recursively. This should produce a number of 407 // child handles with GOPs on them. 408 // 409 FilterAndProcess (&gEfiPciIoProtocolGuid, IsPciDisplay, Connect); 410 411 // 412 // Now add the device path of all handles with GOP on them to ConOut and 413 // ErrOut. 414 // 415 FilterAndProcess (&gEfiGraphicsOutputProtocolGuid, NULL, AddOutput); 416 417 // 418 // Add the hardcoded short-form USB keyboard device path to ConIn. 419 // 420 BdsLibUpdateConsoleVariable (L"ConIn", 421 (EFI_DEVICE_PATH_PROTOCOL *)&mUsbKeyboard, NULL); 422 423 // 424 // Add the hardcoded serial console device path to ConIn, ConOut, ErrOut. 425 // 426 CopyGuid (&mSerialConsole.TermType.Guid, 427 PcdGetPtr (PcdTerminalTypeGuidBuffer)); 428 BdsLibUpdateConsoleVariable (L"ConIn", 429 (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL); 430 BdsLibUpdateConsoleVariable (L"ConOut", 431 (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL); 432 BdsLibUpdateConsoleVariable (L"ErrOut", 433 (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL); 434 435 // 436 // Connect the consoles based on the above variables. 437 // 438 BdsLibConnectAllDefaultConsoles (); 439 440 // 441 // Show the splash screen. 442 // 443 EnableQuietBoot (PcdGetPtr (PcdLogoFile)); 444 445 // 446 // Connect the rest of the devices. 447 // 448 BdsLibConnectAll (); 449 450 // 451 // Process QEMU's -kernel command line option. Note that the kernel booted 452 // this way should receive ACPI tables, which is why we connect all devices 453 // first (see above) -- PCI enumeration blocks ACPI table installation, if 454 // there is a PCI host. 455 // 456 TryRunningQemuKernel (); 457 458 BdsLibEnumerateAllBootOption (BootOptionList); 459 SetBootOrderFromQemu (BootOptionList); 460 // 461 // The BootOrder variable may have changed, reload the in-memory list with 462 // it. 463 // 464 BdsLibBuildOptionFromVar (BootOptionList, L"BootOrder"); 465 466 PlatformBdsEnterFrontPage (GetFrontPageTimeoutFromQemu(), TRUE); 467 } 468 469 /** 470 Hook point after a boot attempt succeeds. We don't expect a boot option to 471 return, so the UEFI 2.0 specification defines that you will default to an 472 interactive mode and stop processing the BootOrder list in this case. This 473 is also a platform implementation and can be customized by IBV/OEM. 474 475 @param Option Pointer to Boot Option that succeeded to boot. 476 477 **/ 478 VOID 479 EFIAPI 480 PlatformBdsBootSuccess ( 481 IN BDS_COMMON_OPTION *Option 482 ) 483 { 484 } 485 486 /** 487 Hook point after a boot attempt fails. 488 489 @param Option Pointer to Boot Option that failed to boot. 490 @param Status Status returned from failed boot. 491 @param ExitData Exit data returned from failed boot. 492 @param ExitDataSize Exit data size returned from failed boot. 493 494 **/ 495 VOID 496 EFIAPI 497 PlatformBdsBootFail ( 498 IN BDS_COMMON_OPTION *Option, 499 IN EFI_STATUS Status, 500 IN CHAR16 *ExitData, 501 IN UINTN ExitDataSize 502 ) 503 { 504 } 505 506 /** 507 This function locks platform flash that is not allowed to be updated during normal boot path. 508 The flash layout is platform specific. 509 **/ 510 VOID 511 EFIAPI 512 PlatformBdsLockNonUpdatableFlash ( 513 VOID 514 ) 515 { 516 return; 517 } 518