1 /** @file
2 
3 Copyright (c) 2004 - 2008, Intel Corporation. All rights reserved.<BR>
4 Copyright (c) 2014, ARM Ltd. All rights reserved.<BR>
5 
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution.  The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10 
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 
14 **/
15 
16 #include "IntelBdsPlatform.h"
17 
18 ///
19 /// Predefined platform default time out value
20 ///
21 UINT16                      gPlatformBootTimeOutDefault;
22 
23 EFI_STATUS
24 EFIAPI
PlatformIntelBdsConstructor(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)25 PlatformIntelBdsConstructor (
26   IN EFI_HANDLE        ImageHandle,
27   IN EFI_SYSTEM_TABLE  *SystemTable
28   )
29 {
30   gPlatformBootTimeOutDefault = (UINT16)PcdGet16 (PcdPlatformBootTimeOut);
31   return EFI_SUCCESS;
32 }
33 
34 /**
35   An empty function to pass error checking of CreateEventEx ().
36 
37   @param  Event                 Event whose notification function is being invoked.
38   @param  Context               Pointer to the notification function's context,
39                                 which is implementation-dependent.
40 
41 **/
42 STATIC
43 VOID
44 EFIAPI
EmptyCallbackFunction(IN EFI_EVENT Event,IN VOID * Context)45 EmptyCallbackFunction (
46   IN EFI_EVENT                Event,
47   IN VOID                     *Context
48   )
49 {
50 }
51 
52 //
53 // BDS Platform Functions
54 //
55 /**
56   Platform Bds init. Include the platform firmware vendor, revision
57   and so crc check.
58 
59 **/
60 VOID
61 EFIAPI
PlatformBdsInit(VOID)62 PlatformBdsInit (
63   VOID
64   )
65 {
66   EFI_EVENT           EndOfDxeEvent;
67   EFI_STATUS          Status;
68 
69   //
70   // Signal EndOfDxe PI Event
71   //
72   Status = gBS->CreateEventEx (
73                   EVT_NOTIFY_SIGNAL,
74                   TPL_CALLBACK,
75                   EmptyCallbackFunction,
76                   NULL,
77                   &gEfiEndOfDxeEventGroupGuid,
78                   &EndOfDxeEvent
79                   );
80   if (!EFI_ERROR (Status)) {
81     gBS->SignalEvent (EndOfDxeEvent);
82     gBS->CloseEvent (EndOfDxeEvent);
83   }
84 }
85 
86 STATIC
87 EFI_STATUS
GetConsoleDevicePathFromVariable(IN CHAR16 * ConsoleVarName,IN CHAR16 * DefaultConsolePaths,OUT EFI_DEVICE_PATH ** DevicePaths)88 GetConsoleDevicePathFromVariable (
89   IN  CHAR16*             ConsoleVarName,
90   IN  CHAR16*             DefaultConsolePaths,
91   OUT EFI_DEVICE_PATH**   DevicePaths
92   )
93 {
94   EFI_STATUS                Status;
95   UINTN                     Size;
96   EFI_DEVICE_PATH_PROTOCOL* DevicePathInstances;
97   EFI_DEVICE_PATH_PROTOCOL* DevicePathInstance;
98   CHAR16*                   DevicePathStr;
99   CHAR16*                   NextDevicePathStr;
100   EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL  *EfiDevicePathFromTextProtocol;
101 
102   Status = EFI_SUCCESS;
103   Size = 0;
104 
105   DevicePathInstances = BdsLibGetVariableAndSize (ConsoleVarName, &gEfiGlobalVariableGuid, &Size);
106   if (DevicePathInstances == NULL) {
107     // In case no default console device path has been defined we assume a driver handles the console (eg: SimpleTextInOutSerial)
108     if ((DefaultConsolePaths == NULL) || (DefaultConsolePaths[0] == L'\0')) {
109       *DevicePaths = NULL;
110       return EFI_SUCCESS;
111     }
112 
113     Status = gBS->LocateProtocol (&gEfiDevicePathFromTextProtocolGuid, NULL, (VOID **)&EfiDevicePathFromTextProtocol);
114     ASSERT_EFI_ERROR(Status);
115 
116     // Extract the Device Path instances from the multi-device path string
117     while ((DefaultConsolePaths != NULL) && (DefaultConsolePaths[0] != L'\0')) {
118       NextDevicePathStr = StrStr (DefaultConsolePaths, L";");
119       if (NextDevicePathStr == NULL) {
120         DevicePathStr = DefaultConsolePaths;
121         DefaultConsolePaths = NULL;
122       } else {
123         DevicePathStr = (CHAR16*)AllocateCopyPool ((NextDevicePathStr - DefaultConsolePaths + 1) * sizeof(CHAR16), DefaultConsolePaths);
124         *(DevicePathStr + (NextDevicePathStr - DefaultConsolePaths)) = L'\0';
125         DefaultConsolePaths = NextDevicePathStr;
126         if (DefaultConsolePaths[0] == L';') {
127           DefaultConsolePaths++;
128         }
129       }
130 
131       DevicePathInstance = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath (DevicePathStr);
132       ASSERT(DevicePathInstance != NULL);
133       DevicePathInstances = AppendDevicePathInstance (DevicePathInstances, DevicePathInstance);
134 
135       if (NextDevicePathStr != NULL) {
136         FreePool (DevicePathStr);
137       }
138       FreePool (DevicePathInstance);
139     }
140 
141     // Set the environment variable with this device path multi-instances
142     Size = GetDevicePathSize (DevicePathInstances);
143     if (Size > 0) {
144       gRT->SetVariable (
145           ConsoleVarName,
146           &gEfiGlobalVariableGuid,
147           EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
148           Size,
149           DevicePathInstances
150           );
151     } else {
152       Status = EFI_INVALID_PARAMETER;
153     }
154   }
155 
156   if (!EFI_ERROR(Status)) {
157     *DevicePaths = DevicePathInstances;
158   }
159   return Status;
160 }
161 
162 STATIC
163 EFI_STATUS
InitializeConsolePipe(IN EFI_DEVICE_PATH * ConsoleDevicePaths,IN EFI_GUID * Protocol,OUT EFI_HANDLE * Handle,OUT VOID ** Interface)164 InitializeConsolePipe (
165   IN EFI_DEVICE_PATH    *ConsoleDevicePaths,
166   IN EFI_GUID           *Protocol,
167   OUT EFI_HANDLE        *Handle,
168   OUT VOID*             *Interface
169   )
170 {
171   EFI_STATUS                Status;
172   UINTN                     Size;
173   UINTN                     NoHandles;
174   EFI_HANDLE                *Buffer;
175   EFI_DEVICE_PATH_PROTOCOL* DevicePath;
176 
177   // Connect all the Device Path Consoles
178   while (ConsoleDevicePaths != NULL) {
179     DevicePath = GetNextDevicePathInstance (&ConsoleDevicePaths, &Size);
180 
181     Status = BdsLibConnectDevicePath (DevicePath);
182     if (!EFI_ERROR (Status)) {
183       //
184       // If BdsLibConnectDevicePath () succeeded, *Handle must have a non-NULL
185       // value. So ASSERT that this is the case.
186       //
187       gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &DevicePath, Handle);
188       ASSERT (*Handle != NULL);
189     }
190     DEBUG_CODE_BEGIN();
191       if (EFI_ERROR(Status)) {
192         // We convert back to the text representation of the device Path
193         EFI_DEVICE_PATH_TO_TEXT_PROTOCOL  *DevicePathToTextProtocol;
194         CHAR16                            *DevicePathTxt;
195 
196         DevicePathToTextProtocol = NULL;
197         gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **) &DevicePathToTextProtocol);
198         if (DevicePathToTextProtocol != NULL) {
199           DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText (DevicePath, TRUE, TRUE);
200 
201           DEBUG((EFI_D_ERROR,"Fail to start the console with the Device Path '%s'. (Error '%r')\n", DevicePathTxt, Status));
202 
203           FreePool (DevicePathTxt);
204         }
205       }
206     DEBUG_CODE_END();
207 
208     // If the console splitter driver is not supported by the platform then use the first Device Path
209     // instance for the console interface.
210     if (!EFI_ERROR(Status) && (*Interface == NULL)) {
211       Status = gBS->HandleProtocol (*Handle, Protocol, Interface);
212     }
213   }
214 
215   // No Device Path has been defined for this console interface. We take the first protocol implementation
216   if (*Interface == NULL) {
217     Status = gBS->LocateHandleBuffer (ByProtocol, Protocol, NULL, &NoHandles, &Buffer);
218     if (EFI_ERROR (Status)) {
219       BdsLibConnectAll ();
220       Status = gBS->LocateHandleBuffer (ByProtocol, Protocol, NULL, &NoHandles, &Buffer);
221     }
222 
223     if (!EFI_ERROR(Status)) {
224       *Handle = Buffer[0];
225       Status = gBS->HandleProtocol (*Handle, Protocol, Interface);
226       ASSERT_EFI_ERROR (Status);
227       FreePool (Buffer);
228     }
229   } else {
230     Status = EFI_SUCCESS;
231   }
232 
233   return Status;
234 }
235 
236 /**
237   Connect the predefined platform default console device. Always try to find
238   and enable the vga device if have.
239 
240   @param PlatformConsole          Predefined platform default console device array.
241 
242   @retval EFI_SUCCESS             Success connect at least one ConIn and ConOut
243                                   device, there must have one ConOut device is
244                                   active vga device.
245   @return Return the status of BdsLibConnectAllDefaultConsoles ()
246 
247 **/
248 EFI_STATUS
PlatformBdsConnectConsole(VOID)249 PlatformBdsConnectConsole (
250   VOID
251   )
252 {
253   EFI_STATUS                Status;
254   EFI_DEVICE_PATH*          ConOutDevicePaths;
255   EFI_DEVICE_PATH*          ConInDevicePaths;
256   EFI_DEVICE_PATH*          ConErrDevicePaths;
257 
258   // By getting the Console Device Paths from the environment variables before initializing the console pipe, we
259   // create the 3 environment variables (ConIn, ConOut, ConErr) that allows to initialize all the console interface
260   // of newly installed console drivers
261   Status = GetConsoleDevicePathFromVariable (L"ConOut", (CHAR16*)PcdGetPtr(PcdDefaultConOutPaths), &ConOutDevicePaths);
262   ASSERT_EFI_ERROR (Status);
263   Status = GetConsoleDevicePathFromVariable (L"ConIn", (CHAR16*)PcdGetPtr(PcdDefaultConInPaths), &ConInDevicePaths);
264   ASSERT_EFI_ERROR (Status);
265   Status = GetConsoleDevicePathFromVariable (L"ErrOut", (CHAR16*)PcdGetPtr(PcdDefaultConOutPaths), &ConErrDevicePaths);
266   ASSERT_EFI_ERROR (Status);
267 
268   // Initialize the Consoles
269   Status = InitializeConsolePipe (ConOutDevicePaths, &gEfiSimpleTextOutProtocolGuid, &gST->ConsoleOutHandle, (VOID **)&gST->ConOut);
270   ASSERT_EFI_ERROR (Status);
271   Status = InitializeConsolePipe (ConInDevicePaths, &gEfiSimpleTextInProtocolGuid, &gST->ConsoleInHandle, (VOID **)&gST->ConIn);
272   ASSERT_EFI_ERROR (Status);
273   Status = InitializeConsolePipe (ConErrDevicePaths, &gEfiSimpleTextOutProtocolGuid, &gST->StandardErrorHandle, (VOID **)&gST->StdErr);
274   if (EFI_ERROR(Status)) {
275     // In case of error, we reuse the console output for the error output
276     gST->StandardErrorHandle = gST->ConsoleOutHandle;
277     gST->StdErr = gST->ConOut;
278   }
279 
280   return Status;
281 }
282 
283 /**
284   Connect with predefined platform connect sequence,
285   the OEM/IBV can customize with their own connect sequence.
286 **/
287 VOID
PlatformBdsConnectSequence(VOID)288 PlatformBdsConnectSequence (
289   VOID
290   )
291 {
292 }
293 
294 /**
295   Load the predefined driver option, OEM/IBV can customize this
296   to load their own drivers
297 
298   @param BdsDriverLists  - The header of the driver option link list.
299 
300 **/
301 VOID
PlatformBdsGetDriverOption(IN OUT LIST_ENTRY * BdsDriverLists)302 PlatformBdsGetDriverOption (
303   IN OUT LIST_ENTRY              *BdsDriverLists
304   )
305 {
306 }
307 
308 /**
309   Perform the platform diagnostic, such like test memory. OEM/IBV also
310   can customize this function to support specific platform diagnostic.
311 
312   @param MemoryTestLevel  The memory test intensive level
313   @param QuietBoot        Indicate if need to enable the quiet boot
314   @param BaseMemoryTest   A pointer to BdsMemoryTest()
315 
316 **/
317 VOID
PlatformBdsDiagnostics(IN EXTENDMEM_COVERAGE_LEVEL MemoryTestLevel,IN BOOLEAN QuietBoot,IN BASEM_MEMORY_TEST BaseMemoryTest)318 PlatformBdsDiagnostics (
319   IN EXTENDMEM_COVERAGE_LEVEL    MemoryTestLevel,
320   IN BOOLEAN                     QuietBoot,
321   IN BASEM_MEMORY_TEST           BaseMemoryTest
322   )
323 {
324 }
325 
326 /**
327   The function will execute with as the platform policy, current policy
328   is driven by boot mode. IBV/OEM can customize this code for their specific
329   policy action.
330 
331   @param  DriverOptionList        The header of the driver option link list
332   @param  BootOptionList          The header of the boot option link list
333   @param  ProcessCapsules         A pointer to ProcessCapsules()
334   @param  BaseMemoryTest          A pointer to BaseMemoryTest()
335 
336 **/
337 VOID
338 EFIAPI
PlatformBdsPolicyBehavior(IN LIST_ENTRY * DriverOptionList,IN LIST_ENTRY * BootOptionList,IN PROCESS_CAPSULES ProcessCapsules,IN BASEM_MEMORY_TEST BaseMemoryTest)339 PlatformBdsPolicyBehavior (
340   IN LIST_ENTRY                      *DriverOptionList,
341   IN LIST_ENTRY                      *BootOptionList,
342   IN PROCESS_CAPSULES                ProcessCapsules,
343   IN BASEM_MEMORY_TEST               BaseMemoryTest
344   )
345 {
346   EFI_STATUS Status;
347 
348   Status = PlatformBdsConnectConsole ();
349   ASSERT_EFI_ERROR (Status);
350 
351   //
352   // Show the splash screen.
353   //
354   EnableQuietBoot (PcdGetPtr (PcdLogoFile));
355 
356   //
357   // Connect _all_ devices, to pick up plug-in and removable devices
358   // TODO: do this more cleanly, permitting faster boot times when boot config
359   //       is known
360   //
361   BdsLibConnectAll ();
362 }
363 
364 /**
365   Hook point after a boot attempt succeeds. We don't expect a boot option to
366   return, so the UEFI 2.0 specification defines that you will default to an
367   interactive mode and stop processing the BootOrder list in this case. This
368   is also a platform implementation and can be customized by IBV/OEM.
369 
370   @param  Option                  Pointer to Boot Option that succeeded to boot.
371 
372 **/
373 VOID
374 EFIAPI
PlatformBdsBootSuccess(IN BDS_COMMON_OPTION * Option)375 PlatformBdsBootSuccess (
376   IN  BDS_COMMON_OPTION *Option
377   )
378 {
379 }
380 
381 /**
382   Hook point after a boot attempt fails.
383 
384   @param  Option                  Pointer to Boot Option that failed to boot.
385   @param  Status                  Status returned from failed boot.
386   @param  ExitData                Exit data returned from failed boot.
387   @param  ExitDataSize            Exit data size returned from failed boot.
388 
389 **/
390 VOID
391 EFIAPI
PlatformBdsBootFail(IN BDS_COMMON_OPTION * Option,IN EFI_STATUS Status,IN CHAR16 * ExitData,IN UINTN ExitDataSize)392 PlatformBdsBootFail (
393   IN  BDS_COMMON_OPTION  *Option,
394   IN  EFI_STATUS         Status,
395   IN  CHAR16             *ExitData,
396   IN  UINTN              ExitDataSize
397   )
398 {
399 }
400 
401 /**
402   This function locks platform flash that is not allowed to be updated during normal boot path.
403   The flash layout is platform specific.
404 **/
405 VOID
406 EFIAPI
PlatformBdsLockNonUpdatableFlash(VOID)407 PlatformBdsLockNonUpdatableFlash (
408   VOID
409   )
410 {
411   return;
412 }
413 
414 
415 /**
416   Lock the ConsoleIn device in system table. All key
417   presses will be ignored until the Password is typed in. The only way to
418   disable the password is to type it in to a ConIn device.
419 
420   @param  Password        Password used to lock ConIn device.
421 
422   @retval EFI_SUCCESS     lock the Console In Spliter virtual handle successfully.
423   @retval EFI_UNSUPPORTED Password not found
424 
425 **/
426 EFI_STATUS
427 EFIAPI
LockKeyboards(IN CHAR16 * Password)428 LockKeyboards (
429   IN  CHAR16    *Password
430   )
431 {
432     return EFI_UNSUPPORTED;
433 }
434