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