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