ArmVirtPkg/PlatformBootManagerLib: link against UefiBootManagerLib
[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
125//\r
126// BDS Platform Functions\r
127//\r
128/**\r
e3fe3c0f
LE
129 Do the platform init, can be customized by OEM/IBV\r
130 Possible things that can be done in PlatformBootManagerBeforeConsole:\r
131 > Update console variable: 1. include hot-plug devices;\r
132 > 2. Clear ConIn and add SOL for AMT\r
133 > Register new Driver#### or Boot####\r
134 > Register new Key####: e.g.: F12\r
135 > Signal ReadyToLock event\r
136 > Authentication action: 1. connect Auth devices;\r
137 > 2. Identify auto logon user.\r
8d620322
LE
138**/\r
139VOID\r
140EFIAPI\r
e3fe3c0f 141PlatformBootManagerBeforeConsole (\r
8d620322
LE
142 VOID\r
143 )\r
144{\r
145 //\r
146 // Signal EndOfDxe PI Event\r
147 //\r
148 EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid);\r
149}\r
150\r
151\r
152/**\r
153 Check if the handle satisfies a particular condition.\r
154\r
155 @param[in] Handle The handle to check.\r
156 @param[in] ReportText A caller-allocated string passed in for reporting\r
157 purposes. It must never be NULL.\r
158\r
159 @retval TRUE The condition is satisfied.\r
160 @retval FALSE Otherwise. This includes the case when the condition could not\r
161 be fully evaluated due to an error.\r
162**/\r
163typedef\r
164BOOLEAN\r
165(EFIAPI *FILTER_FUNCTION) (\r
166 IN EFI_HANDLE Handle,\r
167 IN CONST CHAR16 *ReportText\r
168 );\r
169\r
170\r
171/**\r
172 Process a handle.\r
173\r
174 @param[in] Handle The handle to process.\r
175 @param[in] ReportText A caller-allocated string passed in for reporting\r
176 purposes. It must never be NULL.\r
177**/\r
178typedef\r
179VOID\r
180(EFIAPI *CALLBACK_FUNCTION) (\r
181 IN EFI_HANDLE Handle,\r
182 IN CONST CHAR16 *ReportText\r
183 );\r
184\r
185/**\r
186 Locate all handles that carry the specified protocol, filter them with a\r
187 callback function, and pass each handle that passes the filter to another\r
188 callback.\r
189\r
190 @param[in] ProtocolGuid The protocol to look for.\r
191\r
192 @param[in] Filter The filter function to pass each handle to. If this\r
193 parameter is NULL, then all handles are processed.\r
194\r
195 @param[in] Process The callback function to pass each handle to that\r
196 clears the filter.\r
197**/\r
198STATIC\r
199VOID\r
200FilterAndProcess (\r
201 IN EFI_GUID *ProtocolGuid,\r
202 IN FILTER_FUNCTION Filter OPTIONAL,\r
203 IN CALLBACK_FUNCTION Process\r
204 )\r
205{\r
206 EFI_STATUS Status;\r
207 EFI_HANDLE *Handles;\r
208 UINTN NoHandles;\r
209 UINTN Idx;\r
210\r
211 Status = gBS->LocateHandleBuffer (ByProtocol, ProtocolGuid,\r
212 NULL /* SearchKey */, &NoHandles, &Handles);\r
213 if (EFI_ERROR (Status)) {\r
214 //\r
215 // This is not an error, just an informative condition.\r
216 //\r
217 DEBUG ((EFI_D_VERBOSE, "%a: %g: %r\n", __FUNCTION__, ProtocolGuid,\r
218 Status));\r
219 return;\r
220 }\r
221\r
222 ASSERT (NoHandles > 0);\r
223 for (Idx = 0; Idx < NoHandles; ++Idx) {\r
224 CHAR16 *DevicePathText;\r
225 STATIC CHAR16 Fallback[] = L"<device path unavailable>";\r
226\r
227 //\r
228 // The ConvertDevicePathToText() function handles NULL input transparently.\r
229 //\r
230 DevicePathText = ConvertDevicePathToText (\r
231 DevicePathFromHandle (Handles[Idx]),\r
232 FALSE, // DisplayOnly\r
233 FALSE // AllowShortcuts\r
234 );\r
235 if (DevicePathText == NULL) {\r
236 DevicePathText = Fallback;\r
237 }\r
238\r
239 if (Filter == NULL || Filter (Handles[Idx], DevicePathText)) {\r
240 Process (Handles[Idx], DevicePathText);\r
241 }\r
242\r
243 if (DevicePathText != Fallback) {\r
244 FreePool (DevicePathText);\r
245 }\r
246 }\r
247 gBS->FreePool (Handles);\r
248}\r
249\r
250\r
251/**\r
252 This FILTER_FUNCTION checks if a handle corresponds to a PCI display device.\r
253**/\r
254STATIC\r
255BOOLEAN\r
256EFIAPI\r
257IsPciDisplay (\r
258 IN EFI_HANDLE Handle,\r
259 IN CONST CHAR16 *ReportText\r
260 )\r
261{\r
262 EFI_STATUS Status;\r
263 EFI_PCI_IO_PROTOCOL *PciIo;\r
264 PCI_TYPE00 Pci;\r
265\r
266 Status = gBS->HandleProtocol (Handle, &gEfiPciIoProtocolGuid,\r
267 (VOID**)&PciIo);\r
268 if (EFI_ERROR (Status)) {\r
269 //\r
270 // This is not an error worth reporting.\r
271 //\r
272 return FALSE;\r
273 }\r
274\r
275 Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, 0 /* Offset */,\r
276 sizeof Pci / sizeof (UINT32), &Pci);\r
277 if (EFI_ERROR (Status)) {\r
278 DEBUG ((EFI_D_ERROR, "%a: %s: %r\n", __FUNCTION__, ReportText, Status));\r
279 return FALSE;\r
280 }\r
281\r
282 return IS_PCI_DISPLAY (&Pci);\r
283}\r
284\r
285\r
286/**\r
287 This CALLBACK_FUNCTION attempts to connect a handle non-recursively, asking\r
288 the matching driver to produce all first-level child handles.\r
289**/\r
290STATIC\r
291VOID\r
292EFIAPI\r
293Connect (\r
294 IN EFI_HANDLE Handle,\r
295 IN CONST CHAR16 *ReportText\r
296 )\r
297{\r
298 EFI_STATUS Status;\r
299\r
300 Status = gBS->ConnectController (\r
301 Handle, // ControllerHandle\r
302 NULL, // DriverImageHandle\r
303 NULL, // RemainingDevicePath -- produce all children\r
304 FALSE // Recursive\r
305 );\r
306 DEBUG ((EFI_ERROR (Status) ? EFI_D_ERROR : EFI_D_VERBOSE, "%a: %s: %r\n",\r
307 __FUNCTION__, ReportText, Status));\r
308}\r
309\r
310\r
311/**\r
312 This CALLBACK_FUNCTION retrieves the EFI_DEVICE_PATH_PROTOCOL from the\r
313 handle, and adds it to ConOut and ErrOut.\r
314**/\r
315STATIC\r
316VOID\r
317EFIAPI\r
318AddOutput (\r
319 IN EFI_HANDLE Handle,\r
320 IN CONST CHAR16 *ReportText\r
321 )\r
322{\r
323 EFI_STATUS Status;\r
324 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
325\r
326 DevicePath = DevicePathFromHandle (Handle);\r
327 if (DevicePath == NULL) {\r
328 DEBUG ((EFI_D_ERROR, "%a: %s: handle %p: device path not found\n",\r
329 __FUNCTION__, ReportText, Handle));\r
330 return;\r
331 }\r
332\r
b7a33aff 333 Status = EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);\r
8d620322
LE
334 if (EFI_ERROR (Status)) {\r
335 DEBUG ((EFI_D_ERROR, "%a: %s: adding to ConOut: %r\n", __FUNCTION__,\r
336 ReportText, Status));\r
337 return;\r
338 }\r
339\r
b7a33aff 340 Status = EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);\r
8d620322
LE
341 if (EFI_ERROR (Status)) {\r
342 DEBUG ((EFI_D_ERROR, "%a: %s: adding to ErrOut: %r\n", __FUNCTION__,\r
343 ReportText, Status));\r
344 return;\r
345 }\r
346\r
347 DEBUG ((EFI_D_VERBOSE, "%a: %s: added to ConOut and ErrOut\n", __FUNCTION__,\r
348 ReportText));\r
349}\r
350\r
351\r
352/**\r
e3fe3c0f
LE
353 Do the platform specific action after the console is ready\r
354 Possible things that can be done in PlatformBootManagerAfterConsole:\r
355 > Console post action:\r
356 > Dynamically switch output mode from 100x31 to 80x25 for certain senarino\r
357 > Signal console ready platform customized event\r
358 > Run diagnostics like memory testing\r
359 > Connect certain devices\r
360 > Dispatch aditional option roms\r
361 > Special boot: e.g.: USB boot, enter UI\r
8d620322
LE
362**/\r
363VOID\r
364EFIAPI\r
e3fe3c0f
LE
365PlatformBootManagerAfterConsole (\r
366 VOID\r
8d620322
LE
367 )\r
368{\r
369 //\r
370 // Locate the PCI root bridges and make the PCI bus driver connect each,\r
371 // non-recursively. This will produce a number of child handles with PciIo on\r
372 // them.\r
373 //\r
374 FilterAndProcess (&gEfiPciRootBridgeIoProtocolGuid, NULL, Connect);\r
375\r
376 //\r
377 // Signal the ACPI platform driver that it can download QEMU ACPI tables.\r
378 //\r
379 EfiEventGroupSignal (&gRootBridgesConnectedEventGroupGuid);\r
380\r
381 //\r
382 // Find all display class PCI devices (using the handles from the previous\r
383 // step), and connect them non-recursively. This should produce a number of\r
384 // child handles with GOPs on them.\r
385 //\r
386 FilterAndProcess (&gEfiPciIoProtocolGuid, IsPciDisplay, Connect);\r
387\r
388 //\r
389 // Now add the device path of all handles with GOP on them to ConOut and\r
390 // ErrOut.\r
391 //\r
392 FilterAndProcess (&gEfiGraphicsOutputProtocolGuid, NULL, AddOutput);\r
393\r
394 //\r
395 // Add the hardcoded short-form USB keyboard device path to ConIn.\r
396 //\r
b7a33aff 397 EfiBootManagerUpdateConsoleVariable (ConIn,\r
8d620322
LE
398 (EFI_DEVICE_PATH_PROTOCOL *)&mUsbKeyboard, NULL);\r
399\r
400 //\r
401 // Add the hardcoded serial console device path to ConIn, ConOut, ErrOut.\r
402 //\r
403 CopyGuid (&mSerialConsole.TermType.Guid,\r
404 PcdGetPtr (PcdTerminalTypeGuidBuffer));\r
b7a33aff 405 EfiBootManagerUpdateConsoleVariable (ConIn,\r
8d620322 406 (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);\r
b7a33aff 407 EfiBootManagerUpdateConsoleVariable (ConOut,\r
8d620322 408 (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);\r
b7a33aff 409 EfiBootManagerUpdateConsoleVariable (ErrOut,\r
8d620322
LE
410 (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);\r
411\r
412 //\r
413 // Connect the consoles based on the above variables.\r
414 //\r
415 BdsLibConnectAllDefaultConsoles ();\r
416\r
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
442\r
443 PlatformBdsEnterFrontPage (GetFrontPageTimeoutFromQemu(), TRUE);\r
444}\r
445\r
446/**\r
447 Hook point after a boot attempt succeeds. We don't expect a boot option to\r
448 return, so the UEFI 2.0 specification defines that you will default to an\r
449 interactive mode and stop processing the BootOrder list in this case. This\r
450 is also a platform implementation and can be customized by IBV/OEM.\r
451\r
452 @param Option Pointer to Boot Option that succeeded to boot.\r
453\r
454**/\r
455VOID\r
456EFIAPI\r
457PlatformBdsBootSuccess (\r
458 IN BDS_COMMON_OPTION *Option\r
459 )\r
460{\r
461}\r
462\r
463/**\r
464 Hook point after a boot attempt fails.\r
465\r
466 @param Option Pointer to Boot Option that failed to boot.\r
467 @param Status Status returned from failed boot.\r
468 @param ExitData Exit data returned from failed boot.\r
469 @param ExitDataSize Exit data size returned from failed boot.\r
470\r
471**/\r
472VOID\r
473EFIAPI\r
474PlatformBdsBootFail (\r
475 IN BDS_COMMON_OPTION *Option,\r
476 IN EFI_STATUS Status,\r
477 IN CHAR16 *ExitData,\r
478 IN UINTN ExitDataSize\r
479 )\r
480{\r
481}\r
482\r
483/**\r
484 This function locks platform flash that is not allowed to be updated during normal boot path.\r
485 The flash layout is platform specific.\r
486**/\r
487VOID\r
488EFIAPI\r
489PlatformBdsLockNonUpdatableFlash (\r
490 VOID\r
491 )\r
492{\r
493 return;\r
494}\r
e3fe3c0f
LE
495\r
496/**\r
497 This function is called each second during the boot manager waits the\r
498 timeout.\r
499\r
500 @param TimeoutRemain The remaining timeout.\r
501**/\r
502VOID\r
503EFIAPI\r
504PlatformBootManagerWaitCallback (\r
505 UINT16 TimeoutRemain\r
506 )\r
507{\r
508}\r