]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/BdsDxe/BdsEntry.c
MdeModulePkg FileExplorerDxe: Change file format which has mixed file format.
[mirror_edk2.git] / MdeModulePkg / Universal / BdsDxe / BdsEntry.c
CommitLineData
f4cd24da
RN
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
4982ea57 8(C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>\r
f4cd24da
RN
9Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>\r
10This program and the accompanying materials\r
11are licensed and made available under the terms and conditions of the BSD License\r
12which accompanies this distribution. The full text of the license may be found at\r
13http://opensource.org/licenses/bsd-license.php\r
14\r
15THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
16WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
17\r
18**/\r
19\r
20#include "Bds.h"\r
21#include "Language.h"\r
22#include "HwErrRecSupport.h"\r
23\r
24#define SET_BOOT_OPTION_SUPPORT_KEY_COUNT(a, c) { \\r
25 (a) = ((a) & ~EFI_BOOT_OPTION_SUPPORT_COUNT) | (((c) << LowBitSet32 (EFI_BOOT_OPTION_SUPPORT_COUNT)) & EFI_BOOT_OPTION_SUPPORT_COUNT); \\r
26 }\r
27\r
28///\r
29/// BDS arch protocol instance initial value.\r
30///\r
31EFI_BDS_ARCH_PROTOCOL gBds = {\r
32 BdsEntry\r
33};\r
34\r
35//\r
36// gConnectConInEvent - Event which is signaled when ConIn connection is required\r
37//\r
38EFI_EVENT gConnectConInEvent = NULL;\r
39\r
40///\r
41/// The read-only variables defined in UEFI Spec.\r
42///\r
43CHAR16 *mReadOnlyVariables[] = {\r
44 EFI_PLATFORM_LANG_CODES_VARIABLE_NAME,\r
45 EFI_LANG_CODES_VARIABLE_NAME,\r
46 EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME,\r
47 EFI_HW_ERR_REC_SUPPORT_VARIABLE_NAME,\r
48 EFI_OS_INDICATIONS_SUPPORT_VARIABLE_NAME\r
49 };\r
50\r
1634214d
RN
51CHAR16 *mBdsLoadOptionName[] = {\r
52 L"Driver",\r
53 L"SysPrep",\r
68456d8a
RN
54 L"Boot",\r
55 L"PlatformRecovery"\r
1634214d
RN
56};\r
57\r
f4cd24da
RN
58/**\r
59 Event to Connect ConIn.\r
60\r
61 @param Event Event whose notification function is being invoked.\r
62 @param Context Pointer to the notification function's context,\r
63 which is implementation-dependent.\r
64\r
65**/\r
66VOID\r
67EFIAPI\r
68BdsDxeOnConnectConInCallBack (\r
69 IN EFI_EVENT Event,\r
70 IN VOID *Context\r
71 )\r
72{\r
73 EFI_STATUS Status;\r
74\r
75 //\r
76 // When Osloader call ReadKeyStroke to signal this event\r
77 // no driver dependency is assumed existing. So use a non-dispatch version\r
78 //\r
79 Status = EfiBootManagerConnectConsoleVariable (ConIn);\r
80 if (EFI_ERROR (Status)) {\r
81 //\r
82 // Should not enter this case, if enter, the keyboard will not work.\r
83 // May need platfrom policy to connect keyboard.\r
84 //\r
1634214d 85 DEBUG ((EFI_D_WARN, "[Bds] Connect ConIn failed - %r!!!\n", Status));\r
f4cd24da
RN
86 }\r
87}\r
88\r
89/**\r
90\r
91 Install Boot Device Selection Protocol\r
92\r
93 @param ImageHandle The image handle.\r
94 @param SystemTable The system table.\r
95\r
96 @retval EFI_SUCEESS BDS has finished initializing.\r
97 Return the dispatcher and recall BDS.Entry\r
98 @retval Other Return status from AllocatePool() or gBS->InstallProtocolInterface\r
99\r
100**/\r
101EFI_STATUS\r
102EFIAPI\r
103BdsInitialize (\r
104 IN EFI_HANDLE ImageHandle,\r
105 IN EFI_SYSTEM_TABLE *SystemTable\r
106 )\r
107{\r
108 EFI_STATUS Status;\r
109 EFI_HANDLE Handle;\r
110 //\r
111 // Install protocol interface\r
112 //\r
113 Handle = NULL;\r
114 Status = gBS->InstallMultipleProtocolInterfaces (\r
115 &Handle,\r
116 &gEfiBdsArchProtocolGuid, &gBds,\r
117 NULL\r
118 );\r
119 ASSERT_EFI_ERROR (Status);\r
120\r
121 return Status;\r
122}\r
123\r
f4cd24da
RN
124/**\r
125 Function waits for a given event to fire, or for an optional timeout to expire.\r
126\r
127 @param Event The event to wait for\r
128 @param Timeout An optional timeout value in 100 ns units.\r
129\r
130 @retval EFI_SUCCESS Event fired before Timeout expired.\r
131 @retval EFI_TIME_OUT Timout expired before Event fired..\r
132\r
133**/\r
134EFI_STATUS\r
135BdsWaitForSingleEvent (\r
136 IN EFI_EVENT Event,\r
137 IN UINT64 Timeout OPTIONAL\r
138 )\r
139{\r
140 UINTN Index;\r
141 EFI_STATUS Status;\r
142 EFI_EVENT TimerEvent;\r
143 EFI_EVENT WaitList[2];\r
144\r
145 if (Timeout != 0) {\r
146 //\r
147 // Create a timer event\r
148 //\r
149 Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent);\r
150 if (!EFI_ERROR (Status)) {\r
151 //\r
152 // Set the timer event\r
153 //\r
154 gBS->SetTimer (\r
155 TimerEvent,\r
156 TimerRelative,\r
157 Timeout\r
158 );\r
159\r
160 //\r
161 // Wait for the original event or the timer\r
162 //\r
163 WaitList[0] = Event;\r
164 WaitList[1] = TimerEvent;\r
165 Status = gBS->WaitForEvent (2, WaitList, &Index);\r
166 ASSERT_EFI_ERROR (Status);\r
167 gBS->CloseEvent (TimerEvent);\r
168\r
169 //\r
170 // If the timer expired, change the return to timed out\r
171 //\r
172 if (Index == 1) {\r
173 Status = EFI_TIMEOUT;\r
174 }\r
175 }\r
176 } else {\r
177 //\r
178 // No timeout... just wait on the event\r
179 //\r
180 Status = gBS->WaitForEvent (1, &Event, &Index);\r
181 ASSERT (!EFI_ERROR (Status));\r
182 ASSERT (Index == 0);\r
183 }\r
184\r
185 return Status;\r
186}\r
187\r
188/**\r
189 The function reads user inputs.\r
190\r
191**/\r
192VOID\r
193BdsReadKeys (\r
194 VOID\r
195 )\r
196{\r
197 EFI_STATUS Status;\r
198 EFI_INPUT_KEY Key;\r
199\r
200 if (PcdGetBool (PcdConInConnectOnDemand)) {\r
201 return;\r
202 }\r
203\r
204 while (gST->ConIn != NULL) {\r
205 \r
206 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
207 \r
208 if (EFI_ERROR (Status)) {\r
209 //\r
210 // No more keys.\r
211 //\r
212 break;\r
213 }\r
214 }\r
215}\r
216\r
217/**\r
218 The function waits for the boot manager timeout expires or hotkey is pressed.\r
219\r
220 It calls PlatformBootManagerWaitCallback each second.\r
221\r
222 @param HotkeyTriggered Input hotkey event.\r
223**/\r
224VOID\r
225BdsWait (\r
226 IN EFI_EVENT HotkeyTriggered\r
227 )\r
228{\r
229 EFI_STATUS Status;\r
230 UINT16 TimeoutRemain;\r
231\r
232 DEBUG ((EFI_D_INFO, "[Bds]BdsWait ...Zzzzzzzzzzzz...\n"));\r
233\r
234 TimeoutRemain = PcdGet16 (PcdPlatformBootTimeOut);\r
235 while (TimeoutRemain != 0) {\r
236 DEBUG ((EFI_D_INFO, "[Bds]BdsWait(%d)..Zzzz...\n", (UINTN) TimeoutRemain));\r
237 PlatformBootManagerWaitCallback (TimeoutRemain);\r
238\r
239 BdsReadKeys (); // BUGBUG: Only reading can signal HotkeyTriggered\r
240 // Can be removed after all keyboard drivers invoke callback in timer callback.\r
241\r
242 if (HotkeyTriggered != NULL) {\r
243 Status = BdsWaitForSingleEvent (HotkeyTriggered, EFI_TIMER_PERIOD_SECONDS (1));\r
244 if (!EFI_ERROR (Status)) {\r
245 break;\r
246 }\r
247 } else {\r
248 gBS->Stall (1000000);\r
249 }\r
250\r
251 //\r
252 // 0xffff means waiting forever\r
253 // BDS with no hotkey provided and 0xffff as timeout will "hang" in the loop\r
254 //\r
255 if (TimeoutRemain != 0xffff) {\r
256 TimeoutRemain--;\r
257 }\r
258 }\r
259 DEBUG ((EFI_D_INFO, "[Bds]Exit the waiting!\n"));\r
260}\r
261\r
262/**\r
263 Attempt to boot each boot option in the BootOptions array.\r
264\r
265 @param BootOptions Input boot option array.\r
266 @param BootOptionCount Input boot option count.\r
68456d8a 267 @param BootManagerMenu Input boot manager menu.\r
f4cd24da
RN
268\r
269 @retval TRUE Successfully boot one of the boot options.\r
270 @retval FALSE Failed boot any of the boot options.\r
271**/\r
272BOOLEAN\r
68456d8a 273BootBootOptions (\r
f4cd24da 274 IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions,\r
68456d8a
RN
275 IN UINTN BootOptionCount,\r
276 IN EFI_BOOT_MANAGER_LOAD_OPTION *BootManagerMenu\r
f4cd24da
RN
277 )\r
278{\r
279 UINTN Index;\r
280\r
281 //\r
282 // Attempt boot each boot option\r
283 //\r
284 for (Index = 0; Index < BootOptionCount; Index++) {\r
285 //\r
286 // According to EFI Specification, if a load option is not marked\r
287 // as LOAD_OPTION_ACTIVE, the boot manager will not automatically\r
288 // load the option.\r
289 //\r
290 if ((BootOptions[Index].Attributes & LOAD_OPTION_ACTIVE) == 0) {\r
291 continue;\r
292 }\r
293\r
294 //\r
295 // Boot#### load options with LOAD_OPTION_CATEGORY_APP are executables which are not\r
296 // part of the normal boot processing. Boot options with reserved category values will be\r
297 // ignored by the boot manager.\r
298 //\r
299 if ((BootOptions[Index].Attributes & LOAD_OPTION_CATEGORY) != LOAD_OPTION_CATEGORY_BOOT) {\r
300 continue;\r
301 }\r
302\r
303 //\r
304 // All the driver options should have been processed since\r
305 // now boot will be performed.\r
306 //\r
307 EfiBootManagerBoot (&BootOptions[Index]);\r
308\r
309 //\r
68456d8a 310 // If the boot via Boot#### returns with a status of EFI_SUCCESS, platform firmware\r // supports boot manager menu, and if firmware is configured to boot in an\r // interactive mode, the boot manager will stop processing the BootOrder variable and\r // present a boot manager menu to the user.\r
f4cd24da
RN
311 //\r
312 if (BootOptions[Index].Status == EFI_SUCCESS) {\r
68456d8a 313 EfiBootManagerBoot (BootManagerMenu);\r
f4cd24da
RN
314 break;\r
315 }\r
316 }\r
317\r
318 return (BOOLEAN) (Index < BootOptionCount);\r
319}\r
320\r
321/**\r
68456d8a 322 The function will load and start every Driver####, SysPrep#### or PlatformRecovery####.\r
f4cd24da 323\r
1634214d
RN
324 @param LoadOptions Load option array.\r
325 @param LoadOptionCount Load option count.\r
f4cd24da
RN
326**/\r
327VOID\r
1634214d
RN
328ProcessLoadOptions (\r
329 IN EFI_BOOT_MANAGER_LOAD_OPTION *LoadOptions,\r
330 IN UINTN LoadOptionCount\r
f4cd24da
RN
331 )\r
332{\r
1634214d
RN
333 EFI_STATUS Status;\r
334 UINTN Index;\r
335 BOOLEAN ReconnectAll;\r
336 EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType;\r
f4cd24da 337\r
68456d8a 338 ReconnectAll = FALSE;\r
1634214d 339 LoadOptionType = LoadOptionTypeMax;\r
f4cd24da
RN
340\r
341 //\r
342 // Process the driver option\r
343 //\r
1634214d 344 for (Index = 0; Index < LoadOptionCount; Index++) {\r
f4cd24da 345 //\r
1634214d 346 // All the load options in the array should be of the same type.\r
f4cd24da 347 //\r
68456d8a 348 if (Index == 0) {\r
1634214d 349 LoadOptionType = LoadOptions[Index].OptionType;\r
f4cd24da 350 }\r
1634214d 351 ASSERT (LoadOptionType == LoadOptions[Index].OptionType);\r
f4cd24da 352\r
1634214d 353 Status = EfiBootManagerProcessLoadOption (&LoadOptions[Index]);\r
f4cd24da 354\r
68456d8a
RN
355 if (!EFI_ERROR (Status)) {\r
356 if (LoadOptionType == LoadOptionTypePlatformRecovery) {\r
357 //\r
358 // Stop processing if any entry is successful\r
359 //\r
360 break;\r
361 }\r
362 if ((LoadOptions[Index].Attributes & LOAD_OPTION_FORCE_RECONNECT) != 0) {\r
363 ReconnectAll = TRUE;\r
364 }\r
f4cd24da
RN
365 }\r
366 }\r
1634214d 367\r
f4cd24da 368 //\r
1634214d
RN
369 // If a driver load option is marked as LOAD_OPTION_FORCE_RECONNECT,\r
370 // then all of the EFI drivers in the system will be disconnected and\r
371 // reconnected after the last driver load option is processed.\r
f4cd24da 372 //\r
1634214d 373 if (ReconnectAll && LoadOptionType == LoadOptionTypeDriver) {\r
f4cd24da
RN
374 EfiBootManagerDisconnectAll ();\r
375 EfiBootManagerConnectAll ();\r
376 }\r
f4cd24da
RN
377}\r
378\r
379/**\r
380\r
381 Validate input console variable data. \r
382\r
383 If found the device path is not a valid device path, remove the variable.\r
384 \r
385 @param VariableName Input console variable name.\r
386\r
387**/\r
388VOID\r
389BdsFormalizeConsoleVariable (\r
390 IN CHAR16 *VariableName\r
391 )\r
392{\r
393 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
394 UINTN VariableSize;\r
395 EFI_STATUS Status;\r
396\r
397 GetEfiGlobalVariable2 (VariableName, (VOID **) &DevicePath, &VariableSize);\r
398 if ((DevicePath != NULL) && !IsDevicePathValid (DevicePath, VariableSize)) { \r
399 Status = gRT->SetVariable (\r
400 VariableName,\r
401 &gEfiGlobalVariableGuid,\r
402 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
403 0,\r
404 NULL\r
405 );\r
406 //\r
407 // Deleting variable with current variable implementation shouldn't fail.\r
408 //\r
409 ASSERT_EFI_ERROR (Status);\r
410 }\r
411\r
412 if (DevicePath != NULL) {\r
413 FreePool (DevicePath);\r
414 }\r
415}\r
416\r
417/**\r
418 Formalize OsIndication related variables. \r
419 \r
420 For OsIndicationsSupported, Create a BS/RT/UINT64 variable to report caps \r
421 Delete OsIndications variable if it is not NV/BS/RT UINT64.\r
422 \r
423 Item 3 is used to solve case when OS corrupts OsIndications. Here simply delete this NV variable.\r
424\r
425**/\r
426VOID \r
427BdsFormalizeOSIndicationVariable (\r
428 VOID\r
429 )\r
430{\r
431 EFI_STATUS Status;\r
432 UINT64 OsIndicationSupport;\r
433 UINT64 OsIndication;\r
434 UINTN DataSize;\r
435 UINT32 Attributes;\r
436\r
437 //\r
438 // OS indicater support variable\r
439 //\r
68456d8a 440 OsIndicationSupport = EFI_OS_INDICATIONS_BOOT_TO_FW_UI | EFI_OS_INDICATIONS_START_PLATFORM_RECOVERY;\r
f4cd24da 441 Status = gRT->SetVariable (\r
cc4812f6 442 EFI_OS_INDICATIONS_SUPPORT_VARIABLE_NAME,\r
f4cd24da
RN
443 &gEfiGlobalVariableGuid,\r
444 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
445 sizeof(UINT64),\r
446 &OsIndicationSupport\r
447 );\r
448 //\r
449 // Platform needs to make sure setting volatile variable before calling 3rd party code shouldn't fail.\r
450 //\r
451 ASSERT_EFI_ERROR (Status);\r
452\r
453 //\r
454 // If OsIndications is invalid, remove it.\r
455 // Invalid case\r
456 // 1. Data size != UINT64\r
457 // 2. OsIndication value inconsistence\r
458 // 3. OsIndication attribute inconsistence\r
459 //\r
460 OsIndication = 0;\r
461 Attributes = 0;\r
462 DataSize = sizeof(UINT64);\r
463 Status = gRT->GetVariable (\r
cc4812f6 464 EFI_OS_INDICATIONS_VARIABLE_NAME,\r
f4cd24da
RN
465 &gEfiGlobalVariableGuid,\r
466 &Attributes,\r
467 &DataSize,\r
468 &OsIndication\r
469 );\r
470 if (Status == EFI_NOT_FOUND) {\r
471 return;\r
472 }\r
473\r
474 if ((DataSize != sizeof (OsIndication)) ||\r
475 ((OsIndication & ~OsIndicationSupport) != 0) ||\r
476 (Attributes != (EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE))\r
477 ){\r
478\r
479 DEBUG ((EFI_D_ERROR, "[Bds] Unformalized OsIndications variable exists. Delete it\n"));\r
480 Status = gRT->SetVariable (\r
cc4812f6 481 EFI_OS_INDICATIONS_VARIABLE_NAME,\r
f4cd24da
RN
482 &gEfiGlobalVariableGuid,\r
483 0,\r
484 0,\r
485 NULL\r
486 );\r
487 //\r
488 // Deleting variable with current variable implementation shouldn't fail.\r
489 //\r
490 ASSERT_EFI_ERROR(Status);\r
491 }\r
492}\r
493\r
494/**\r
495\r
496 Validate variables. \r
497\r
498**/\r
499VOID \r
500BdsFormalizeEfiGlobalVariable (\r
501 VOID\r
502 )\r
503{\r
504 //\r
505 // Validate Console variable.\r
506 //\r
cc4812f6
RN
507 BdsFormalizeConsoleVariable (EFI_CON_IN_VARIABLE_NAME);\r
508 BdsFormalizeConsoleVariable (EFI_CON_OUT_VARIABLE_NAME);\r
509 BdsFormalizeConsoleVariable (EFI_ERR_OUT_VARIABLE_NAME);\r
f4cd24da
RN
510\r
511 //\r
512 // Validate OSIndication related variable.\r
513 //\r
514 BdsFormalizeOSIndicationVariable ();\r
515}\r
516\r
517/**\r
518\r
519 Allocate a block of memory that will contain performance data to OS.\r
520\r
521**/\r
522VOID\r
523BdsAllocateMemoryForPerformanceData (\r
524 VOID\r
525 )\r
526{\r
527 EFI_STATUS Status;\r
528 EFI_PHYSICAL_ADDRESS AcpiLowMemoryBase;\r
529 EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;\r
530\r
531 AcpiLowMemoryBase = 0x0FFFFFFFFULL;\r
532\r
533 //\r
534 // Allocate a block of memory that will contain performance data to OS.\r
535 //\r
536 Status = gBS->AllocatePages (\r
537 AllocateMaxAddress,\r
538 EfiReservedMemoryType,\r
539 EFI_SIZE_TO_PAGES (PERF_DATA_MAX_LENGTH),\r
540 &AcpiLowMemoryBase\r
541 );\r
542 if (!EFI_ERROR (Status)) {\r
543 //\r
544 // Save the pointer to variable for use in S3 resume.\r
545 //\r
546 Status = BdsDxeSetVariableAndReportStatusCodeOnError (\r
547 L"PerfDataMemAddr",\r
548 &gPerformanceProtocolGuid,\r
549 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
550 sizeof (EFI_PHYSICAL_ADDRESS),\r
551 &AcpiLowMemoryBase\r
552 );\r
553 if (EFI_ERROR (Status)) {\r
554 DEBUG ((EFI_D_ERROR, "[Bds] PerfDataMemAddr (%08x) cannot be saved to NV storage.\n", AcpiLowMemoryBase));\r
555 }\r
556 //\r
557 // Mark L"PerfDataMemAddr" variable to read-only if the Variable Lock protocol exists\r
558 // Still lock it even the variable cannot be saved to prevent it's set by 3rd party code.\r
559 //\r
560 Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock);\r
561 if (!EFI_ERROR (Status)) {\r
562 Status = VariableLock->RequestToLock (VariableLock, L"PerfDataMemAddr", &gPerformanceProtocolGuid);\r
563 ASSERT_EFI_ERROR (Status);\r
564 }\r
565 }\r
566}\r
567\r
568/**\r
569\r
570 Service routine for BdsInstance->Entry(). Devices are connected, the\r
571 consoles are initialized, and the boot options are tried.\r
572\r
573 @param This Protocol Instance structure.\r
574\r
575**/\r
576VOID\r
577EFIAPI\r
578BdsEntry (\r
579 IN EFI_BDS_ARCH_PROTOCOL *This\r
580 )\r
581{\r
1634214d
RN
582 EFI_BOOT_MANAGER_LOAD_OPTION *LoadOptions;\r
583 UINTN LoadOptionCount;\r
f4cd24da
RN
584 CHAR16 *FirmwareVendor;\r
585 EFI_EVENT HotkeyTriggered;\r
586 UINT64 OsIndication;\r
587 UINTN DataSize;\r
588 EFI_STATUS Status;\r
589 UINT32 BootOptionSupport;\r
590 UINT16 BootTimeOut;\r
591 EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;\r
592 UINTN Index;\r
d175f4e6 593 EFI_BOOT_MANAGER_LOAD_OPTION LoadOption;\r
f4cd24da
RN
594 UINT16 *BootNext;\r
595 CHAR16 BootNextVariableName[sizeof ("Boot####")];\r
1634214d
RN
596 EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu;\r
597 BOOLEAN BootFwUi;\r
68456d8a
RN
598 BOOLEAN PlatformRecovery;\r
599 BOOLEAN BootSuccess;\r
d175f4e6 600 EFI_DEVICE_PATH_PROTOCOL *FilePath;\r
f4cd24da
RN
601\r
602 HotkeyTriggered = NULL;\r
603 Status = EFI_SUCCESS;\r
68456d8a 604 BootSuccess = FALSE;\r
f4cd24da
RN
605\r
606 //\r
607 // Insert the performance probe\r
608 //\r
609 PERF_END (NULL, "DXE", NULL, 0);\r
610 PERF_START (NULL, "BDS", NULL, 0);\r
611 DEBUG ((EFI_D_INFO, "[Bds] Entry...\n"));\r
612\r
613 PERF_CODE (\r
614 BdsAllocateMemoryForPerformanceData ();\r
615 );\r
616\r
617 //\r
618 // Fill in FirmwareVendor and FirmwareRevision from PCDs\r
619 //\r
620 FirmwareVendor = (CHAR16 *) PcdGetPtr (PcdFirmwareVendor);\r
621 gST->FirmwareVendor = AllocateRuntimeCopyPool (StrSize (FirmwareVendor), FirmwareVendor);\r
622 ASSERT (gST->FirmwareVendor != NULL);\r
623 gST->FirmwareRevision = PcdGet32 (PcdFirmwareRevision);\r
624\r
625 //\r
626 // Fixup Tasble CRC after we updated Firmware Vendor and Revision\r
627 //\r
628 gST->Hdr.CRC32 = 0;\r
629 gBS->CalculateCrc32 ((VOID *) gST, sizeof (EFI_SYSTEM_TABLE), &gST->Hdr.CRC32);\r
630\r
631 //\r
632 // Validate Variable.\r
633 //\r
634 BdsFormalizeEfiGlobalVariable ();\r
635\r
636 //\r
637 // Mark the read-only variables if the Variable Lock protocol exists\r
638 //\r
639 Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock);\r
640 DEBUG ((EFI_D_INFO, "[BdsDxe] Locate Variable Lock protocol - %r\n", Status));\r
641 if (!EFI_ERROR (Status)) {\r
642 for (Index = 0; Index < sizeof (mReadOnlyVariables) / sizeof (mReadOnlyVariables[0]); Index++) {\r
643 Status = VariableLock->RequestToLock (VariableLock, mReadOnlyVariables[Index], &gEfiGlobalVariableGuid);\r
644 ASSERT_EFI_ERROR (Status);\r
645 }\r
646 }\r
647\r
648 InitializeHwErrRecSupport ();\r
649\r
650 //\r
651 // Initialize L"Timeout" EFI global variable.\r
652 //\r
653 BootTimeOut = PcdGet16 (PcdPlatformBootTimeOut);\r
654 if (BootTimeOut != 0xFFFF) {\r
655 //\r
656 // If time out value equal 0xFFFF, no need set to 0xFFFF to variable area because UEFI specification\r
657 // define same behavior between no value or 0xFFFF value for L"Timeout".\r
658 //\r
659 BdsDxeSetVariableAndReportStatusCodeOnError (\r
660 EFI_TIME_OUT_VARIABLE_NAME,\r
661 &gEfiGlobalVariableGuid,\r
662 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
663 sizeof (UINT16),\r
664 &BootTimeOut\r
665 );\r
666 }\r
667\r
668 //\r
669 // Initialize L"BootOptionSupport" EFI global variable.\r
670 // Lazy-ConIn implictly disables BDS hotkey.\r
671 //\r
1634214d 672 BootOptionSupport = EFI_BOOT_OPTION_SUPPORT_APP | EFI_BOOT_OPTION_SUPPORT_SYSPREP;\r
f4cd24da
RN
673 if (!PcdGetBool (PcdConInConnectOnDemand)) {\r
674 BootOptionSupport |= EFI_BOOT_OPTION_SUPPORT_KEY;\r
675 SET_BOOT_OPTION_SUPPORT_KEY_COUNT (BootOptionSupport, 3);\r
676 }\r
677 Status = gRT->SetVariable (\r
678 EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME,\r
679 &gEfiGlobalVariableGuid,\r
680 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
681 sizeof (BootOptionSupport),\r
682 &BootOptionSupport\r
683 );\r
684 //\r
685 // Platform needs to make sure setting volatile variable before calling 3rd party code shouldn't fail.\r
686 //\r
687 ASSERT_EFI_ERROR (Status);\r
688\r
689 //\r
690 // Cache and remove the "BootNext" NV variable.\r
691 //\r
692 GetEfiGlobalVariable2 (EFI_BOOT_NEXT_VARIABLE_NAME, (VOID **) &BootNext, &DataSize);\r
693 if (DataSize != sizeof (UINT16)) {\r
694 if (BootNext != NULL) {\r
695 FreePool (BootNext);\r
696 }\r
697 BootNext = NULL;\r
698 }\r
699 Status = gRT->SetVariable (\r
700 EFI_BOOT_NEXT_VARIABLE_NAME,\r
701 &gEfiGlobalVariableGuid,\r
702 0,\r
703 0,\r
704 NULL\r
705 );\r
706 //\r
707 // Deleting NV variable shouldn't fail unless it doesn't exist.\r
708 //\r
709 ASSERT (Status == EFI_SUCCESS || Status == EFI_NOT_FOUND);\r
710\r
711 //\r
712 // Initialize the platform language variables\r
713 //\r
714 InitializeLanguage (TRUE);\r
715\r
d175f4e6
RN
716 //\r
717 // System firmware must include a PlatformRecovery#### variable specifying\r
718 // a short-form File Path Media Device Path containing the platform default\r
719 // file path for removable media\r
720 //\r
721 FilePath = FileDevicePath (NULL, EFI_REMOVABLE_MEDIA_FILE_NAME);\r
722 Status = EfiBootManagerInitializeLoadOption (\r
723 &LoadOption,\r
724 0,\r
725 LoadOptionTypePlatformRecovery,\r
726 LOAD_OPTION_ACTIVE,\r
727 L"Default PlatformRecovery",\r
728 FilePath,\r
729 NULL,\r
730 0\r
731 );\r
732 ASSERT_EFI_ERROR (Status);\r
733 EfiBootManagerLoadOptionToVariable (&LoadOption);\r
734 EfiBootManagerFreeLoadOption (&LoadOption);\r
735 FreePool (FilePath);\r
736\r
f4cd24da
RN
737 //\r
738 // Report Status Code to indicate connecting drivers will happen\r
739 //\r
740 REPORT_STATUS_CODE (\r
741 EFI_PROGRESS_CODE,\r
742 (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_BEGIN_CONNECTING_DRIVERS)\r
743 );\r
744\r
745 //\r
746 // Do the platform init, can be customized by OEM/IBV\r
747 // Possible things that can be done in PlatformBootManagerBeforeConsole:\r
748 // > Update console variable: 1. include hot-plug devices; 2. Clear ConIn and add SOL for AMT\r
749 // > Register new Driver#### or Boot####\r
750 // > Register new Key####: e.g.: F12 \r
751 // > Signal ReadyToLock event\r
752 // > Authentication action: 1. connect Auth devices; 2. Identify auto logon user.\r
753 //\r
754 PERF_START (NULL, "PlatformBootManagerBeforeConsole", "BDS", 0);\r
755 PlatformBootManagerBeforeConsole ();\r
756 PERF_END (NULL, "PlatformBootManagerBeforeConsole", "BDS", 0);\r
757\r
758 //\r
759 // Initialize hotkey service\r
760 //\r
761 EfiBootManagerStartHotkeyService (&HotkeyTriggered);\r
762\r
763 //\r
1634214d 764 // Execute Driver Options\r
f4cd24da 765 //\r
1634214d
RN
766 LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypeDriver);\r
767 ProcessLoadOptions (LoadOptions, LoadOptionCount);\r
768 EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);\r
f4cd24da
RN
769\r
770 //\r
771 // Connect consoles\r
772 //\r
773 PERF_START (NULL, "EfiBootManagerConnectAllDefaultConsoles", "BDS", 0);\r
774 if (PcdGetBool (PcdConInConnectOnDemand)) {\r
775 EfiBootManagerConnectConsoleVariable (ConOut);\r
776 EfiBootManagerConnectConsoleVariable (ErrOut);\r
777\r
778 //\r
779 // Initialize ConnectConIn event\r
780 //\r
781 Status = gBS->CreateEventEx (\r
782 EVT_NOTIFY_SIGNAL,\r
783 TPL_CALLBACK,\r
784 BdsDxeOnConnectConInCallBack,\r
785 NULL,\r
786 &gConnectConInEventGuid,\r
787 &gConnectConInEvent\r
788 );\r
789 if (EFI_ERROR (Status)) {\r
790 gConnectConInEvent = NULL;\r
791 }\r
792 } else {\r
793 EfiBootManagerConnectAllDefaultConsoles ();\r
794 }\r
795 PERF_END (NULL, "EfiBootManagerConnectAllDefaultConsoles", "BDS", 0);\r
796\r
797 //\r
798 // Do the platform specific action after the console is ready\r
799 // Possible things that can be done in PlatformBootManagerAfterConsole:\r
800 // > Console post action:\r
801 // > Dynamically switch output mode from 100x31 to 80x25 for certain senarino\r
802 // > Signal console ready platform customized event\r
803 // > Run diagnostics like memory testing\r
804 // > Connect certain devices\r
805 // > Dispatch aditional option roms\r
806 // > Special boot: e.g.: USB boot, enter UI\r
807 // \r
808 PERF_START (NULL, "PlatformBootManagerAfterConsole", "BDS", 0);\r
809 PlatformBootManagerAfterConsole ();\r
810 PERF_END (NULL, "PlatformBootManagerAfterConsole", "BDS", 0);\r
68456d8a
RN
811 //\r
812 // Boot to Boot Manager Menu when EFI_OS_INDICATIONS_BOOT_TO_FW_UI is set. Skip HotkeyBoot\r
813 //\r
814 DataSize = sizeof (UINT64);\r
815 Status = gRT->GetVariable (\r
816 EFI_OS_INDICATIONS_VARIABLE_NAME,\r
817 &gEfiGlobalVariableGuid,\r
818 NULL,\r
819 &DataSize,\r
820 &OsIndication\r
821 );\r
822 if (EFI_ERROR (Status)) {\r
823 OsIndication = 0;\r
824 }\r
f4cd24da
RN
825\r
826 DEBUG_CODE (\r
1634214d 827 EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType;\r
68456d8a 828 DEBUG ((EFI_D_INFO, "[Bds]OsIndication: %016x\n", OsIndication));\r
1634214d
RN
829 DEBUG ((EFI_D_INFO, "[Bds]=============Begin Load Options Dumping ...=============\n"));\r
830 for (LoadOptionType = 0; LoadOptionType < LoadOptionTypeMax; LoadOptionType++) {\r
f4cd24da 831 DEBUG ((\r
1634214d
RN
832 EFI_D_INFO, " %s Options:\n",\r
833 mBdsLoadOptionName[LoadOptionType]\r
f4cd24da 834 ));\r
1634214d
RN
835 LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionType);\r
836 for (Index = 0; Index < LoadOptionCount; Index++) {\r
837 DEBUG ((\r
838 EFI_D_INFO, " %s%04x: %s \t\t 0x%04x\n",\r
839 mBdsLoadOptionName[LoadOptionType],\r
840 LoadOptions[Index].OptionNumber,\r
841 LoadOptions[Index].Description,\r
842 LoadOptions[Index].Attributes\r
843 ));\r
844 }\r
845 EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);\r
f4cd24da 846 }\r
1634214d
RN
847 DEBUG ((EFI_D_INFO, "[Bds]=============End Load Options Dumping=============\n"));\r
848 );\r
f4cd24da
RN
849\r
850 //\r
68456d8a 851 // BootManagerMenu always contains the correct information even call fails.\r
f4cd24da 852 //\r
68456d8a 853 EfiBootManagerGetBootManagerMenu (&BootManagerMenu);\r
1634214d 854\r
68456d8a
RN
855 BootFwUi = (BOOLEAN) ((OsIndication & EFI_OS_INDICATIONS_BOOT_TO_FW_UI) != 0);\r
856 PlatformRecovery = (BOOLEAN) ((OsIndication & EFI_OS_INDICATIONS_START_PLATFORM_RECOVERY) != 0);\r
1634214d
RN
857 //\r
858 // Clear EFI_OS_INDICATIONS_BOOT_TO_FW_UI to acknowledge OS\r
859 // \r
68456d8a
RN
860 if (BootFwUi || PlatformRecovery) {\r
861 OsIndication &= ~((UINT64) (EFI_OS_INDICATIONS_BOOT_TO_FW_UI | EFI_OS_INDICATIONS_START_PLATFORM_RECOVERY));\r
f4cd24da 862 Status = gRT->SetVariable (\r
cc4812f6 863 EFI_OS_INDICATIONS_VARIABLE_NAME,\r
f4cd24da
RN
864 &gEfiGlobalVariableGuid,\r
865 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
866 sizeof(UINT64),\r
867 &OsIndication\r
868 );\r
869 //\r
870 // Changing the content without increasing its size with current variable implementation shouldn't fail.\r
871 //\r
872 ASSERT_EFI_ERROR (Status);\r
1634214d 873 }\r
f4cd24da 874\r
1634214d
RN
875 //\r
876 // Launch Boot Manager Menu directly when EFI_OS_INDICATIONS_BOOT_TO_FW_UI is set. Skip HotkeyBoot\r
877 //\r
878 if (BootFwUi) {\r
f4cd24da
RN
879 //\r
880 // Follow generic rule, Call BdsDxeOnConnectConInCallBack to connect ConIn before enter UI\r
881 //\r
882 if (PcdGetBool (PcdConInConnectOnDemand)) {\r
883 BdsDxeOnConnectConInCallBack (NULL, NULL);\r
884 }\r
885\r
886 //\r
1634214d 887 // Directly enter the setup page.\r
f4cd24da 888 //\r
1634214d 889 EfiBootManagerBoot (&BootManagerMenu);\r
f4cd24da
RN
890 }\r
891\r
68456d8a
RN
892 if (!PlatformRecovery) {\r
893 //\r
894 // Execute SysPrep####\r
895 //\r
896 LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypeSysPrep);\r
897 ProcessLoadOptions (LoadOptions, LoadOptionCount);\r
898 EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);\r
1634214d 899\r
68456d8a
RN
900 //\r
901 // Execute Key####\r
902 //\r
903 PERF_START (NULL, "BdsWait", "BDS", 0);\r
904 BdsWait (HotkeyTriggered);\r
905 PERF_END (NULL, "BdsWait", "BDS", 0);\r
1634214d 906\r
68456d8a
RN
907 //\r
908 // BdsReadKeys() can be removed after all keyboard drivers invoke callback in timer callback.\r
909 //\r
910 BdsReadKeys ();\r
1634214d 911\r
68456d8a 912 EfiBootManagerHotkeyBoot ();\r
1634214d 913\r
68456d8a
RN
914 //\r
915 // Boot to "BootNext"\r
916 //\r
917 if (BootNext != NULL) {\r
918 UnicodeSPrint (BootNextVariableName, sizeof (BootNextVariableName), L"Boot%04x", *BootNext);\r
919 Status = EfiBootManagerVariableToLoadOption (BootNextVariableName, &LoadOption);\r
920 if (!EFI_ERROR (Status)) {\r
d175f4e6
RN
921 EfiBootManagerBoot (&LoadOption);\r
922 EfiBootManagerFreeLoadOption (&LoadOption);\r
68456d8a
RN
923 if (LoadOption.Status == EFI_SUCCESS) {\r
924 //\r
925 // Boot to Boot Manager Menu upon EFI_SUCCESS\r
926 //\r
927 EfiBootManagerBoot (&BootManagerMenu);\r
928 }\r
f4cd24da
RN
929 }\r
930 }\r
68456d8a
RN
931\r
932 do {\r
933 //\r
934 // Retry to boot if any of the boot succeeds\r
935 //\r
936 LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypeBoot);\r
937 BootSuccess = BootBootOptions (LoadOptions, LoadOptionCount, &BootManagerMenu);\r
938 EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);\r
939 } while (BootSuccess);\r
f4cd24da
RN
940 }\r
941\r
68456d8a
RN
942 EfiBootManagerFreeLoadOption (&BootManagerMenu);\r
943\r
944 if (!BootSuccess) {\r
945 LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypePlatformRecovery);\r
946 ProcessLoadOptions (LoadOptions, LoadOptionCount);\r
947 EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);\r
f4cd24da 948 }\r
68456d8a
RN
949\r
950 DEBUG ((EFI_D_ERROR, "[Bds] Unable to boot!\n"));\r
951 CpuDeadLoop ();\r
f4cd24da
RN
952}\r
953\r
954/**\r
955 Set the variable and report the error through status code upon failure.\r
956\r
957 @param VariableName A Null-terminated string that is the name of the vendor's variable.\r
958 Each VariableName is unique for each VendorGuid. VariableName must\r
959 contain 1 or more characters. If VariableName is an empty string,\r
960 then EFI_INVALID_PARAMETER is returned.\r
961 @param VendorGuid A unique identifier for the vendor.\r
962 @param Attributes Attributes bitmask to set for the variable.\r
963 @param DataSize The size in bytes of the Data buffer. Unless the EFI_VARIABLE_APPEND_WRITE, \r
964 EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, or \r
965 EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute is set, a size of zero \r
966 causes the variable to be deleted. When the EFI_VARIABLE_APPEND_WRITE attribute is \r
967 set, then a SetVariable() call with a DataSize of zero will not cause any change to \r
968 the variable value (the timestamp associated with the variable may be updated however \r
969 even if no new data value is provided,see the description of the \r
970 EFI_VARIABLE_AUTHENTICATION_2 descriptor below. In this case the DataSize will not \r
971 be zero since the EFI_VARIABLE_AUTHENTICATION_2 descriptor will be populated). \r
972 @param Data The contents for the variable.\r
973\r
974 @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as\r
975 defined by the Attributes.\r
976 @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits, name, and GUID was supplied, or the\r
977 DataSize exceeds the maximum allowed.\r
978 @retval EFI_INVALID_PARAMETER VariableName is an empty string.\r
979 @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data.\r
980 @retval EFI_DEVICE_ERROR The variable could not be retrieved due to a hardware error.\r
981 @retval EFI_WRITE_PROTECTED The variable in question is read-only.\r
982 @retval EFI_WRITE_PROTECTED The variable in question cannot be deleted.\r
983 @retval EFI_SECURITY_VIOLATION The variable could not be written due to EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS \r
984 or EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACESS being set, but the AuthInfo \r
985 does NOT pass the validation check carried out by the firmware.\r
986\r
987 @retval EFI_NOT_FOUND The variable trying to be updated or deleted was not found.\r
988**/\r
989EFI_STATUS\r
990BdsDxeSetVariableAndReportStatusCodeOnError (\r
991 IN CHAR16 *VariableName,\r
992 IN EFI_GUID *VendorGuid,\r
993 IN UINT32 Attributes,\r
994 IN UINTN DataSize,\r
995 IN VOID *Data\r
996 )\r
997{\r
998 EFI_STATUS Status;\r
999 EDKII_SET_VARIABLE_STATUS *SetVariableStatus;\r
1000 UINTN NameSize;\r
1001\r
1002 Status = gRT->SetVariable (\r
1003 VariableName,\r
1004 VendorGuid,\r
1005 Attributes,\r
1006 DataSize,\r
1007 Data\r
1008 );\r
1009 if (EFI_ERROR (Status)) {\r
1010 NameSize = StrSize (VariableName);\r
1011 SetVariableStatus = AllocatePool (sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + DataSize);\r
1012 if (SetVariableStatus != NULL) {\r
1013 CopyGuid (&SetVariableStatus->Guid, VendorGuid);\r
1014 SetVariableStatus->NameSize = NameSize;\r
1015 SetVariableStatus->DataSize = DataSize;\r
1016 SetVariableStatus->SetStatus = Status;\r
1017 SetVariableStatus->Attributes = Attributes;\r
1018 CopyMem (SetVariableStatus + 1, VariableName, NameSize);\r
1019 CopyMem (((UINT8 *) (SetVariableStatus + 1)) + NameSize, Data, DataSize);\r
1020\r
1021 REPORT_STATUS_CODE_EX (\r
1022 EFI_ERROR_CODE,\r
1023 PcdGet32 (PcdErrorCodeSetVariable),\r
1024 0,\r
1025 NULL,\r
1026 &gEdkiiStatusCodeDataTypeVariableGuid,\r
1027 SetVariableStatus,\r
1028 sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + DataSize\r
1029 );\r
1030\r
1031 FreePool (SetVariableStatus);\r
1032 }\r
1033 }\r
1034\r
1035 return Status;\r
1036}\r