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