]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPkg/Library/PlatformBootManagerLib/PlatformBm.c
ArmPkg: Apply uncrustify changes
[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
429309e0 40#define DP_NODE_LEN(Type) { (UINT8)sizeof (Type), (UINT8)(sizeof (Type) >> 8) }\r
c976f9cb 41\r
c976f9cb
AB
42#pragma pack (1)\r
43typedef struct {\r
429309e0
MK
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
c976f9cb
AB
48} PLATFORM_SERIAL_CONSOLE;\r
49#pragma pack ()\r
50\r
429309e0 51STATIC PLATFORM_SERIAL_CONSOLE mSerialConsole = {\r
c976f9cb
AB
52 //\r
53 // VENDOR_DEVICE_PATH SerialDxe\r
54 //\r
55 {\r
429309e0 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
429309e0 64 { MESSAGING_DEVICE_PATH, MSG_UART_DP, DP_NODE_LEN (UART_DEVICE_PATH) },\r
c976f9cb
AB
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
c976f9cb
AB
94#pragma pack (1)\r
95typedef struct {\r
429309e0
MK
96 USB_CLASS_DEVICE_PATH Keyboard;\r
97 EFI_DEVICE_PATH_PROTOCOL End;\r
c976f9cb
AB
98} PLATFORM_USB_KEYBOARD;\r
99#pragma pack ()\r
100\r
429309e0 101STATIC PLATFORM_USB_KEYBOARD mUsbKeyboard = {\r
c976f9cb
AB
102 //\r
103 // USB_CLASS_DEVICE_PATH Keyboard\r
104 //\r
105 {\r
106 {\r
107 MESSAGING_DEVICE_PATH, MSG_USB_CLASS_DP,\r
108 DP_NODE_LEN (USB_CLASS_DEVICE_PATH)\r
109 },\r
110 0xFFFF, // VendorId: any\r
111 0xFFFF, // ProductId: any\r
112 3, // DeviceClass: HID\r
113 1, // DeviceSubClass: boot\r
114 1 // DeviceProtocol: keyboard\r
115 },\r
116\r
117 //\r
118 // EFI_DEVICE_PATH_PROTOCOL End\r
119 //\r
120 {\r
121 END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
122 DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL)\r
123 }\r
124};\r
125\r
c976f9cb
AB
126/**\r
127 Check if the handle satisfies a particular condition.\r
128\r
129 @param[in] Handle The handle to check.\r
130 @param[in] ReportText A caller-allocated string passed in for reporting\r
131 purposes. It must never be NULL.\r
132\r
133 @retval TRUE The condition is satisfied.\r
134 @retval FALSE Otherwise. This includes the case when the condition could not\r
135 be fully evaluated due to an error.\r
136**/\r
137typedef\r
138BOOLEAN\r
429309e0 139(EFIAPI *FILTER_FUNCTION)(\r
c976f9cb
AB
140 IN EFI_HANDLE Handle,\r
141 IN CONST CHAR16 *ReportText\r
142 );\r
143\r
c976f9cb
AB
144/**\r
145 Process a handle.\r
146\r
147 @param[in] Handle The handle to process.\r
148 @param[in] ReportText A caller-allocated string passed in for reporting\r
149 purposes. It must never be NULL.\r
150**/\r
151typedef\r
152VOID\r
429309e0 153(EFIAPI *CALLBACK_FUNCTION)(\r
c976f9cb
AB
154 IN EFI_HANDLE Handle,\r
155 IN CONST CHAR16 *ReportText\r
156 );\r
157\r
158/**\r
159 Locate all handles that carry the specified protocol, filter them with a\r
160 callback function, and pass each handle that passes the filter to another\r
161 callback.\r
162\r
163 @param[in] ProtocolGuid The protocol to look for.\r
164\r
165 @param[in] Filter The filter function to pass each handle to. If this\r
166 parameter is NULL, then all handles are processed.\r
167\r
168 @param[in] Process The callback function to pass each handle to that\r
169 clears the filter.\r
170**/\r
171STATIC\r
172VOID\r
173FilterAndProcess (\r
429309e0
MK
174 IN EFI_GUID *ProtocolGuid,\r
175 IN FILTER_FUNCTION Filter OPTIONAL,\r
176 IN CALLBACK_FUNCTION Process\r
c976f9cb
AB
177 )\r
178{\r
429309e0
MK
179 EFI_STATUS Status;\r
180 EFI_HANDLE *Handles;\r
181 UINTN NoHandles;\r
182 UINTN Idx;\r
183\r
184 Status = gBS->LocateHandleBuffer (\r
185 ByProtocol,\r
186 ProtocolGuid,\r
187 NULL /* SearchKey */,\r
188 &NoHandles,\r
189 &Handles\r
190 );\r
c976f9cb
AB
191 if (EFI_ERROR (Status)) {\r
192 //\r
193 // This is not an error, just an informative condition.\r
194 //\r
429309e0
MK
195 DEBUG ((\r
196 DEBUG_VERBOSE,\r
197 "%a: %g: %r\n",\r
198 __FUNCTION__,\r
199 ProtocolGuid,\r
200 Status\r
201 ));\r
c976f9cb
AB
202 return;\r
203 }\r
204\r
205 ASSERT (NoHandles > 0);\r
206 for (Idx = 0; Idx < NoHandles; ++Idx) {\r
429309e0
MK
207 CHAR16 *DevicePathText;\r
208 STATIC CHAR16 Fallback[] = L"<device path unavailable>";\r
c976f9cb
AB
209\r
210 //\r
211 // The ConvertDevicePathToText() function handles NULL input transparently.\r
212 //\r
213 DevicePathText = ConvertDevicePathToText (\r
214 DevicePathFromHandle (Handles[Idx]),\r
215 FALSE, // DisplayOnly\r
216 FALSE // AllowShortcuts\r
217 );\r
218 if (DevicePathText == NULL) {\r
219 DevicePathText = Fallback;\r
220 }\r
221\r
429309e0 222 if ((Filter == NULL) || Filter (Handles[Idx], DevicePathText)) {\r
c976f9cb
AB
223 Process (Handles[Idx], DevicePathText);\r
224 }\r
225\r
226 if (DevicePathText != Fallback) {\r
227 FreePool (DevicePathText);\r
228 }\r
229 }\r
429309e0 230\r
c976f9cb
AB
231 gBS->FreePool (Handles);\r
232}\r
233\r
c976f9cb
AB
234/**\r
235 This FILTER_FUNCTION checks if a handle corresponds to a PCI display device.\r
236**/\r
237STATIC\r
238BOOLEAN\r
239EFIAPI\r
240IsPciDisplay (\r
429309e0
MK
241 IN EFI_HANDLE Handle,\r
242 IN CONST CHAR16 *ReportText\r
c976f9cb
AB
243 )\r
244{\r
429309e0
MK
245 EFI_STATUS Status;\r
246 EFI_PCI_IO_PROTOCOL *PciIo;\r
247 PCI_TYPE00 Pci;\r
c976f9cb 248\r
429309e0
MK
249 Status = gBS->HandleProtocol (\r
250 Handle,\r
251 &gEfiPciIoProtocolGuid,\r
252 (VOID **)&PciIo\r
253 );\r
c976f9cb
AB
254 if (EFI_ERROR (Status)) {\r
255 //\r
256 // This is not an error worth reporting.\r
257 //\r
258 return FALSE;\r
259 }\r
260\r
429309e0
MK
261 Status = PciIo->Pci.Read (\r
262 PciIo,\r
263 EfiPciIoWidthUint32,\r
264 0 /* Offset */,\r
265 sizeof Pci / sizeof (UINT32),\r
266 &Pci\r
267 );\r
c976f9cb 268 if (EFI_ERROR (Status)) {\r
a4a582e1 269 DEBUG ((DEBUG_ERROR, "%a: %s: %r\n", __FUNCTION__, ReportText, Status));\r
c976f9cb
AB
270 return FALSE;\r
271 }\r
272\r
273 return IS_PCI_DISPLAY (&Pci);\r
274}\r
275\r
0ae52d4f
AB
276/**\r
277 This FILTER_FUNCTION checks if a handle corresponds to a non-discoverable\r
278 USB host controller.\r
279**/\r
280STATIC\r
281BOOLEAN\r
282EFIAPI\r
283IsUsbHost (\r
429309e0
MK
284 IN EFI_HANDLE Handle,\r
285 IN CONST CHAR16 *ReportText\r
0ae52d4f
AB
286 )\r
287{\r
429309e0
MK
288 NON_DISCOVERABLE_DEVICE *Device;\r
289 EFI_STATUS Status;\r
0ae52d4f 290\r
429309e0
MK
291 Status = gBS->HandleProtocol (\r
292 Handle,\r
0ae52d4f 293 &gEdkiiNonDiscoverableDeviceProtocolGuid,\r
429309e0
MK
294 (VOID **)&Device\r
295 );\r
0ae52d4f
AB
296 if (EFI_ERROR (Status)) {\r
297 return FALSE;\r
298 }\r
299\r
300 if (CompareGuid (Device->Type, &gEdkiiNonDiscoverableUhciDeviceGuid) ||\r
301 CompareGuid (Device->Type, &gEdkiiNonDiscoverableEhciDeviceGuid) ||\r
429309e0
MK
302 CompareGuid (Device->Type, &gEdkiiNonDiscoverableXhciDeviceGuid))\r
303 {\r
0ae52d4f
AB
304 return TRUE;\r
305 }\r
429309e0 306\r
0ae52d4f
AB
307 return FALSE;\r
308}\r
309\r
c976f9cb
AB
310/**\r
311 This CALLBACK_FUNCTION attempts to connect a handle non-recursively, asking\r
312 the matching driver to produce all first-level child handles.\r
313**/\r
314STATIC\r
315VOID\r
316EFIAPI\r
317Connect (\r
429309e0
MK
318 IN EFI_HANDLE Handle,\r
319 IN CONST CHAR16 *ReportText\r
c976f9cb
AB
320 )\r
321{\r
429309e0 322 EFI_STATUS Status;\r
c976f9cb
AB
323\r
324 Status = gBS->ConnectController (\r
325 Handle, // ControllerHandle\r
326 NULL, // DriverImageHandle\r
327 NULL, // RemainingDevicePath -- produce all children\r
328 FALSE // Recursive\r
329 );\r
429309e0
MK
330 DEBUG ((\r
331 EFI_ERROR (Status) ? DEBUG_ERROR : DEBUG_VERBOSE,\r
332 "%a: %s: %r\n",\r
333 __FUNCTION__,\r
334 ReportText,\r
335 Status\r
336 ));\r
c976f9cb
AB
337}\r
338\r
c976f9cb
AB
339/**\r
340 This CALLBACK_FUNCTION retrieves the EFI_DEVICE_PATH_PROTOCOL from the\r
341 handle, and adds it to ConOut and ErrOut.\r
342**/\r
343STATIC\r
344VOID\r
345EFIAPI\r
346AddOutput (\r
429309e0
MK
347 IN EFI_HANDLE Handle,\r
348 IN CONST CHAR16 *ReportText\r
c976f9cb
AB
349 )\r
350{\r
429309e0
MK
351 EFI_STATUS Status;\r
352 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
c976f9cb
AB
353\r
354 DevicePath = DevicePathFromHandle (Handle);\r
355 if (DevicePath == NULL) {\r
429309e0
MK
356 DEBUG ((\r
357 DEBUG_ERROR,\r
358 "%a: %s: handle %p: device path not found\n",\r
359 __FUNCTION__,\r
360 ReportText,\r
361 Handle\r
362 ));\r
c976f9cb
AB
363 return;\r
364 }\r
365\r
366 Status = EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);\r
367 if (EFI_ERROR (Status)) {\r
429309e0
MK
368 DEBUG ((\r
369 DEBUG_ERROR,\r
370 "%a: %s: adding to ConOut: %r\n",\r
371 __FUNCTION__,\r
372 ReportText,\r
373 Status\r
374 ));\r
c976f9cb
AB
375 return;\r
376 }\r
377\r
378 Status = EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);\r
379 if (EFI_ERROR (Status)) {\r
429309e0
MK
380 DEBUG ((\r
381 DEBUG_ERROR,\r
382 "%a: %s: adding to ErrOut: %r\n",\r
383 __FUNCTION__,\r
384 ReportText,\r
385 Status\r
386 ));\r
c976f9cb
AB
387 return;\r
388 }\r
389\r
429309e0
MK
390 DEBUG ((\r
391 DEBUG_VERBOSE,\r
392 "%a: %s: added to ConOut and ErrOut\n",\r
393 __FUNCTION__,\r
394 ReportText\r
395 ));\r
c976f9cb
AB
396}\r
397\r
398STATIC\r
399VOID\r
400PlatformRegisterFvBootOption (\r
429309e0
MK
401 CONST EFI_GUID *FileGuid,\r
402 CHAR16 *Description,\r
403 UINT32 Attributes,\r
404 EFI_INPUT_KEY *Key\r
c976f9cb
AB
405 )\r
406{\r
429309e0
MK
407 EFI_STATUS Status;\r
408 INTN OptionIndex;\r
409 EFI_BOOT_MANAGER_LOAD_OPTION NewOption;\r
410 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;\r
411 UINTN BootOptionCount;\r
412 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode;\r
413 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;\r
414 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
c976f9cb
AB
415\r
416 Status = gBS->HandleProtocol (\r
417 gImageHandle,\r
418 &gEfiLoadedImageProtocolGuid,\r
429309e0 419 (VOID **)&LoadedImage\r
c976f9cb
AB
420 );\r
421 ASSERT_EFI_ERROR (Status);\r
422\r
423 EfiInitializeFwVolDevicepathNode (&FileNode, FileGuid);\r
424 DevicePath = DevicePathFromHandle (LoadedImage->DeviceHandle);\r
425 ASSERT (DevicePath != NULL);\r
426 DevicePath = AppendDevicePathNode (\r
427 DevicePath,\r
429309e0 428 (EFI_DEVICE_PATH_PROTOCOL *)&FileNode\r
c976f9cb
AB
429 );\r
430 ASSERT (DevicePath != NULL);\r
431\r
432 Status = EfiBootManagerInitializeLoadOption (\r
433 &NewOption,\r
434 LoadOptionNumberUnassigned,\r
435 LoadOptionTypeBoot,\r
436 Attributes,\r
437 Description,\r
438 DevicePath,\r
439 NULL,\r
440 0\r
441 );\r
442 ASSERT_EFI_ERROR (Status);\r
443 FreePool (DevicePath);\r
444\r
445 BootOptions = EfiBootManagerGetLoadOptions (\r
429309e0
MK
446 &BootOptionCount,\r
447 LoadOptionTypeBoot\r
c976f9cb
AB
448 );\r
449\r
450 OptionIndex = EfiBootManagerFindLoadOption (\r
429309e0
MK
451 &NewOption,\r
452 BootOptions,\r
453 BootOptionCount\r
c976f9cb
AB
454 );\r
455\r
456 if (OptionIndex == -1) {\r
457 Status = EfiBootManagerAddLoadOptionVariable (&NewOption, MAX_UINTN);\r
458 ASSERT_EFI_ERROR (Status);\r
429309e0
MK
459 Status = EfiBootManagerAddKeyOptionVariable (\r
460 NULL,\r
461 (UINT16)NewOption.OptionNumber,\r
462 0,\r
463 Key,\r
464 NULL\r
465 );\r
321b0788 466 ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);\r
c976f9cb 467 }\r
429309e0 468\r
c976f9cb
AB
469 EfiBootManagerFreeLoadOption (&NewOption);\r
470 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);\r
471}\r
472\r
1b6e7633
HZ
473STATIC\r
474VOID\r
475GetPlatformOptions (\r
476 VOID\r
477 )\r
478{\r
479 EFI_STATUS Status;\r
480 EFI_BOOT_MANAGER_LOAD_OPTION *CurrentBootOptions;\r
481 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;\r
482 EFI_INPUT_KEY *BootKeys;\r
483 PLATFORM_BOOT_MANAGER_PROTOCOL *PlatformBootManager;\r
484 UINTN CurrentBootOptionCount;\r
485 UINTN Index;\r
486 UINTN BootCount;\r
487\r
429309e0
MK
488 Status = gBS->LocateProtocol (\r
489 &gPlatformBootManagerProtocolGuid,\r
490 NULL,\r
491 (VOID **)&PlatformBootManager\r
492 );\r
1b6e7633
HZ
493 if (EFI_ERROR (Status)) {\r
494 return;\r
495 }\r
429309e0 496\r
1b6e7633
HZ
497 Status = PlatformBootManager->GetPlatformBootOptionsAndKeys (\r
498 &BootCount,\r
499 &BootOptions,\r
500 &BootKeys\r
501 );\r
502 if (EFI_ERROR (Status)) {\r
503 return;\r
504 }\r
429309e0 505\r
1b6e7633
HZ
506 //\r
507 // Fetch the existent boot options. If there are none, CurrentBootCount\r
508 // will be zeroed.\r
509 //\r
510 CurrentBootOptions = EfiBootManagerGetLoadOptions (\r
511 &CurrentBootOptionCount,\r
512 LoadOptionTypeBoot\r
513 );\r
514 //\r
515 // Process the platform boot options.\r
516 //\r
517 for (Index = 0; Index < BootCount; Index++) {\r
429309e0
MK
518 INTN Match;\r
519 UINTN BootOptionNumber;\r
1b6e7633
HZ
520\r
521 //\r
522 // If there are any preexistent boot options, and the subject platform boot\r
523 // option is already among them, then don't try to add it. Just get its\r
524 // assigned boot option number so we can associate a hotkey with it. Note\r
525 // that EfiBootManagerFindLoadOption() deals fine with (CurrentBootOptions\r
526 // == NULL) if (CurrentBootCount == 0).\r
527 //\r
528 Match = EfiBootManagerFindLoadOption (\r
529 &BootOptions[Index],\r
530 CurrentBootOptions,\r
531 CurrentBootOptionCount\r
532 );\r
533 if (Match >= 0) {\r
534 BootOptionNumber = CurrentBootOptions[Match].OptionNumber;\r
535 } else {\r
536 //\r
537 // Add the platform boot options as a new one, at the end of the boot\r
538 // order. Note that if the platform provided this boot option with an\r
539 // unassigned option number, then the below function call will assign a\r
540 // number.\r
541 //\r
542 Status = EfiBootManagerAddLoadOptionVariable (\r
543 &BootOptions[Index],\r
544 MAX_UINTN\r
545 );\r
546 if (EFI_ERROR (Status)) {\r
429309e0
MK
547 DEBUG ((\r
548 DEBUG_ERROR,\r
549 "%a: failed to register \"%s\": %r\n",\r
550 __FUNCTION__,\r
551 BootOptions[Index].Description,\r
552 Status\r
553 ));\r
1b6e7633
HZ
554 continue;\r
555 }\r
429309e0 556\r
1b6e7633
HZ
557 BootOptionNumber = BootOptions[Index].OptionNumber;\r
558 }\r
559\r
560 //\r
561 // Register a hotkey with the boot option, if requested.\r
562 //\r
563 if (BootKeys[Index].UnicodeChar == L'\0') {\r
564 continue;\r
565 }\r
566\r
567 Status = EfiBootManagerAddKeyOptionVariable (\r
568 NULL,\r
569 BootOptionNumber,\r
570 0,\r
2b2959dd 571 &BootKeys[Index],\r
1b6e7633
HZ
572 NULL\r
573 );\r
574 if (EFI_ERROR (Status)) {\r
429309e0
MK
575 DEBUG ((\r
576 DEBUG_ERROR,\r
577 "%a: failed to register hotkey for \"%s\": %r\n",\r
578 __FUNCTION__,\r
579 BootOptions[Index].Description,\r
580 Status\r
581 ));\r
1b6e7633
HZ
582 }\r
583 }\r
429309e0 584\r
1b6e7633
HZ
585 EfiBootManagerFreeLoadOptions (CurrentBootOptions, CurrentBootOptionCount);\r
586 EfiBootManagerFreeLoadOptions (BootOptions, BootCount);\r
587 FreePool (BootKeys);\r
588}\r
589\r
c976f9cb
AB
590STATIC\r
591VOID\r
592PlatformRegisterOptionsAndKeys (\r
593 VOID\r
594 )\r
595{\r
429309e0
MK
596 EFI_STATUS Status;\r
597 EFI_INPUT_KEY Enter;\r
598 EFI_INPUT_KEY F2;\r
599 EFI_INPUT_KEY Esc;\r
600 EFI_BOOT_MANAGER_LOAD_OPTION BootOption;\r
c976f9cb 601\r
1b6e7633
HZ
602 GetPlatformOptions ();\r
603\r
c976f9cb
AB
604 //\r
605 // Register ENTER as CONTINUE key\r
606 //\r
607 Enter.ScanCode = SCAN_NULL;\r
608 Enter.UnicodeChar = CHAR_CARRIAGE_RETURN;\r
429309e0 609 Status = EfiBootManagerRegisterContinueKeyOption (0, &Enter, NULL);\r
c976f9cb
AB
610 ASSERT_EFI_ERROR (Status);\r
611\r
612 //\r
613 // Map F2 and ESC to Boot Manager Menu\r
614 //\r
615 F2.ScanCode = SCAN_F2;\r
616 F2.UnicodeChar = CHAR_NULL;\r
617 Esc.ScanCode = SCAN_ESC;\r
618 Esc.UnicodeChar = CHAR_NULL;\r
429309e0 619 Status = EfiBootManagerGetBootManagerMenu (&BootOption);\r
c976f9cb
AB
620 ASSERT_EFI_ERROR (Status);\r
621 Status = EfiBootManagerAddKeyOptionVariable (\r
429309e0
MK
622 NULL,\r
623 (UINT16)BootOption.OptionNumber,\r
624 0,\r
625 &F2,\r
626 NULL\r
c976f9cb
AB
627 );\r
628 ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);\r
629 Status = EfiBootManagerAddKeyOptionVariable (\r
429309e0
MK
630 NULL,\r
631 (UINT16)BootOption.OptionNumber,\r
632 0,\r
633 &Esc,\r
634 NULL\r
c976f9cb
AB
635 );\r
636 ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);\r
637}\r
638\r
c976f9cb
AB
639//\r
640// BDS Platform Functions\r
641//\r
429309e0 642\r
c976f9cb
AB
643/**\r
644 Do the platform init, can be customized by OEM/IBV\r
645 Possible things that can be done in PlatformBootManagerBeforeConsole:\r
646 > Update console variable: 1. include hot-plug devices;\r
647 > 2. Clear ConIn and add SOL for AMT\r
648 > Register new Driver#### or Boot####\r
649 > Register new Key####: e.g.: F12\r
650 > Signal ReadyToLock event\r
651 > Authentication action: 1. connect Auth devices;\r
652 > 2. Identify auto logon user.\r
653**/\r
654VOID\r
655EFIAPI\r
656PlatformBootManagerBeforeConsole (\r
657 VOID\r
658 )\r
659{\r
660 //\r
661 // Signal EndOfDxe PI Event\r
662 //\r
663 EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid);\r
664\r
0f9395d7
SM
665 //\r
666 // Dispatch deferred images after EndOfDxe event.\r
667 //\r
668 EfiBootManagerDispatchDeferredImages ();\r
669\r
c976f9cb
AB
670 //\r
671 // Locate the PCI root bridges and make the PCI bus driver connect each,\r
672 // non-recursively. This will produce a number of child handles with PciIo on\r
673 // them.\r
674 //\r
675 FilterAndProcess (&gEfiPciRootBridgeIoProtocolGuid, NULL, Connect);\r
676\r
677 //\r
678 // Find all display class PCI devices (using the handles from the previous\r
679 // step), and connect them non-recursively. This should produce a number of\r
680 // child handles with GOPs on them.\r
681 //\r
682 FilterAndProcess (&gEfiPciIoProtocolGuid, IsPciDisplay, Connect);\r
683\r
684 //\r
685 // Now add the device path of all handles with GOP on them to ConOut and\r
686 // ErrOut.\r
687 //\r
688 FilterAndProcess (&gEfiGraphicsOutputProtocolGuid, NULL, AddOutput);\r
689\r
0ae52d4f
AB
690 //\r
691 // The core BDS code connects short-form USB device paths by explicitly\r
692 // looking for handles with PCI I/O installed, and checking the PCI class\r
693 // code whether it matches the one for a USB host controller. This means\r
694 // non-discoverable USB host controllers need to have the non-discoverable\r
695 // PCI driver attached first.\r
696 //\r
697 FilterAndProcess (&gEdkiiNonDiscoverableDeviceProtocolGuid, IsUsbHost, Connect);\r
698\r
c976f9cb
AB
699 //\r
700 // Add the hardcoded short-form USB keyboard device path to ConIn.\r
701 //\r
429309e0
MK
702 EfiBootManagerUpdateConsoleVariable (\r
703 ConIn,\r
704 (EFI_DEVICE_PATH_PROTOCOL *)&mUsbKeyboard,\r
705 NULL\r
706 );\r
c976f9cb
AB
707\r
708 //\r
709 // Add the hardcoded serial console device path to ConIn, ConOut, ErrOut.\r
710 //\r
429309e0
MK
711 STATIC_ASSERT (\r
712 FixedPcdGet8 (PcdDefaultTerminalType) == 4,\r
713 "PcdDefaultTerminalType must be TTYTERM"\r
714 );\r
715 STATIC_ASSERT (\r
716 FixedPcdGet8 (PcdUartDefaultParity) != 0,\r
717 "PcdUartDefaultParity must be set to an actual value, not 'default'"\r
718 );\r
719 STATIC_ASSERT (\r
720 FixedPcdGet8 (PcdUartDefaultStopBits) != 0,\r
721 "PcdUartDefaultStopBits must be set to an actual value, not 'default'"\r
722 );\r
b1d3895f 723\r
c976f9cb
AB
724 CopyGuid (&mSerialConsole.TermType.Guid, &gEfiTtyTermGuid);\r
725\r
429309e0
MK
726 EfiBootManagerUpdateConsoleVariable (\r
727 ConIn,\r
728 (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole,\r
729 NULL\r
730 );\r
731 EfiBootManagerUpdateConsoleVariable (\r
732 ConOut,\r
733 (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole,\r
734 NULL\r
735 );\r
736 EfiBootManagerUpdateConsoleVariable (\r
737 ErrOut,\r
738 (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole,\r
739 NULL\r
740 );\r
c976f9cb
AB
741\r
742 //\r
743 // Register platform-specific boot options and keyboard shortcuts.\r
744 //\r
745 PlatformRegisterOptionsAndKeys ();\r
746}\r
747\r
cae82316
AB
748STATIC\r
749VOID\r
750HandleCapsules (\r
751 VOID\r
752 )\r
753{\r
429309e0
MK
754 ESRT_MANAGEMENT_PROTOCOL *EsrtManagement;\r
755 EFI_PEI_HOB_POINTERS HobPointer;\r
756 EFI_CAPSULE_HEADER *CapsuleHeader;\r
757 BOOLEAN NeedReset;\r
758 EFI_STATUS Status;\r
cae82316
AB
759\r
760 DEBUG ((DEBUG_INFO, "%a: processing capsules ...\n", __FUNCTION__));\r
761\r
429309e0
MK
762 Status = gBS->LocateProtocol (\r
763 &gEsrtManagementProtocolGuid,\r
764 NULL,\r
765 (VOID **)&EsrtManagement\r
766 );\r
cae82316
AB
767 if (!EFI_ERROR (Status)) {\r
768 EsrtManagement->SyncEsrtFmp ();\r
769 }\r
770\r
771 //\r
772 // Find all capsule images from hob\r
773 //\r
774 HobPointer.Raw = GetHobList ();\r
429309e0
MK
775 NeedReset = FALSE;\r
776 while ((HobPointer.Raw = GetNextHob (\r
777 EFI_HOB_TYPE_UEFI_CAPSULE,\r
778 HobPointer.Raw\r
779 )) != NULL)\r
780 {\r
cae82316
AB
781 CapsuleHeader = (VOID *)(UINTN)HobPointer.Capsule->BaseAddress;\r
782\r
783 Status = ProcessCapsuleImage (CapsuleHeader);\r
784 if (EFI_ERROR (Status)) {\r
429309e0
MK
785 DEBUG ((\r
786 DEBUG_ERROR,\r
787 "%a: failed to process capsule %p - %r\n",\r
788 __FUNCTION__,\r
789 CapsuleHeader,\r
790 Status\r
791 ));\r
cae82316
AB
792 return;\r
793 }\r
794\r
429309e0 795 NeedReset = TRUE;\r
cae82316
AB
796 HobPointer.Raw = GET_NEXT_HOB (HobPointer);\r
797 }\r
798\r
799 if (NeedReset) {\r
429309e0
MK
800 DEBUG ((\r
801 DEBUG_WARN,\r
802 "%a: capsule update successful, resetting ...\n",\r
803 __FUNCTION__\r
804 ));\r
805\r
806 gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);\r
807 CpuDeadLoop ();\r
cae82316
AB
808 }\r
809}\r
810\r
429309e0 811#define VERSION_STRING_PREFIX L"Tianocore/EDK2 firmware version "\r
6c4194c9 812\r
cae735f6
GB
813/**\r
814 This functions checks the value of BootDiscoverPolicy variable and\r
815 connect devices of class specified by that variable. Then it refreshes\r
816 Boot order for newly discovered boot device.\r
817\r
818 @retval EFI_SUCCESS Devices connected successfully or connection\r
819 not required.\r
820 @retval others Return values from GetVariable(), LocateProtocol()\r
821 and ConnectDeviceClass().\r
822**/\r
823STATIC\r
824EFI_STATUS\r
825BootDiscoveryPolicyHandler (\r
826 VOID\r
827 )\r
828{\r
429309e0
MK
829 EFI_STATUS Status;\r
830 UINT32 DiscoveryPolicy;\r
831 UINT32 DiscoveryPolicyOld;\r
832 UINTN Size;\r
833 EFI_BOOT_MANAGER_POLICY_PROTOCOL *BMPolicy;\r
834 EFI_GUID *Class;\r
835\r
836 Size = sizeof (DiscoveryPolicy);\r
cae735f6
GB
837 Status = gRT->GetVariable (\r
838 BOOT_DISCOVERY_POLICY_VAR,\r
839 &gBootDiscoveryPolicyMgrFormsetGuid,\r
840 NULL,\r
841 &Size,\r
842 &DiscoveryPolicy\r
843 );\r
844 if (Status == EFI_NOT_FOUND) {\r
845 DiscoveryPolicy = PcdGet32 (PcdBootDiscoveryPolicy);\r
429309e0 846 Status = PcdSet32S (PcdBootDiscoveryPolicy, DiscoveryPolicy);\r
cae735f6
GB
847 if (Status == EFI_NOT_FOUND) {\r
848 return EFI_SUCCESS;\r
849 } else if (EFI_ERROR (Status)) {\r
850 return Status;\r
851 }\r
852 } else if (EFI_ERROR (Status)) {\r
853 return Status;\r
854 }\r
855\r
856 if (DiscoveryPolicy == BDP_CONNECT_MINIMAL) {\r
857 return EFI_SUCCESS;\r
858 }\r
859\r
860 switch (DiscoveryPolicy) {\r
861 case BDP_CONNECT_NET:\r
862 Class = &gEfiBootManagerPolicyNetworkGuid;\r
863 break;\r
864 case BDP_CONNECT_ALL:\r
865 Class = &gEfiBootManagerPolicyConnectAllGuid;\r
866 break;\r
867 default:\r
868 DEBUG ((\r
869 DEBUG_INFO,\r
870 "%a - Unexpected DiscoveryPolicy (0x%x). Run Minimal Discovery Policy\n",\r
871 __FUNCTION__,\r
872 DiscoveryPolicy\r
873 ));\r
874 return EFI_SUCCESS;\r
875 }\r
876\r
877 Status = gBS->LocateProtocol (\r
878 &gEfiBootManagerPolicyProtocolGuid,\r
879 NULL,\r
880 (VOID **)&BMPolicy\r
881 );\r
882 if (EFI_ERROR (Status)) {\r
429309e0
MK
883 DEBUG ((\r
884 DEBUG_INFO,\r
885 "%a - Failed to locate gEfiBootManagerPolicyProtocolGuid."\r
886 "Driver connect will be skipped.\n",\r
887 __FUNCTION__\r
888 ));\r
cae735f6
GB
889 return Status;\r
890 }\r
891\r
892 Status = BMPolicy->ConnectDeviceClass (BMPolicy, Class);\r
429309e0 893 if (EFI_ERROR (Status)) {\r
cae735f6
GB
894 DEBUG ((DEBUG_ERROR, "%a - ConnectDeviceClass returns - %r\n", __FUNCTION__, Status));\r
895 return Status;\r
896 }\r
897\r
898 //\r
899 // Refresh Boot Options if Boot Discovery Policy has been changed\r
900 //\r
429309e0 901 Size = sizeof (DiscoveryPolicyOld);\r
cae735f6
GB
902 Status = gRT->GetVariable (\r
903 BOOT_DISCOVERY_POLICY_OLD_VAR,\r
904 &gBootDiscoveryPolicyMgrFormsetGuid,\r
905 NULL,\r
906 &Size,\r
907 &DiscoveryPolicyOld\r
908 );\r
909 if ((Status == EFI_NOT_FOUND) || (DiscoveryPolicyOld != DiscoveryPolicy)) {\r
910 EfiBootManagerRefreshAllBootOption ();\r
911\r
912 Status = gRT->SetVariable (\r
913 BOOT_DISCOVERY_POLICY_OLD_VAR,\r
914 &gBootDiscoveryPolicyMgrFormsetGuid,\r
915 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
916 sizeof (DiscoveryPolicyOld),\r
917 &DiscoveryPolicy\r
918 );\r
919 }\r
920\r
921 return EFI_SUCCESS;\r
922}\r
923\r
c976f9cb
AB
924/**\r
925 Do the platform specific action after the console is ready\r
926 Possible things that can be done in PlatformBootManagerAfterConsole:\r
927 > Console post action:\r
ff5fef14 928 > Dynamically switch output mode from 100x31 to 80x25 for certain scenario\r
c976f9cb
AB
929 > Signal console ready platform customized event\r
930 > Run diagnostics like memory testing\r
931 > Connect certain devices\r
ff5fef14 932 > Dispatch additional option roms\r
c976f9cb
AB
933 > Special boot: e.g.: USB boot, enter UI\r
934**/\r
935VOID\r
936EFIAPI\r
937PlatformBootManagerAfterConsole (\r
938 VOID\r
939 )\r
940{\r
13ca0abb 941 EFI_STATUS Status;\r
6c4194c9
AB
942 EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;\r
943 UINTN FirmwareVerLength;\r
944 UINTN PosX;\r
945 UINTN PosY;\r
321b0788 946 EFI_INPUT_KEY Key;\r
6c4194c9
AB
947\r
948 FirmwareVerLength = StrLen (PcdGetPtr (PcdFirmwareVersionString));\r
c976f9cb
AB
949\r
950 //\r
951 // Show the splash screen.\r
952 //\r
a43d75e1
AB
953 Status = BootLogoEnableLogo ();\r
954 if (EFI_ERROR (Status)) {\r
6c4194c9 955 if (FirmwareVerLength > 0) {\r
429309e0
MK
956 Print (\r
957 VERSION_STRING_PREFIX L"%s\n",\r
958 PcdGetPtr (PcdFirmwareVersionString)\r
959 );\r
6c4194c9 960 }\r
429309e0 961\r
a43d75e1 962 Print (L"Press ESCAPE for boot options ");\r
6c4194c9 963 } else if (FirmwareVerLength > 0) {\r
429309e0
MK
964 Status = gBS->HandleProtocol (\r
965 gST->ConsoleOutHandle,\r
966 &gEfiGraphicsOutputProtocolGuid,\r
967 (VOID **)&GraphicsOutput\r
968 );\r
6c4194c9
AB
969 if (!EFI_ERROR (Status)) {\r
970 PosX = (GraphicsOutput->Mode->Info->HorizontalResolution -\r
971 (StrLen (VERSION_STRING_PREFIX) + FirmwareVerLength) *\r
972 EFI_GLYPH_WIDTH) / 2;\r
973 PosY = 0;\r
974\r
429309e0
MK
975 PrintXY (\r
976 PosX,\r
977 PosY,\r
978 NULL,\r
979 NULL,\r
980 VERSION_STRING_PREFIX L"%s",\r
981 PcdGetPtr (PcdFirmwareVersionString)\r
982 );\r
6c4194c9 983 }\r
a43d75e1 984 }\r
6c4194c9 985\r
cae735f6
GB
986 //\r
987 // Connect device specified by BootDiscoverPolicy variable and\r
988 // refresh Boot order for newly discovered boot devices\r
989 //\r
990 BootDiscoveryPolicyHandler ();\r
991\r
cae82316
AB
992 //\r
993 // On ARM, there is currently no reason to use the phased capsule\r
994 // update approach where some capsules are dispatched before EndOfDxe\r
995 // and some are dispatched after. So just handle all capsules here,\r
996 // when the console is up and we can actually give the user some\r
997 // feedback about what is going on.\r
998 //\r
999 HandleCapsules ();\r
4bbcc285 1000\r
c976f9cb
AB
1001 //\r
1002 // Register UEFI Shell\r
1003 //\r
429309e0
MK
1004 Key.ScanCode = SCAN_NULL;\r
1005 Key.UnicodeChar = L's';\r
344f615d 1006 PlatformRegisterFvBootOption (&gUefiShellFileGuid, L"UEFI Shell", 0, &Key);\r
c976f9cb
AB
1007}\r
1008\r
1009/**\r
1010 This function is called each second during the boot manager waits the\r
1011 timeout.\r
1012\r
1013 @param TimeoutRemain The remaining timeout.\r
1014**/\r
1015VOID\r
1016EFIAPI\r
1017PlatformBootManagerWaitCallback (\r
429309e0 1018 UINT16 TimeoutRemain\r
c976f9cb
AB
1019 )\r
1020{\r
429309e0
MK
1021 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black;\r
1022 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White;\r
1023 UINT16 Timeout;\r
1024 EFI_STATUS Status;\r
a43d75e1
AB
1025\r
1026 Timeout = PcdGet16 (PcdPlatformBootTimeOut);\r
1027\r
1028 Black.Raw = 0x00000000;\r
1029 White.Raw = 0x00FFFFFF;\r
1030\r
1031 Status = BootLogoUpdateProgress (\r
1032 White.Pixel,\r
1033 Black.Pixel,\r
1034 L"Press ESCAPE for boot options",\r
1035 White.Pixel,\r
1036 (Timeout - TimeoutRemain) * 100 / Timeout,\r
1037 0\r
1038 );\r
1039 if (EFI_ERROR (Status)) {\r
1040 Print (L".");\r
1041 }\r
c976f9cb 1042}\r
eea668c9
RN
1043\r
1044/**\r
1045 The function is called when no boot option could be launched,\r
1046 including platform recovery options and options pointing to applications\r
1047 built into firmware volumes.\r
1048\r
1049 If this function returns, BDS attempts to enter an infinite loop.\r
1050**/\r
1051VOID\r
1052EFIAPI\r
1053PlatformBootManagerUnableToBoot (\r
1054 VOID\r
1055 )\r
1056{\r
429309e0
MK
1057 EFI_STATUS Status;\r
1058 EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu;\r
1059 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;\r
1060 UINTN OldBootOptionCount;\r
1061 UINTN NewBootOptionCount;\r
2d233af6
AB
1062\r
1063 //\r
1064 // Record the total number of boot configured boot options\r
1065 //\r
429309e0
MK
1066 BootOptions = EfiBootManagerGetLoadOptions (\r
1067 &OldBootOptionCount,\r
1068 LoadOptionTypeBoot\r
1069 );\r
2d233af6
AB
1070 EfiBootManagerFreeLoadOptions (BootOptions, OldBootOptionCount);\r
1071\r
1072 //\r
1073 // Connect all devices, and regenerate all boot options\r
1074 //\r
1075 EfiBootManagerConnectAll ();\r
1076 EfiBootManagerRefreshAllBootOption ();\r
1077\r
1078 //\r
1079 // Record the updated number of boot configured boot options\r
1080 //\r
429309e0
MK
1081 BootOptions = EfiBootManagerGetLoadOptions (\r
1082 &NewBootOptionCount,\r
1083 LoadOptionTypeBoot\r
1084 );\r
2d233af6
AB
1085 EfiBootManagerFreeLoadOptions (BootOptions, NewBootOptionCount);\r
1086\r
1087 //\r
1088 // If the number of configured boot options has changed, reboot\r
1089 // the system so the new boot options will be taken into account\r
1090 // while executing the ordinary BDS bootflow sequence.\r
1b6c3a94
LL
1091 // *Unless* persistent varstore is being emulated, since we would\r
1092 // then end up in an endless reboot loop.\r
2d233af6 1093 //\r
1b6c3a94
LL
1094 if (!PcdGetBool (PcdEmuVariableNvModeEnable)) {\r
1095 if (NewBootOptionCount != OldBootOptionCount) {\r
429309e0
MK
1096 DEBUG ((\r
1097 DEBUG_WARN,\r
1098 "%a: rebooting after refreshing all boot options\n",\r
1099 __FUNCTION__\r
1100 ));\r
1b6c3a94
LL
1101 gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);\r
1102 }\r
2d233af6 1103 }\r
40e2e3ca
AB
1104\r
1105 Status = EfiBootManagerGetBootManagerMenu (&BootManagerMenu);\r
1106 if (EFI_ERROR (Status)) {\r
1107 return;\r
1108 }\r
1109\r
429309e0 1110 for ( ; ;) {\r
40e2e3ca
AB
1111 EfiBootManagerBoot (&BootManagerMenu);\r
1112 }\r
eea668c9 1113}\r