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