ArmVirtPkg/PlatformBootManagerLib: don't launch the Boot Manager Menu
[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
6 Copyright (c) 2004 - 2008, Intel Corporation. All rights reserved.<BR>\r
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
25#include <Protocol/PciIo.h>\r
26#include <Protocol/PciRootBridgeIo.h>\r
27#include <Guid/EventGroup.h>\r
28#include <Guid/RootBridgesConnectedEventGroup.h>\r
29\r
30#include "PlatformBm.h"\r
31\r
32#define DP_NODE_LEN(Type) { (UINT8)sizeof (Type), (UINT8)(sizeof (Type) >> 8) }\r
33\r
34\r
35#pragma pack (1)\r
36typedef struct {\r
37 VENDOR_DEVICE_PATH SerialDxe;\r
38 UART_DEVICE_PATH Uart;\r
39 VENDOR_DEFINED_DEVICE_PATH TermType;\r
40 EFI_DEVICE_PATH_PROTOCOL End;\r
41} PLATFORM_SERIAL_CONSOLE;\r
42#pragma pack ()\r
43\r
44#define SERIAL_DXE_FILE_GUID { \\r
45 0xD3987D4B, 0x971A, 0x435F, \\r
46 { 0x8C, 0xAF, 0x49, 0x67, 0xEB, 0x62, 0x72, 0x41 } \\r
47 }\r
48\r
49STATIC PLATFORM_SERIAL_CONSOLE mSerialConsole = {\r
50 //\r
51 // VENDOR_DEVICE_PATH SerialDxe\r
52 //\r
53 {\r
54 { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, DP_NODE_LEN (VENDOR_DEVICE_PATH) },\r
55 SERIAL_DXE_FILE_GUID\r
56 },\r
57\r
58 //\r
59 // UART_DEVICE_PATH Uart\r
60 //\r
61 {\r
62 { MESSAGING_DEVICE_PATH, MSG_UART_DP, DP_NODE_LEN (UART_DEVICE_PATH) },\r
63 0, // Reserved\r
64 FixedPcdGet64 (PcdUartDefaultBaudRate), // BaudRate\r
65 FixedPcdGet8 (PcdUartDefaultDataBits), // DataBits\r
66 FixedPcdGet8 (PcdUartDefaultParity), // Parity\r
67 FixedPcdGet8 (PcdUartDefaultStopBits) // StopBits\r
68 },\r
69\r
70 //\r
71 // VENDOR_DEFINED_DEVICE_PATH TermType\r
72 //\r
73 {\r
74 {\r
75 MESSAGING_DEVICE_PATH, MSG_VENDOR_DP,\r
76 DP_NODE_LEN (VENDOR_DEFINED_DEVICE_PATH)\r
77 }\r
78 //\r
79 // Guid to be filled in dynamically\r
80 //\r
81 },\r
82\r
83 //\r
84 // EFI_DEVICE_PATH_PROTOCOL End\r
85 //\r
86 {\r
87 END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
88 DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL)\r
89 }\r
90};\r
91\r
92\r
93#pragma pack (1)\r
94typedef struct {\r
95 USB_CLASS_DEVICE_PATH Keyboard;\r
96 EFI_DEVICE_PATH_PROTOCOL End;\r
97} PLATFORM_USB_KEYBOARD;\r
98#pragma pack ()\r
99\r
100STATIC PLATFORM_USB_KEYBOARD mUsbKeyboard = {\r
101 //\r
102 // USB_CLASS_DEVICE_PATH Keyboard\r
103 //\r
104 {\r
105 {\r
106 MESSAGING_DEVICE_PATH, MSG_USB_CLASS_DP,\r
107 DP_NODE_LEN (USB_CLASS_DEVICE_PATH)\r
108 },\r
109 0xFFFF, // VendorId: any\r
110 0xFFFF, // ProductId: any\r
111 3, // DeviceClass: HID\r
112 1, // DeviceSubClass: boot\r
113 1 // DeviceProtocol: keyboard\r
114 },\r
115\r
116 //\r
117 // EFI_DEVICE_PATH_PROTOCOL End\r
118 //\r
119 {\r
120 END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
121 DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL)\r
122 }\r
123};\r
124\r
8d620322
LE
125\r
126/**\r
127 Check if the handle satisfies a particular condition.\r
128\r
129 @param[in] Handle The handle to check.\r
130 @param[in] ReportText A caller-allocated string passed in for reporting\r
131 purposes. It must never be NULL.\r
132\r
133 @retval TRUE The condition is satisfied.\r
134 @retval FALSE Otherwise. This includes the case when the condition could not\r
135 be fully evaluated due to an error.\r
136**/\r
137typedef\r
138BOOLEAN\r
139(EFIAPI *FILTER_FUNCTION) (\r
140 IN EFI_HANDLE Handle,\r
141 IN CONST CHAR16 *ReportText\r
142 );\r
143\r
144\r
145/**\r
146 Process a handle.\r
147\r
148 @param[in] Handle The handle to process.\r
149 @param[in] ReportText A caller-allocated string passed in for reporting\r
150 purposes. It must never be NULL.\r
151**/\r
152typedef\r
153VOID\r
154(EFIAPI *CALLBACK_FUNCTION) (\r
155 IN EFI_HANDLE Handle,\r
156 IN CONST CHAR16 *ReportText\r
157 );\r
158\r
159/**\r
160 Locate all handles that carry the specified protocol, filter them with a\r
161 callback function, and pass each handle that passes the filter to another\r
162 callback.\r
163\r
164 @param[in] ProtocolGuid The protocol to look for.\r
165\r
166 @param[in] Filter The filter function to pass each handle to. If this\r
167 parameter is NULL, then all handles are processed.\r
168\r
169 @param[in] Process The callback function to pass each handle to that\r
170 clears the filter.\r
171**/\r
172STATIC\r
173VOID\r
174FilterAndProcess (\r
175 IN EFI_GUID *ProtocolGuid,\r
176 IN FILTER_FUNCTION Filter OPTIONAL,\r
177 IN CALLBACK_FUNCTION Process\r
178 )\r
179{\r
180 EFI_STATUS Status;\r
181 EFI_HANDLE *Handles;\r
182 UINTN NoHandles;\r
183 UINTN Idx;\r
184\r
185 Status = gBS->LocateHandleBuffer (ByProtocol, ProtocolGuid,\r
186 NULL /* SearchKey */, &NoHandles, &Handles);\r
187 if (EFI_ERROR (Status)) {\r
188 //\r
189 // This is not an error, just an informative condition.\r
190 //\r
191 DEBUG ((EFI_D_VERBOSE, "%a: %g: %r\n", __FUNCTION__, ProtocolGuid,\r
192 Status));\r
193 return;\r
194 }\r
195\r
196 ASSERT (NoHandles > 0);\r
197 for (Idx = 0; Idx < NoHandles; ++Idx) {\r
198 CHAR16 *DevicePathText;\r
199 STATIC CHAR16 Fallback[] = L"<device path unavailable>";\r
200\r
201 //\r
202 // The ConvertDevicePathToText() function handles NULL input transparently.\r
203 //\r
204 DevicePathText = ConvertDevicePathToText (\r
205 DevicePathFromHandle (Handles[Idx]),\r
206 FALSE, // DisplayOnly\r
207 FALSE // AllowShortcuts\r
208 );\r
209 if (DevicePathText == NULL) {\r
210 DevicePathText = Fallback;\r
211 }\r
212\r
213 if (Filter == NULL || Filter (Handles[Idx], DevicePathText)) {\r
214 Process (Handles[Idx], DevicePathText);\r
215 }\r
216\r
217 if (DevicePathText != Fallback) {\r
218 FreePool (DevicePathText);\r
219 }\r
220 }\r
221 gBS->FreePool (Handles);\r
222}\r
223\r
224\r
225/**\r
226 This FILTER_FUNCTION checks if a handle corresponds to a PCI display device.\r
227**/\r
228STATIC\r
229BOOLEAN\r
230EFIAPI\r
231IsPciDisplay (\r
232 IN EFI_HANDLE Handle,\r
233 IN CONST CHAR16 *ReportText\r
234 )\r
235{\r
236 EFI_STATUS Status;\r
237 EFI_PCI_IO_PROTOCOL *PciIo;\r
238 PCI_TYPE00 Pci;\r
239\r
240 Status = gBS->HandleProtocol (Handle, &gEfiPciIoProtocolGuid,\r
241 (VOID**)&PciIo);\r
242 if (EFI_ERROR (Status)) {\r
243 //\r
244 // This is not an error worth reporting.\r
245 //\r
246 return FALSE;\r
247 }\r
248\r
249 Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, 0 /* Offset */,\r
250 sizeof Pci / sizeof (UINT32), &Pci);\r
251 if (EFI_ERROR (Status)) {\r
252 DEBUG ((EFI_D_ERROR, "%a: %s: %r\n", __FUNCTION__, ReportText, Status));\r
253 return FALSE;\r
254 }\r
255\r
256 return IS_PCI_DISPLAY (&Pci);\r
257}\r
258\r
259\r
260/**\r
261 This CALLBACK_FUNCTION attempts to connect a handle non-recursively, asking\r
262 the matching driver to produce all first-level child handles.\r
263**/\r
264STATIC\r
265VOID\r
266EFIAPI\r
267Connect (\r
268 IN EFI_HANDLE Handle,\r
269 IN CONST CHAR16 *ReportText\r
270 )\r
271{\r
272 EFI_STATUS Status;\r
273\r
274 Status = gBS->ConnectController (\r
275 Handle, // ControllerHandle\r
276 NULL, // DriverImageHandle\r
277 NULL, // RemainingDevicePath -- produce all children\r
278 FALSE // Recursive\r
279 );\r
280 DEBUG ((EFI_ERROR (Status) ? EFI_D_ERROR : EFI_D_VERBOSE, "%a: %s: %r\n",\r
281 __FUNCTION__, ReportText, Status));\r
282}\r
283\r
284\r
285/**\r
286 This CALLBACK_FUNCTION retrieves the EFI_DEVICE_PATH_PROTOCOL from the\r
287 handle, and adds it to ConOut and ErrOut.\r
288**/\r
289STATIC\r
290VOID\r
291EFIAPI\r
292AddOutput (\r
293 IN EFI_HANDLE Handle,\r
294 IN CONST CHAR16 *ReportText\r
295 )\r
296{\r
297 EFI_STATUS Status;\r
298 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
299\r
300 DevicePath = DevicePathFromHandle (Handle);\r
301 if (DevicePath == NULL) {\r
302 DEBUG ((EFI_D_ERROR, "%a: %s: handle %p: device path not found\n",\r
303 __FUNCTION__, ReportText, Handle));\r
304 return;\r
305 }\r
306\r
b7a33aff 307 Status = EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);\r
8d620322
LE
308 if (EFI_ERROR (Status)) {\r
309 DEBUG ((EFI_D_ERROR, "%a: %s: adding to ConOut: %r\n", __FUNCTION__,\r
310 ReportText, Status));\r
311 return;\r
312 }\r
313\r
b7a33aff 314 Status = EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);\r
8d620322
LE
315 if (EFI_ERROR (Status)) {\r
316 DEBUG ((EFI_D_ERROR, "%a: %s: adding to ErrOut: %r\n", __FUNCTION__,\r
317 ReportText, Status));\r
318 return;\r
319 }\r
320\r
321 DEBUG ((EFI_D_VERBOSE, "%a: %s: added to ConOut and ErrOut\n", __FUNCTION__,\r
322 ReportText));\r
323}\r
324\r
325\r
e2a193b7
LE
326//\r
327// BDS Platform Functions\r
328//\r
8d620322 329/**\r
e2a193b7
LE
330 Do the platform init, can be customized by OEM/IBV\r
331 Possible things that can be done in PlatformBootManagerBeforeConsole:\r
332 > Update console variable: 1. include hot-plug devices;\r
333 > 2. Clear ConIn and add SOL for AMT\r
334 > Register new Driver#### or Boot####\r
335 > Register new Key####: e.g.: F12\r
336 > Signal ReadyToLock event\r
337 > Authentication action: 1. connect Auth devices;\r
338 > 2. Identify auto logon user.\r
8d620322
LE
339**/\r
340VOID\r
341EFIAPI\r
e2a193b7 342PlatformBootManagerBeforeConsole (\r
e3fe3c0f 343 VOID\r
8d620322
LE
344 )\r
345{\r
e2a193b7
LE
346 //\r
347 // Signal EndOfDxe PI Event\r
348 //\r
349 EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid);\r
350\r
8d620322
LE
351 //\r
352 // Locate the PCI root bridges and make the PCI bus driver connect each,\r
353 // non-recursively. This will produce a number of child handles with PciIo on\r
354 // them.\r
355 //\r
356 FilterAndProcess (&gEfiPciRootBridgeIoProtocolGuid, NULL, Connect);\r
357\r
358 //\r
359 // Signal the ACPI platform driver that it can download QEMU ACPI tables.\r
360 //\r
361 EfiEventGroupSignal (&gRootBridgesConnectedEventGroupGuid);\r
362\r
363 //\r
364 // Find all display class PCI devices (using the handles from the previous\r
365 // step), and connect them non-recursively. This should produce a number of\r
366 // child handles with GOPs on them.\r
367 //\r
368 FilterAndProcess (&gEfiPciIoProtocolGuid, IsPciDisplay, Connect);\r
369\r
370 //\r
371 // Now add the device path of all handles with GOP on them to ConOut and\r
372 // ErrOut.\r
373 //\r
374 FilterAndProcess (&gEfiGraphicsOutputProtocolGuid, NULL, AddOutput);\r
375\r
376 //\r
377 // Add the hardcoded short-form USB keyboard device path to ConIn.\r
378 //\r
b7a33aff 379 EfiBootManagerUpdateConsoleVariable (ConIn,\r
8d620322
LE
380 (EFI_DEVICE_PATH_PROTOCOL *)&mUsbKeyboard, NULL);\r
381\r
382 //\r
383 // Add the hardcoded serial console device path to ConIn, ConOut, ErrOut.\r
384 //\r
385 CopyGuid (&mSerialConsole.TermType.Guid,\r
386 PcdGetPtr (PcdTerminalTypeGuidBuffer));\r
b7a33aff 387 EfiBootManagerUpdateConsoleVariable (ConIn,\r
8d620322 388 (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);\r
b7a33aff 389 EfiBootManagerUpdateConsoleVariable (ConOut,\r
8d620322 390 (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);\r
b7a33aff 391 EfiBootManagerUpdateConsoleVariable (ErrOut,\r
8d620322 392 (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);\r
48799ab2
LE
393\r
394 //\r
395 // Set the front page timeout from the QEMU configuration.\r
396 //\r
397 PcdSet16 (PcdPlatformBootTimeOut, GetFrontPageTimeoutFromQemu ());\r
e2a193b7 398}\r
8d620322 399\r
e2a193b7
LE
400/**\r
401 Do the platform specific action after the console is ready\r
402 Possible things that can be done in PlatformBootManagerAfterConsole:\r
403 > Console post action:\r
404 > Dynamically switch output mode from 100x31 to 80x25 for certain senarino\r
405 > Signal console ready platform customized event\r
406 > Run diagnostics like memory testing\r
407 > Connect certain devices\r
408 > Dispatch aditional option roms\r
409 > Special boot: e.g.: USB boot, enter UI\r
410**/\r
411VOID\r
412EFIAPI\r
413PlatformBootManagerAfterConsole (\r
414 VOID\r
415 )\r
416{\r
8d620322
LE
417 //\r
418 // Show the splash screen.\r
419 //\r
420 EnableQuietBoot (PcdGetPtr (PcdLogoFile));\r
421\r
422 //\r
423 // Connect the rest of the devices.\r
424 //\r
425 BdsLibConnectAll ();\r
426\r
427 //\r
428 // Process QEMU's -kernel command line option. Note that the kernel booted\r
429 // this way should receive ACPI tables, which is why we connect all devices\r
430 // first (see above) -- PCI enumeration blocks ACPI table installation, if\r
431 // there is a PCI host.\r
432 //\r
433 TryRunningQemuKernel ();\r
434\r
435 BdsLibEnumerateAllBootOption (BootOptionList);\r
436 SetBootOrderFromQemu (BootOptionList);\r
437 //\r
438 // The BootOrder variable may have changed, reload the in-memory list with\r
439 // it.\r
440 //\r
441 BdsLibBuildOptionFromVar (BootOptionList, L"BootOrder");\r
8d620322
LE
442}\r
443\r
444/**\r
445 Hook point after a boot attempt succeeds. We don't expect a boot option to\r
446 return, so the UEFI 2.0 specification defines that you will default to an\r
447 interactive mode and stop processing the BootOrder list in this case. This\r
448 is also a platform implementation and can be customized by IBV/OEM.\r
449\r
450 @param Option Pointer to Boot Option that succeeded to boot.\r
451\r
452**/\r
453VOID\r
454EFIAPI\r
455PlatformBdsBootSuccess (\r
456 IN BDS_COMMON_OPTION *Option\r
457 )\r
458{\r
459}\r
460\r
461/**\r
462 Hook point after a boot attempt fails.\r
463\r
464 @param Option Pointer to Boot Option that failed to boot.\r
465 @param Status Status returned from failed boot.\r
466 @param ExitData Exit data returned from failed boot.\r
467 @param ExitDataSize Exit data size returned from failed boot.\r
468\r
469**/\r
470VOID\r
471EFIAPI\r
472PlatformBdsBootFail (\r
473 IN BDS_COMMON_OPTION *Option,\r
474 IN EFI_STATUS Status,\r
475 IN CHAR16 *ExitData,\r
476 IN UINTN ExitDataSize\r
477 )\r
478{\r
479}\r
480\r
481/**\r
482 This function locks platform flash that is not allowed to be updated during normal boot path.\r
483 The flash layout is platform specific.\r
484**/\r
485VOID\r
486EFIAPI\r
487PlatformBdsLockNonUpdatableFlash (\r
488 VOID\r
489 )\r
490{\r
491 return;\r
492}\r
e3fe3c0f
LE
493\r
494/**\r
495 This function is called each second during the boot manager waits the\r
496 timeout.\r
497\r
498 @param TimeoutRemain The remaining timeout.\r
499**/\r
500VOID\r
501EFIAPI\r
502PlatformBootManagerWaitCallback (\r
503 UINT16 TimeoutRemain\r
504 )\r
505{\r
506}\r