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