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