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