1 /** @file
2 This file include all platform action which can be customized
3 by IBV/OEM.
4 
5 Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
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 "PlatformBootManager.h"
17 
18 EFI_GUID mUefiShellFileGuid = {0x7C04A583, 0x9E3E, 0x4f1c, {0xAD, 0x65, 0xE0, 0x52, 0x68, 0xD0, 0xB4, 0xD1 }};
19 
20 /**
21   Return the index of the load option in the load option array.
22 
23   The function consider two load options are equal when the
24   OptionType, Attributes, Description, FilePath and OptionalData are equal.
25 
26   @param Key    Pointer to the load option to be found.
27   @param Array  Pointer to the array of load options to be found.
28   @param Count  Number of entries in the Array.
29 
30   @retval -1          Key wasn't found in the Array.
31   @retval 0 ~ Count-1 The index of the Key in the Array.
32 **/
33 INTN
PlatformFindLoadOption(IN CONST EFI_BOOT_MANAGER_LOAD_OPTION * Key,IN CONST EFI_BOOT_MANAGER_LOAD_OPTION * Array,IN UINTN Count)34 PlatformFindLoadOption (
35   IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Key,
36   IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Array,
37   IN UINTN                              Count
38   )
39 {
40   UINTN                             Index;
41 
42   for (Index = 0; Index < Count; Index++) {
43     if ((Key->OptionType == Array[Index].OptionType) &&
44         (Key->Attributes == Array[Index].Attributes) &&
45         (StrCmp (Key->Description, Array[Index].Description) == 0) &&
46         (CompareMem (Key->FilePath, Array[Index].FilePath, GetDevicePathSize (Key->FilePath)) == 0) &&
47         (Key->OptionalDataSize == Array[Index].OptionalDataSize) &&
48         (CompareMem (Key->OptionalData, Array[Index].OptionalData, Key->OptionalDataSize) == 0)) {
49       return (INTN) Index;
50     }
51   }
52 
53   return -1;
54 }
55 
56 VOID
PlatformRegisterFvBootOption(EFI_GUID * FileGuid,CHAR16 * Description,UINT32 Attributes)57 PlatformRegisterFvBootOption (
58   EFI_GUID  *FileGuid,
59   CHAR16    *Description,
60   UINT32    Attributes
61   )
62 {
63   EFI_STATUS                        Status;
64   EFI_HANDLE                        *HandleBuffer;
65   UINTN                             HandleCount;
66   UINTN                             IndexFv;
67   EFI_FIRMWARE_VOLUME2_PROTOCOL     *Fv;
68   CHAR16                            *UiSection;
69   UINTN                             UiSectionLength;
70   UINT32                            AuthenticationStatus;
71   EFI_HANDLE                        FvHandle;
72   MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode;
73   EFI_DEVICE_PATH_PROTOCOL          *DevicePath;
74   EFI_BOOT_MANAGER_LOAD_OPTION      *BootOptions;
75   UINTN                             BootOptionCount;
76   UINTN                             OptionIndex;
77   EFI_BOOT_MANAGER_LOAD_OPTION      NewOption;
78 
79   //
80   // Locate all available FVs.
81   //
82   HandleBuffer = NULL;
83   Status = gBS->LocateHandleBuffer (
84                   ByProtocol,
85                   &gEfiFirmwareVolume2ProtocolGuid,
86                   NULL,
87                   &HandleCount,
88                   &HandleBuffer
89                   );
90   if (EFI_ERROR (Status)) {
91     return;
92   }
93 
94   //
95   // Go through FVs one by one to find the required FFS file
96   //
97   for (IndexFv = 0, FvHandle = NULL; IndexFv < HandleCount && FvHandle == NULL; IndexFv++) {
98     Status = gBS->HandleProtocol (
99                     HandleBuffer[IndexFv],
100                     &gEfiFirmwareVolume2ProtocolGuid,
101                     (VOID **)&Fv
102                     );
103     if (EFI_ERROR (Status)) {
104       continue;
105     }
106 
107     //
108     // Attempt to read a EFI_SECTION_USER_INTERFACE section from the required FFS file
109     //
110     UiSection = NULL;
111     Status = Fv->ReadSection (
112                    Fv,
113                    FileGuid,
114                    EFI_SECTION_USER_INTERFACE,
115                    0,
116                    (VOID **) &UiSection,
117                    &UiSectionLength,
118                    &AuthenticationStatus
119                    );
120     if (EFI_ERROR (Status)) {
121       continue;
122     }
123     FreePool (UiSection);
124 
125     //
126     // Save the handle of the FV where the FFS file was found
127     //
128     FvHandle = HandleBuffer[IndexFv];
129   }
130 
131   //
132   // Free the buffer of FV handles
133   //
134   FreePool (HandleBuffer);
135 
136   //
137   // If the FFS file was not found, then return
138   //
139   if (FvHandle == NULL) {
140     return;
141   }
142 
143   //
144   // Create a device path for the FFS file that was found
145   //
146   EfiInitializeFwVolDevicepathNode (&FileNode, FileGuid);
147   DevicePath = AppendDevicePathNode (
148                  DevicePathFromHandle (FvHandle),
149                  (EFI_DEVICE_PATH_PROTOCOL *) &FileNode
150                  );
151 
152   //
153   // Create and add a new load option for the FFS file that was found
154   //
155   Status = EfiBootManagerInitializeLoadOption (
156              &NewOption,
157              LoadOptionNumberUnassigned,
158              LoadOptionTypeBoot,
159              Attributes,
160              Description,
161              DevicePath,
162              NULL,
163              0
164              );
165   if (!EFI_ERROR (Status)) {
166     BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
167 
168     OptionIndex = PlatformFindLoadOption (&NewOption, BootOptions, BootOptionCount);
169 
170     if (OptionIndex == -1) {
171       Status = EfiBootManagerAddLoadOptionVariable (&NewOption, (UINTN) -1);
172       ASSERT_EFI_ERROR (Status);
173     }
174     EfiBootManagerFreeLoadOption (&NewOption);
175     EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
176   }
177 }
178 
179 VOID
180 EFIAPI
InternalBdsEmptyCallbackFuntion(IN EFI_EVENT Event,IN VOID * Context)181 InternalBdsEmptyCallbackFuntion (
182   IN EFI_EVENT  Event,
183   IN VOID       *Context
184   )
185 {
186   return;
187 }
188 
189 /**
190   Do the platform specific action before the console is connected.
191 
192   Such as:
193     Update console variable;
194     Register new Driver#### or Boot####;
195     Signal ReadyToLock event.
196 **/
197 VOID
198 EFIAPI
PlatformBootManagerBeforeConsole(VOID)199 PlatformBootManagerBeforeConsole (
200   VOID
201   )
202 {
203   EFI_STATUS                    Status;
204   UINTN                         Index;
205   EFI_INPUT_KEY                 Enter;
206   EFI_INPUT_KEY                 F2;
207   EFI_BOOT_MANAGER_LOAD_OPTION  BootOption;
208   EFI_ACPI_S3_SAVE_PROTOCOL     *AcpiS3Save;
209   EFI_HANDLE                    Handle;
210   EFI_EVENT                     EndOfDxeEvent;
211 
212   //
213   // Update the console variables.
214   //
215   for (Index = 0; gPlatformConsole[Index].DevicePath != NULL; Index++) {
216     if ((gPlatformConsole[Index].ConnectType & CONSOLE_IN) == CONSOLE_IN) {
217       EfiBootManagerUpdateConsoleVariable (ConIn, gPlatformConsole[Index].DevicePath, NULL);
218     }
219 
220     if ((gPlatformConsole[Index].ConnectType & CONSOLE_OUT) == CONSOLE_OUT) {
221       EfiBootManagerUpdateConsoleVariable (ConOut, gPlatformConsole[Index].DevicePath, NULL);
222     }
223 
224     if ((gPlatformConsole[Index].ConnectType & STD_ERROR) == STD_ERROR) {
225       EfiBootManagerUpdateConsoleVariable (ErrOut, gPlatformConsole[Index].DevicePath, NULL);
226     }
227   }
228 
229   //
230   // Register ENTER as CONTINUE key
231   //
232   Enter.ScanCode    = SCAN_NULL;
233   Enter.UnicodeChar = CHAR_CARRIAGE_RETURN;
234   EfiBootManagerRegisterContinueKeyOption (0, &Enter, NULL);
235 
236   //
237   // Map F2 to Boot Manager Menu
238   //
239   F2.ScanCode    = SCAN_F2;
240   F2.UnicodeChar = CHAR_NULL;
241   EfiBootManagerGetBootManagerMenu (&BootOption);
242   EfiBootManagerAddKeyOptionVariable (NULL, (UINT16) BootOption.OptionNumber, 0, &F2, NULL);
243 
244   //
245   // Register UEFI Shell
246   //
247   PlatformRegisterFvBootOption (&mUefiShellFileGuid, L"UEFI Shell", LOAD_OPTION_ACTIVE);
248 
249   //
250   // Prepare for S3
251   //
252   Status = gBS->LocateProtocol (&gEfiAcpiS3SaveProtocolGuid, NULL, (VOID **)&AcpiS3Save);
253   if (!EFI_ERROR (Status)) {
254     AcpiS3Save->S3Save (AcpiS3Save, NULL);
255   }
256 
257   //
258   // Inform PI SMM drivers that BDS may run 3rd party code
259   // Create and signal End of DXE event group
260   //
261   Status = gBS->CreateEventEx (
262                   EVT_NOTIFY_SIGNAL,
263                   TPL_CALLBACK,
264                   InternalBdsEmptyCallbackFuntion,
265                   NULL,
266                   &gEfiEndOfDxeEventGroupGuid,
267                   &EndOfDxeEvent
268                   );
269   ASSERT_EFI_ERROR (Status);
270   gBS->SignalEvent (EndOfDxeEvent);
271   gBS->CloseEvent (EndOfDxeEvent);
272 
273   DEBUG((EFI_D_INFO,"All EndOfDxe callbacks have returned successfully\n"));
274 
275   //
276   // Install SMM Ready To Lock protocol so all resources can be locked down
277   // before BDS runs 3rd party code.  This action must be done last so all
278   // other SMM driver signals are processed before this final lock down action.
279   //
280   Handle = NULL;
281   Status = gBS->InstallProtocolInterface (
282                   &Handle,
283                   &gEfiDxeSmmReadyToLockProtocolGuid,
284                   EFI_NATIVE_INTERFACE,
285                   NULL
286                   );
287   ASSERT_EFI_ERROR (Status);
288 }
289 
290 /**
291   Do the platform specific action after the console is connected.
292 
293   Such as:
294     Dynamically switch output mode;
295     Signal console ready platform customized event;
296     Run diagnostics like memory testing;
297     Connect certain devices;
298     Dispatch additional option ROMs
299 **/
300 VOID
301 EFIAPI
PlatformBootManagerAfterConsole(VOID)302 PlatformBootManagerAfterConsole (
303   VOID
304   )
305 {
306   EFI_STATUS  Status;
307 
308   Print (
309     L"\n"
310     L"F2      to enter Boot Manager Menu.\n"
311     L"ENTER   to boot directly.\n"
312     L"\n"
313     );
314 
315   //
316   // Use a DynamicHii type pcd to save the boot status, which is used to
317   // control configuration mode, such as FULL/MINIMAL/NO_CHANGES configuration.
318   //
319   if (PcdGetBool(PcdBootState)) {
320     Status = PcdSetBoolS (PcdBootState, FALSE);
321     ASSERT_EFI_ERROR (Status);
322   }
323 }
324 
325 /**
326   This function is called each second during the boot manager waits the timeout.
327 
328   @param TimeoutRemain  The remaining timeout.
329 **/
330 VOID
331 EFIAPI
PlatformBootManagerWaitCallback(UINT16 TimeoutRemain)332 PlatformBootManagerWaitCallback (
333   UINT16  TimeoutRemain
334   )
335 {
336   Print (L"\r%-2d seconds remained...", TimeoutRemain);
337 }
338