]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPkg/Library/PlatformBootManagerLib/PlatformBm.c
ccdb3e0a5d78a51b3aef96d67fbf429e9e82b1bd
[mirror_edk2.git] / ArmPkg / Library / PlatformBootManagerLib / PlatformBm.c
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, 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 <IndustryStandard/Pci22.h>
20 #include <Library/BootLogoLib.h>
21 #include <Library/CapsuleLib.h>
22 #include <Library/DevicePathLib.h>
23 #include <Library/HobLib.h>
24 #include <Library/PcdLib.h>
25 #include <Library/UefiBootManagerLib.h>
26 #include <Library/UefiLib.h>
27 #include <Protocol/DevicePath.h>
28 #include <Protocol/EsrtManagement.h>
29 #include <Protocol/GraphicsOutput.h>
30 #include <Protocol/LoadedImage.h>
31 #include <Protocol/PciIo.h>
32 #include <Protocol/PciRootBridgeIo.h>
33 #include <Guid/EventGroup.h>
34 #include <Guid/TtyTerm.h>
35
36 #include "PlatformBm.h"
37
38 #define DP_NODE_LEN(Type) { (UINT8)sizeof (Type), (UINT8)(sizeof (Type) >> 8) }
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 ((EFI_D_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 FILTER_FUNCTION checks if a handle corresponds to a PCI display device.
232 **/
233 STATIC
234 BOOLEAN
235 EFIAPI
236 IsPciDisplay (
237 IN EFI_HANDLE Handle,
238 IN CONST CHAR16 *ReportText
239 )
240 {
241 EFI_STATUS Status;
242 EFI_PCI_IO_PROTOCOL *PciIo;
243 PCI_TYPE00 Pci;
244
245 Status = gBS->HandleProtocol (Handle, &gEfiPciIoProtocolGuid,
246 (VOID**)&PciIo);
247 if (EFI_ERROR (Status)) {
248 //
249 // This is not an error worth reporting.
250 //
251 return FALSE;
252 }
253
254 Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, 0 /* Offset */,
255 sizeof Pci / sizeof (UINT32), &Pci);
256 if (EFI_ERROR (Status)) {
257 DEBUG ((EFI_D_ERROR, "%a: %s: %r\n", __FUNCTION__, ReportText, Status));
258 return FALSE;
259 }
260
261 return IS_PCI_DISPLAY (&Pci);
262 }
263
264
265 /**
266 This CALLBACK_FUNCTION attempts to connect a handle non-recursively, asking
267 the matching driver to produce all first-level child handles.
268 **/
269 STATIC
270 VOID
271 EFIAPI
272 Connect (
273 IN EFI_HANDLE Handle,
274 IN CONST CHAR16 *ReportText
275 )
276 {
277 EFI_STATUS Status;
278
279 Status = gBS->ConnectController (
280 Handle, // ControllerHandle
281 NULL, // DriverImageHandle
282 NULL, // RemainingDevicePath -- produce all children
283 FALSE // Recursive
284 );
285 DEBUG ((EFI_ERROR (Status) ? EFI_D_ERROR : EFI_D_VERBOSE, "%a: %s: %r\n",
286 __FUNCTION__, ReportText, Status));
287 }
288
289
290 /**
291 This CALLBACK_FUNCTION retrieves the EFI_DEVICE_PATH_PROTOCOL from the
292 handle, and adds it to ConOut and ErrOut.
293 **/
294 STATIC
295 VOID
296 EFIAPI
297 AddOutput (
298 IN EFI_HANDLE Handle,
299 IN CONST CHAR16 *ReportText
300 )
301 {
302 EFI_STATUS Status;
303 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
304
305 DevicePath = DevicePathFromHandle (Handle);
306 if (DevicePath == NULL) {
307 DEBUG ((EFI_D_ERROR, "%a: %s: handle %p: device path not found\n",
308 __FUNCTION__, ReportText, Handle));
309 return;
310 }
311
312 Status = EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
313 if (EFI_ERROR (Status)) {
314 DEBUG ((EFI_D_ERROR, "%a: %s: adding to ConOut: %r\n", __FUNCTION__,
315 ReportText, Status));
316 return;
317 }
318
319 Status = EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);
320 if (EFI_ERROR (Status)) {
321 DEBUG ((EFI_D_ERROR, "%a: %s: adding to ErrOut: %r\n", __FUNCTION__,
322 ReportText, Status));
323 return;
324 }
325
326 DEBUG ((EFI_D_VERBOSE, "%a: %s: added to ConOut and ErrOut\n", __FUNCTION__,
327 ReportText));
328 }
329
330 STATIC
331 VOID
332 PlatformRegisterFvBootOption (
333 CONST EFI_GUID *FileGuid,
334 CHAR16 *Description,
335 UINT32 Attributes
336 )
337 {
338 EFI_STATUS Status;
339 INTN OptionIndex;
340 EFI_BOOT_MANAGER_LOAD_OPTION NewOption;
341 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
342 UINTN BootOptionCount;
343 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode;
344 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
345 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
346
347 Status = gBS->HandleProtocol (
348 gImageHandle,
349 &gEfiLoadedImageProtocolGuid,
350 (VOID **) &LoadedImage
351 );
352 ASSERT_EFI_ERROR (Status);
353
354 EfiInitializeFwVolDevicepathNode (&FileNode, FileGuid);
355 DevicePath = DevicePathFromHandle (LoadedImage->DeviceHandle);
356 ASSERT (DevicePath != NULL);
357 DevicePath = AppendDevicePathNode (
358 DevicePath,
359 (EFI_DEVICE_PATH_PROTOCOL *) &FileNode
360 );
361 ASSERT (DevicePath != NULL);
362
363 Status = EfiBootManagerInitializeLoadOption (
364 &NewOption,
365 LoadOptionNumberUnassigned,
366 LoadOptionTypeBoot,
367 Attributes,
368 Description,
369 DevicePath,
370 NULL,
371 0
372 );
373 ASSERT_EFI_ERROR (Status);
374 FreePool (DevicePath);
375
376 BootOptions = EfiBootManagerGetLoadOptions (
377 &BootOptionCount, LoadOptionTypeBoot
378 );
379
380 OptionIndex = EfiBootManagerFindLoadOption (
381 &NewOption, BootOptions, BootOptionCount
382 );
383
384 if (OptionIndex == -1) {
385 Status = EfiBootManagerAddLoadOptionVariable (&NewOption, MAX_UINTN);
386 ASSERT_EFI_ERROR (Status);
387 }
388 EfiBootManagerFreeLoadOption (&NewOption);
389 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
390 }
391
392
393 STATIC
394 VOID
395 PlatformRegisterOptionsAndKeys (
396 VOID
397 )
398 {
399 EFI_STATUS Status;
400 EFI_INPUT_KEY Enter;
401 EFI_INPUT_KEY F2;
402 EFI_INPUT_KEY Esc;
403 EFI_BOOT_MANAGER_LOAD_OPTION BootOption;
404
405 //
406 // Register ENTER as CONTINUE key
407 //
408 Enter.ScanCode = SCAN_NULL;
409 Enter.UnicodeChar = CHAR_CARRIAGE_RETURN;
410 Status = EfiBootManagerRegisterContinueKeyOption (0, &Enter, NULL);
411 ASSERT_EFI_ERROR (Status);
412
413 //
414 // Map F2 and ESC to Boot Manager Menu
415 //
416 F2.ScanCode = SCAN_F2;
417 F2.UnicodeChar = CHAR_NULL;
418 Esc.ScanCode = SCAN_ESC;
419 Esc.UnicodeChar = CHAR_NULL;
420 Status = EfiBootManagerGetBootManagerMenu (&BootOption);
421 ASSERT_EFI_ERROR (Status);
422 Status = EfiBootManagerAddKeyOptionVariable (
423 NULL, (UINT16) BootOption.OptionNumber, 0, &F2, NULL
424 );
425 ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);
426 Status = EfiBootManagerAddKeyOptionVariable (
427 NULL, (UINT16) BootOption.OptionNumber, 0, &Esc, NULL
428 );
429 ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);
430 }
431
432
433 //
434 // BDS Platform Functions
435 //
436 /**
437 Do the platform init, can be customized by OEM/IBV
438 Possible things that can be done in PlatformBootManagerBeforeConsole:
439 > Update console variable: 1. include hot-plug devices;
440 > 2. Clear ConIn and add SOL for AMT
441 > Register new Driver#### or Boot####
442 > Register new Key####: e.g.: F12
443 > Signal ReadyToLock event
444 > Authentication action: 1. connect Auth devices;
445 > 2. Identify auto logon user.
446 **/
447 VOID
448 EFIAPI
449 PlatformBootManagerBeforeConsole (
450 VOID
451 )
452 {
453 EFI_STATUS Status;
454 ESRT_MANAGEMENT_PROTOCOL *EsrtManagement;
455
456 if (GetBootModeHob() == BOOT_ON_FLASH_UPDATE) {
457 DEBUG ((DEBUG_INFO, "ProcessCapsules Before EndOfDxe ......\n"));
458 Status = ProcessCapsules ();
459 DEBUG ((DEBUG_INFO, "ProcessCapsules returned %r\n", Status));
460 } else {
461 Status = gBS->LocateProtocol (&gEsrtManagementProtocolGuid, NULL,
462 (VOID **)&EsrtManagement);
463 if (!EFI_ERROR (Status)) {
464 EsrtManagement->SyncEsrtFmp ();
465 }
466 }
467
468 //
469 // Signal EndOfDxe PI Event
470 //
471 EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid);
472
473 //
474 // Locate the PCI root bridges and make the PCI bus driver connect each,
475 // non-recursively. This will produce a number of child handles with PciIo on
476 // them.
477 //
478 FilterAndProcess (&gEfiPciRootBridgeIoProtocolGuid, NULL, Connect);
479
480 //
481 // Find all display class PCI devices (using the handles from the previous
482 // step), and connect them non-recursively. This should produce a number of
483 // child handles with GOPs on them.
484 //
485 FilterAndProcess (&gEfiPciIoProtocolGuid, IsPciDisplay, Connect);
486
487 //
488 // Now add the device path of all handles with GOP on them to ConOut and
489 // ErrOut.
490 //
491 FilterAndProcess (&gEfiGraphicsOutputProtocolGuid, NULL, AddOutput);
492
493 //
494 // Add the hardcoded short-form USB keyboard device path to ConIn.
495 //
496 EfiBootManagerUpdateConsoleVariable (ConIn,
497 (EFI_DEVICE_PATH_PROTOCOL *)&mUsbKeyboard, NULL);
498
499 //
500 // Add the hardcoded serial console device path to ConIn, ConOut, ErrOut.
501 //
502 ASSERT (FixedPcdGet8 (PcdDefaultTerminalType) == 4);
503 CopyGuid (&mSerialConsole.TermType.Guid, &gEfiTtyTermGuid);
504
505 EfiBootManagerUpdateConsoleVariable (ConIn,
506 (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);
507 EfiBootManagerUpdateConsoleVariable (ConOut,
508 (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);
509 EfiBootManagerUpdateConsoleVariable (ErrOut,
510 (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);
511
512 //
513 // Register platform-specific boot options and keyboard shortcuts.
514 //
515 PlatformRegisterOptionsAndKeys ();
516 }
517
518 #define VERSION_STRING_PREFIX L"Tianocore/EDK2 firmware version "
519
520 /**
521 Do the platform specific action after the console is ready
522 Possible things that can be done in PlatformBootManagerAfterConsole:
523 > Console post action:
524 > Dynamically switch output mode from 100x31 to 80x25 for certain senarino
525 > Signal console ready platform customized event
526 > Run diagnostics like memory testing
527 > Connect certain devices
528 > Dispatch aditional option roms
529 > Special boot: e.g.: USB boot, enter UI
530 **/
531 VOID
532 EFIAPI
533 PlatformBootManagerAfterConsole (
534 VOID
535 )
536 {
537 ESRT_MANAGEMENT_PROTOCOL *EsrtManagement;
538 EFI_STATUS Status;
539 EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
540 UINTN FirmwareVerLength;
541 UINTN PosX;
542 UINTN PosY;
543
544 FirmwareVerLength = StrLen (PcdGetPtr (PcdFirmwareVersionString));
545
546 //
547 // Show the splash screen.
548 //
549 Status = BootLogoEnableLogo ();
550 if (EFI_ERROR (Status)) {
551 if (FirmwareVerLength > 0) {
552 Print (VERSION_STRING_PREFIX L"%s",
553 PcdGetPtr (PcdFirmwareVersionString));
554 }
555 Print (L"Press ESCAPE for boot options ");
556 } else if (FirmwareVerLength > 0) {
557 Status = gBS->HandleProtocol (gST->ConsoleOutHandle,
558 &gEfiGraphicsOutputProtocolGuid, (VOID **)&GraphicsOutput);
559 if (!EFI_ERROR (Status)) {
560 PosX = (GraphicsOutput->Mode->Info->HorizontalResolution -
561 (StrLen (VERSION_STRING_PREFIX) + FirmwareVerLength) *
562 EFI_GLYPH_WIDTH) / 2;
563 PosY = 0;
564
565 PrintXY (PosX, PosY, NULL, NULL, VERSION_STRING_PREFIX L"%s",
566 PcdGetPtr (PcdFirmwareVersionString));
567 }
568 }
569
570 //
571 // Connect the rest of the devices.
572 //
573 EfiBootManagerConnectAll ();
574
575 Status = gBS->LocateProtocol (&gEsrtManagementProtocolGuid, NULL,
576 (VOID **)&EsrtManagement);
577 if (!EFI_ERROR (Status)) {
578 EsrtManagement->SyncEsrtFmp ();
579 }
580
581 if (GetBootModeHob() == BOOT_ON_FLASH_UPDATE) {
582 DEBUG((DEBUG_INFO, "ProcessCapsules After EndOfDxe ......\n"));
583 Status = ProcessCapsules ();
584 DEBUG((DEBUG_INFO, "ProcessCapsules returned %r\n", Status));
585 }
586
587 //
588 // Enumerate all possible boot options.
589 //
590 EfiBootManagerRefreshAllBootOption ();
591
592 //
593 // Register UEFI Shell
594 //
595 PlatformRegisterFvBootOption (
596 &gUefiShellFileGuid, L"UEFI Shell", LOAD_OPTION_ACTIVE
597 );
598 }
599
600 /**
601 This function is called each second during the boot manager waits the
602 timeout.
603
604 @param TimeoutRemain The remaining timeout.
605 **/
606 VOID
607 EFIAPI
608 PlatformBootManagerWaitCallback (
609 UINT16 TimeoutRemain
610 )
611 {
612 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black;
613 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White;
614 UINT16 Timeout;
615 EFI_STATUS Status;
616
617 Timeout = PcdGet16 (PcdPlatformBootTimeOut);
618
619 Black.Raw = 0x00000000;
620 White.Raw = 0x00FFFFFF;
621
622 Status = BootLogoUpdateProgress (
623 White.Pixel,
624 Black.Pixel,
625 L"Press ESCAPE for boot options",
626 White.Pixel,
627 (Timeout - TimeoutRemain) * 100 / Timeout,
628 0
629 );
630 if (EFI_ERROR (Status)) {
631 Print (L".");
632 }
633 }