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