]> git.proxmox.com Git - mirror_edk2.git/blame - ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBm.c
OvmfPkg: remove QemuBootOrderLib instance
[mirror_edk2.git] / ArmVirtPkg / Library / PlatformBootManagerLib / PlatformBm.c
CommitLineData
8d620322
LE
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
793b3b5b 6 Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR>\r
8d620322
LE
7\r
8 This program and the accompanying materials are licensed and made available\r
9 under the terms and conditions of the BSD License which accompanies this\r
10 distribution. The full text of the license may be found at\r
11 http://opensource.org/licenses/bsd-license.php\r
12\r
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT\r
14 WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
15\r
16**/\r
17\r
18#include <IndustryStandard/Pci22.h>\r
19#include <Library/DevicePathLib.h>\r
20#include <Library/PcdLib.h>\r
8d620322 21#include <Library/QemuBootOrderLib.h>\r
2c5c33cd 22#include <Library/UefiBootManagerLib.h>\r
8d620322
LE
23#include <Protocol/DevicePath.h>\r
24#include <Protocol/GraphicsOutput.h>\r
793b3b5b 25#include <Protocol/LoadedImage.h>\r
8d620322
LE
26#include <Protocol/PciIo.h>\r
27#include <Protocol/PciRootBridgeIo.h>\r
28#include <Guid/EventGroup.h>\r
29#include <Guid/RootBridgesConnectedEventGroup.h>\r
30\r
31#include "PlatformBm.h"\r
32\r
33#define DP_NODE_LEN(Type) { (UINT8)sizeof (Type), (UINT8)(sizeof (Type) >> 8) }\r
34\r
35\r
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
8d620322
LE
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
b7a33aff 308 Status = EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);\r
8d620322
LE
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
b7a33aff 315 Status = EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);\r
8d620322
LE
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
793b3b5b
LE
326STATIC\r
327VOID\r
328PlatformRegisterFvBootOption (\r
329 EFI_GUID *FileGuid,\r
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
389STATIC\r
390VOID\r
391PlatformRegisterOptionsAndKeys (\r
392 VOID\r
393 )\r
394{\r
395 EFI_STATUS Status;\r
396 EFI_INPUT_KEY Enter;\r
397 EFI_INPUT_KEY F2;\r
398 EFI_INPUT_KEY Esc;\r
399 EFI_BOOT_MANAGER_LOAD_OPTION BootOption;\r
400\r
401 //\r
402 // Register ENTER as CONTINUE key\r
403 //\r
404 Enter.ScanCode = SCAN_NULL;\r
405 Enter.UnicodeChar = CHAR_CARRIAGE_RETURN;\r
406 Status = EfiBootManagerRegisterContinueKeyOption (0, &Enter, NULL);\r
407 ASSERT_EFI_ERROR (Status);\r
408\r
409 //\r
410 // Map F2 and ESC to Boot Manager Menu\r
411 //\r
412 F2.ScanCode = SCAN_F2;\r
413 F2.UnicodeChar = CHAR_NULL;\r
414 Esc.ScanCode = SCAN_ESC;\r
415 Esc.UnicodeChar = CHAR_NULL;\r
416 Status = EfiBootManagerGetBootManagerMenu (&BootOption);\r
417 ASSERT_EFI_ERROR (Status);\r
418 Status = EfiBootManagerAddKeyOptionVariable (\r
419 NULL, (UINT16) BootOption.OptionNumber, 0, &F2, NULL\r
420 );\r
421 ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);\r
422 Status = EfiBootManagerAddKeyOptionVariable (\r
423 NULL, (UINT16) BootOption.OptionNumber, 0, &Esc, NULL\r
424 );\r
425 ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);\r
426 //\r
427 // Register UEFI Shell\r
428 //\r
429 PlatformRegisterFvBootOption (\r
430 PcdGetPtr (PcdShellFile), L"EFI Internal Shell", LOAD_OPTION_ACTIVE\r
431 );\r
432}\r
433\r
8d620322 434\r
e2a193b7
LE
435//\r
436// BDS Platform Functions\r
437//\r
8d620322 438/**\r
e2a193b7
LE
439 Do the platform init, can be customized by OEM/IBV\r
440 Possible things that can be done in PlatformBootManagerBeforeConsole:\r
441 > Update console variable: 1. include hot-plug devices;\r
442 > 2. Clear ConIn and add SOL for AMT\r
443 > Register new Driver#### or Boot####\r
444 > Register new Key####: e.g.: F12\r
445 > Signal ReadyToLock event\r
446 > Authentication action: 1. connect Auth devices;\r
447 > 2. Identify auto logon user.\r
8d620322
LE
448**/\r
449VOID\r
450EFIAPI\r
e2a193b7 451PlatformBootManagerBeforeConsole (\r
e3fe3c0f 452 VOID\r
8d620322
LE
453 )\r
454{\r
e2a193b7
LE
455 //\r
456 // Signal EndOfDxe PI Event\r
457 //\r
458 EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid);\r
459\r
8d620322
LE
460 //\r
461 // Locate the PCI root bridges and make the PCI bus driver connect each,\r
462 // non-recursively. This will produce a number of child handles with PciIo on\r
463 // them.\r
464 //\r
465 FilterAndProcess (&gEfiPciRootBridgeIoProtocolGuid, NULL, Connect);\r
466\r
467 //\r
468 // Signal the ACPI platform driver that it can download QEMU ACPI tables.\r
469 //\r
470 EfiEventGroupSignal (&gRootBridgesConnectedEventGroupGuid);\r
471\r
472 //\r
473 // Find all display class PCI devices (using the handles from the previous\r
474 // step), and connect them non-recursively. This should produce a number of\r
475 // child handles with GOPs on them.\r
476 //\r
477 FilterAndProcess (&gEfiPciIoProtocolGuid, IsPciDisplay, Connect);\r
478\r
479 //\r
480 // Now add the device path of all handles with GOP on them to ConOut and\r
481 // ErrOut.\r
482 //\r
483 FilterAndProcess (&gEfiGraphicsOutputProtocolGuid, NULL, AddOutput);\r
484\r
485 //\r
486 // Add the hardcoded short-form USB keyboard device path to ConIn.\r
487 //\r
b7a33aff 488 EfiBootManagerUpdateConsoleVariable (ConIn,\r
8d620322
LE
489 (EFI_DEVICE_PATH_PROTOCOL *)&mUsbKeyboard, NULL);\r
490\r
491 //\r
492 // Add the hardcoded serial console device path to ConIn, ConOut, ErrOut.\r
493 //\r
494 CopyGuid (&mSerialConsole.TermType.Guid,\r
495 PcdGetPtr (PcdTerminalTypeGuidBuffer));\r
b7a33aff 496 EfiBootManagerUpdateConsoleVariable (ConIn,\r
8d620322 497 (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);\r
b7a33aff 498 EfiBootManagerUpdateConsoleVariable (ConOut,\r
8d620322 499 (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);\r
b7a33aff 500 EfiBootManagerUpdateConsoleVariable (ErrOut,\r
8d620322 501 (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);\r
48799ab2
LE
502\r
503 //\r
504 // Set the front page timeout from the QEMU configuration.\r
505 //\r
506 PcdSet16 (PcdPlatformBootTimeOut, GetFrontPageTimeoutFromQemu ());\r
793b3b5b
LE
507\r
508 //\r
509 // Register platform-specific boot options and keyboard shortcuts.\r
510 //\r
511 PlatformRegisterOptionsAndKeys ();\r
e2a193b7 512}\r
8d620322 513\r
e2a193b7
LE
514/**\r
515 Do the platform specific action after the console is ready\r
516 Possible things that can be done in PlatformBootManagerAfterConsole:\r
517 > Console post action:\r
518 > Dynamically switch output mode from 100x31 to 80x25 for certain senarino\r
519 > Signal console ready platform customized event\r
520 > Run diagnostics like memory testing\r
521 > Connect certain devices\r
522 > Dispatch aditional option roms\r
523 > Special boot: e.g.: USB boot, enter UI\r
524**/\r
525VOID\r
526EFIAPI\r
527PlatformBootManagerAfterConsole (\r
528 VOID\r
529 )\r
530{\r
8d620322
LE
531 //\r
532 // Show the splash screen.\r
533 //\r
534 EnableQuietBoot (PcdGetPtr (PcdLogoFile));\r
535\r
536 //\r
537 // Connect the rest of the devices.\r
538 //\r
fa0f1954 539 EfiBootManagerConnectAll ();\r
8d620322
LE
540\r
541 //\r
542 // Process QEMU's -kernel command line option. Note that the kernel booted\r
543 // this way should receive ACPI tables, which is why we connect all devices\r
544 // first (see above) -- PCI enumeration blocks ACPI table installation, if\r
545 // there is a PCI host.\r
546 //\r
547 TryRunningQemuKernel ();\r
548\r
8d620322 549 //\r
afa456de
LE
550 // Enumerate all possible boot options, then filter and reorder them based on\r
551 // the QEMU configuration.\r
8d620322 552 //\r
afa456de
LE
553 EfiBootManagerRefreshAllBootOption ();\r
554 SetBootOrderFromQemu (NULL);\r
8d620322
LE
555}\r
556\r
e3fe3c0f
LE
557/**\r
558 This function is called each second during the boot manager waits the\r
559 timeout.\r
560\r
561 @param TimeoutRemain The remaining timeout.\r
562**/\r
563VOID\r
564EFIAPI\r
565PlatformBootManagerWaitCallback (\r
566 UINT16 TimeoutRemain\r
567 )\r
568{\r
569}\r