]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/BdsDxe/BdsEntry.c
MdeModulePkg BdsDxe: Change file format which the existed folder 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
311b5a6f
ED
310 // If the boot via Boot#### returns with a status of EFI_SUCCESS, platform firmware\r
311 // supports boot manager menu, and if firmware is configured to boot in an\r
312 // interactive mode, the boot manager will stop processing the BootOrder variable and\r
313 // present a boot manager menu to the user.\r
f4cd24da
RN
314 //\r
315 if (BootOptions[Index].Status == EFI_SUCCESS) {\r
68456d8a 316 EfiBootManagerBoot (BootManagerMenu);\r
f4cd24da
RN
317 break;\r
318 }\r
319 }\r
320\r
321 return (BOOLEAN) (Index < BootOptionCount);\r
322}\r
323\r
324/**\r
68456d8a 325 The function will load and start every Driver####, SysPrep#### or PlatformRecovery####.\r
f4cd24da 326\r
1634214d
RN
327 @param LoadOptions Load option array.\r
328 @param LoadOptionCount Load option count.\r
f4cd24da
RN
329**/\r
330VOID\r
1634214d
RN
331ProcessLoadOptions (\r
332 IN EFI_BOOT_MANAGER_LOAD_OPTION *LoadOptions,\r
333 IN UINTN LoadOptionCount\r
f4cd24da
RN
334 )\r
335{\r
1634214d
RN
336 EFI_STATUS Status;\r
337 UINTN Index;\r
338 BOOLEAN ReconnectAll;\r
339 EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType;\r
f4cd24da 340\r
68456d8a 341 ReconnectAll = FALSE;\r
1634214d 342 LoadOptionType = LoadOptionTypeMax;\r
f4cd24da
RN
343\r
344 //\r
345 // Process the driver option\r
346 //\r
1634214d 347 for (Index = 0; Index < LoadOptionCount; Index++) {\r
f4cd24da 348 //\r
1634214d 349 // All the load options in the array should be of the same type.\r
f4cd24da 350 //\r
68456d8a 351 if (Index == 0) {\r
1634214d 352 LoadOptionType = LoadOptions[Index].OptionType;\r
f4cd24da 353 }\r
1634214d 354 ASSERT (LoadOptionType == LoadOptions[Index].OptionType);\r
f4cd24da 355\r
1634214d 356 Status = EfiBootManagerProcessLoadOption (&LoadOptions[Index]);\r
f4cd24da 357\r
68456d8a
RN
358 if (!EFI_ERROR (Status)) {\r
359 if (LoadOptionType == LoadOptionTypePlatformRecovery) {\r
360 //\r
361 // Stop processing if any entry is successful\r
362 //\r
363 break;\r
364 }\r
365 if ((LoadOptions[Index].Attributes & LOAD_OPTION_FORCE_RECONNECT) != 0) {\r
366 ReconnectAll = TRUE;\r
367 }\r
f4cd24da
RN
368 }\r
369 }\r
1634214d 370\r
f4cd24da 371 //\r
1634214d
RN
372 // If a driver load option is marked as LOAD_OPTION_FORCE_RECONNECT,\r
373 // then all of the EFI drivers in the system will be disconnected and\r
374 // reconnected after the last driver load option is processed.\r
f4cd24da 375 //\r
1634214d 376 if (ReconnectAll && LoadOptionType == LoadOptionTypeDriver) {\r
f4cd24da
RN
377 EfiBootManagerDisconnectAll ();\r
378 EfiBootManagerConnectAll ();\r
379 }\r
f4cd24da
RN
380}\r
381\r
382/**\r
383\r
384 Validate input console variable data. \r
385\r
386 If found the device path is not a valid device path, remove the variable.\r
387 \r
388 @param VariableName Input console variable name.\r
389\r
390**/\r
391VOID\r
392BdsFormalizeConsoleVariable (\r
393 IN CHAR16 *VariableName\r
394 )\r
395{\r
396 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
397 UINTN VariableSize;\r
398 EFI_STATUS Status;\r
399\r
400 GetEfiGlobalVariable2 (VariableName, (VOID **) &DevicePath, &VariableSize);\r
401 if ((DevicePath != NULL) && !IsDevicePathValid (DevicePath, VariableSize)) { \r
402 Status = gRT->SetVariable (\r
403 VariableName,\r
404 &gEfiGlobalVariableGuid,\r
405 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
406 0,\r
407 NULL\r
408 );\r
409 //\r
410 // Deleting variable with current variable implementation shouldn't fail.\r
411 //\r
412 ASSERT_EFI_ERROR (Status);\r
413 }\r
414\r
415 if (DevicePath != NULL) {\r
416 FreePool (DevicePath);\r
417 }\r
418}\r
419\r
420/**\r
421 Formalize OsIndication related variables. \r
422 \r
423 For OsIndicationsSupported, Create a BS/RT/UINT64 variable to report caps \r
424 Delete OsIndications variable if it is not NV/BS/RT UINT64.\r
425 \r
426 Item 3 is used to solve case when OS corrupts OsIndications. Here simply delete this NV variable.\r
427\r
428**/\r
429VOID \r
430BdsFormalizeOSIndicationVariable (\r
431 VOID\r
432 )\r
433{\r
434 EFI_STATUS Status;\r
435 UINT64 OsIndicationSupport;\r
436 UINT64 OsIndication;\r
437 UINTN DataSize;\r
438 UINT32 Attributes;\r
439\r
440 //\r
441 // OS indicater support variable\r
442 //\r
68456d8a 443 OsIndicationSupport = EFI_OS_INDICATIONS_BOOT_TO_FW_UI | EFI_OS_INDICATIONS_START_PLATFORM_RECOVERY;\r
f4cd24da 444 Status = gRT->SetVariable (\r
cc4812f6 445 EFI_OS_INDICATIONS_SUPPORT_VARIABLE_NAME,\r
f4cd24da
RN
446 &gEfiGlobalVariableGuid,\r
447 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
448 sizeof(UINT64),\r
449 &OsIndicationSupport\r
450 );\r
451 //\r
452 // Platform needs to make sure setting volatile variable before calling 3rd party code shouldn't fail.\r
453 //\r
454 ASSERT_EFI_ERROR (Status);\r
455\r
456 //\r
457 // If OsIndications is invalid, remove it.\r
458 // Invalid case\r
459 // 1. Data size != UINT64\r
460 // 2. OsIndication value inconsistence\r
461 // 3. OsIndication attribute inconsistence\r
462 //\r
463 OsIndication = 0;\r
464 Attributes = 0;\r
465 DataSize = sizeof(UINT64);\r
466 Status = gRT->GetVariable (\r
cc4812f6 467 EFI_OS_INDICATIONS_VARIABLE_NAME,\r
f4cd24da
RN
468 &gEfiGlobalVariableGuid,\r
469 &Attributes,\r
470 &DataSize,\r
471 &OsIndication\r
472 );\r
473 if (Status == EFI_NOT_FOUND) {\r
474 return;\r
475 }\r
476\r
477 if ((DataSize != sizeof (OsIndication)) ||\r
478 ((OsIndication & ~OsIndicationSupport) != 0) ||\r
479 (Attributes != (EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE))\r
480 ){\r
481\r
482 DEBUG ((EFI_D_ERROR, "[Bds] Unformalized OsIndications variable exists. Delete it\n"));\r
483 Status = gRT->SetVariable (\r
cc4812f6 484 EFI_OS_INDICATIONS_VARIABLE_NAME,\r
f4cd24da
RN
485 &gEfiGlobalVariableGuid,\r
486 0,\r
487 0,\r
488 NULL\r
489 );\r
490 //\r
491 // Deleting variable with current variable implementation shouldn't fail.\r
492 //\r
493 ASSERT_EFI_ERROR(Status);\r
494 }\r
495}\r
496\r
497/**\r
498\r
499 Validate variables. \r
500\r
501**/\r
502VOID \r
503BdsFormalizeEfiGlobalVariable (\r
504 VOID\r
505 )\r
506{\r
507 //\r
508 // Validate Console variable.\r
509 //\r
cc4812f6
RN
510 BdsFormalizeConsoleVariable (EFI_CON_IN_VARIABLE_NAME);\r
511 BdsFormalizeConsoleVariable (EFI_CON_OUT_VARIABLE_NAME);\r
512 BdsFormalizeConsoleVariable (EFI_ERR_OUT_VARIABLE_NAME);\r
f4cd24da
RN
513\r
514 //\r
515 // Validate OSIndication related variable.\r
516 //\r
517 BdsFormalizeOSIndicationVariable ();\r
518}\r
519\r
520/**\r
521\r
522 Allocate a block of memory that will contain performance data to OS.\r
523\r
524**/\r
525VOID\r
526BdsAllocateMemoryForPerformanceData (\r
527 VOID\r
528 )\r
529{\r
530 EFI_STATUS Status;\r
531 EFI_PHYSICAL_ADDRESS AcpiLowMemoryBase;\r
532 EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;\r
533\r
534 AcpiLowMemoryBase = 0x0FFFFFFFFULL;\r
535\r
536 //\r
537 // Allocate a block of memory that will contain performance data to OS.\r
538 //\r
539 Status = gBS->AllocatePages (\r
540 AllocateMaxAddress,\r
541 EfiReservedMemoryType,\r
542 EFI_SIZE_TO_PAGES (PERF_DATA_MAX_LENGTH),\r
543 &AcpiLowMemoryBase\r
544 );\r
545 if (!EFI_ERROR (Status)) {\r
546 //\r
547 // Save the pointer to variable for use in S3 resume.\r
548 //\r
549 Status = BdsDxeSetVariableAndReportStatusCodeOnError (\r
550 L"PerfDataMemAddr",\r
551 &gPerformanceProtocolGuid,\r
552 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
553 sizeof (EFI_PHYSICAL_ADDRESS),\r
554 &AcpiLowMemoryBase\r
555 );\r
556 if (EFI_ERROR (Status)) {\r
557 DEBUG ((EFI_D_ERROR, "[Bds] PerfDataMemAddr (%08x) cannot be saved to NV storage.\n", AcpiLowMemoryBase));\r
558 }\r
559 //\r
560 // Mark L"PerfDataMemAddr" variable to read-only if the Variable Lock protocol exists\r
561 // Still lock it even the variable cannot be saved to prevent it's set by 3rd party code.\r
562 //\r
563 Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock);\r
564 if (!EFI_ERROR (Status)) {\r
565 Status = VariableLock->RequestToLock (VariableLock, L"PerfDataMemAddr", &gPerformanceProtocolGuid);\r
566 ASSERT_EFI_ERROR (Status);\r
567 }\r
568 }\r
569}\r
570\r
571/**\r
572\r
573 Service routine for BdsInstance->Entry(). Devices are connected, the\r
574 consoles are initialized, and the boot options are tried.\r
575\r
576 @param This Protocol Instance structure.\r
577\r
578**/\r
579VOID\r
580EFIAPI\r
581BdsEntry (\r
582 IN EFI_BDS_ARCH_PROTOCOL *This\r
583 )\r
584{\r
1634214d
RN
585 EFI_BOOT_MANAGER_LOAD_OPTION *LoadOptions;\r
586 UINTN LoadOptionCount;\r
f4cd24da
RN
587 CHAR16 *FirmwareVendor;\r
588 EFI_EVENT HotkeyTriggered;\r
589 UINT64 OsIndication;\r
590 UINTN DataSize;\r
591 EFI_STATUS Status;\r
592 UINT32 BootOptionSupport;\r
593 UINT16 BootTimeOut;\r
594 EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;\r
595 UINTN Index;\r
d175f4e6 596 EFI_BOOT_MANAGER_LOAD_OPTION LoadOption;\r
f4cd24da
RN
597 UINT16 *BootNext;\r
598 CHAR16 BootNextVariableName[sizeof ("Boot####")];\r
1634214d
RN
599 EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu;\r
600 BOOLEAN BootFwUi;\r
68456d8a
RN
601 BOOLEAN PlatformRecovery;\r
602 BOOLEAN BootSuccess;\r
d175f4e6 603 EFI_DEVICE_PATH_PROTOCOL *FilePath;\r
f4cd24da
RN
604\r
605 HotkeyTriggered = NULL;\r
606 Status = EFI_SUCCESS;\r
68456d8a 607 BootSuccess = FALSE;\r
f4cd24da
RN
608\r
609 //\r
610 // Insert the performance probe\r
611 //\r
612 PERF_END (NULL, "DXE", NULL, 0);\r
613 PERF_START (NULL, "BDS", NULL, 0);\r
614 DEBUG ((EFI_D_INFO, "[Bds] Entry...\n"));\r
615\r
616 PERF_CODE (\r
617 BdsAllocateMemoryForPerformanceData ();\r
618 );\r
619\r
620 //\r
621 // Fill in FirmwareVendor and FirmwareRevision from PCDs\r
622 //\r
623 FirmwareVendor = (CHAR16 *) PcdGetPtr (PcdFirmwareVendor);\r
624 gST->FirmwareVendor = AllocateRuntimeCopyPool (StrSize (FirmwareVendor), FirmwareVendor);\r
625 ASSERT (gST->FirmwareVendor != NULL);\r
626 gST->FirmwareRevision = PcdGet32 (PcdFirmwareRevision);\r
627\r
628 //\r
629 // Fixup Tasble CRC after we updated Firmware Vendor and Revision\r
630 //\r
631 gST->Hdr.CRC32 = 0;\r
632 gBS->CalculateCrc32 ((VOID *) gST, sizeof (EFI_SYSTEM_TABLE), &gST->Hdr.CRC32);\r
633\r
634 //\r
635 // Validate Variable.\r
636 //\r
637 BdsFormalizeEfiGlobalVariable ();\r
638\r
639 //\r
640 // Mark the read-only variables if the Variable Lock protocol exists\r
641 //\r
642 Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock);\r
643 DEBUG ((EFI_D_INFO, "[BdsDxe] Locate Variable Lock protocol - %r\n", Status));\r
644 if (!EFI_ERROR (Status)) {\r
645 for (Index = 0; Index < sizeof (mReadOnlyVariables) / sizeof (mReadOnlyVariables[0]); Index++) {\r
646 Status = VariableLock->RequestToLock (VariableLock, mReadOnlyVariables[Index], &gEfiGlobalVariableGuid);\r
647 ASSERT_EFI_ERROR (Status);\r
648 }\r
649 }\r
650\r
651 InitializeHwErrRecSupport ();\r
652\r
653 //\r
654 // Initialize L"Timeout" EFI global variable.\r
655 //\r
656 BootTimeOut = PcdGet16 (PcdPlatformBootTimeOut);\r
657 if (BootTimeOut != 0xFFFF) {\r
658 //\r
659 // If time out value equal 0xFFFF, no need set to 0xFFFF to variable area because UEFI specification\r
660 // define same behavior between no value or 0xFFFF value for L"Timeout".\r
661 //\r
662 BdsDxeSetVariableAndReportStatusCodeOnError (\r
663 EFI_TIME_OUT_VARIABLE_NAME,\r
664 &gEfiGlobalVariableGuid,\r
665 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
666 sizeof (UINT16),\r
667 &BootTimeOut\r
668 );\r
669 }\r
670\r
671 //\r
672 // Initialize L"BootOptionSupport" EFI global variable.\r
673 // Lazy-ConIn implictly disables BDS hotkey.\r
674 //\r
1634214d 675 BootOptionSupport = EFI_BOOT_OPTION_SUPPORT_APP | EFI_BOOT_OPTION_SUPPORT_SYSPREP;\r
f4cd24da
RN
676 if (!PcdGetBool (PcdConInConnectOnDemand)) {\r
677 BootOptionSupport |= EFI_BOOT_OPTION_SUPPORT_KEY;\r
678 SET_BOOT_OPTION_SUPPORT_KEY_COUNT (BootOptionSupport, 3);\r
679 }\r
680 Status = gRT->SetVariable (\r
681 EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME,\r
682 &gEfiGlobalVariableGuid,\r
683 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
684 sizeof (BootOptionSupport),\r
685 &BootOptionSupport\r
686 );\r
687 //\r
688 // Platform needs to make sure setting volatile variable before calling 3rd party code shouldn't fail.\r
689 //\r
690 ASSERT_EFI_ERROR (Status);\r
691\r
692 //\r
693 // Cache and remove the "BootNext" NV variable.\r
694 //\r
695 GetEfiGlobalVariable2 (EFI_BOOT_NEXT_VARIABLE_NAME, (VOID **) &BootNext, &DataSize);\r
696 if (DataSize != sizeof (UINT16)) {\r
697 if (BootNext != NULL) {\r
698 FreePool (BootNext);\r
699 }\r
700 BootNext = NULL;\r
701 }\r
702 Status = gRT->SetVariable (\r
703 EFI_BOOT_NEXT_VARIABLE_NAME,\r
704 &gEfiGlobalVariableGuid,\r
705 0,\r
706 0,\r
707 NULL\r
708 );\r
709 //\r
710 // Deleting NV variable shouldn't fail unless it doesn't exist.\r
711 //\r
712 ASSERT (Status == EFI_SUCCESS || Status == EFI_NOT_FOUND);\r
713\r
714 //\r
715 // Initialize the platform language variables\r
716 //\r
717 InitializeLanguage (TRUE);\r
718\r
d175f4e6
RN
719 //\r
720 // System firmware must include a PlatformRecovery#### variable specifying\r
721 // a short-form File Path Media Device Path containing the platform default\r
722 // file path for removable media\r
723 //\r
724 FilePath = FileDevicePath (NULL, EFI_REMOVABLE_MEDIA_FILE_NAME);\r
725 Status = EfiBootManagerInitializeLoadOption (\r
726 &LoadOption,\r
727 0,\r
728 LoadOptionTypePlatformRecovery,\r
729 LOAD_OPTION_ACTIVE,\r
730 L"Default PlatformRecovery",\r
731 FilePath,\r
732 NULL,\r
733 0\r
734 );\r
735 ASSERT_EFI_ERROR (Status);\r
736 EfiBootManagerLoadOptionToVariable (&LoadOption);\r
737 EfiBootManagerFreeLoadOption (&LoadOption);\r
738 FreePool (FilePath);\r
739\r
f4cd24da
RN
740 //\r
741 // Report Status Code to indicate connecting drivers will happen\r
742 //\r
743 REPORT_STATUS_CODE (\r
744 EFI_PROGRESS_CODE,\r
745 (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_BEGIN_CONNECTING_DRIVERS)\r
746 );\r
747\r
748 //\r
749 // Do the platform init, can be customized by OEM/IBV\r
750 // Possible things that can be done in PlatformBootManagerBeforeConsole:\r
751 // > Update console variable: 1. include hot-plug devices; 2. Clear ConIn and add SOL for AMT\r
752 // > Register new Driver#### or Boot####\r
753 // > Register new Key####: e.g.: F12 \r
754 // > Signal ReadyToLock event\r
755 // > Authentication action: 1. connect Auth devices; 2. Identify auto logon user.\r
756 //\r
757 PERF_START (NULL, "PlatformBootManagerBeforeConsole", "BDS", 0);\r
758 PlatformBootManagerBeforeConsole ();\r
759 PERF_END (NULL, "PlatformBootManagerBeforeConsole", "BDS", 0);\r
760\r
761 //\r
762 // Initialize hotkey service\r
763 //\r
764 EfiBootManagerStartHotkeyService (&HotkeyTriggered);\r
765\r
766 //\r
1634214d 767 // Execute Driver Options\r
f4cd24da 768 //\r
1634214d
RN
769 LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypeDriver);\r
770 ProcessLoadOptions (LoadOptions, LoadOptionCount);\r
771 EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);\r
f4cd24da
RN
772\r
773 //\r
774 // Connect consoles\r
775 //\r
776 PERF_START (NULL, "EfiBootManagerConnectAllDefaultConsoles", "BDS", 0);\r
777 if (PcdGetBool (PcdConInConnectOnDemand)) {\r
778 EfiBootManagerConnectConsoleVariable (ConOut);\r
779 EfiBootManagerConnectConsoleVariable (ErrOut);\r
780\r
781 //\r
782 // Initialize ConnectConIn event\r
783 //\r
784 Status = gBS->CreateEventEx (\r
785 EVT_NOTIFY_SIGNAL,\r
786 TPL_CALLBACK,\r
787 BdsDxeOnConnectConInCallBack,\r
788 NULL,\r
789 &gConnectConInEventGuid,\r
790 &gConnectConInEvent\r
791 );\r
792 if (EFI_ERROR (Status)) {\r
793 gConnectConInEvent = NULL;\r
794 }\r
795 } else {\r
796 EfiBootManagerConnectAllDefaultConsoles ();\r
797 }\r
798 PERF_END (NULL, "EfiBootManagerConnectAllDefaultConsoles", "BDS", 0);\r
799\r
800 //\r
801 // Do the platform specific action after the console is ready\r
802 // Possible things that can be done in PlatformBootManagerAfterConsole:\r
803 // > Console post action:\r
804 // > Dynamically switch output mode from 100x31 to 80x25 for certain senarino\r
805 // > Signal console ready platform customized event\r
806 // > Run diagnostics like memory testing\r
807 // > Connect certain devices\r
808 // > Dispatch aditional option roms\r
809 // > Special boot: e.g.: USB boot, enter UI\r
810 // \r
811 PERF_START (NULL, "PlatformBootManagerAfterConsole", "BDS", 0);\r
812 PlatformBootManagerAfterConsole ();\r
813 PERF_END (NULL, "PlatformBootManagerAfterConsole", "BDS", 0);\r
68456d8a
RN
814 //\r
815 // Boot to Boot Manager Menu when EFI_OS_INDICATIONS_BOOT_TO_FW_UI is set. Skip HotkeyBoot\r
816 //\r
817 DataSize = sizeof (UINT64);\r
818 Status = gRT->GetVariable (\r
819 EFI_OS_INDICATIONS_VARIABLE_NAME,\r
820 &gEfiGlobalVariableGuid,\r
821 NULL,\r
822 &DataSize,\r
823 &OsIndication\r
824 );\r
825 if (EFI_ERROR (Status)) {\r
826 OsIndication = 0;\r
827 }\r
f4cd24da
RN
828\r
829 DEBUG_CODE (\r
1634214d 830 EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType;\r
68456d8a 831 DEBUG ((EFI_D_INFO, "[Bds]OsIndication: %016x\n", OsIndication));\r
1634214d
RN
832 DEBUG ((EFI_D_INFO, "[Bds]=============Begin Load Options Dumping ...=============\n"));\r
833 for (LoadOptionType = 0; LoadOptionType < LoadOptionTypeMax; LoadOptionType++) {\r
f4cd24da 834 DEBUG ((\r
1634214d
RN
835 EFI_D_INFO, " %s Options:\n",\r
836 mBdsLoadOptionName[LoadOptionType]\r
f4cd24da 837 ));\r
1634214d
RN
838 LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionType);\r
839 for (Index = 0; Index < LoadOptionCount; Index++) {\r
840 DEBUG ((\r
841 EFI_D_INFO, " %s%04x: %s \t\t 0x%04x\n",\r
842 mBdsLoadOptionName[LoadOptionType],\r
843 LoadOptions[Index].OptionNumber,\r
844 LoadOptions[Index].Description,\r
845 LoadOptions[Index].Attributes\r
846 ));\r
847 }\r
848 EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);\r
f4cd24da 849 }\r
1634214d
RN
850 DEBUG ((EFI_D_INFO, "[Bds]=============End Load Options Dumping=============\n"));\r
851 );\r
f4cd24da
RN
852\r
853 //\r
68456d8a 854 // BootManagerMenu always contains the correct information even call fails.\r
f4cd24da 855 //\r
68456d8a 856 EfiBootManagerGetBootManagerMenu (&BootManagerMenu);\r
1634214d 857\r
68456d8a
RN
858 BootFwUi = (BOOLEAN) ((OsIndication & EFI_OS_INDICATIONS_BOOT_TO_FW_UI) != 0);\r
859 PlatformRecovery = (BOOLEAN) ((OsIndication & EFI_OS_INDICATIONS_START_PLATFORM_RECOVERY) != 0);\r
1634214d
RN
860 //\r
861 // Clear EFI_OS_INDICATIONS_BOOT_TO_FW_UI to acknowledge OS\r
862 // \r
68456d8a
RN
863 if (BootFwUi || PlatformRecovery) {\r
864 OsIndication &= ~((UINT64) (EFI_OS_INDICATIONS_BOOT_TO_FW_UI | EFI_OS_INDICATIONS_START_PLATFORM_RECOVERY));\r
f4cd24da 865 Status = gRT->SetVariable (\r
cc4812f6 866 EFI_OS_INDICATIONS_VARIABLE_NAME,\r
f4cd24da
RN
867 &gEfiGlobalVariableGuid,\r
868 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
869 sizeof(UINT64),\r
870 &OsIndication\r
871 );\r
872 //\r
873 // Changing the content without increasing its size with current variable implementation shouldn't fail.\r
874 //\r
875 ASSERT_EFI_ERROR (Status);\r
1634214d 876 }\r
f4cd24da 877\r
1634214d
RN
878 //\r
879 // Launch Boot Manager Menu directly when EFI_OS_INDICATIONS_BOOT_TO_FW_UI is set. Skip HotkeyBoot\r
880 //\r
881 if (BootFwUi) {\r
f4cd24da
RN
882 //\r
883 // Follow generic rule, Call BdsDxeOnConnectConInCallBack to connect ConIn before enter UI\r
884 //\r
885 if (PcdGetBool (PcdConInConnectOnDemand)) {\r
886 BdsDxeOnConnectConInCallBack (NULL, NULL);\r
887 }\r
888\r
889 //\r
1634214d 890 // Directly enter the setup page.\r
f4cd24da 891 //\r
1634214d 892 EfiBootManagerBoot (&BootManagerMenu);\r
f4cd24da
RN
893 }\r
894\r
68456d8a
RN
895 if (!PlatformRecovery) {\r
896 //\r
897 // Execute SysPrep####\r
898 //\r
899 LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypeSysPrep);\r
900 ProcessLoadOptions (LoadOptions, LoadOptionCount);\r
901 EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);\r
1634214d 902\r
68456d8a
RN
903 //\r
904 // Execute Key####\r
905 //\r
906 PERF_START (NULL, "BdsWait", "BDS", 0);\r
907 BdsWait (HotkeyTriggered);\r
908 PERF_END (NULL, "BdsWait", "BDS", 0);\r
1634214d 909\r
68456d8a
RN
910 //\r
911 // BdsReadKeys() can be removed after all keyboard drivers invoke callback in timer callback.\r
912 //\r
913 BdsReadKeys ();\r
1634214d 914\r
68456d8a 915 EfiBootManagerHotkeyBoot ();\r
1634214d 916\r
68456d8a
RN
917 //\r
918 // Boot to "BootNext"\r
919 //\r
920 if (BootNext != NULL) {\r
921 UnicodeSPrint (BootNextVariableName, sizeof (BootNextVariableName), L"Boot%04x", *BootNext);\r
922 Status = EfiBootManagerVariableToLoadOption (BootNextVariableName, &LoadOption);\r
923 if (!EFI_ERROR (Status)) {\r
d175f4e6
RN
924 EfiBootManagerBoot (&LoadOption);\r
925 EfiBootManagerFreeLoadOption (&LoadOption);\r
68456d8a
RN
926 if (LoadOption.Status == EFI_SUCCESS) {\r
927 //\r
928 // Boot to Boot Manager Menu upon EFI_SUCCESS\r
929 //\r
930 EfiBootManagerBoot (&BootManagerMenu);\r
931 }\r
f4cd24da
RN
932 }\r
933 }\r
68456d8a
RN
934\r
935 do {\r
936 //\r
937 // Retry to boot if any of the boot succeeds\r
938 //\r
939 LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypeBoot);\r
940 BootSuccess = BootBootOptions (LoadOptions, LoadOptionCount, &BootManagerMenu);\r
941 EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);\r
942 } while (BootSuccess);\r
f4cd24da
RN
943 }\r
944\r
68456d8a
RN
945 EfiBootManagerFreeLoadOption (&BootManagerMenu);\r
946\r
947 if (!BootSuccess) {\r
948 LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypePlatformRecovery);\r
949 ProcessLoadOptions (LoadOptions, LoadOptionCount);\r
950 EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);\r
f4cd24da 951 }\r
68456d8a
RN
952\r
953 DEBUG ((EFI_D_ERROR, "[Bds] Unable to boot!\n"));\r
954 CpuDeadLoop ();\r
f4cd24da
RN
955}\r
956\r
957/**\r
958 Set the variable and report the error through status code upon failure.\r
959\r
960 @param VariableName A Null-terminated string that is the name of the vendor's variable.\r
961 Each VariableName is unique for each VendorGuid. VariableName must\r
962 contain 1 or more characters. If VariableName is an empty string,\r
963 then EFI_INVALID_PARAMETER is returned.\r
964 @param VendorGuid A unique identifier for the vendor.\r
965 @param Attributes Attributes bitmask to set for the variable.\r
966 @param DataSize The size in bytes of the Data buffer. Unless the EFI_VARIABLE_APPEND_WRITE, \r
967 EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, or \r
968 EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute is set, a size of zero \r
969 causes the variable to be deleted. When the EFI_VARIABLE_APPEND_WRITE attribute is \r
970 set, then a SetVariable() call with a DataSize of zero will not cause any change to \r
971 the variable value (the timestamp associated with the variable may be updated however \r
972 even if no new data value is provided,see the description of the \r
973 EFI_VARIABLE_AUTHENTICATION_2 descriptor below. In this case the DataSize will not \r
974 be zero since the EFI_VARIABLE_AUTHENTICATION_2 descriptor will be populated). \r
975 @param Data The contents for the variable.\r
976\r
977 @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as\r
978 defined by the Attributes.\r
979 @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits, name, and GUID was supplied, or the\r
980 DataSize exceeds the maximum allowed.\r
981 @retval EFI_INVALID_PARAMETER VariableName is an empty string.\r
982 @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data.\r
983 @retval EFI_DEVICE_ERROR The variable could not be retrieved due to a hardware error.\r
984 @retval EFI_WRITE_PROTECTED The variable in question is read-only.\r
985 @retval EFI_WRITE_PROTECTED The variable in question cannot be deleted.\r
986 @retval EFI_SECURITY_VIOLATION The variable could not be written due to EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS \r
987 or EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACESS being set, but the AuthInfo \r
988 does NOT pass the validation check carried out by the firmware.\r
989\r
990 @retval EFI_NOT_FOUND The variable trying to be updated or deleted was not found.\r
991**/\r
992EFI_STATUS\r
993BdsDxeSetVariableAndReportStatusCodeOnError (\r
994 IN CHAR16 *VariableName,\r
995 IN EFI_GUID *VendorGuid,\r
996 IN UINT32 Attributes,\r
997 IN UINTN DataSize,\r
998 IN VOID *Data\r
999 )\r
1000{\r
1001 EFI_STATUS Status;\r
1002 EDKII_SET_VARIABLE_STATUS *SetVariableStatus;\r
1003 UINTN NameSize;\r
1004\r
1005 Status = gRT->SetVariable (\r
1006 VariableName,\r
1007 VendorGuid,\r
1008 Attributes,\r
1009 DataSize,\r
1010 Data\r
1011 );\r
1012 if (EFI_ERROR (Status)) {\r
1013 NameSize = StrSize (VariableName);\r
1014 SetVariableStatus = AllocatePool (sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + DataSize);\r
1015 if (SetVariableStatus != NULL) {\r
1016 CopyGuid (&SetVariableStatus->Guid, VendorGuid);\r
1017 SetVariableStatus->NameSize = NameSize;\r
1018 SetVariableStatus->DataSize = DataSize;\r
1019 SetVariableStatus->SetStatus = Status;\r
1020 SetVariableStatus->Attributes = Attributes;\r
1021 CopyMem (SetVariableStatus + 1, VariableName, NameSize);\r
1022 CopyMem (((UINT8 *) (SetVariableStatus + 1)) + NameSize, Data, DataSize);\r
1023\r
1024 REPORT_STATUS_CODE_EX (\r
1025 EFI_ERROR_CODE,\r
1026 PcdGet32 (PcdErrorCodeSetVariable),\r
1027 0,\r
1028 NULL,\r
1029 &gEdkiiStatusCodeDataTypeVariableGuid,\r
1030 SetVariableStatus,\r
1031 sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + DataSize\r
1032 );\r
1033\r
1034 FreePool (SetVariableStatus);\r
1035 }\r
1036 }\r
1037\r
1038 return Status;\r
1039}\r