]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPkg/Library/PlatformBootManagerLib/PlatformBm.c
ArmPkg: Change use of EFI_D_* to DEBUG_*
[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
cae735f6 5 Copyright (c) 2014 - 2021, ARM Ltd. All rights reserved.<BR>\r
eea668c9 6 Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>\r
c976f9cb 7 Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>\r
cae735f6 8 Copyright (c) 2021, Semihalf All rights reserved.<BR>\r
c976f9cb 9\r
4059386c 10 SPDX-License-Identifier: BSD-2-Clause-Patent\r
c976f9cb
AB
11\r
12**/\r
13\r
14#include <IndustryStandard/Pci22.h>\r
a43d75e1 15#include <Library/BootLogoLib.h>\r
4bbcc285 16#include <Library/CapsuleLib.h>\r
c976f9cb 17#include <Library/DevicePathLib.h>\r
4bbcc285 18#include <Library/HobLib.h>\r
c976f9cb
AB
19#include <Library/PcdLib.h>\r
20#include <Library/UefiBootManagerLib.h>\r
21#include <Library/UefiLib.h>\r
cae82316 22#include <Library/UefiRuntimeServicesTableLib.h>\r
cae735f6 23#include <Protocol/BootManagerPolicy.h>\r
c976f9cb 24#include <Protocol/DevicePath.h>\r
13ca0abb 25#include <Protocol/EsrtManagement.h>\r
c976f9cb
AB
26#include <Protocol/GraphicsOutput.h>\r
27#include <Protocol/LoadedImage.h>\r
0ae52d4f 28#include <Protocol/NonDiscoverableDevice.h>\r
c976f9cb
AB
29#include <Protocol/PciIo.h>\r
30#include <Protocol/PciRootBridgeIo.h>\r
1b6e7633 31#include <Protocol/PlatformBootManager.h>\r
cae735f6 32#include <Guid/BootDiscoveryPolicy.h>\r
c976f9cb 33#include <Guid/EventGroup.h>\r
0ae52d4f 34#include <Guid/NonDiscoverableDevice.h>\r
c976f9cb 35#include <Guid/TtyTerm.h>\r
6631c096 36#include <Guid/SerialPortLibVendor.h>\r
c976f9cb
AB
37\r
38#include "PlatformBm.h"\r
39\r
40#define DP_NODE_LEN(Type) { (UINT8)sizeof (Type), (UINT8)(sizeof (Type) >> 8) }\r
41\r
c976f9cb
AB
42#pragma pack (1)\r
43typedef struct {\r
44 VENDOR_DEVICE_PATH SerialDxe;\r
45 UART_DEVICE_PATH Uart;\r
46 VENDOR_DEFINED_DEVICE_PATH TermType;\r
47 EFI_DEVICE_PATH_PROTOCOL End;\r
48} PLATFORM_SERIAL_CONSOLE;\r
49#pragma pack ()\r
50\r
c976f9cb
AB
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
6631c096 57 EDKII_SERIAL_PORT_LIB_VENDOR_GUID\r
c976f9cb
AB
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
a4a582e1 193 DEBUG ((DEBUG_VERBOSE, "%a: %g: %r\n", __FUNCTION__, ProtocolGuid,\r
c976f9cb
AB
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
a4a582e1 254 DEBUG ((DEBUG_ERROR, "%a: %s: %r\n", __FUNCTION__, ReportText, Status));\r
c976f9cb
AB
255 return FALSE;\r
256 }\r
257\r
258 return IS_PCI_DISPLAY (&Pci);\r
259}\r
260\r
261\r
0ae52d4f
AB
262/**\r
263 This FILTER_FUNCTION checks if a handle corresponds to a non-discoverable\r
264 USB host controller.\r
265**/\r
266STATIC\r
267BOOLEAN\r
268EFIAPI\r
269IsUsbHost (\r
270 IN EFI_HANDLE Handle,\r
271 IN CONST CHAR16 *ReportText\r
272 )\r
273{\r
274 NON_DISCOVERABLE_DEVICE *Device;\r
275 EFI_STATUS Status;\r
276\r
277 Status = gBS->HandleProtocol (Handle,\r
278 &gEdkiiNonDiscoverableDeviceProtocolGuid,\r
279 (VOID **)&Device);\r
280 if (EFI_ERROR (Status)) {\r
281 return FALSE;\r
282 }\r
283\r
284 if (CompareGuid (Device->Type, &gEdkiiNonDiscoverableUhciDeviceGuid) ||\r
285 CompareGuid (Device->Type, &gEdkiiNonDiscoverableEhciDeviceGuid) ||\r
286 CompareGuid (Device->Type, &gEdkiiNonDiscoverableXhciDeviceGuid)) {\r
287 return TRUE;\r
288 }\r
289 return FALSE;\r
290}\r
291\r
292\r
c976f9cb
AB
293/**\r
294 This CALLBACK_FUNCTION attempts to connect a handle non-recursively, asking\r
295 the matching driver to produce all first-level child handles.\r
296**/\r
297STATIC\r
298VOID\r
299EFIAPI\r
300Connect (\r
301 IN EFI_HANDLE Handle,\r
302 IN CONST CHAR16 *ReportText\r
303 )\r
304{\r
305 EFI_STATUS Status;\r
306\r
307 Status = gBS->ConnectController (\r
308 Handle, // ControllerHandle\r
309 NULL, // DriverImageHandle\r
310 NULL, // RemainingDevicePath -- produce all children\r
311 FALSE // Recursive\r
312 );\r
a4a582e1 313 DEBUG ((EFI_ERROR (Status) ? DEBUG_ERROR : DEBUG_VERBOSE, "%a: %s: %r\n",\r
c976f9cb
AB
314 __FUNCTION__, ReportText, Status));\r
315}\r
316\r
317\r
318/**\r
319 This CALLBACK_FUNCTION retrieves the EFI_DEVICE_PATH_PROTOCOL from the\r
320 handle, and adds it to ConOut and ErrOut.\r
321**/\r
322STATIC\r
323VOID\r
324EFIAPI\r
325AddOutput (\r
326 IN EFI_HANDLE Handle,\r
327 IN CONST CHAR16 *ReportText\r
328 )\r
329{\r
330 EFI_STATUS Status;\r
331 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
332\r
333 DevicePath = DevicePathFromHandle (Handle);\r
334 if (DevicePath == NULL) {\r
a4a582e1 335 DEBUG ((DEBUG_ERROR, "%a: %s: handle %p: device path not found\n",\r
c976f9cb
AB
336 __FUNCTION__, ReportText, Handle));\r
337 return;\r
338 }\r
339\r
340 Status = EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);\r
341 if (EFI_ERROR (Status)) {\r
a4a582e1 342 DEBUG ((DEBUG_ERROR, "%a: %s: adding to ConOut: %r\n", __FUNCTION__,\r
c976f9cb
AB
343 ReportText, Status));\r
344 return;\r
345 }\r
346\r
347 Status = EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);\r
348 if (EFI_ERROR (Status)) {\r
a4a582e1 349 DEBUG ((DEBUG_ERROR, "%a: %s: adding to ErrOut: %r\n", __FUNCTION__,\r
c976f9cb
AB
350 ReportText, Status));\r
351 return;\r
352 }\r
353\r
a4a582e1 354 DEBUG ((DEBUG_VERBOSE, "%a: %s: added to ConOut and ErrOut\n", __FUNCTION__,\r
c976f9cb
AB
355 ReportText));\r
356}\r
357\r
358STATIC\r
359VOID\r
360PlatformRegisterFvBootOption (\r
07548e17 361 CONST EFI_GUID *FileGuid,\r
c976f9cb 362 CHAR16 *Description,\r
321b0788
AB
363 UINT32 Attributes,\r
364 EFI_INPUT_KEY *Key\r
c976f9cb
AB
365 )\r
366{\r
367 EFI_STATUS Status;\r
368 INTN OptionIndex;\r
369 EFI_BOOT_MANAGER_LOAD_OPTION NewOption;\r
370 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;\r
371 UINTN BootOptionCount;\r
372 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode;\r
373 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;\r
374 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
375\r
376 Status = gBS->HandleProtocol (\r
377 gImageHandle,\r
378 &gEfiLoadedImageProtocolGuid,\r
379 (VOID **) &LoadedImage\r
380 );\r
381 ASSERT_EFI_ERROR (Status);\r
382\r
383 EfiInitializeFwVolDevicepathNode (&FileNode, FileGuid);\r
384 DevicePath = DevicePathFromHandle (LoadedImage->DeviceHandle);\r
385 ASSERT (DevicePath != NULL);\r
386 DevicePath = AppendDevicePathNode (\r
387 DevicePath,\r
388 (EFI_DEVICE_PATH_PROTOCOL *) &FileNode\r
389 );\r
390 ASSERT (DevicePath != NULL);\r
391\r
392 Status = EfiBootManagerInitializeLoadOption (\r
393 &NewOption,\r
394 LoadOptionNumberUnassigned,\r
395 LoadOptionTypeBoot,\r
396 Attributes,\r
397 Description,\r
398 DevicePath,\r
399 NULL,\r
400 0\r
401 );\r
402 ASSERT_EFI_ERROR (Status);\r
403 FreePool (DevicePath);\r
404\r
405 BootOptions = EfiBootManagerGetLoadOptions (\r
406 &BootOptionCount, LoadOptionTypeBoot\r
407 );\r
408\r
409 OptionIndex = EfiBootManagerFindLoadOption (\r
410 &NewOption, BootOptions, BootOptionCount\r
411 );\r
412\r
413 if (OptionIndex == -1) {\r
414 Status = EfiBootManagerAddLoadOptionVariable (&NewOption, MAX_UINTN);\r
415 ASSERT_EFI_ERROR (Status);\r
321b0788
AB
416 Status = EfiBootManagerAddKeyOptionVariable (NULL,\r
417 (UINT16)NewOption.OptionNumber, 0, Key, NULL);\r
418 ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);\r
c976f9cb
AB
419 }\r
420 EfiBootManagerFreeLoadOption (&NewOption);\r
421 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);\r
422}\r
423\r
424\r
1b6e7633
HZ
425STATIC\r
426VOID\r
427GetPlatformOptions (\r
428 VOID\r
429 )\r
430{\r
431 EFI_STATUS Status;\r
432 EFI_BOOT_MANAGER_LOAD_OPTION *CurrentBootOptions;\r
433 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;\r
434 EFI_INPUT_KEY *BootKeys;\r
435 PLATFORM_BOOT_MANAGER_PROTOCOL *PlatformBootManager;\r
436 UINTN CurrentBootOptionCount;\r
437 UINTN Index;\r
438 UINTN BootCount;\r
439\r
440 Status = gBS->LocateProtocol (&gPlatformBootManagerProtocolGuid, NULL,\r
441 (VOID **)&PlatformBootManager);\r
442 if (EFI_ERROR (Status)) {\r
443 return;\r
444 }\r
445 Status = PlatformBootManager->GetPlatformBootOptionsAndKeys (\r
446 &BootCount,\r
447 &BootOptions,\r
448 &BootKeys\r
449 );\r
450 if (EFI_ERROR (Status)) {\r
451 return;\r
452 }\r
453 //\r
454 // Fetch the existent boot options. If there are none, CurrentBootCount\r
455 // will be zeroed.\r
456 //\r
457 CurrentBootOptions = EfiBootManagerGetLoadOptions (\r
458 &CurrentBootOptionCount,\r
459 LoadOptionTypeBoot\r
460 );\r
461 //\r
462 // Process the platform boot options.\r
463 //\r
464 for (Index = 0; Index < BootCount; Index++) {\r
465 INTN Match;\r
466 UINTN BootOptionNumber;\r
467\r
468 //\r
469 // If there are any preexistent boot options, and the subject platform boot\r
470 // option is already among them, then don't try to add it. Just get its\r
471 // assigned boot option number so we can associate a hotkey with it. Note\r
472 // that EfiBootManagerFindLoadOption() deals fine with (CurrentBootOptions\r
473 // == NULL) if (CurrentBootCount == 0).\r
474 //\r
475 Match = EfiBootManagerFindLoadOption (\r
476 &BootOptions[Index],\r
477 CurrentBootOptions,\r
478 CurrentBootOptionCount\r
479 );\r
480 if (Match >= 0) {\r
481 BootOptionNumber = CurrentBootOptions[Match].OptionNumber;\r
482 } else {\r
483 //\r
484 // Add the platform boot options as a new one, at the end of the boot\r
485 // order. Note that if the platform provided this boot option with an\r
486 // unassigned option number, then the below function call will assign a\r
487 // number.\r
488 //\r
489 Status = EfiBootManagerAddLoadOptionVariable (\r
490 &BootOptions[Index],\r
491 MAX_UINTN\r
492 );\r
493 if (EFI_ERROR (Status)) {\r
494 DEBUG ((DEBUG_ERROR, "%a: failed to register \"%s\": %r\n",\r
495 __FUNCTION__, BootOptions[Index].Description, Status));\r
496 continue;\r
497 }\r
498 BootOptionNumber = BootOptions[Index].OptionNumber;\r
499 }\r
500\r
501 //\r
502 // Register a hotkey with the boot option, if requested.\r
503 //\r
504 if (BootKeys[Index].UnicodeChar == L'\0') {\r
505 continue;\r
506 }\r
507\r
508 Status = EfiBootManagerAddKeyOptionVariable (\r
509 NULL,\r
510 BootOptionNumber,\r
511 0,\r
2b2959dd 512 &BootKeys[Index],\r
1b6e7633
HZ
513 NULL\r
514 );\r
515 if (EFI_ERROR (Status)) {\r
516 DEBUG ((DEBUG_ERROR, "%a: failed to register hotkey for \"%s\": %r\n",\r
517 __FUNCTION__, BootOptions[Index].Description, Status));\r
518 }\r
519 }\r
520 EfiBootManagerFreeLoadOptions (CurrentBootOptions, CurrentBootOptionCount);\r
521 EfiBootManagerFreeLoadOptions (BootOptions, BootCount);\r
522 FreePool (BootKeys);\r
523}\r
524\r
c976f9cb
AB
525STATIC\r
526VOID\r
527PlatformRegisterOptionsAndKeys (\r
528 VOID\r
529 )\r
530{\r
531 EFI_STATUS Status;\r
532 EFI_INPUT_KEY Enter;\r
533 EFI_INPUT_KEY F2;\r
534 EFI_INPUT_KEY Esc;\r
535 EFI_BOOT_MANAGER_LOAD_OPTION BootOption;\r
536\r
1b6e7633
HZ
537 GetPlatformOptions ();\r
538\r
c976f9cb
AB
539 //\r
540 // Register ENTER as CONTINUE key\r
541 //\r
542 Enter.ScanCode = SCAN_NULL;\r
543 Enter.UnicodeChar = CHAR_CARRIAGE_RETURN;\r
544 Status = EfiBootManagerRegisterContinueKeyOption (0, &Enter, NULL);\r
545 ASSERT_EFI_ERROR (Status);\r
546\r
547 //\r
548 // Map F2 and ESC to Boot Manager Menu\r
549 //\r
550 F2.ScanCode = SCAN_F2;\r
551 F2.UnicodeChar = CHAR_NULL;\r
552 Esc.ScanCode = SCAN_ESC;\r
553 Esc.UnicodeChar = CHAR_NULL;\r
554 Status = EfiBootManagerGetBootManagerMenu (&BootOption);\r
555 ASSERT_EFI_ERROR (Status);\r
556 Status = EfiBootManagerAddKeyOptionVariable (\r
557 NULL, (UINT16) BootOption.OptionNumber, 0, &F2, NULL\r
558 );\r
559 ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);\r
560 Status = EfiBootManagerAddKeyOptionVariable (\r
561 NULL, (UINT16) BootOption.OptionNumber, 0, &Esc, NULL\r
562 );\r
563 ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);\r
564}\r
565\r
566\r
567//\r
568// BDS Platform Functions\r
569//\r
570/**\r
571 Do the platform init, can be customized by OEM/IBV\r
572 Possible things that can be done in PlatformBootManagerBeforeConsole:\r
573 > Update console variable: 1. include hot-plug devices;\r
574 > 2. Clear ConIn and add SOL for AMT\r
575 > Register new Driver#### or Boot####\r
576 > Register new Key####: e.g.: F12\r
577 > Signal ReadyToLock event\r
578 > Authentication action: 1. connect Auth devices;\r
579 > 2. Identify auto logon user.\r
580**/\r
581VOID\r
582EFIAPI\r
583PlatformBootManagerBeforeConsole (\r
584 VOID\r
585 )\r
586{\r
587 //\r
588 // Signal EndOfDxe PI Event\r
589 //\r
590 EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid);\r
591\r
0f9395d7
SM
592 //\r
593 // Dispatch deferred images after EndOfDxe event.\r
594 //\r
595 EfiBootManagerDispatchDeferredImages ();\r
596\r
c976f9cb
AB
597 //\r
598 // Locate the PCI root bridges and make the PCI bus driver connect each,\r
599 // non-recursively. This will produce a number of child handles with PciIo on\r
600 // them.\r
601 //\r
602 FilterAndProcess (&gEfiPciRootBridgeIoProtocolGuid, NULL, Connect);\r
603\r
604 //\r
605 // Find all display class PCI devices (using the handles from the previous\r
606 // step), and connect them non-recursively. This should produce a number of\r
607 // child handles with GOPs on them.\r
608 //\r
609 FilterAndProcess (&gEfiPciIoProtocolGuid, IsPciDisplay, Connect);\r
610\r
611 //\r
612 // Now add the device path of all handles with GOP on them to ConOut and\r
613 // ErrOut.\r
614 //\r
615 FilterAndProcess (&gEfiGraphicsOutputProtocolGuid, NULL, AddOutput);\r
616\r
0ae52d4f
AB
617 //\r
618 // The core BDS code connects short-form USB device paths by explicitly\r
619 // looking for handles with PCI I/O installed, and checking the PCI class\r
620 // code whether it matches the one for a USB host controller. This means\r
621 // non-discoverable USB host controllers need to have the non-discoverable\r
622 // PCI driver attached first.\r
623 //\r
624 FilterAndProcess (&gEdkiiNonDiscoverableDeviceProtocolGuid, IsUsbHost, Connect);\r
625\r
c976f9cb
AB
626 //\r
627 // Add the hardcoded short-form USB keyboard device path to ConIn.\r
628 //\r
629 EfiBootManagerUpdateConsoleVariable (ConIn,\r
630 (EFI_DEVICE_PATH_PROTOCOL *)&mUsbKeyboard, NULL);\r
631\r
632 //\r
633 // Add the hardcoded serial console device path to ConIn, ConOut, ErrOut.\r
634 //\r
b1d3895f
AB
635 STATIC_ASSERT (FixedPcdGet8 (PcdDefaultTerminalType) == 4,\r
636 "PcdDefaultTerminalType must be TTYTERM");\r
7191dd3c
AB
637 STATIC_ASSERT (FixedPcdGet8 (PcdUartDefaultParity) != 0,\r
638 "PcdUartDefaultParity must be set to an actual value, not 'default'");\r
639 STATIC_ASSERT (FixedPcdGet8 (PcdUartDefaultStopBits) != 0,\r
640 "PcdUartDefaultStopBits must be set to an actual value, not 'default'");\r
b1d3895f 641\r
c976f9cb
AB
642 CopyGuid (&mSerialConsole.TermType.Guid, &gEfiTtyTermGuid);\r
643\r
644 EfiBootManagerUpdateConsoleVariable (ConIn,\r
645 (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);\r
646 EfiBootManagerUpdateConsoleVariable (ConOut,\r
647 (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);\r
648 EfiBootManagerUpdateConsoleVariable (ErrOut,\r
649 (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);\r
650\r
651 //\r
652 // Register platform-specific boot options and keyboard shortcuts.\r
653 //\r
654 PlatformRegisterOptionsAndKeys ();\r
655}\r
656\r
cae82316
AB
657STATIC\r
658VOID\r
659HandleCapsules (\r
660 VOID\r
661 )\r
662{\r
663 ESRT_MANAGEMENT_PROTOCOL *EsrtManagement;\r
664 EFI_PEI_HOB_POINTERS HobPointer;\r
665 EFI_CAPSULE_HEADER *CapsuleHeader;\r
666 BOOLEAN NeedReset;\r
667 EFI_STATUS Status;\r
668\r
669 DEBUG ((DEBUG_INFO, "%a: processing capsules ...\n", __FUNCTION__));\r
670\r
671 Status = gBS->LocateProtocol (&gEsrtManagementProtocolGuid, NULL,\r
672 (VOID **)&EsrtManagement);\r
673 if (!EFI_ERROR (Status)) {\r
674 EsrtManagement->SyncEsrtFmp ();\r
675 }\r
676\r
677 //\r
678 // Find all capsule images from hob\r
679 //\r
680 HobPointer.Raw = GetHobList ();\r
681 NeedReset = FALSE;\r
682 while ((HobPointer.Raw = GetNextHob (EFI_HOB_TYPE_UEFI_CAPSULE,\r
683 HobPointer.Raw)) != NULL) {\r
684 CapsuleHeader = (VOID *)(UINTN)HobPointer.Capsule->BaseAddress;\r
685\r
686 Status = ProcessCapsuleImage (CapsuleHeader);\r
687 if (EFI_ERROR (Status)) {\r
688 DEBUG ((DEBUG_ERROR, "%a: failed to process capsule %p - %r\n",\r
689 __FUNCTION__, CapsuleHeader, Status));\r
690 return;\r
691 }\r
692\r
693 NeedReset = TRUE;\r
694 HobPointer.Raw = GET_NEXT_HOB (HobPointer);\r
695 }\r
696\r
697 if (NeedReset) {\r
698 DEBUG ((DEBUG_WARN, "%a: capsule update successful, resetting ...\n",\r
699 __FUNCTION__));\r
700\r
701 gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);\r
702 CpuDeadLoop();\r
703 }\r
704}\r
705\r
706\r
6c4194c9
AB
707#define VERSION_STRING_PREFIX L"Tianocore/EDK2 firmware version "\r
708\r
cae735f6
GB
709/**\r
710 This functions checks the value of BootDiscoverPolicy variable and\r
711 connect devices of class specified by that variable. Then it refreshes\r
712 Boot order for newly discovered boot device.\r
713\r
714 @retval EFI_SUCCESS Devices connected successfully or connection\r
715 not required.\r
716 @retval others Return values from GetVariable(), LocateProtocol()\r
717 and ConnectDeviceClass().\r
718**/\r
719STATIC\r
720EFI_STATUS\r
721BootDiscoveryPolicyHandler (\r
722 VOID\r
723 )\r
724{\r
725 EFI_STATUS Status;\r
726 UINT32 DiscoveryPolicy;\r
727 UINT32 DiscoveryPolicyOld;\r
728 UINTN Size;\r
729 EFI_BOOT_MANAGER_POLICY_PROTOCOL *BMPolicy;\r
730 EFI_GUID *Class;\r
731\r
732 Size = sizeof (DiscoveryPolicy);\r
733 Status = gRT->GetVariable (\r
734 BOOT_DISCOVERY_POLICY_VAR,\r
735 &gBootDiscoveryPolicyMgrFormsetGuid,\r
736 NULL,\r
737 &Size,\r
738 &DiscoveryPolicy\r
739 );\r
740 if (Status == EFI_NOT_FOUND) {\r
741 DiscoveryPolicy = PcdGet32 (PcdBootDiscoveryPolicy);\r
742 Status = PcdSet32S (PcdBootDiscoveryPolicy, DiscoveryPolicy);\r
743 if (Status == EFI_NOT_FOUND) {\r
744 return EFI_SUCCESS;\r
745 } else if (EFI_ERROR (Status)) {\r
746 return Status;\r
747 }\r
748 } else if (EFI_ERROR (Status)) {\r
749 return Status;\r
750 }\r
751\r
752 if (DiscoveryPolicy == BDP_CONNECT_MINIMAL) {\r
753 return EFI_SUCCESS;\r
754 }\r
755\r
756 switch (DiscoveryPolicy) {\r
757 case BDP_CONNECT_NET:\r
758 Class = &gEfiBootManagerPolicyNetworkGuid;\r
759 break;\r
760 case BDP_CONNECT_ALL:\r
761 Class = &gEfiBootManagerPolicyConnectAllGuid;\r
762 break;\r
763 default:\r
764 DEBUG ((\r
765 DEBUG_INFO,\r
766 "%a - Unexpected DiscoveryPolicy (0x%x). Run Minimal Discovery Policy\n",\r
767 __FUNCTION__,\r
768 DiscoveryPolicy\r
769 ));\r
770 return EFI_SUCCESS;\r
771 }\r
772\r
773 Status = gBS->LocateProtocol (\r
774 &gEfiBootManagerPolicyProtocolGuid,\r
775 NULL,\r
776 (VOID **)&BMPolicy\r
777 );\r
778 if (EFI_ERROR (Status)) {\r
779 DEBUG ((DEBUG_INFO, "%a - Failed to locate gEfiBootManagerPolicyProtocolGuid."\r
780 "Driver connect will be skipped.\n", __FUNCTION__));\r
781 return Status;\r
782 }\r
783\r
784 Status = BMPolicy->ConnectDeviceClass (BMPolicy, Class);\r
785 if (EFI_ERROR (Status)){\r
786 DEBUG ((DEBUG_ERROR, "%a - ConnectDeviceClass returns - %r\n", __FUNCTION__, Status));\r
787 return Status;\r
788 }\r
789\r
790 //\r
791 // Refresh Boot Options if Boot Discovery Policy has been changed\r
792 //\r
793 Size = sizeof (DiscoveryPolicyOld);\r
794 Status = gRT->GetVariable (\r
795 BOOT_DISCOVERY_POLICY_OLD_VAR,\r
796 &gBootDiscoveryPolicyMgrFormsetGuid,\r
797 NULL,\r
798 &Size,\r
799 &DiscoveryPolicyOld\r
800 );\r
801 if ((Status == EFI_NOT_FOUND) || (DiscoveryPolicyOld != DiscoveryPolicy)) {\r
802 EfiBootManagerRefreshAllBootOption ();\r
803\r
804 Status = gRT->SetVariable (\r
805 BOOT_DISCOVERY_POLICY_OLD_VAR,\r
806 &gBootDiscoveryPolicyMgrFormsetGuid,\r
807 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
808 sizeof (DiscoveryPolicyOld),\r
809 &DiscoveryPolicy\r
810 );\r
811 }\r
812\r
813 return EFI_SUCCESS;\r
814}\r
815\r
c976f9cb
AB
816/**\r
817 Do the platform specific action after the console is ready\r
818 Possible things that can be done in PlatformBootManagerAfterConsole:\r
819 > Console post action:\r
ff5fef14 820 > Dynamically switch output mode from 100x31 to 80x25 for certain scenario\r
c976f9cb
AB
821 > Signal console ready platform customized event\r
822 > Run diagnostics like memory testing\r
823 > Connect certain devices\r
ff5fef14 824 > Dispatch additional option roms\r
c976f9cb
AB
825 > Special boot: e.g.: USB boot, enter UI\r
826**/\r
827VOID\r
828EFIAPI\r
829PlatformBootManagerAfterConsole (\r
830 VOID\r
831 )\r
832{\r
13ca0abb 833 EFI_STATUS Status;\r
6c4194c9
AB
834 EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;\r
835 UINTN FirmwareVerLength;\r
836 UINTN PosX;\r
837 UINTN PosY;\r
321b0788 838 EFI_INPUT_KEY Key;\r
6c4194c9
AB
839\r
840 FirmwareVerLength = StrLen (PcdGetPtr (PcdFirmwareVersionString));\r
c976f9cb
AB
841\r
842 //\r
843 // Show the splash screen.\r
844 //\r
a43d75e1
AB
845 Status = BootLogoEnableLogo ();\r
846 if (EFI_ERROR (Status)) {\r
6c4194c9 847 if (FirmwareVerLength > 0) {\r
26b99f3b 848 Print (VERSION_STRING_PREFIX L"%s\n",\r
6c4194c9
AB
849 PcdGetPtr (PcdFirmwareVersionString));\r
850 }\r
a43d75e1 851 Print (L"Press ESCAPE for boot options ");\r
6c4194c9
AB
852 } else if (FirmwareVerLength > 0) {\r
853 Status = gBS->HandleProtocol (gST->ConsoleOutHandle,\r
854 &gEfiGraphicsOutputProtocolGuid, (VOID **)&GraphicsOutput);\r
855 if (!EFI_ERROR (Status)) {\r
856 PosX = (GraphicsOutput->Mode->Info->HorizontalResolution -\r
857 (StrLen (VERSION_STRING_PREFIX) + FirmwareVerLength) *\r
858 EFI_GLYPH_WIDTH) / 2;\r
859 PosY = 0;\r
860\r
861 PrintXY (PosX, PosY, NULL, NULL, VERSION_STRING_PREFIX L"%s",\r
862 PcdGetPtr (PcdFirmwareVersionString));\r
863 }\r
a43d75e1 864 }\r
6c4194c9 865\r
cae735f6
GB
866 //\r
867 // Connect device specified by BootDiscoverPolicy variable and\r
868 // refresh Boot order for newly discovered boot devices\r
869 //\r
870 BootDiscoveryPolicyHandler ();\r
871\r
cae82316
AB
872 //\r
873 // On ARM, there is currently no reason to use the phased capsule\r
874 // update approach where some capsules are dispatched before EndOfDxe\r
875 // and some are dispatched after. So just handle all capsules here,\r
876 // when the console is up and we can actually give the user some\r
877 // feedback about what is going on.\r
878 //\r
879 HandleCapsules ();\r
4bbcc285 880\r
c976f9cb
AB
881 //\r
882 // Register UEFI Shell\r
883 //\r
321b0788
AB
884 Key.ScanCode = SCAN_NULL;\r
885 Key.UnicodeChar = L's';\r
344f615d 886 PlatformRegisterFvBootOption (&gUefiShellFileGuid, L"UEFI Shell", 0, &Key);\r
c976f9cb
AB
887}\r
888\r
889/**\r
890 This function is called each second during the boot manager waits the\r
891 timeout.\r
892\r
893 @param TimeoutRemain The remaining timeout.\r
894**/\r
895VOID\r
896EFIAPI\r
897PlatformBootManagerWaitCallback (\r
898 UINT16 TimeoutRemain\r
899 )\r
900{\r
a43d75e1
AB
901 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black;\r
902 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White;\r
903 UINT16 Timeout;\r
904 EFI_STATUS Status;\r
905\r
906 Timeout = PcdGet16 (PcdPlatformBootTimeOut);\r
907\r
908 Black.Raw = 0x00000000;\r
909 White.Raw = 0x00FFFFFF;\r
910\r
911 Status = BootLogoUpdateProgress (\r
912 White.Pixel,\r
913 Black.Pixel,\r
914 L"Press ESCAPE for boot options",\r
915 White.Pixel,\r
916 (Timeout - TimeoutRemain) * 100 / Timeout,\r
917 0\r
918 );\r
919 if (EFI_ERROR (Status)) {\r
920 Print (L".");\r
921 }\r
c976f9cb 922}\r
eea668c9
RN
923\r
924/**\r
925 The function is called when no boot option could be launched,\r
926 including platform recovery options and options pointing to applications\r
927 built into firmware volumes.\r
928\r
929 If this function returns, BDS attempts to enter an infinite loop.\r
930**/\r
931VOID\r
932EFIAPI\r
933PlatformBootManagerUnableToBoot (\r
934 VOID\r
935 )\r
936{\r
40e2e3ca
AB
937 EFI_STATUS Status;\r
938 EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu;\r
2d233af6
AB
939 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;\r
940 UINTN OldBootOptionCount;\r
941 UINTN NewBootOptionCount;\r
942\r
943 //\r
944 // Record the total number of boot configured boot options\r
945 //\r
946 BootOptions = EfiBootManagerGetLoadOptions (&OldBootOptionCount,\r
947 LoadOptionTypeBoot);\r
948 EfiBootManagerFreeLoadOptions (BootOptions, OldBootOptionCount);\r
949\r
950 //\r
951 // Connect all devices, and regenerate all boot options\r
952 //\r
953 EfiBootManagerConnectAll ();\r
954 EfiBootManagerRefreshAllBootOption ();\r
955\r
956 //\r
957 // Record the updated number of boot configured boot options\r
958 //\r
959 BootOptions = EfiBootManagerGetLoadOptions (&NewBootOptionCount,\r
960 LoadOptionTypeBoot);\r
961 EfiBootManagerFreeLoadOptions (BootOptions, NewBootOptionCount);\r
962\r
963 //\r
964 // If the number of configured boot options has changed, reboot\r
965 // the system so the new boot options will be taken into account\r
966 // while executing the ordinary BDS bootflow sequence.\r
1b6c3a94
LL
967 // *Unless* persistent varstore is being emulated, since we would\r
968 // then end up in an endless reboot loop.\r
2d233af6 969 //\r
1b6c3a94
LL
970 if (!PcdGetBool (PcdEmuVariableNvModeEnable)) {\r
971 if (NewBootOptionCount != OldBootOptionCount) {\r
972 DEBUG ((DEBUG_WARN, "%a: rebooting after refreshing all boot options\n",\r
973 __FUNCTION__));\r
974 gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);\r
975 }\r
2d233af6 976 }\r
40e2e3ca
AB
977\r
978 Status = EfiBootManagerGetBootManagerMenu (&BootManagerMenu);\r
979 if (EFI_ERROR (Status)) {\r
980 return;\r
981 }\r
982\r
983 for (;;) {\r
984 EfiBootManagerBoot (&BootManagerMenu);\r
985 }\r
eea668c9 986}\r