ArmVirtPkg: duplicate PlatformIntelBdsLib to PlatformBootManagerLib
[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
21#include <Library/PlatformBdsLib.h>\r
22#include <Library/QemuBootOrderLib.h>\r
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
129 Platform Bds init. Include the platform firmware vendor, revision\r
130 and so crc check.\r
131\r
132**/\r
133VOID\r
134EFIAPI\r
135PlatformBdsInit (\r
136 VOID\r
137 )\r
138{\r
139 //\r
140 // Signal EndOfDxe PI Event\r
141 //\r
142 EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid);\r
143}\r
144\r
145\r
146/**\r
147 Check if the handle satisfies a particular condition.\r
148\r
149 @param[in] Handle The handle to check.\r
150 @param[in] ReportText A caller-allocated string passed in for reporting\r
151 purposes. It must never be NULL.\r
152\r
153 @retval TRUE The condition is satisfied.\r
154 @retval FALSE Otherwise. This includes the case when the condition could not\r
155 be fully evaluated due to an error.\r
156**/\r
157typedef\r
158BOOLEAN\r
159(EFIAPI *FILTER_FUNCTION) (\r
160 IN EFI_HANDLE Handle,\r
161 IN CONST CHAR16 *ReportText\r
162 );\r
163\r
164\r
165/**\r
166 Process a handle.\r
167\r
168 @param[in] Handle The handle to process.\r
169 @param[in] ReportText A caller-allocated string passed in for reporting\r
170 purposes. It must never be NULL.\r
171**/\r
172typedef\r
173VOID\r
174(EFIAPI *CALLBACK_FUNCTION) (\r
175 IN EFI_HANDLE Handle,\r
176 IN CONST CHAR16 *ReportText\r
177 );\r
178\r
179/**\r
180 Locate all handles that carry the specified protocol, filter them with a\r
181 callback function, and pass each handle that passes the filter to another\r
182 callback.\r
183\r
184 @param[in] ProtocolGuid The protocol to look for.\r
185\r
186 @param[in] Filter The filter function to pass each handle to. If this\r
187 parameter is NULL, then all handles are processed.\r
188\r
189 @param[in] Process The callback function to pass each handle to that\r
190 clears the filter.\r
191**/\r
192STATIC\r
193VOID\r
194FilterAndProcess (\r
195 IN EFI_GUID *ProtocolGuid,\r
196 IN FILTER_FUNCTION Filter OPTIONAL,\r
197 IN CALLBACK_FUNCTION Process\r
198 )\r
199{\r
200 EFI_STATUS Status;\r
201 EFI_HANDLE *Handles;\r
202 UINTN NoHandles;\r
203 UINTN Idx;\r
204\r
205 Status = gBS->LocateHandleBuffer (ByProtocol, ProtocolGuid,\r
206 NULL /* SearchKey */, &NoHandles, &Handles);\r
207 if (EFI_ERROR (Status)) {\r
208 //\r
209 // This is not an error, just an informative condition.\r
210 //\r
211 DEBUG ((EFI_D_VERBOSE, "%a: %g: %r\n", __FUNCTION__, ProtocolGuid,\r
212 Status));\r
213 return;\r
214 }\r
215\r
216 ASSERT (NoHandles > 0);\r
217 for (Idx = 0; Idx < NoHandles; ++Idx) {\r
218 CHAR16 *DevicePathText;\r
219 STATIC CHAR16 Fallback[] = L"<device path unavailable>";\r
220\r
221 //\r
222 // The ConvertDevicePathToText() function handles NULL input transparently.\r
223 //\r
224 DevicePathText = ConvertDevicePathToText (\r
225 DevicePathFromHandle (Handles[Idx]),\r
226 FALSE, // DisplayOnly\r
227 FALSE // AllowShortcuts\r
228 );\r
229 if (DevicePathText == NULL) {\r
230 DevicePathText = Fallback;\r
231 }\r
232\r
233 if (Filter == NULL || Filter (Handles[Idx], DevicePathText)) {\r
234 Process (Handles[Idx], DevicePathText);\r
235 }\r
236\r
237 if (DevicePathText != Fallback) {\r
238 FreePool (DevicePathText);\r
239 }\r
240 }\r
241 gBS->FreePool (Handles);\r
242}\r
243\r
244\r
245/**\r
246 This FILTER_FUNCTION checks if a handle corresponds to a PCI display device.\r
247**/\r
248STATIC\r
249BOOLEAN\r
250EFIAPI\r
251IsPciDisplay (\r
252 IN EFI_HANDLE Handle,\r
253 IN CONST CHAR16 *ReportText\r
254 )\r
255{\r
256 EFI_STATUS Status;\r
257 EFI_PCI_IO_PROTOCOL *PciIo;\r
258 PCI_TYPE00 Pci;\r
259\r
260 Status = gBS->HandleProtocol (Handle, &gEfiPciIoProtocolGuid,\r
261 (VOID**)&PciIo);\r
262 if (EFI_ERROR (Status)) {\r
263 //\r
264 // This is not an error worth reporting.\r
265 //\r
266 return FALSE;\r
267 }\r
268\r
269 Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, 0 /* Offset */,\r
270 sizeof Pci / sizeof (UINT32), &Pci);\r
271 if (EFI_ERROR (Status)) {\r
272 DEBUG ((EFI_D_ERROR, "%a: %s: %r\n", __FUNCTION__, ReportText, Status));\r
273 return FALSE;\r
274 }\r
275\r
276 return IS_PCI_DISPLAY (&Pci);\r
277}\r
278\r
279\r
280/**\r
281 This CALLBACK_FUNCTION attempts to connect a handle non-recursively, asking\r
282 the matching driver to produce all first-level child handles.\r
283**/\r
284STATIC\r
285VOID\r
286EFIAPI\r
287Connect (\r
288 IN EFI_HANDLE Handle,\r
289 IN CONST CHAR16 *ReportText\r
290 )\r
291{\r
292 EFI_STATUS Status;\r
293\r
294 Status = gBS->ConnectController (\r
295 Handle, // ControllerHandle\r
296 NULL, // DriverImageHandle\r
297 NULL, // RemainingDevicePath -- produce all children\r
298 FALSE // Recursive\r
299 );\r
300 DEBUG ((EFI_ERROR (Status) ? EFI_D_ERROR : EFI_D_VERBOSE, "%a: %s: %r\n",\r
301 __FUNCTION__, ReportText, Status));\r
302}\r
303\r
304\r
305/**\r
306 This CALLBACK_FUNCTION retrieves the EFI_DEVICE_PATH_PROTOCOL from the\r
307 handle, and adds it to ConOut and ErrOut.\r
308**/\r
309STATIC\r
310VOID\r
311EFIAPI\r
312AddOutput (\r
313 IN EFI_HANDLE Handle,\r
314 IN CONST CHAR16 *ReportText\r
315 )\r
316{\r
317 EFI_STATUS Status;\r
318 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
319\r
320 DevicePath = DevicePathFromHandle (Handle);\r
321 if (DevicePath == NULL) {\r
322 DEBUG ((EFI_D_ERROR, "%a: %s: handle %p: device path not found\n",\r
323 __FUNCTION__, ReportText, Handle));\r
324 return;\r
325 }\r
326\r
327 Status = BdsLibUpdateConsoleVariable (L"ConOut", DevicePath, NULL);\r
328 if (EFI_ERROR (Status)) {\r
329 DEBUG ((EFI_D_ERROR, "%a: %s: adding to ConOut: %r\n", __FUNCTION__,\r
330 ReportText, Status));\r
331 return;\r
332 }\r
333\r
334 Status = BdsLibUpdateConsoleVariable (L"ErrOut", DevicePath, NULL);\r
335 if (EFI_ERROR (Status)) {\r
336 DEBUG ((EFI_D_ERROR, "%a: %s: adding to ErrOut: %r\n", __FUNCTION__,\r
337 ReportText, Status));\r
338 return;\r
339 }\r
340\r
341 DEBUG ((EFI_D_VERBOSE, "%a: %s: added to ConOut and ErrOut\n", __FUNCTION__,\r
342 ReportText));\r
343}\r
344\r
345\r
346/**\r
347 The function will execute with as the platform policy, current policy\r
348 is driven by boot mode. IBV/OEM can customize this code for their specific\r
349 policy action.\r
350\r
351 @param DriverOptionList The header of the driver option link list\r
352 @param BootOptionList The header of the boot option link list\r
353 @param ProcessCapsules A pointer to ProcessCapsules()\r
354 @param BaseMemoryTest A pointer to BaseMemoryTest()\r
355\r
356**/\r
357VOID\r
358EFIAPI\r
359PlatformBdsPolicyBehavior (\r
360 IN LIST_ENTRY *DriverOptionList,\r
361 IN LIST_ENTRY *BootOptionList,\r
362 IN PROCESS_CAPSULES ProcessCapsules,\r
363 IN BASEM_MEMORY_TEST BaseMemoryTest\r
364 )\r
365{\r
366 //\r
367 // Locate the PCI root bridges and make the PCI bus driver connect each,\r
368 // non-recursively. This will produce a number of child handles with PciIo on\r
369 // them.\r
370 //\r
371 FilterAndProcess (&gEfiPciRootBridgeIoProtocolGuid, NULL, Connect);\r
372\r
373 //\r
374 // Signal the ACPI platform driver that it can download QEMU ACPI tables.\r
375 //\r
376 EfiEventGroupSignal (&gRootBridgesConnectedEventGroupGuid);\r
377\r
378 //\r
379 // Find all display class PCI devices (using the handles from the previous\r
380 // step), and connect them non-recursively. This should produce a number of\r
381 // child handles with GOPs on them.\r
382 //\r
383 FilterAndProcess (&gEfiPciIoProtocolGuid, IsPciDisplay, Connect);\r
384\r
385 //\r
386 // Now add the device path of all handles with GOP on them to ConOut and\r
387 // ErrOut.\r
388 //\r
389 FilterAndProcess (&gEfiGraphicsOutputProtocolGuid, NULL, AddOutput);\r
390\r
391 //\r
392 // Add the hardcoded short-form USB keyboard device path to ConIn.\r
393 //\r
394 BdsLibUpdateConsoleVariable (L"ConIn",\r
395 (EFI_DEVICE_PATH_PROTOCOL *)&mUsbKeyboard, NULL);\r
396\r
397 //\r
398 // Add the hardcoded serial console device path to ConIn, ConOut, ErrOut.\r
399 //\r
400 CopyGuid (&mSerialConsole.TermType.Guid,\r
401 PcdGetPtr (PcdTerminalTypeGuidBuffer));\r
402 BdsLibUpdateConsoleVariable (L"ConIn",\r
403 (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);\r
404 BdsLibUpdateConsoleVariable (L"ConOut",\r
405 (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);\r
406 BdsLibUpdateConsoleVariable (L"ErrOut",\r
407 (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);\r
408\r
409 //\r
410 // Connect the consoles based on the above variables.\r
411 //\r
412 BdsLibConnectAllDefaultConsoles ();\r
413\r
414 //\r
415 // Show the splash screen.\r
416 //\r
417 EnableQuietBoot (PcdGetPtr (PcdLogoFile));\r
418\r
419 //\r
420 // Connect the rest of the devices.\r
421 //\r
422 BdsLibConnectAll ();\r
423\r
424 //\r
425 // Process QEMU's -kernel command line option. Note that the kernel booted\r
426 // this way should receive ACPI tables, which is why we connect all devices\r
427 // first (see above) -- PCI enumeration blocks ACPI table installation, if\r
428 // there is a PCI host.\r
429 //\r
430 TryRunningQemuKernel ();\r
431\r
432 BdsLibEnumerateAllBootOption (BootOptionList);\r
433 SetBootOrderFromQemu (BootOptionList);\r
434 //\r
435 // The BootOrder variable may have changed, reload the in-memory list with\r
436 // it.\r
437 //\r
438 BdsLibBuildOptionFromVar (BootOptionList, L"BootOrder");\r
439\r
440 PlatformBdsEnterFrontPage (GetFrontPageTimeoutFromQemu(), TRUE);\r
441}\r
442\r
443/**\r
444 Hook point after a boot attempt succeeds. We don't expect a boot option to\r
445 return, so the UEFI 2.0 specification defines that you will default to an\r
446 interactive mode and stop processing the BootOrder list in this case. This\r
447 is also a platform implementation and can be customized by IBV/OEM.\r
448\r
449 @param Option Pointer to Boot Option that succeeded to boot.\r
450\r
451**/\r
452VOID\r
453EFIAPI\r
454PlatformBdsBootSuccess (\r
455 IN BDS_COMMON_OPTION *Option\r
456 )\r
457{\r
458}\r
459\r
460/**\r
461 Hook point after a boot attempt fails.\r
462\r
463 @param Option Pointer to Boot Option that failed to boot.\r
464 @param Status Status returned from failed boot.\r
465 @param ExitData Exit data returned from failed boot.\r
466 @param ExitDataSize Exit data size returned from failed boot.\r
467\r
468**/\r
469VOID\r
470EFIAPI\r
471PlatformBdsBootFail (\r
472 IN BDS_COMMON_OPTION *Option,\r
473 IN EFI_STATUS Status,\r
474 IN CHAR16 *ExitData,\r
475 IN UINTN ExitDataSize\r
476 )\r
477{\r
478}\r
479\r
480/**\r
481 This function locks platform flash that is not allowed to be updated during normal boot path.\r
482 The flash layout is platform specific.\r
483**/\r
484VOID\r
485EFIAPI\r
486PlatformBdsLockNonUpdatableFlash (\r
487 VOID\r
488 )\r
489{\r
490 return;\r
491}\r