]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPkg/Library/PlatformBootManagerLib/PlatformBm.c
ArmPkg: Replace BSD License with BSD+Patent License
[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
eea668c9 6 Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>\r
c976f9cb
AB
7 Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>\r
8\r
4059386c 9 SPDX-License-Identifier: BSD-2-Clause-Patent\r
c976f9cb
AB
10\r
11**/\r
12\r
13#include <IndustryStandard/Pci22.h>\r
a43d75e1 14#include <Library/BootLogoLib.h>\r
4bbcc285 15#include <Library/CapsuleLib.h>\r
c976f9cb 16#include <Library/DevicePathLib.h>\r
4bbcc285 17#include <Library/HobLib.h>\r
c976f9cb
AB
18#include <Library/PcdLib.h>\r
19#include <Library/UefiBootManagerLib.h>\r
20#include <Library/UefiLib.h>\r
cae82316 21#include <Library/UefiRuntimeServicesTableLib.h>\r
c976f9cb 22#include <Protocol/DevicePath.h>\r
13ca0abb 23#include <Protocol/EsrtManagement.h>\r
c976f9cb
AB
24#include <Protocol/GraphicsOutput.h>\r
25#include <Protocol/LoadedImage.h>\r
26#include <Protocol/PciIo.h>\r
27#include <Protocol/PciRootBridgeIo.h>\r
1b6e7633 28#include <Protocol/PlatformBootManager.h>\r
c976f9cb
AB
29#include <Guid/EventGroup.h>\r
30#include <Guid/TtyTerm.h>\r
31\r
32#include "PlatformBm.h"\r
33\r
34#define DP_NODE_LEN(Type) { (UINT8)sizeof (Type), (UINT8)(sizeof (Type) >> 8) }\r
35\r
c976f9cb
AB
36#pragma pack (1)\r
37typedef struct {\r
38 VENDOR_DEVICE_PATH SerialDxe;\r
39 UART_DEVICE_PATH Uart;\r
40 VENDOR_DEFINED_DEVICE_PATH TermType;\r
41 EFI_DEVICE_PATH_PROTOCOL End;\r
42} PLATFORM_SERIAL_CONSOLE;\r
43#pragma pack ()\r
44\r
45#define SERIAL_DXE_FILE_GUID { \\r
46 0xD3987D4B, 0x971A, 0x435F, \\r
47 { 0x8C, 0xAF, 0x49, 0x67, 0xEB, 0x62, 0x72, 0x41 } \\r
48 }\r
49\r
50STATIC PLATFORM_SERIAL_CONSOLE mSerialConsole = {\r
51 //\r
52 // VENDOR_DEVICE_PATH SerialDxe\r
53 //\r
54 {\r
55 { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, DP_NODE_LEN (VENDOR_DEVICE_PATH) },\r
56 SERIAL_DXE_FILE_GUID\r
57 },\r
58\r
59 //\r
60 // UART_DEVICE_PATH Uart\r
61 //\r
62 {\r
63 { MESSAGING_DEVICE_PATH, MSG_UART_DP, DP_NODE_LEN (UART_DEVICE_PATH) },\r
64 0, // Reserved\r
65 FixedPcdGet64 (PcdUartDefaultBaudRate), // BaudRate\r
66 FixedPcdGet8 (PcdUartDefaultDataBits), // DataBits\r
67 FixedPcdGet8 (PcdUartDefaultParity), // Parity\r
68 FixedPcdGet8 (PcdUartDefaultStopBits) // StopBits\r
69 },\r
70\r
71 //\r
72 // VENDOR_DEFINED_DEVICE_PATH TermType\r
73 //\r
74 {\r
75 {\r
76 MESSAGING_DEVICE_PATH, MSG_VENDOR_DP,\r
77 DP_NODE_LEN (VENDOR_DEFINED_DEVICE_PATH)\r
78 }\r
79 //\r
80 // Guid to be filled in dynamically\r
81 //\r
82 },\r
83\r
84 //\r
85 // EFI_DEVICE_PATH_PROTOCOL End\r
86 //\r
87 {\r
88 END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
89 DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL)\r
90 }\r
91};\r
92\r
93\r
94#pragma pack (1)\r
95typedef struct {\r
96 USB_CLASS_DEVICE_PATH Keyboard;\r
97 EFI_DEVICE_PATH_PROTOCOL End;\r
98} PLATFORM_USB_KEYBOARD;\r
99#pragma pack ()\r
100\r
101STATIC PLATFORM_USB_KEYBOARD mUsbKeyboard = {\r
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
126\r
127/**\r
128 Check if the handle satisfies a particular condition.\r
129\r
130 @param[in] Handle The handle to check.\r
131 @param[in] ReportText A caller-allocated string passed in for reporting\r
132 purposes. It must never be NULL.\r
133\r
134 @retval TRUE The condition is satisfied.\r
135 @retval FALSE Otherwise. This includes the case when the condition could not\r
136 be fully evaluated due to an error.\r
137**/\r
138typedef\r
139BOOLEAN\r
140(EFIAPI *FILTER_FUNCTION) (\r
141 IN EFI_HANDLE Handle,\r
142 IN CONST CHAR16 *ReportText\r
143 );\r
144\r
145\r
146/**\r
147 Process a handle.\r
148\r
149 @param[in] Handle The handle to process.\r
150 @param[in] ReportText A caller-allocated string passed in for reporting\r
151 purposes. It must never be NULL.\r
152**/\r
153typedef\r
154VOID\r
155(EFIAPI *CALLBACK_FUNCTION) (\r
156 IN EFI_HANDLE Handle,\r
157 IN CONST CHAR16 *ReportText\r
158 );\r
159\r
160/**\r
161 Locate all handles that carry the specified protocol, filter them with a\r
162 callback function, and pass each handle that passes the filter to another\r
163 callback.\r
164\r
165 @param[in] ProtocolGuid The protocol to look for.\r
166\r
167 @param[in] Filter The filter function to pass each handle to. If this\r
168 parameter is NULL, then all handles are processed.\r
169\r
170 @param[in] Process The callback function to pass each handle to that\r
171 clears the filter.\r
172**/\r
173STATIC\r
174VOID\r
175FilterAndProcess (\r
176 IN EFI_GUID *ProtocolGuid,\r
177 IN FILTER_FUNCTION Filter OPTIONAL,\r
178 IN CALLBACK_FUNCTION Process\r
179 )\r
180{\r
181 EFI_STATUS Status;\r
182 EFI_HANDLE *Handles;\r
183 UINTN NoHandles;\r
184 UINTN Idx;\r
185\r
186 Status = gBS->LocateHandleBuffer (ByProtocol, ProtocolGuid,\r
187 NULL /* SearchKey */, &NoHandles, &Handles);\r
188 if (EFI_ERROR (Status)) {\r
189 //\r
190 // This is not an error, just an informative condition.\r
191 //\r
192 DEBUG ((EFI_D_VERBOSE, "%a: %g: %r\n", __FUNCTION__, ProtocolGuid,\r
193 Status));\r
194 return;\r
195 }\r
196\r
197 ASSERT (NoHandles > 0);\r
198 for (Idx = 0; Idx < NoHandles; ++Idx) {\r
199 CHAR16 *DevicePathText;\r
200 STATIC CHAR16 Fallback[] = L"<device path unavailable>";\r
201\r
202 //\r
203 // The ConvertDevicePathToText() function handles NULL input transparently.\r
204 //\r
205 DevicePathText = ConvertDevicePathToText (\r
206 DevicePathFromHandle (Handles[Idx]),\r
207 FALSE, // DisplayOnly\r
208 FALSE // AllowShortcuts\r
209 );\r
210 if (DevicePathText == NULL) {\r
211 DevicePathText = Fallback;\r
212 }\r
213\r
214 if (Filter == NULL || Filter (Handles[Idx], DevicePathText)) {\r
215 Process (Handles[Idx], DevicePathText);\r
216 }\r
217\r
218 if (DevicePathText != Fallback) {\r
219 FreePool (DevicePathText);\r
220 }\r
221 }\r
222 gBS->FreePool (Handles);\r
223}\r
224\r
225\r
226/**\r
227 This FILTER_FUNCTION checks if a handle corresponds to a PCI display device.\r
228**/\r
229STATIC\r
230BOOLEAN\r
231EFIAPI\r
232IsPciDisplay (\r
233 IN EFI_HANDLE Handle,\r
234 IN CONST CHAR16 *ReportText\r
235 )\r
236{\r
237 EFI_STATUS Status;\r
238 EFI_PCI_IO_PROTOCOL *PciIo;\r
239 PCI_TYPE00 Pci;\r
240\r
241 Status = gBS->HandleProtocol (Handle, &gEfiPciIoProtocolGuid,\r
242 (VOID**)&PciIo);\r
243 if (EFI_ERROR (Status)) {\r
244 //\r
245 // This is not an error worth reporting.\r
246 //\r
247 return FALSE;\r
248 }\r
249\r
250 Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, 0 /* Offset */,\r
251 sizeof Pci / sizeof (UINT32), &Pci);\r
252 if (EFI_ERROR (Status)) {\r
253 DEBUG ((EFI_D_ERROR, "%a: %s: %r\n", __FUNCTION__, ReportText, Status));\r
254 return FALSE;\r
255 }\r
256\r
257 return IS_PCI_DISPLAY (&Pci);\r
258}\r
259\r
260\r
261/**\r
262 This CALLBACK_FUNCTION attempts to connect a handle non-recursively, asking\r
263 the matching driver to produce all first-level child handles.\r
264**/\r
265STATIC\r
266VOID\r
267EFIAPI\r
268Connect (\r
269 IN EFI_HANDLE Handle,\r
270 IN CONST CHAR16 *ReportText\r
271 )\r
272{\r
273 EFI_STATUS Status;\r
274\r
275 Status = gBS->ConnectController (\r
276 Handle, // ControllerHandle\r
277 NULL, // DriverImageHandle\r
278 NULL, // RemainingDevicePath -- produce all children\r
279 FALSE // Recursive\r
280 );\r
281 DEBUG ((EFI_ERROR (Status) ? EFI_D_ERROR : EFI_D_VERBOSE, "%a: %s: %r\n",\r
282 __FUNCTION__, ReportText, Status));\r
283}\r
284\r
285\r
286/**\r
287 This CALLBACK_FUNCTION retrieves the EFI_DEVICE_PATH_PROTOCOL from the\r
288 handle, and adds it to ConOut and ErrOut.\r
289**/\r
290STATIC\r
291VOID\r
292EFIAPI\r
293AddOutput (\r
294 IN EFI_HANDLE Handle,\r
295 IN CONST CHAR16 *ReportText\r
296 )\r
297{\r
298 EFI_STATUS Status;\r
299 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
300\r
301 DevicePath = DevicePathFromHandle (Handle);\r
302 if (DevicePath == NULL) {\r
303 DEBUG ((EFI_D_ERROR, "%a: %s: handle %p: device path not found\n",\r
304 __FUNCTION__, ReportText, Handle));\r
305 return;\r
306 }\r
307\r
308 Status = EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);\r
309 if (EFI_ERROR (Status)) {\r
310 DEBUG ((EFI_D_ERROR, "%a: %s: adding to ConOut: %r\n", __FUNCTION__,\r
311 ReportText, Status));\r
312 return;\r
313 }\r
314\r
315 Status = EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);\r
316 if (EFI_ERROR (Status)) {\r
317 DEBUG ((EFI_D_ERROR, "%a: %s: adding to ErrOut: %r\n", __FUNCTION__,\r
318 ReportText, Status));\r
319 return;\r
320 }\r
321\r
322 DEBUG ((EFI_D_VERBOSE, "%a: %s: added to ConOut and ErrOut\n", __FUNCTION__,\r
323 ReportText));\r
324}\r
325\r
326STATIC\r
327VOID\r
328PlatformRegisterFvBootOption (\r
07548e17 329 CONST EFI_GUID *FileGuid,\r
c976f9cb
AB
330 CHAR16 *Description,\r
331 UINT32 Attributes\r
332 )\r
333{\r
334 EFI_STATUS Status;\r
335 INTN OptionIndex;\r
336 EFI_BOOT_MANAGER_LOAD_OPTION NewOption;\r
337 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;\r
338 UINTN BootOptionCount;\r
339 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode;\r
340 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;\r
341 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
342\r
343 Status = gBS->HandleProtocol (\r
344 gImageHandle,\r
345 &gEfiLoadedImageProtocolGuid,\r
346 (VOID **) &LoadedImage\r
347 );\r
348 ASSERT_EFI_ERROR (Status);\r
349\r
350 EfiInitializeFwVolDevicepathNode (&FileNode, FileGuid);\r
351 DevicePath = DevicePathFromHandle (LoadedImage->DeviceHandle);\r
352 ASSERT (DevicePath != NULL);\r
353 DevicePath = AppendDevicePathNode (\r
354 DevicePath,\r
355 (EFI_DEVICE_PATH_PROTOCOL *) &FileNode\r
356 );\r
357 ASSERT (DevicePath != NULL);\r
358\r
359 Status = EfiBootManagerInitializeLoadOption (\r
360 &NewOption,\r
361 LoadOptionNumberUnassigned,\r
362 LoadOptionTypeBoot,\r
363 Attributes,\r
364 Description,\r
365 DevicePath,\r
366 NULL,\r
367 0\r
368 );\r
369 ASSERT_EFI_ERROR (Status);\r
370 FreePool (DevicePath);\r
371\r
372 BootOptions = EfiBootManagerGetLoadOptions (\r
373 &BootOptionCount, LoadOptionTypeBoot\r
374 );\r
375\r
376 OptionIndex = EfiBootManagerFindLoadOption (\r
377 &NewOption, BootOptions, BootOptionCount\r
378 );\r
379\r
380 if (OptionIndex == -1) {\r
381 Status = EfiBootManagerAddLoadOptionVariable (&NewOption, MAX_UINTN);\r
382 ASSERT_EFI_ERROR (Status);\r
383 }\r
384 EfiBootManagerFreeLoadOption (&NewOption);\r
385 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);\r
386}\r
387\r
388\r
1b6e7633
HZ
389STATIC\r
390VOID\r
391GetPlatformOptions (\r
392 VOID\r
393 )\r
394{\r
395 EFI_STATUS Status;\r
396 EFI_BOOT_MANAGER_LOAD_OPTION *CurrentBootOptions;\r
397 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;\r
398 EFI_INPUT_KEY *BootKeys;\r
399 PLATFORM_BOOT_MANAGER_PROTOCOL *PlatformBootManager;\r
400 UINTN CurrentBootOptionCount;\r
401 UINTN Index;\r
402 UINTN BootCount;\r
403\r
404 Status = gBS->LocateProtocol (&gPlatformBootManagerProtocolGuid, NULL,\r
405 (VOID **)&PlatformBootManager);\r
406 if (EFI_ERROR (Status)) {\r
407 return;\r
408 }\r
409 Status = PlatformBootManager->GetPlatformBootOptionsAndKeys (\r
410 &BootCount,\r
411 &BootOptions,\r
412 &BootKeys\r
413 );\r
414 if (EFI_ERROR (Status)) {\r
415 return;\r
416 }\r
417 //\r
418 // Fetch the existent boot options. If there are none, CurrentBootCount\r
419 // will be zeroed.\r
420 //\r
421 CurrentBootOptions = EfiBootManagerGetLoadOptions (\r
422 &CurrentBootOptionCount,\r
423 LoadOptionTypeBoot\r
424 );\r
425 //\r
426 // Process the platform boot options.\r
427 //\r
428 for (Index = 0; Index < BootCount; Index++) {\r
429 INTN Match;\r
430 UINTN BootOptionNumber;\r
431\r
432 //\r
433 // If there are any preexistent boot options, and the subject platform boot\r
434 // option is already among them, then don't try to add it. Just get its\r
435 // assigned boot option number so we can associate a hotkey with it. Note\r
436 // that EfiBootManagerFindLoadOption() deals fine with (CurrentBootOptions\r
437 // == NULL) if (CurrentBootCount == 0).\r
438 //\r
439 Match = EfiBootManagerFindLoadOption (\r
440 &BootOptions[Index],\r
441 CurrentBootOptions,\r
442 CurrentBootOptionCount\r
443 );\r
444 if (Match >= 0) {\r
445 BootOptionNumber = CurrentBootOptions[Match].OptionNumber;\r
446 } else {\r
447 //\r
448 // Add the platform boot options as a new one, at the end of the boot\r
449 // order. Note that if the platform provided this boot option with an\r
450 // unassigned option number, then the below function call will assign a\r
451 // number.\r
452 //\r
453 Status = EfiBootManagerAddLoadOptionVariable (\r
454 &BootOptions[Index],\r
455 MAX_UINTN\r
456 );\r
457 if (EFI_ERROR (Status)) {\r
458 DEBUG ((DEBUG_ERROR, "%a: failed to register \"%s\": %r\n",\r
459 __FUNCTION__, BootOptions[Index].Description, Status));\r
460 continue;\r
461 }\r
462 BootOptionNumber = BootOptions[Index].OptionNumber;\r
463 }\r
464\r
465 //\r
466 // Register a hotkey with the boot option, if requested.\r
467 //\r
468 if (BootKeys[Index].UnicodeChar == L'\0') {\r
469 continue;\r
470 }\r
471\r
472 Status = EfiBootManagerAddKeyOptionVariable (\r
473 NULL,\r
474 BootOptionNumber,\r
475 0,\r
2b2959dd 476 &BootKeys[Index],\r
1b6e7633
HZ
477 NULL\r
478 );\r
479 if (EFI_ERROR (Status)) {\r
480 DEBUG ((DEBUG_ERROR, "%a: failed to register hotkey for \"%s\": %r\n",\r
481 __FUNCTION__, BootOptions[Index].Description, Status));\r
482 }\r
483 }\r
484 EfiBootManagerFreeLoadOptions (CurrentBootOptions, CurrentBootOptionCount);\r
485 EfiBootManagerFreeLoadOptions (BootOptions, BootCount);\r
486 FreePool (BootKeys);\r
487}\r
488\r
c976f9cb
AB
489STATIC\r
490VOID\r
491PlatformRegisterOptionsAndKeys (\r
492 VOID\r
493 )\r
494{\r
495 EFI_STATUS Status;\r
496 EFI_INPUT_KEY Enter;\r
497 EFI_INPUT_KEY F2;\r
498 EFI_INPUT_KEY Esc;\r
499 EFI_BOOT_MANAGER_LOAD_OPTION BootOption;\r
500\r
1b6e7633
HZ
501 GetPlatformOptions ();\r
502\r
c976f9cb
AB
503 //\r
504 // Register ENTER as CONTINUE key\r
505 //\r
506 Enter.ScanCode = SCAN_NULL;\r
507 Enter.UnicodeChar = CHAR_CARRIAGE_RETURN;\r
508 Status = EfiBootManagerRegisterContinueKeyOption (0, &Enter, NULL);\r
509 ASSERT_EFI_ERROR (Status);\r
510\r
511 //\r
512 // Map F2 and ESC to Boot Manager Menu\r
513 //\r
514 F2.ScanCode = SCAN_F2;\r
515 F2.UnicodeChar = CHAR_NULL;\r
516 Esc.ScanCode = SCAN_ESC;\r
517 Esc.UnicodeChar = CHAR_NULL;\r
518 Status = EfiBootManagerGetBootManagerMenu (&BootOption);\r
519 ASSERT_EFI_ERROR (Status);\r
520 Status = EfiBootManagerAddKeyOptionVariable (\r
521 NULL, (UINT16) BootOption.OptionNumber, 0, &F2, NULL\r
522 );\r
523 ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);\r
524 Status = EfiBootManagerAddKeyOptionVariable (\r
525 NULL, (UINT16) BootOption.OptionNumber, 0, &Esc, NULL\r
526 );\r
527 ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);\r
528}\r
529\r
530\r
531//\r
532// BDS Platform Functions\r
533//\r
534/**\r
535 Do the platform init, can be customized by OEM/IBV\r
536 Possible things that can be done in PlatformBootManagerBeforeConsole:\r
537 > Update console variable: 1. include hot-plug devices;\r
538 > 2. Clear ConIn and add SOL for AMT\r
539 > Register new Driver#### or Boot####\r
540 > Register new Key####: e.g.: F12\r
541 > Signal ReadyToLock event\r
542 > Authentication action: 1. connect Auth devices;\r
543 > 2. Identify auto logon user.\r
544**/\r
545VOID\r
546EFIAPI\r
547PlatformBootManagerBeforeConsole (\r
548 VOID\r
549 )\r
550{\r
551 //\r
552 // Signal EndOfDxe PI Event\r
553 //\r
554 EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid);\r
555\r
556 //\r
557 // Locate the PCI root bridges and make the PCI bus driver connect each,\r
558 // non-recursively. This will produce a number of child handles with PciIo on\r
559 // them.\r
560 //\r
561 FilterAndProcess (&gEfiPciRootBridgeIoProtocolGuid, NULL, Connect);\r
562\r
563 //\r
564 // Find all display class PCI devices (using the handles from the previous\r
565 // step), and connect them non-recursively. This should produce a number of\r
566 // child handles with GOPs on them.\r
567 //\r
568 FilterAndProcess (&gEfiPciIoProtocolGuid, IsPciDisplay, Connect);\r
569\r
570 //\r
571 // Now add the device path of all handles with GOP on them to ConOut and\r
572 // ErrOut.\r
573 //\r
574 FilterAndProcess (&gEfiGraphicsOutputProtocolGuid, NULL, AddOutput);\r
575\r
576 //\r
577 // Add the hardcoded short-form USB keyboard device path to ConIn.\r
578 //\r
579 EfiBootManagerUpdateConsoleVariable (ConIn,\r
580 (EFI_DEVICE_PATH_PROTOCOL *)&mUsbKeyboard, NULL);\r
581\r
582 //\r
583 // Add the hardcoded serial console device path to ConIn, ConOut, ErrOut.\r
584 //\r
585 ASSERT (FixedPcdGet8 (PcdDefaultTerminalType) == 4);\r
586 CopyGuid (&mSerialConsole.TermType.Guid, &gEfiTtyTermGuid);\r
587\r
588 EfiBootManagerUpdateConsoleVariable (ConIn,\r
589 (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);\r
590 EfiBootManagerUpdateConsoleVariable (ConOut,\r
591 (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);\r
592 EfiBootManagerUpdateConsoleVariable (ErrOut,\r
593 (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);\r
594\r
595 //\r
596 // Register platform-specific boot options and keyboard shortcuts.\r
597 //\r
598 PlatformRegisterOptionsAndKeys ();\r
599}\r
600\r
cae82316
AB
601STATIC\r
602VOID\r
603HandleCapsules (\r
604 VOID\r
605 )\r
606{\r
607 ESRT_MANAGEMENT_PROTOCOL *EsrtManagement;\r
608 EFI_PEI_HOB_POINTERS HobPointer;\r
609 EFI_CAPSULE_HEADER *CapsuleHeader;\r
610 BOOLEAN NeedReset;\r
611 EFI_STATUS Status;\r
612\r
613 DEBUG ((DEBUG_INFO, "%a: processing capsules ...\n", __FUNCTION__));\r
614\r
615 Status = gBS->LocateProtocol (&gEsrtManagementProtocolGuid, NULL,\r
616 (VOID **)&EsrtManagement);\r
617 if (!EFI_ERROR (Status)) {\r
618 EsrtManagement->SyncEsrtFmp ();\r
619 }\r
620\r
621 //\r
622 // Find all capsule images from hob\r
623 //\r
624 HobPointer.Raw = GetHobList ();\r
625 NeedReset = FALSE;\r
626 while ((HobPointer.Raw = GetNextHob (EFI_HOB_TYPE_UEFI_CAPSULE,\r
627 HobPointer.Raw)) != NULL) {\r
628 CapsuleHeader = (VOID *)(UINTN)HobPointer.Capsule->BaseAddress;\r
629\r
630 Status = ProcessCapsuleImage (CapsuleHeader);\r
631 if (EFI_ERROR (Status)) {\r
632 DEBUG ((DEBUG_ERROR, "%a: failed to process capsule %p - %r\n",\r
633 __FUNCTION__, CapsuleHeader, Status));\r
634 return;\r
635 }\r
636\r
637 NeedReset = TRUE;\r
638 HobPointer.Raw = GET_NEXT_HOB (HobPointer);\r
639 }\r
640\r
641 if (NeedReset) {\r
642 DEBUG ((DEBUG_WARN, "%a: capsule update successful, resetting ...\n",\r
643 __FUNCTION__));\r
644\r
645 gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);\r
646 CpuDeadLoop();\r
647 }\r
648}\r
649\r
650\r
6c4194c9
AB
651#define VERSION_STRING_PREFIX L"Tianocore/EDK2 firmware version "\r
652\r
c976f9cb
AB
653/**\r
654 Do the platform specific action after the console is ready\r
655 Possible things that can be done in PlatformBootManagerAfterConsole:\r
656 > Console post action:\r
657 > Dynamically switch output mode from 100x31 to 80x25 for certain senarino\r
658 > Signal console ready platform customized event\r
659 > Run diagnostics like memory testing\r
660 > Connect certain devices\r
661 > Dispatch aditional option roms\r
662 > Special boot: e.g.: USB boot, enter UI\r
663**/\r
664VOID\r
665EFIAPI\r
666PlatformBootManagerAfterConsole (\r
667 VOID\r
668 )\r
669{\r
13ca0abb 670 EFI_STATUS Status;\r
6c4194c9
AB
671 EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;\r
672 UINTN FirmwareVerLength;\r
673 UINTN PosX;\r
674 UINTN PosY;\r
675\r
676 FirmwareVerLength = StrLen (PcdGetPtr (PcdFirmwareVersionString));\r
c976f9cb
AB
677\r
678 //\r
679 // Show the splash screen.\r
680 //\r
a43d75e1
AB
681 Status = BootLogoEnableLogo ();\r
682 if (EFI_ERROR (Status)) {\r
6c4194c9 683 if (FirmwareVerLength > 0) {\r
26b99f3b 684 Print (VERSION_STRING_PREFIX L"%s\n",\r
6c4194c9
AB
685 PcdGetPtr (PcdFirmwareVersionString));\r
686 }\r
a43d75e1 687 Print (L"Press ESCAPE for boot options ");\r
6c4194c9
AB
688 } else if (FirmwareVerLength > 0) {\r
689 Status = gBS->HandleProtocol (gST->ConsoleOutHandle,\r
690 &gEfiGraphicsOutputProtocolGuid, (VOID **)&GraphicsOutput);\r
691 if (!EFI_ERROR (Status)) {\r
692 PosX = (GraphicsOutput->Mode->Info->HorizontalResolution -\r
693 (StrLen (VERSION_STRING_PREFIX) + FirmwareVerLength) *\r
694 EFI_GLYPH_WIDTH) / 2;\r
695 PosY = 0;\r
696\r
697 PrintXY (PosX, PosY, NULL, NULL, VERSION_STRING_PREFIX L"%s",\r
698 PcdGetPtr (PcdFirmwareVersionString));\r
699 }\r
a43d75e1 700 }\r
6c4194c9 701\r
c976f9cb
AB
702 //\r
703 // Connect the rest of the devices.\r
704 //\r
705 EfiBootManagerConnectAll ();\r
706\r
cae82316
AB
707 //\r
708 // On ARM, there is currently no reason to use the phased capsule\r
709 // update approach where some capsules are dispatched before EndOfDxe\r
710 // and some are dispatched after. So just handle all capsules here,\r
711 // when the console is up and we can actually give the user some\r
712 // feedback about what is going on.\r
713 //\r
714 HandleCapsules ();\r
4bbcc285 715\r
c976f9cb
AB
716 //\r
717 // Enumerate all possible boot options.\r
718 //\r
719 EfiBootManagerRefreshAllBootOption ();\r
720\r
721 //\r
722 // Register UEFI Shell\r
723 //\r
724 PlatformRegisterFvBootOption (\r
07548e17 725 &gUefiShellFileGuid, L"UEFI Shell", LOAD_OPTION_ACTIVE\r
c976f9cb
AB
726 );\r
727}\r
728\r
729/**\r
730 This function is called each second during the boot manager waits the\r
731 timeout.\r
732\r
733 @param TimeoutRemain The remaining timeout.\r
734**/\r
735VOID\r
736EFIAPI\r
737PlatformBootManagerWaitCallback (\r
738 UINT16 TimeoutRemain\r
739 )\r
740{\r
a43d75e1
AB
741 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black;\r
742 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White;\r
743 UINT16 Timeout;\r
744 EFI_STATUS Status;\r
745\r
746 Timeout = PcdGet16 (PcdPlatformBootTimeOut);\r
747\r
748 Black.Raw = 0x00000000;\r
749 White.Raw = 0x00FFFFFF;\r
750\r
751 Status = BootLogoUpdateProgress (\r
752 White.Pixel,\r
753 Black.Pixel,\r
754 L"Press ESCAPE for boot options",\r
755 White.Pixel,\r
756 (Timeout - TimeoutRemain) * 100 / Timeout,\r
757 0\r
758 );\r
759 if (EFI_ERROR (Status)) {\r
760 Print (L".");\r
761 }\r
c976f9cb 762}\r
eea668c9
RN
763\r
764/**\r
765 The function is called when no boot option could be launched,\r
766 including platform recovery options and options pointing to applications\r
767 built into firmware volumes.\r
768\r
769 If this function returns, BDS attempts to enter an infinite loop.\r
770**/\r
771VOID\r
772EFIAPI\r
773PlatformBootManagerUnableToBoot (\r
774 VOID\r
775 )\r
776{\r
777 return;\r
778}\r