]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - IntelFrameworkModulePkg/Universal/BdsDxe/BdsEntry.c
Fix some corner case for LazyConIn feature
[mirror_edk2.git] / IntelFrameworkModulePkg / Universal / BdsDxe / BdsEntry.c
... / ...
CommitLineData
1/** @file\r
2 This module produce main entry for BDS phase - BdsEntry.\r
3 When this module was dispatched by DxeCore, gEfiBdsArchProtocolGuid will be installed\r
4 which contains interface of BdsEntry.\r
5 After DxeCore finish DXE phase, gEfiBdsArchProtocolGuid->BdsEntry will be invoked\r
6 to enter BDS phase.\r
7\r
8Copyright (c) 2004 - 2012, Intel Corporation. All rights reserved.<BR>\r
9This program and the accompanying materials\r
10are licensed and made available under the terms and conditions of the BSD License\r
11which accompanies this distribution. The full text of the license may be found at\r
12http://opensource.org/licenses/bsd-license.php\r
13\r
14THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
15WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
16\r
17**/\r
18\r
19#include "Bds.h"\r
20#include "Language.h"\r
21#include "FrontPage.h"\r
22#include "Hotkey.h"\r
23#include "HwErrRecSupport.h"\r
24\r
25///\r
26/// BDS arch protocol instance initial value.\r
27///\r
28/// Note: Current BDS not directly get the BootMode, DefaultBoot,\r
29/// TimeoutDefault, MemoryTestLevel value from the BDS arch protocol.\r
30/// Please refer to the library useage of BdsLibGetBootMode, BdsLibGetTimeout\r
31/// and PlatformBdsDiagnostics in BdsPlatform.c\r
32///\r
33EFI_HANDLE gBdsHandle = NULL;\r
34\r
35EFI_BDS_ARCH_PROTOCOL gBds = {\r
36 BdsEntry\r
37};\r
38\r
39UINT16 *mBootNext = NULL;\r
40\r
41/**\r
42\r
43 Install Boot Device Selection Protocol\r
44\r
45 @param ImageHandle The image handle.\r
46 @param SystemTable The system table.\r
47\r
48 @retval EFI_SUCEESS BDS has finished initializing.\r
49 Return the dispatcher and recall BDS.Entry\r
50 @retval Other Return status from AllocatePool() or gBS->InstallProtocolInterface\r
51\r
52**/\r
53EFI_STATUS\r
54EFIAPI\r
55BdsInitialize (\r
56 IN EFI_HANDLE ImageHandle,\r
57 IN EFI_SYSTEM_TABLE *SystemTable\r
58 )\r
59{\r
60 EFI_STATUS Status;\r
61\r
62 //\r
63 // Install protocol interface\r
64 //\r
65 Status = gBS->InstallMultipleProtocolInterfaces (\r
66 &gBdsHandle,\r
67 &gEfiBdsArchProtocolGuid, &gBds,\r
68 NULL\r
69 );\r
70 ASSERT_EFI_ERROR (Status);\r
71\r
72 return Status;\r
73}\r
74\r
75\r
76/**\r
77 An empty function to pass error checking of CreateEventEx ().\r
78\r
79 @param Event Event whose notification function is being invoked.\r
80 @param Context Pointer to the notification function's context,\r
81 which is implementation-dependent.\r
82\r
83**/\r
84VOID\r
85EFIAPI\r
86BdsEmptyCallbackFunction (\r
87 IN EFI_EVENT Event,\r
88 IN VOID *Context\r
89 )\r
90{\r
91}\r
92\r
93/**\r
94\r
95 This function attempts to boot for the boot order specified\r
96 by platform policy.\r
97\r
98**/\r
99VOID\r
100BdsBootDeviceSelect (\r
101 VOID\r
102 )\r
103{\r
104 EFI_STATUS Status;\r
105 LIST_ENTRY *Link;\r
106 BDS_COMMON_OPTION *BootOption;\r
107 UINTN ExitDataSize;\r
108 CHAR16 *ExitData;\r
109 UINT16 Timeout;\r
110 LIST_ENTRY BootLists;\r
111 CHAR16 Buffer[20];\r
112 BOOLEAN BootNextExist;\r
113 LIST_ENTRY *LinkBootNext;\r
114 EFI_EVENT ConnectConInEvent;\r
115\r
116 //\r
117 // Got the latest boot option\r
118 //\r
119 BootNextExist = FALSE;\r
120 LinkBootNext = NULL;\r
121 ConnectConInEvent = NULL;\r
122 InitializeListHead (&BootLists);\r
123\r
124 //\r
125 // First check the boot next option\r
126 //\r
127 ZeroMem (Buffer, sizeof (Buffer));\r
128\r
129 //\r
130 // Create Event to signal ConIn connection request\r
131 //\r
132 if (PcdGetBool (PcdConInConnectOnDemand)) {\r
133 Status = gBS->CreateEventEx (\r
134 EVT_NOTIFY_SIGNAL,\r
135 TPL_CALLBACK,\r
136 BdsEmptyCallbackFunction,\r
137 NULL,\r
138 &gConnectConInEventGuid,\r
139 &ConnectConInEvent\r
140 );\r
141 if (EFI_ERROR(Status)) {\r
142 ConnectConInEvent = NULL;\r
143 }\r
144 }\r
145\r
146 if (mBootNext != NULL) {\r
147 //\r
148 // Indicate we have the boot next variable, so this time\r
149 // boot will always have this boot option\r
150 //\r
151 BootNextExist = TRUE;\r
152\r
153 //\r
154 // Clear the this variable so it's only exist in this time boot\r
155 //\r
156 gRT->SetVariable (\r
157 L"BootNext",\r
158 &gEfiGlobalVariableGuid,\r
159 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
160 0,\r
161 mBootNext\r
162 );\r
163\r
164 //\r
165 // Add the boot next boot option\r
166 //\r
167 UnicodeSPrint (Buffer, sizeof (Buffer), L"Boot%04x", *mBootNext);\r
168 BootOption = BdsLibVariableToOption (&BootLists, Buffer);\r
169\r
170 //\r
171 // If fail to get boot option from variable, just return and do nothing.\r
172 //\r
173 if (BootOption == NULL) {\r
174 return;\r
175 }\r
176\r
177 BootOption->BootCurrent = *mBootNext;\r
178 }\r
179 //\r
180 // Parse the boot order to get boot option\r
181 //\r
182 BdsLibBuildOptionFromVar (&BootLists, L"BootOrder");\r
183\r
184 //\r
185 // When we didn't have chance to build boot option variables in the first \r
186 // full configuration boot (e.g.: Reset in the first page or in Device Manager),\r
187 // we have no boot options in the following mini configuration boot.\r
188 // Give the last chance to enumerate the boot options.\r
189 //\r
190 if (IsListEmpty (&BootLists)) {\r
191 BdsLibEnumerateAllBootOption (&BootLists);\r
192 }\r
193\r
194 Link = BootLists.ForwardLink;\r
195\r
196 //\r
197 // Parameter check, make sure the loop will be valid\r
198 //\r
199 if (Link == NULL) {\r
200 return ;\r
201 }\r
202 //\r
203 // Here we make the boot in a loop, every boot success will\r
204 // return to the front page\r
205 //\r
206 for (;;) {\r
207 //\r
208 // Check the boot option list first\r
209 //\r
210 if (Link == &BootLists) {\r
211 //\r
212 // When LazyConIn enabled, signal connect ConIn event before enter UI\r
213 //\r
214 if (PcdGetBool (PcdConInConnectOnDemand) && ConnectConInEvent != NULL) {\r
215 gBS->SignalEvent (ConnectConInEvent);\r
216 }\r
217\r
218 //\r
219 // There are two ways to enter here:\r
220 // 1. There is no active boot option, give user chance to\r
221 // add new boot option\r
222 // 2. All the active boot option processed, and there is no\r
223 // one is success to boot, then we back here to allow user\r
224 // add new active boot option\r
225 //\r
226 Timeout = 0xffff;\r
227 PlatformBdsEnterFrontPage (Timeout, FALSE);\r
228 InitializeListHead (&BootLists);\r
229 BdsLibBuildOptionFromVar (&BootLists, L"BootOrder");\r
230 Link = BootLists.ForwardLink;\r
231 continue;\r
232 }\r
233 //\r
234 // Get the boot option from the link list\r
235 //\r
236 BootOption = CR (Link, BDS_COMMON_OPTION, Link, BDS_LOAD_OPTION_SIGNATURE);\r
237\r
238 //\r
239 // According to EFI Specification, if a load option is not marked\r
240 // as LOAD_OPTION_ACTIVE, the boot manager will not automatically\r
241 // load the option.\r
242 //\r
243 if (!IS_LOAD_OPTION_TYPE (BootOption->Attribute, LOAD_OPTION_ACTIVE)) {\r
244 //\r
245 // skip the header of the link list, because it has no boot option\r
246 //\r
247 Link = Link->ForwardLink;\r
248 continue;\r
249 }\r
250 //\r
251 // Make sure the boot option device path connected,\r
252 // but ignore the BBS device path\r
253 //\r
254 if (DevicePathType (BootOption->DevicePath) != BBS_DEVICE_PATH) {\r
255 //\r
256 // Notes: the internal shell can not been connected with device path\r
257 // so we do not check the status here\r
258 //\r
259 BdsLibConnectDevicePath (BootOption->DevicePath);\r
260 }\r
261\r
262 //\r
263 // Restore to original mode before launching boot option.\r
264 //\r
265 BdsSetConsoleMode (FALSE);\r
266 \r
267 //\r
268 // All the driver options should have been processed since\r
269 // now boot will be performed.\r
270 //\r
271 Status = BdsLibBootViaBootOption (BootOption, BootOption->DevicePath, &ExitDataSize, &ExitData);\r
272 if (Status != EFI_SUCCESS) {\r
273 //\r
274 // Call platform action to indicate the boot fail\r
275 //\r
276 BootOption->StatusString = GetStringById (STRING_TOKEN (STR_BOOT_FAILED));\r
277 PlatformBdsBootFail (BootOption, Status, ExitData, ExitDataSize);\r
278\r
279 //\r
280 // Check the next boot option\r
281 //\r
282 Link = Link->ForwardLink;\r
283\r
284 } else {\r
285 //\r
286 // Call platform action to indicate the boot success\r
287 //\r
288 BootOption->StatusString = GetStringById (STRING_TOKEN (STR_BOOT_SUCCEEDED));\r
289 PlatformBdsBootSuccess (BootOption);\r
290\r
291 //\r
292 // Boot success, then stop process the boot order, and\r
293 // present the boot manager menu, front page\r
294 //\r
295\r
296 //\r
297 // When LazyConIn enabled, signal connect ConIn Event before enter UI\r
298 //\r
299 if (PcdGetBool (PcdConInConnectOnDemand) && ConnectConInEvent != NULL) {\r
300 gBS->SignalEvent (ConnectConInEvent);\r
301 }\r
302\r
303 Timeout = 0xffff;\r
304 PlatformBdsEnterFrontPage (Timeout, FALSE);\r
305\r
306 //\r
307 // Rescan the boot option list, avoid potential risk of the boot\r
308 // option change in front page\r
309 //\r
310 if (BootNextExist) {\r
311 LinkBootNext = BootLists.ForwardLink;\r
312 }\r
313\r
314 InitializeListHead (&BootLists);\r
315 if (LinkBootNext != NULL) {\r
316 //\r
317 // Reserve the boot next option\r
318 //\r
319 InsertTailList (&BootLists, LinkBootNext);\r
320 }\r
321\r
322 BdsLibBuildOptionFromVar (&BootLists, L"BootOrder");\r
323 Link = BootLists.ForwardLink;\r
324 }\r
325 }\r
326\r
327}\r
328\r
329/**\r
330\r
331 Validate input console variable data. \r
332\r
333 If found the device path is not a valid device path, remove the variable.\r
334 \r
335 @param VariableName Input console variable name.\r
336\r
337**/\r
338VOID\r
339BdsFormalizeConsoleVariable (\r
340 IN CHAR16 *VariableName\r
341 )\r
342{\r
343 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
344 UINTN VariableSize;\r
345 EFI_STATUS Status;\r
346\r
347 DevicePath = BdsLibGetVariableAndSize (\r
348 VariableName,\r
349 &gEfiGlobalVariableGuid,\r
350 &VariableSize\r
351 );\r
352 if ((DevicePath != NULL) && !IsDevicePathValid (DevicePath, VariableSize)) { \r
353 Status = gRT->SetVariable (\r
354 VariableName,\r
355 &gEfiGlobalVariableGuid,\r
356 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
357 0,\r
358 NULL\r
359 );\r
360 ASSERT_EFI_ERROR (Status);\r
361 }\r
362}\r
363\r
364/**\r
365\r
366 Formalize Bds global variables. \r
367\r
368 1. For ConIn/ConOut/ConErr, if found the device path is not a valid device path, remove the variable.\r
369 2. For OsIndicationsSupported, Create a BS/RT/UINT64 variable to report caps \r
370 3. Delete OsIndications variable if it is not NV/BS/RT UINT64\r
371 Item 3 is used to solve case when OS corrupts OsIndications. Here simply delete this NV variable.\r
372 \r
373**/\r
374VOID \r
375BdsFormalizeEfiGlobalVariable (\r
376 VOID\r
377 )\r
378{\r
379 EFI_STATUS Status;\r
380 UINT64 OsIndicationSupport;\r
381 UINT64 OsIndication;\r
382 UINTN DataSize;\r
383 UINT32 Attributes;\r
384 \r
385 //\r
386 // Validate Console variable.\r
387 //\r
388 BdsFormalizeConsoleVariable (L"ConIn");\r
389 BdsFormalizeConsoleVariable (L"ConOut");\r
390 BdsFormalizeConsoleVariable (L"ErrOut");\r
391\r
392 //\r
393 // OS indicater support variable\r
394 //\r
395 OsIndicationSupport = EFI_OS_INDICATIONS_BOOT_TO_FW_UI;\r
396 Status = gRT->SetVariable (\r
397 L"OsIndicationsSupported",\r
398 &gEfiGlobalVariableGuid,\r
399 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
400 sizeof(UINT64),\r
401 &OsIndicationSupport\r
402 );\r
403 ASSERT_EFI_ERROR (Status);\r
404\r
405 //\r
406 // If OsIndications is invalid, remove it.\r
407 // Invalid case\r
408 // 1. Data size != UINT64\r
409 // 2. OsIndication value inconsistence\r
410 // 3. OsIndication attribute inconsistence\r
411 //\r
412 OsIndication = 0;\r
413 Attributes = 0;\r
414 DataSize = sizeof(UINT64);\r
415 Status = gRT->GetVariable (\r
416 L"OsIndications",\r
417 &gEfiGlobalVariableGuid,\r
418 &Attributes,\r
419 &DataSize,\r
420 &OsIndication\r
421 );\r
422\r
423 if (!EFI_ERROR(Status)) {\r
424 if (DataSize != sizeof(UINT64) ||\r
425 (OsIndication & ~OsIndicationSupport) != 0 ||\r
426 Attributes != (EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE)){\r
427\r
428 DEBUG ((EFI_D_ERROR, "Unformalized OsIndications variable exists. Delete it\n"));\r
429 Status = gRT->SetVariable (\r
430 L"OsIndications",\r
431 &gEfiGlobalVariableGuid,\r
432 Attributes,\r
433 0,\r
434 &OsIndication\r
435 );\r
436 ASSERT_EFI_ERROR (Status);\r
437 }\r
438 }\r
439\r
440}\r
441\r
442/**\r
443\r
444 Service routine for BdsInstance->Entry(). Devices are connected, the\r
445 consoles are initialized, and the boot options are tried.\r
446\r
447 @param This Protocol Instance structure.\r
448\r
449**/\r
450VOID\r
451EFIAPI\r
452BdsEntry (\r
453 IN EFI_BDS_ARCH_PROTOCOL *This\r
454 )\r
455{\r
456 LIST_ENTRY DriverOptionList;\r
457 LIST_ENTRY BootOptionList;\r
458 UINTN BootNextSize;\r
459 CHAR16 *FirmwareVendor;\r
460\r
461 //\r
462 // Insert the performance probe\r
463 //\r
464 PERF_END (NULL, "DXE", NULL, 0);\r
465 PERF_START (NULL, "BDS", NULL, 0);\r
466\r
467 //\r
468 // Initialize the global system boot option and driver option\r
469 //\r
470 InitializeListHead (&DriverOptionList);\r
471 InitializeListHead (&BootOptionList);\r
472\r
473 //\r
474 // Initialize hotkey service\r
475 //\r
476 InitializeHotkeyService ();\r
477\r
478 //\r
479 // Fill in FirmwareVendor and FirmwareRevision from PCDs\r
480 //\r
481 FirmwareVendor = (CHAR16 *)PcdGetPtr (PcdFirmwareVendor);\r
482 gST->FirmwareVendor = AllocateRuntimeCopyPool (StrSize (FirmwareVendor), FirmwareVendor);\r
483 ASSERT (gST->FirmwareVendor != NULL);\r
484 gST->FirmwareRevision = PcdGet32 (PcdFirmwareRevision);\r
485\r
486 //\r
487 // Fixup Tasble CRC after we updated Firmware Vendor and Revision\r
488 //\r
489 gBS->CalculateCrc32 ((VOID *)gST, sizeof(EFI_SYSTEM_TABLE), &gST->Hdr.CRC32);\r
490\r
491 //\r
492 // Validate Variable.\r
493 //\r
494 BdsFormalizeEfiGlobalVariable();\r
495\r
496 //\r
497 // Do the platform init, can be customized by OEM/IBV\r
498 //\r
499 PERF_START (NULL, "PlatformBds", "BDS", 0);\r
500 PlatformBdsInit ();\r
501\r
502 InitializeHwErrRecSupport();\r
503\r
504 //\r
505 // bugbug: platform specific code\r
506 // Initialize the platform specific string and language\r
507 //\r
508 InitializeStringSupport ();\r
509 InitializeLanguage (TRUE);\r
510 InitializeFrontPage (TRUE);\r
511\r
512 //\r
513 // Set up the device list based on EFI 1.1 variables\r
514 // process Driver#### and Load the driver's in the\r
515 // driver option list\r
516 //\r
517 BdsLibBuildOptionFromVar (&DriverOptionList, L"DriverOrder");\r
518 if (!IsListEmpty (&DriverOptionList)) {\r
519 BdsLibLoadDrivers (&DriverOptionList);\r
520 }\r
521 //\r
522 // Check if we have the boot next option\r
523 //\r
524 mBootNext = BdsLibGetVariableAndSize (\r
525 L"BootNext",\r
526 &gEfiGlobalVariableGuid,\r
527 &BootNextSize\r
528 );\r
529\r
530 //\r
531 // Setup some platform policy here\r
532 //\r
533 PlatformBdsPolicyBehavior (&DriverOptionList, &BootOptionList, BdsProcessCapsules, BdsMemoryTest);\r
534 PERF_END (NULL, "PlatformBds", "BDS", 0);\r
535\r
536 //\r
537 // BDS select the boot device to load OS\r
538 //\r
539 BdsBootDeviceSelect ();\r
540\r
541 //\r
542 // Only assert here since this is the right behavior, we should never\r
543 // return back to DxeCore.\r
544 //\r
545 ASSERT (FALSE);\r
546\r
547 return ;\r
548}\r