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