]> git.proxmox.com Git - mirror_edk2.git/blob - ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBm.c
ArmVirtPkg/PlatformBootManagerLib: Postpone the shell registration
[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
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 // Signal the ACPI platform driver that it can download QEMU ACPI tables.
464 //
465 EfiEventGroupSignal (&gRootBridgesConnectedEventGroupGuid);
466
467 //
468 // Find all display class PCI devices (using the handles from the previous
469 // step), and connect them non-recursively. This should produce a number of
470 // child handles with GOPs on them.
471 //
472 FilterAndProcess (&gEfiPciIoProtocolGuid, IsPciDisplay, Connect);
473
474 //
475 // Now add the device path of all handles with GOP on them to ConOut and
476 // ErrOut.
477 //
478 FilterAndProcess (&gEfiGraphicsOutputProtocolGuid, NULL, AddOutput);
479
480 //
481 // Add the hardcoded short-form USB keyboard device path to ConIn.
482 //
483 EfiBootManagerUpdateConsoleVariable (ConIn,
484 (EFI_DEVICE_PATH_PROTOCOL *)&mUsbKeyboard, NULL);
485
486 //
487 // Add the hardcoded serial console device path to ConIn, ConOut, ErrOut.
488 //
489 CopyGuid (&mSerialConsole.TermType.Guid,
490 PcdGetPtr (PcdTerminalTypeGuidBuffer));
491 EfiBootManagerUpdateConsoleVariable (ConIn,
492 (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);
493 EfiBootManagerUpdateConsoleVariable (ConOut,
494 (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);
495 EfiBootManagerUpdateConsoleVariable (ErrOut,
496 (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);
497
498 //
499 // Set the front page timeout from the QEMU configuration.
500 //
501 PcdSet16 (PcdPlatformBootTimeOut, GetFrontPageTimeoutFromQemu ());
502
503 //
504 // Register platform-specific boot options and keyboard shortcuts.
505 //
506 PlatformRegisterOptionsAndKeys ();
507 }
508
509 /**
510 Do the platform specific action after the console is ready
511 Possible things that can be done in PlatformBootManagerAfterConsole:
512 > Console post action:
513 > Dynamically switch output mode from 100x31 to 80x25 for certain senarino
514 > Signal console ready platform customized event
515 > Run diagnostics like memory testing
516 > Connect certain devices
517 > Dispatch aditional option roms
518 > Special boot: e.g.: USB boot, enter UI
519 **/
520 VOID
521 EFIAPI
522 PlatformBootManagerAfterConsole (
523 VOID
524 )
525 {
526 //
527 // Show the splash screen.
528 //
529 BootLogoEnableLogo (
530 ImageFormatBmp, // ImageFormat
531 PcdGetPtr (PcdLogoFile), // Logo
532 EdkiiPlatformLogoDisplayAttributeCenter, // Attribute
533 0, // OffsetX
534 0 // OffsetY
535 );
536
537 //
538 // Connect the rest of the devices.
539 //
540 EfiBootManagerConnectAll ();
541
542 //
543 // Process QEMU's -kernel command line option. Note that the kernel booted
544 // this way should receive ACPI tables, which is why we connect all devices
545 // first (see above) -- PCI enumeration blocks ACPI table installation, if
546 // there is a PCI host.
547 //
548 TryRunningQemuKernel ();
549
550 //
551 // Enumerate all possible boot options, then filter and reorder them based on
552 // the QEMU configuration.
553 //
554 EfiBootManagerRefreshAllBootOption ();
555
556 //
557 // Register UEFI Shell
558 //
559 PlatformRegisterFvBootOption (
560 PcdGetPtr (PcdShellFile), L"EFI Internal Shell", LOAD_OPTION_ACTIVE
561 );
562
563 SetBootOrderFromQemu ();
564 }
565
566 /**
567 This function is called each second during the boot manager waits the
568 timeout.
569
570 @param TimeoutRemain The remaining timeout.
571 **/
572 VOID
573 EFIAPI
574 PlatformBootManagerWaitCallback (
575 UINT16 TimeoutRemain
576 )
577 {
578 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black;
579 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White;
580 UINT16 Timeout;
581
582 Timeout = PcdGet16 (PcdPlatformBootTimeOut);
583
584 Black.Raw = 0x00000000;
585 White.Raw = 0x00FFFFFF;
586
587 BootLogoUpdateProgress (
588 White.Pixel,
589 Black.Pixel,
590 L"Start boot option",
591 White.Pixel,
592 (Timeout - TimeoutRemain) * 100 / Timeout,
593 0
594 );
595 }