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