]> git.proxmox.com Git - mirror_edk2.git/blob - ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBm.c
ArmVirtPkg/PlatformBootManagerLib: rebase boot logo display to BootLogoLib
[mirror_edk2.git] / ArmVirtPkg / 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
8 This program and the accompanying materials are licensed and made available
9 under the terms and conditions of the BSD License which accompanies this
10 distribution. The full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php
12
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
14 WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15
16 **/
17
18 #include <IndustryStandard/Pci22.h>
19 #include <Library/BootLogoLib.h>
20 #include <Library/DevicePathLib.h>
21 #include <Library/PcdLib.h>
22 #include <Library/QemuBootOrderLib.h>
23 #include <Library/UefiBootManagerLib.h>
24 #include <Protocol/DevicePath.h>
25 #include <Protocol/GraphicsOutput.h>
26 #include <Protocol/LoadedImage.h>
27 #include <Protocol/PciIo.h>
28 #include <Protocol/PciRootBridgeIo.h>
29 #include <Guid/EventGroup.h>
30 #include <Guid/RootBridgesConnectedEventGroup.h>
31
32 #include "PlatformBm.h"
33
34 #define DP_NODE_LEN(Type) { (UINT8)sizeof (Type), (UINT8)(sizeof (Type) >> 8) }
35
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 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 // Register UEFI Shell
429 //
430 PlatformRegisterFvBootOption (
431 PcdGetPtr (PcdShellFile), L"EFI Internal Shell", LOAD_OPTION_ACTIVE
432 );
433 }
434
435
436 //
437 // BDS Platform Functions
438 //
439 /**
440 Do the platform init, can be customized by OEM/IBV
441 Possible things that can be done in PlatformBootManagerBeforeConsole:
442 > Update console variable: 1. include hot-plug devices;
443 > 2. Clear ConIn and add SOL for AMT
444 > Register new Driver#### or Boot####
445 > Register new Key####: e.g.: F12
446 > Signal ReadyToLock event
447 > Authentication action: 1. connect Auth devices;
448 > 2. Identify auto logon user.
449 **/
450 VOID
451 EFIAPI
452 PlatformBootManagerBeforeConsole (
453 VOID
454 )
455 {
456 //
457 // Signal EndOfDxe PI Event
458 //
459 EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid);
460
461 //
462 // Locate the PCI root bridges and make the PCI bus driver connect each,
463 // non-recursively. This will produce a number of child handles with PciIo on
464 // them.
465 //
466 FilterAndProcess (&gEfiPciRootBridgeIoProtocolGuid, NULL, Connect);
467
468 //
469 // Signal the ACPI platform driver that it can download QEMU ACPI tables.
470 //
471 EfiEventGroupSignal (&gRootBridgesConnectedEventGroupGuid);
472
473 //
474 // Find all display class PCI devices (using the handles from the previous
475 // step), and connect them non-recursively. This should produce a number of
476 // child handles with GOPs on them.
477 //
478 FilterAndProcess (&gEfiPciIoProtocolGuid, IsPciDisplay, Connect);
479
480 //
481 // Now add the device path of all handles with GOP on them to ConOut and
482 // ErrOut.
483 //
484 FilterAndProcess (&gEfiGraphicsOutputProtocolGuid, NULL, AddOutput);
485
486 //
487 // Add the hardcoded short-form USB keyboard device path to ConIn.
488 //
489 EfiBootManagerUpdateConsoleVariable (ConIn,
490 (EFI_DEVICE_PATH_PROTOCOL *)&mUsbKeyboard, NULL);
491
492 //
493 // Add the hardcoded serial console device path to ConIn, ConOut, ErrOut.
494 //
495 CopyGuid (&mSerialConsole.TermType.Guid,
496 PcdGetPtr (PcdTerminalTypeGuidBuffer));
497 EfiBootManagerUpdateConsoleVariable (ConIn,
498 (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);
499 EfiBootManagerUpdateConsoleVariable (ConOut,
500 (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);
501 EfiBootManagerUpdateConsoleVariable (ErrOut,
502 (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);
503
504 //
505 // Set the front page timeout from the QEMU configuration.
506 //
507 PcdSet16 (PcdPlatformBootTimeOut, GetFrontPageTimeoutFromQemu ());
508
509 //
510 // Register platform-specific boot options and keyboard shortcuts.
511 //
512 PlatformRegisterOptionsAndKeys ();
513 }
514
515 /**
516 Do the platform specific action after the console is ready
517 Possible things that can be done in PlatformBootManagerAfterConsole:
518 > Console post action:
519 > Dynamically switch output mode from 100x31 to 80x25 for certain senarino
520 > Signal console ready platform customized event
521 > Run diagnostics like memory testing
522 > Connect certain devices
523 > Dispatch aditional option roms
524 > Special boot: e.g.: USB boot, enter UI
525 **/
526 VOID
527 EFIAPI
528 PlatformBootManagerAfterConsole (
529 VOID
530 )
531 {
532 //
533 // Show the splash screen.
534 //
535 BootLogoEnableLogo (
536 ImageFormatBmp, // ImageFormat
537 PcdGetPtr (PcdLogoFile), // Logo
538 EdkiiPlatformLogoDisplayAttributeCenter, // Attribute
539 0, // OffsetX
540 0 // OffsetY
541 );
542
543 //
544 // Connect the rest of the devices.
545 //
546 EfiBootManagerConnectAll ();
547
548 //
549 // Process QEMU's -kernel command line option. Note that the kernel booted
550 // this way should receive ACPI tables, which is why we connect all devices
551 // first (see above) -- PCI enumeration blocks ACPI table installation, if
552 // there is a PCI host.
553 //
554 TryRunningQemuKernel ();
555
556 //
557 // Enumerate all possible boot options, then filter and reorder them based on
558 // the QEMU configuration.
559 //
560 EfiBootManagerRefreshAllBootOption ();
561 SetBootOrderFromQemu ();
562 }
563
564 /**
565 This function is called each second during the boot manager waits the
566 timeout.
567
568 @param TimeoutRemain The remaining timeout.
569 **/
570 VOID
571 EFIAPI
572 PlatformBootManagerWaitCallback (
573 UINT16 TimeoutRemain
574 )
575 {
576 }