]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/BdsDxe/BdsEntry.c
MdeModulePkg: Add PlatformRecovery#### pointing to default file path
[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
54 L"Boot"\r
55};\r
56\r
f4cd24da
RN
57CHAR16 mRecoveryBoot[] = L"Recovery Boot";\r
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
124/**\r
125 Emuerate all possible bootable medias in the following order:\r
126 1. Removable BlockIo - The boot option only points to the removable media\r
127 device, like USB key, DVD, Floppy etc.\r
128 2. Fixed BlockIo - The boot option only points to a Fixed blockIo device,\r
129 like HardDisk.\r
130 3. Non-BlockIo SimpleFileSystem - The boot option points to a device supporting\r
131 SimpleFileSystem Protocol, but not supporting BlockIo\r
132 protocol.\r
133 4. LoadFile - The boot option points to the media supporting \r
134 LoadFile protocol.\r
135 Reference: UEFI Spec chapter 3.3 Boot Option Variables Default Boot Behavior\r
136\r
137 @param BootOptionCount Return the boot option count which has been found.\r
138\r
139 @retval Pointer to the boot option array.\r
140**/\r
141EFI_BOOT_MANAGER_LOAD_OPTION *\r
142BdsEnumerateBootOptions (\r
143 UINTN *BootOptionCount\r
144 )\r
145{\r
146 EFI_STATUS Status;\r
147 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;\r
f4cd24da
RN
148 UINTN HandleCount;\r
149 EFI_HANDLE *Handles;\r
150 EFI_BLOCK_IO_PROTOCOL *BlkIo;\r
151 UINTN Removable;\r
152 UINTN Index;\r
153\r
154 ASSERT (BootOptionCount != NULL);\r
155\r
156 *BootOptionCount = 0;\r
157 BootOptions = NULL;\r
158\r
159 //\r
160 // Parse removable block io followed by fixed block io\r
161 //\r
162 gBS->LocateHandleBuffer (\r
163 ByProtocol,\r
164 &gEfiBlockIoProtocolGuid,\r
165 NULL,\r
166 &HandleCount,\r
167 &Handles\r
168 );\r
169\r
170 for (Removable = 0; Removable < 2; Removable++) {\r
171 for (Index = 0; Index < HandleCount; Index++) {\r
172 Status = gBS->HandleProtocol (\r
173 Handles[Index],\r
174 &gEfiBlockIoProtocolGuid,\r
175 (VOID **) &BlkIo\r
176 );\r
177 if (EFI_ERROR (Status)) {\r
178 continue;\r
179 }\r
180\r
181 //\r
182 // Skip the logical partitions\r
183 //\r
184 if (BlkIo->Media->LogicalPartition) {\r
185 continue;\r
186 }\r
187\r
188 //\r
189 // Skip the fixed block io then the removable block io\r
190 //\r
191 if (BlkIo->Media->RemovableMedia == ((Removable == 0) ? FALSE : TRUE)) {\r
192 continue;\r
193 }\r
194\r
195 BootOptions = ReallocatePool (\r
196 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),\r
197 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),\r
198 BootOptions\r
199 );\r
200 ASSERT (BootOptions != NULL);\r
201\r
202 Status = EfiBootManagerInitializeLoadOption (\r
203 &BootOptions[(*BootOptionCount)++],\r
204 LoadOptionNumberUnassigned,\r
205 LoadOptionTypeBoot,\r
206 LOAD_OPTION_ACTIVE,\r
207 mRecoveryBoot,\r
208 DevicePathFromHandle (Handles[Index]),\r
209 NULL,\r
210 0\r
211 );\r
212 ASSERT_EFI_ERROR (Status);\r
213 }\r
214 }\r
215\r
216 if (HandleCount != 0) {\r
217 FreePool (Handles);\r
218 }\r
219\r
220 //\r
221 // Parse simple file system not based on block io\r
222 //\r
f4cd24da
RN
223 gBS->LocateHandleBuffer (\r
224 ByProtocol,\r
225 &gEfiSimpleFileSystemProtocolGuid,\r
226 NULL,\r
227 &HandleCount,\r
228 &Handles\r
229 );\r
230 for (Index = 0; Index < HandleCount; Index++) {\r
231 Status = gBS->HandleProtocol (\r
232 Handles[Index],\r
233 &gEfiBlockIoProtocolGuid,\r
234 (VOID **) &BlkIo\r
235 );\r
236 if (!EFI_ERROR (Status)) {\r
237 //\r
238 // Skip if the file system handle supports a BlkIo protocol, which we've handled in above\r
239 //\r
240 continue;\r
241 }\r
242 BootOptions = ReallocatePool (\r
243 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),\r
244 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),\r
245 BootOptions\r
246 );\r
247 ASSERT (BootOptions != NULL);\r
248\r
249 Status = EfiBootManagerInitializeLoadOption (\r
250 &BootOptions[(*BootOptionCount)++],\r
251 LoadOptionNumberUnassigned,\r
252 LoadOptionTypeBoot,\r
253 LOAD_OPTION_ACTIVE,\r
254 mRecoveryBoot,\r
255 DevicePathFromHandle (Handles[Index]),\r
256 NULL,\r
257 0\r
258 );\r
259 ASSERT_EFI_ERROR (Status);\r
260 }\r
261\r
262 if (HandleCount != 0) {\r
263 FreePool (Handles);\r
264 }\r
265\r
266 //\r
267 // Parse load file, assuming UEFI Network boot option\r
268 //\r
269 gBS->LocateHandleBuffer (\r
270 ByProtocol,\r
271 &gEfiLoadFileProtocolGuid,\r
272 NULL,\r
273 &HandleCount,\r
274 &Handles\r
275 );\r
276 for (Index = 0; Index < HandleCount; Index++) {\r
277\r
278 BootOptions = ReallocatePool (\r
279 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),\r
280 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),\r
281 BootOptions\r
282 );\r
283 ASSERT (BootOptions != NULL);\r
284\r
285 Status = EfiBootManagerInitializeLoadOption (\r
286 &BootOptions[(*BootOptionCount)++],\r
287 LoadOptionNumberUnassigned,\r
288 LoadOptionTypeBoot,\r
289 LOAD_OPTION_ACTIVE,\r
290 mRecoveryBoot,\r
291 DevicePathFromHandle (Handles[Index]),\r
292 NULL,\r
293 0\r
294 );\r
295 ASSERT_EFI_ERROR (Status);\r
296 }\r
297\r
298 if (HandleCount != 0) {\r
299 FreePool (Handles);\r
300 }\r
301\r
302 return BootOptions;\r
303}\r
304\r
305/**\r
306 Function waits for a given event to fire, or for an optional timeout to expire.\r
307\r
308 @param Event The event to wait for\r
309 @param Timeout An optional timeout value in 100 ns units.\r
310\r
311 @retval EFI_SUCCESS Event fired before Timeout expired.\r
312 @retval EFI_TIME_OUT Timout expired before Event fired..\r
313\r
314**/\r
315EFI_STATUS\r
316BdsWaitForSingleEvent (\r
317 IN EFI_EVENT Event,\r
318 IN UINT64 Timeout OPTIONAL\r
319 )\r
320{\r
321 UINTN Index;\r
322 EFI_STATUS Status;\r
323 EFI_EVENT TimerEvent;\r
324 EFI_EVENT WaitList[2];\r
325\r
326 if (Timeout != 0) {\r
327 //\r
328 // Create a timer event\r
329 //\r
330 Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent);\r
331 if (!EFI_ERROR (Status)) {\r
332 //\r
333 // Set the timer event\r
334 //\r
335 gBS->SetTimer (\r
336 TimerEvent,\r
337 TimerRelative,\r
338 Timeout\r
339 );\r
340\r
341 //\r
342 // Wait for the original event or the timer\r
343 //\r
344 WaitList[0] = Event;\r
345 WaitList[1] = TimerEvent;\r
346 Status = gBS->WaitForEvent (2, WaitList, &Index);\r
347 ASSERT_EFI_ERROR (Status);\r
348 gBS->CloseEvent (TimerEvent);\r
349\r
350 //\r
351 // If the timer expired, change the return to timed out\r
352 //\r
353 if (Index == 1) {\r
354 Status = EFI_TIMEOUT;\r
355 }\r
356 }\r
357 } else {\r
358 //\r
359 // No timeout... just wait on the event\r
360 //\r
361 Status = gBS->WaitForEvent (1, &Event, &Index);\r
362 ASSERT (!EFI_ERROR (Status));\r
363 ASSERT (Index == 0);\r
364 }\r
365\r
366 return Status;\r
367}\r
368\r
369/**\r
370 The function reads user inputs.\r
371\r
372**/\r
373VOID\r
374BdsReadKeys (\r
375 VOID\r
376 )\r
377{\r
378 EFI_STATUS Status;\r
379 EFI_INPUT_KEY Key;\r
380\r
381 if (PcdGetBool (PcdConInConnectOnDemand)) {\r
382 return;\r
383 }\r
384\r
385 while (gST->ConIn != NULL) {\r
386 \r
387 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
388 \r
389 if (EFI_ERROR (Status)) {\r
390 //\r
391 // No more keys.\r
392 //\r
393 break;\r
394 }\r
395 }\r
396}\r
397\r
398/**\r
399 The function waits for the boot manager timeout expires or hotkey is pressed.\r
400\r
401 It calls PlatformBootManagerWaitCallback each second.\r
402\r
403 @param HotkeyTriggered Input hotkey event.\r
404**/\r
405VOID\r
406BdsWait (\r
407 IN EFI_EVENT HotkeyTriggered\r
408 )\r
409{\r
410 EFI_STATUS Status;\r
411 UINT16 TimeoutRemain;\r
412\r
413 DEBUG ((EFI_D_INFO, "[Bds]BdsWait ...Zzzzzzzzzzzz...\n"));\r
414\r
415 TimeoutRemain = PcdGet16 (PcdPlatformBootTimeOut);\r
416 while (TimeoutRemain != 0) {\r
417 DEBUG ((EFI_D_INFO, "[Bds]BdsWait(%d)..Zzzz...\n", (UINTN) TimeoutRemain));\r
418 PlatformBootManagerWaitCallback (TimeoutRemain);\r
419\r
420 BdsReadKeys (); // BUGBUG: Only reading can signal HotkeyTriggered\r
421 // Can be removed after all keyboard drivers invoke callback in timer callback.\r
422\r
423 if (HotkeyTriggered != NULL) {\r
424 Status = BdsWaitForSingleEvent (HotkeyTriggered, EFI_TIMER_PERIOD_SECONDS (1));\r
425 if (!EFI_ERROR (Status)) {\r
426 break;\r
427 }\r
428 } else {\r
429 gBS->Stall (1000000);\r
430 }\r
431\r
432 //\r
433 // 0xffff means waiting forever\r
434 // BDS with no hotkey provided and 0xffff as timeout will "hang" in the loop\r
435 //\r
436 if (TimeoutRemain != 0xffff) {\r
437 TimeoutRemain--;\r
438 }\r
439 }\r
440 DEBUG ((EFI_D_INFO, "[Bds]Exit the waiting!\n"));\r
441}\r
442\r
443/**\r
444 Attempt to boot each boot option in the BootOptions array.\r
445\r
446 @param BootOptions Input boot option array.\r
447 @param BootOptionCount Input boot option count.\r
448\r
449 @retval TRUE Successfully boot one of the boot options.\r
450 @retval FALSE Failed boot any of the boot options.\r
451**/\r
452BOOLEAN\r
453BootAllBootOptions (\r
454 IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions,\r
455 IN UINTN BootOptionCount\r
456 )\r
457{\r
458 UINTN Index;\r
459\r
460 //\r
461 // Attempt boot each boot option\r
462 //\r
463 for (Index = 0; Index < BootOptionCount; Index++) {\r
464 //\r
465 // According to EFI Specification, if a load option is not marked\r
466 // as LOAD_OPTION_ACTIVE, the boot manager will not automatically\r
467 // load the option.\r
468 //\r
469 if ((BootOptions[Index].Attributes & LOAD_OPTION_ACTIVE) == 0) {\r
470 continue;\r
471 }\r
472\r
473 //\r
474 // Boot#### load options with LOAD_OPTION_CATEGORY_APP are executables which are not\r
475 // part of the normal boot processing. Boot options with reserved category values will be\r
476 // ignored by the boot manager.\r
477 //\r
478 if ((BootOptions[Index].Attributes & LOAD_OPTION_CATEGORY) != LOAD_OPTION_CATEGORY_BOOT) {\r
479 continue;\r
480 }\r
481\r
482 //\r
483 // All the driver options should have been processed since\r
484 // now boot will be performed.\r
485 //\r
486 EfiBootManagerBoot (&BootOptions[Index]);\r
487\r
488 //\r
489 // Successful boot breaks the loop, otherwise tries next boot option\r
490 //\r
491 if (BootOptions[Index].Status == EFI_SUCCESS) {\r
492 break;\r
493 }\r
494 }\r
495\r
496 return (BOOLEAN) (Index < BootOptionCount);\r
497}\r
498\r
499/**\r
500 This function attempts to boot per the boot order specified by platform policy.\r
501\r
502 If the boot via Boot#### returns with a status of EFI_SUCCESS the boot manager will stop \r
503 processing the BootOrder variable and present a boot manager menu to the user. If a boot via \r
504 Boot#### returns a status other than EFI_SUCCESS, the boot has failed and the next Boot####\r
505 in the BootOrder variable will be tried until all possibilities are exhausted.\r
506 -- Chapter 3.1.1 Boot Manager Programming, the 4th paragraph\r
507**/\r
508VOID\r
509DefaultBootBehavior (\r
510 VOID\r
511 )\r
512{\r
513 UINTN BootOptionCount;\r
514 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;\r
515 EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu;\r
516\r
517 EfiBootManagerGetBootManagerMenu (&BootManagerMenu);\r
518 //\r
519 // BootManagerMenu always contains the correct information even the above function returns failure.\r
520 //\r
521\r
522 BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);\r
523\r
524 if (BootAllBootOptions (BootOptions, BootOptionCount)) {\r
525 //\r
526 // Follow generic rule, Call BdsDxeOnConnectConInCallBack to connect ConIn before enter UI\r
527 //\r
528 if (PcdGetBool (PcdConInConnectOnDemand)) {\r
529 BdsDxeOnConnectConInCallBack (NULL, NULL);\r
530 }\r
531\r
532 //\r
533 // Show the Boot Manager Menu after successful boot\r
534 //\r
535 EfiBootManagerBoot (&BootManagerMenu);\r
536 } else {\r
537 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);\r
538 //\r
539 // Re-scan all EFI boot options in case all the boot#### are deleted or failed to boot\r
540 //\r
541 // If no valid boot options exist, the boot manager will enumerate all removable media\r
542 // devices followed by all fixed media devices. The order within each group is undefined.\r
543 // These new default boot options are not saved to non volatile storage.The boot manger\r
544 // will then attempt toboot from each boot option.\r
545 // -- Chapter 3.3 Boot Manager Programming, the 2nd paragraph\r
546 //\r
547 EfiBootManagerConnectAll ();\r
548 BootOptions = BdsEnumerateBootOptions (&BootOptionCount);\r
549\r
550 if (!BootAllBootOptions (BootOptions, BootOptionCount)) {\r
551 DEBUG ((EFI_D_ERROR, "[Bds]No bootable device!\n"));\r
552 EfiBootManagerBoot (&BootManagerMenu);\r
553 }\r
554 }\r
555\r
556 EfiBootManagerFreeLoadOption (&BootManagerMenu);\r
557 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);\r
558}\r
559\r
560/**\r
1634214d 561 The function will load and start every Driver####/SysPrep####.\r
f4cd24da 562\r
1634214d
RN
563 @param LoadOptions Load option array.\r
564 @param LoadOptionCount Load option count.\r
f4cd24da
RN
565\r
566**/\r
567VOID\r
1634214d
RN
568ProcessLoadOptions (\r
569 IN EFI_BOOT_MANAGER_LOAD_OPTION *LoadOptions,\r
570 IN UINTN LoadOptionCount\r
f4cd24da
RN
571 )\r
572{\r
1634214d
RN
573 EFI_STATUS Status;\r
574 UINTN Index;\r
575 BOOLEAN ReconnectAll;\r
576 EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType;\r
f4cd24da
RN
577\r
578 ReconnectAll = FALSE;\r
1634214d 579 LoadOptionType = LoadOptionTypeMax;\r
f4cd24da
RN
580\r
581 //\r
582 // Process the driver option\r
583 //\r
1634214d 584 for (Index = 0; Index < LoadOptionCount; Index++) {\r
f4cd24da 585 //\r
1634214d 586 // All the load options in the array should be of the same type.\r
f4cd24da 587 //\r
1634214d
RN
588 if (LoadOptionType == LoadOptionTypeMax) {\r
589 LoadOptionType = LoadOptions[Index].OptionType;\r
f4cd24da 590 }\r
1634214d
RN
591 ASSERT (LoadOptionType == LoadOptions[Index].OptionType);\r
592 ASSERT (LoadOptionType == LoadOptionTypeDriver || LoadOptionType == LoadOptionTypeSysPrep);\r
f4cd24da 593\r
1634214d 594 Status = EfiBootManagerProcessLoadOption (&LoadOptions[Index]);\r
f4cd24da 595\r
1634214d
RN
596 if (!EFI_ERROR (Status) && ((LoadOptions[Index].Attributes & LOAD_OPTION_FORCE_RECONNECT) != 0)) {\r
597 ReconnectAll = TRUE;\r
f4cd24da
RN
598 }\r
599 }\r
1634214d 600\r
f4cd24da 601 //\r
1634214d
RN
602 // If a driver load option is marked as LOAD_OPTION_FORCE_RECONNECT,\r
603 // then all of the EFI drivers in the system will be disconnected and\r
604 // reconnected after the last driver load option is processed.\r
f4cd24da 605 //\r
1634214d 606 if (ReconnectAll && LoadOptionType == LoadOptionTypeDriver) {\r
f4cd24da
RN
607 EfiBootManagerDisconnectAll ();\r
608 EfiBootManagerConnectAll ();\r
609 }\r
f4cd24da
RN
610}\r
611\r
612/**\r
613\r
614 Validate input console variable data. \r
615\r
616 If found the device path is not a valid device path, remove the variable.\r
617 \r
618 @param VariableName Input console variable name.\r
619\r
620**/\r
621VOID\r
622BdsFormalizeConsoleVariable (\r
623 IN CHAR16 *VariableName\r
624 )\r
625{\r
626 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
627 UINTN VariableSize;\r
628 EFI_STATUS Status;\r
629\r
630 GetEfiGlobalVariable2 (VariableName, (VOID **) &DevicePath, &VariableSize);\r
631 if ((DevicePath != NULL) && !IsDevicePathValid (DevicePath, VariableSize)) { \r
632 Status = gRT->SetVariable (\r
633 VariableName,\r
634 &gEfiGlobalVariableGuid,\r
635 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
636 0,\r
637 NULL\r
638 );\r
639 //\r
640 // Deleting variable with current variable implementation shouldn't fail.\r
641 //\r
642 ASSERT_EFI_ERROR (Status);\r
643 }\r
644\r
645 if (DevicePath != NULL) {\r
646 FreePool (DevicePath);\r
647 }\r
648}\r
649\r
650/**\r
651 Formalize OsIndication related variables. \r
652 \r
653 For OsIndicationsSupported, Create a BS/RT/UINT64 variable to report caps \r
654 Delete OsIndications variable if it is not NV/BS/RT UINT64.\r
655 \r
656 Item 3 is used to solve case when OS corrupts OsIndications. Here simply delete this NV variable.\r
657\r
658**/\r
659VOID \r
660BdsFormalizeOSIndicationVariable (\r
661 VOID\r
662 )\r
663{\r
664 EFI_STATUS Status;\r
665 UINT64 OsIndicationSupport;\r
666 UINT64 OsIndication;\r
667 UINTN DataSize;\r
668 UINT32 Attributes;\r
669\r
670 //\r
671 // OS indicater support variable\r
672 //\r
673 OsIndicationSupport = EFI_OS_INDICATIONS_BOOT_TO_FW_UI;\r
674 Status = gRT->SetVariable (\r
cc4812f6 675 EFI_OS_INDICATIONS_SUPPORT_VARIABLE_NAME,\r
f4cd24da
RN
676 &gEfiGlobalVariableGuid,\r
677 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
678 sizeof(UINT64),\r
679 &OsIndicationSupport\r
680 );\r
681 //\r
682 // Platform needs to make sure setting volatile variable before calling 3rd party code shouldn't fail.\r
683 //\r
684 ASSERT_EFI_ERROR (Status);\r
685\r
686 //\r
687 // If OsIndications is invalid, remove it.\r
688 // Invalid case\r
689 // 1. Data size != UINT64\r
690 // 2. OsIndication value inconsistence\r
691 // 3. OsIndication attribute inconsistence\r
692 //\r
693 OsIndication = 0;\r
694 Attributes = 0;\r
695 DataSize = sizeof(UINT64);\r
696 Status = gRT->GetVariable (\r
cc4812f6 697 EFI_OS_INDICATIONS_VARIABLE_NAME,\r
f4cd24da
RN
698 &gEfiGlobalVariableGuid,\r
699 &Attributes,\r
700 &DataSize,\r
701 &OsIndication\r
702 );\r
703 if (Status == EFI_NOT_FOUND) {\r
704 return;\r
705 }\r
706\r
707 if ((DataSize != sizeof (OsIndication)) ||\r
708 ((OsIndication & ~OsIndicationSupport) != 0) ||\r
709 (Attributes != (EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE))\r
710 ){\r
711\r
712 DEBUG ((EFI_D_ERROR, "[Bds] Unformalized OsIndications variable exists. Delete it\n"));\r
713 Status = gRT->SetVariable (\r
cc4812f6 714 EFI_OS_INDICATIONS_VARIABLE_NAME,\r
f4cd24da
RN
715 &gEfiGlobalVariableGuid,\r
716 0,\r
717 0,\r
718 NULL\r
719 );\r
720 //\r
721 // Deleting variable with current variable implementation shouldn't fail.\r
722 //\r
723 ASSERT_EFI_ERROR(Status);\r
724 }\r
725}\r
726\r
727/**\r
728\r
729 Validate variables. \r
730\r
731**/\r
732VOID \r
733BdsFormalizeEfiGlobalVariable (\r
734 VOID\r
735 )\r
736{\r
737 //\r
738 // Validate Console variable.\r
739 //\r
cc4812f6
RN
740 BdsFormalizeConsoleVariable (EFI_CON_IN_VARIABLE_NAME);\r
741 BdsFormalizeConsoleVariable (EFI_CON_OUT_VARIABLE_NAME);\r
742 BdsFormalizeConsoleVariable (EFI_ERR_OUT_VARIABLE_NAME);\r
f4cd24da
RN
743\r
744 //\r
745 // Validate OSIndication related variable.\r
746 //\r
747 BdsFormalizeOSIndicationVariable ();\r
748}\r
749\r
750/**\r
751\r
752 Allocate a block of memory that will contain performance data to OS.\r
753\r
754**/\r
755VOID\r
756BdsAllocateMemoryForPerformanceData (\r
757 VOID\r
758 )\r
759{\r
760 EFI_STATUS Status;\r
761 EFI_PHYSICAL_ADDRESS AcpiLowMemoryBase;\r
762 EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;\r
763\r
764 AcpiLowMemoryBase = 0x0FFFFFFFFULL;\r
765\r
766 //\r
767 // Allocate a block of memory that will contain performance data to OS.\r
768 //\r
769 Status = gBS->AllocatePages (\r
770 AllocateMaxAddress,\r
771 EfiReservedMemoryType,\r
772 EFI_SIZE_TO_PAGES (PERF_DATA_MAX_LENGTH),\r
773 &AcpiLowMemoryBase\r
774 );\r
775 if (!EFI_ERROR (Status)) {\r
776 //\r
777 // Save the pointer to variable for use in S3 resume.\r
778 //\r
779 Status = BdsDxeSetVariableAndReportStatusCodeOnError (\r
780 L"PerfDataMemAddr",\r
781 &gPerformanceProtocolGuid,\r
782 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
783 sizeof (EFI_PHYSICAL_ADDRESS),\r
784 &AcpiLowMemoryBase\r
785 );\r
786 if (EFI_ERROR (Status)) {\r
787 DEBUG ((EFI_D_ERROR, "[Bds] PerfDataMemAddr (%08x) cannot be saved to NV storage.\n", AcpiLowMemoryBase));\r
788 }\r
789 //\r
790 // Mark L"PerfDataMemAddr" variable to read-only if the Variable Lock protocol exists\r
791 // Still lock it even the variable cannot be saved to prevent it's set by 3rd party code.\r
792 //\r
793 Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock);\r
794 if (!EFI_ERROR (Status)) {\r
795 Status = VariableLock->RequestToLock (VariableLock, L"PerfDataMemAddr", &gPerformanceProtocolGuid);\r
796 ASSERT_EFI_ERROR (Status);\r
797 }\r
798 }\r
799}\r
800\r
801/**\r
802\r
803 Service routine for BdsInstance->Entry(). Devices are connected, the\r
804 consoles are initialized, and the boot options are tried.\r
805\r
806 @param This Protocol Instance structure.\r
807\r
808**/\r
809VOID\r
810EFIAPI\r
811BdsEntry (\r
812 IN EFI_BDS_ARCH_PROTOCOL *This\r
813 )\r
814{\r
1634214d
RN
815 EFI_BOOT_MANAGER_LOAD_OPTION *LoadOptions;\r
816 UINTN LoadOptionCount;\r
f4cd24da
RN
817 CHAR16 *FirmwareVendor;\r
818 EFI_EVENT HotkeyTriggered;\r
819 UINT64 OsIndication;\r
820 UINTN DataSize;\r
821 EFI_STATUS Status;\r
822 UINT32 BootOptionSupport;\r
823 UINT16 BootTimeOut;\r
824 EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;\r
825 UINTN Index;\r
d175f4e6 826 EFI_BOOT_MANAGER_LOAD_OPTION LoadOption;\r
f4cd24da
RN
827 UINT16 *BootNext;\r
828 CHAR16 BootNextVariableName[sizeof ("Boot####")];\r
1634214d
RN
829 EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu;\r
830 BOOLEAN BootFwUi;\r
d175f4e6 831 EFI_DEVICE_PATH_PROTOCOL *FilePath;\r
f4cd24da
RN
832\r
833 HotkeyTriggered = NULL;\r
834 Status = EFI_SUCCESS;\r
835\r
836 //\r
837 // Insert the performance probe\r
838 //\r
839 PERF_END (NULL, "DXE", NULL, 0);\r
840 PERF_START (NULL, "BDS", NULL, 0);\r
841 DEBUG ((EFI_D_INFO, "[Bds] Entry...\n"));\r
842\r
843 PERF_CODE (\r
844 BdsAllocateMemoryForPerformanceData ();\r
845 );\r
846\r
847 //\r
848 // Fill in FirmwareVendor and FirmwareRevision from PCDs\r
849 //\r
850 FirmwareVendor = (CHAR16 *) PcdGetPtr (PcdFirmwareVendor);\r
851 gST->FirmwareVendor = AllocateRuntimeCopyPool (StrSize (FirmwareVendor), FirmwareVendor);\r
852 ASSERT (gST->FirmwareVendor != NULL);\r
853 gST->FirmwareRevision = PcdGet32 (PcdFirmwareRevision);\r
854\r
855 //\r
856 // Fixup Tasble CRC after we updated Firmware Vendor and Revision\r
857 //\r
858 gST->Hdr.CRC32 = 0;\r
859 gBS->CalculateCrc32 ((VOID *) gST, sizeof (EFI_SYSTEM_TABLE), &gST->Hdr.CRC32);\r
860\r
861 //\r
862 // Validate Variable.\r
863 //\r
864 BdsFormalizeEfiGlobalVariable ();\r
865\r
866 //\r
867 // Mark the read-only variables if the Variable Lock protocol exists\r
868 //\r
869 Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock);\r
870 DEBUG ((EFI_D_INFO, "[BdsDxe] Locate Variable Lock protocol - %r\n", Status));\r
871 if (!EFI_ERROR (Status)) {\r
872 for (Index = 0; Index < sizeof (mReadOnlyVariables) / sizeof (mReadOnlyVariables[0]); Index++) {\r
873 Status = VariableLock->RequestToLock (VariableLock, mReadOnlyVariables[Index], &gEfiGlobalVariableGuid);\r
874 ASSERT_EFI_ERROR (Status);\r
875 }\r
876 }\r
877\r
878 InitializeHwErrRecSupport ();\r
879\r
880 //\r
881 // Initialize L"Timeout" EFI global variable.\r
882 //\r
883 BootTimeOut = PcdGet16 (PcdPlatformBootTimeOut);\r
884 if (BootTimeOut != 0xFFFF) {\r
885 //\r
886 // If time out value equal 0xFFFF, no need set to 0xFFFF to variable area because UEFI specification\r
887 // define same behavior between no value or 0xFFFF value for L"Timeout".\r
888 //\r
889 BdsDxeSetVariableAndReportStatusCodeOnError (\r
890 EFI_TIME_OUT_VARIABLE_NAME,\r
891 &gEfiGlobalVariableGuid,\r
892 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
893 sizeof (UINT16),\r
894 &BootTimeOut\r
895 );\r
896 }\r
897\r
898 //\r
899 // Initialize L"BootOptionSupport" EFI global variable.\r
900 // Lazy-ConIn implictly disables BDS hotkey.\r
901 //\r
1634214d 902 BootOptionSupport = EFI_BOOT_OPTION_SUPPORT_APP | EFI_BOOT_OPTION_SUPPORT_SYSPREP;\r
f4cd24da
RN
903 if (!PcdGetBool (PcdConInConnectOnDemand)) {\r
904 BootOptionSupport |= EFI_BOOT_OPTION_SUPPORT_KEY;\r
905 SET_BOOT_OPTION_SUPPORT_KEY_COUNT (BootOptionSupport, 3);\r
906 }\r
907 Status = gRT->SetVariable (\r
908 EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME,\r
909 &gEfiGlobalVariableGuid,\r
910 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
911 sizeof (BootOptionSupport),\r
912 &BootOptionSupport\r
913 );\r
914 //\r
915 // Platform needs to make sure setting volatile variable before calling 3rd party code shouldn't fail.\r
916 //\r
917 ASSERT_EFI_ERROR (Status);\r
918\r
919 //\r
920 // Cache and remove the "BootNext" NV variable.\r
921 //\r
922 GetEfiGlobalVariable2 (EFI_BOOT_NEXT_VARIABLE_NAME, (VOID **) &BootNext, &DataSize);\r
923 if (DataSize != sizeof (UINT16)) {\r
924 if (BootNext != NULL) {\r
925 FreePool (BootNext);\r
926 }\r
927 BootNext = NULL;\r
928 }\r
929 Status = gRT->SetVariable (\r
930 EFI_BOOT_NEXT_VARIABLE_NAME,\r
931 &gEfiGlobalVariableGuid,\r
932 0,\r
933 0,\r
934 NULL\r
935 );\r
936 //\r
937 // Deleting NV variable shouldn't fail unless it doesn't exist.\r
938 //\r
939 ASSERT (Status == EFI_SUCCESS || Status == EFI_NOT_FOUND);\r
940\r
941 //\r
942 // Initialize the platform language variables\r
943 //\r
944 InitializeLanguage (TRUE);\r
945\r
d175f4e6
RN
946 //\r
947 // System firmware must include a PlatformRecovery#### variable specifying\r
948 // a short-form File Path Media Device Path containing the platform default\r
949 // file path for removable media\r
950 //\r
951 FilePath = FileDevicePath (NULL, EFI_REMOVABLE_MEDIA_FILE_NAME);\r
952 Status = EfiBootManagerInitializeLoadOption (\r
953 &LoadOption,\r
954 0,\r
955 LoadOptionTypePlatformRecovery,\r
956 LOAD_OPTION_ACTIVE,\r
957 L"Default PlatformRecovery",\r
958 FilePath,\r
959 NULL,\r
960 0\r
961 );\r
962 ASSERT_EFI_ERROR (Status);\r
963 EfiBootManagerLoadOptionToVariable (&LoadOption);\r
964 EfiBootManagerFreeLoadOption (&LoadOption);\r
965 FreePool (FilePath);\r
966\r
f4cd24da
RN
967 //\r
968 // Report Status Code to indicate connecting drivers will happen\r
969 //\r
970 REPORT_STATUS_CODE (\r
971 EFI_PROGRESS_CODE,\r
972 (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_BEGIN_CONNECTING_DRIVERS)\r
973 );\r
974\r
975 //\r
976 // Do the platform init, can be customized by OEM/IBV\r
977 // Possible things that can be done in PlatformBootManagerBeforeConsole:\r
978 // > Update console variable: 1. include hot-plug devices; 2. Clear ConIn and add SOL for AMT\r
979 // > Register new Driver#### or Boot####\r
980 // > Register new Key####: e.g.: F12 \r
981 // > Signal ReadyToLock event\r
982 // > Authentication action: 1. connect Auth devices; 2. Identify auto logon user.\r
983 //\r
984 PERF_START (NULL, "PlatformBootManagerBeforeConsole", "BDS", 0);\r
985 PlatformBootManagerBeforeConsole ();\r
986 PERF_END (NULL, "PlatformBootManagerBeforeConsole", "BDS", 0);\r
987\r
988 //\r
989 // Initialize hotkey service\r
990 //\r
991 EfiBootManagerStartHotkeyService (&HotkeyTriggered);\r
992\r
993 //\r
1634214d 994 // Execute Driver Options\r
f4cd24da 995 //\r
1634214d
RN
996 LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypeDriver);\r
997 ProcessLoadOptions (LoadOptions, LoadOptionCount);\r
998 EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);\r
f4cd24da
RN
999\r
1000 //\r
1001 // Connect consoles\r
1002 //\r
1003 PERF_START (NULL, "EfiBootManagerConnectAllDefaultConsoles", "BDS", 0);\r
1004 if (PcdGetBool (PcdConInConnectOnDemand)) {\r
1005 EfiBootManagerConnectConsoleVariable (ConOut);\r
1006 EfiBootManagerConnectConsoleVariable (ErrOut);\r
1007\r
1008 //\r
1009 // Initialize ConnectConIn event\r
1010 //\r
1011 Status = gBS->CreateEventEx (\r
1012 EVT_NOTIFY_SIGNAL,\r
1013 TPL_CALLBACK,\r
1014 BdsDxeOnConnectConInCallBack,\r
1015 NULL,\r
1016 &gConnectConInEventGuid,\r
1017 &gConnectConInEvent\r
1018 );\r
1019 if (EFI_ERROR (Status)) {\r
1020 gConnectConInEvent = NULL;\r
1021 }\r
1022 } else {\r
1023 EfiBootManagerConnectAllDefaultConsoles ();\r
1024 }\r
1025 PERF_END (NULL, "EfiBootManagerConnectAllDefaultConsoles", "BDS", 0);\r
1026\r
1027 //\r
1028 // Do the platform specific action after the console is ready\r
1029 // Possible things that can be done in PlatformBootManagerAfterConsole:\r
1030 // > Console post action:\r
1031 // > Dynamically switch output mode from 100x31 to 80x25 for certain senarino\r
1032 // > Signal console ready platform customized event\r
1033 // > Run diagnostics like memory testing\r
1034 // > Connect certain devices\r
1035 // > Dispatch aditional option roms\r
1036 // > Special boot: e.g.: USB boot, enter UI\r
1037 // \r
1038 PERF_START (NULL, "PlatformBootManagerAfterConsole", "BDS", 0);\r
1039 PlatformBootManagerAfterConsole ();\r
1040 PERF_END (NULL, "PlatformBootManagerAfterConsole", "BDS", 0);\r
1041\r
1042 DEBUG_CODE (\r
1634214d
RN
1043 EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType;\r
1044 DEBUG ((EFI_D_INFO, "[Bds]=============Begin Load Options Dumping ...=============\n"));\r
1045 for (LoadOptionType = 0; LoadOptionType < LoadOptionTypeMax; LoadOptionType++) {\r
f4cd24da 1046 DEBUG ((\r
1634214d
RN
1047 EFI_D_INFO, " %s Options:\n",\r
1048 mBdsLoadOptionName[LoadOptionType]\r
f4cd24da 1049 ));\r
1634214d
RN
1050 LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionType);\r
1051 for (Index = 0; Index < LoadOptionCount; Index++) {\r
1052 DEBUG ((\r
1053 EFI_D_INFO, " %s%04x: %s \t\t 0x%04x\n",\r
1054 mBdsLoadOptionName[LoadOptionType],\r
1055 LoadOptions[Index].OptionNumber,\r
1056 LoadOptions[Index].Description,\r
1057 LoadOptions[Index].Attributes\r
1058 ));\r
1059 }\r
1060 EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);\r
f4cd24da 1061 }\r
1634214d
RN
1062 DEBUG ((EFI_D_INFO, "[Bds]=============End Load Options Dumping=============\n"));\r
1063 );\r
f4cd24da
RN
1064\r
1065 //\r
1066 // Boot to Boot Manager Menu when EFI_OS_INDICATIONS_BOOT_TO_FW_UI is set. Skip HotkeyBoot\r
1067 //\r
1068 DataSize = sizeof (UINT64);\r
1069 Status = gRT->GetVariable (\r
cc4812f6 1070 EFI_OS_INDICATIONS_VARIABLE_NAME,\r
f4cd24da
RN
1071 &gEfiGlobalVariableGuid,\r
1072 NULL,\r
1073 &DataSize,\r
1074 &OsIndication\r
1075 );\r
1634214d
RN
1076 if (EFI_ERROR (Status)) {\r
1077 OsIndication = 0;\r
1078 }\r
1079\r
1080 BootFwUi = (BOOLEAN) ((OsIndication & EFI_OS_INDICATIONS_BOOT_TO_FW_UI) != 0);\r
1081 //\r
1082 // Clear EFI_OS_INDICATIONS_BOOT_TO_FW_UI to acknowledge OS\r
1083 // \r
1084 if (BootFwUi) {\r
f4cd24da
RN
1085 OsIndication &= ~((UINT64) EFI_OS_INDICATIONS_BOOT_TO_FW_UI);\r
1086 Status = gRT->SetVariable (\r
cc4812f6 1087 EFI_OS_INDICATIONS_VARIABLE_NAME,\r
f4cd24da
RN
1088 &gEfiGlobalVariableGuid,\r
1089 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
1090 sizeof(UINT64),\r
1091 &OsIndication\r
1092 );\r
1093 //\r
1094 // Changing the content without increasing its size with current variable implementation shouldn't fail.\r
1095 //\r
1096 ASSERT_EFI_ERROR (Status);\r
1634214d 1097 }\r
f4cd24da 1098\r
1634214d
RN
1099 //\r
1100 // Launch Boot Manager Menu directly when EFI_OS_INDICATIONS_BOOT_TO_FW_UI is set. Skip HotkeyBoot\r
1101 //\r
1102 if (BootFwUi) {\r
f4cd24da
RN
1103 //\r
1104 // Follow generic rule, Call BdsDxeOnConnectConInCallBack to connect ConIn before enter UI\r
1105 //\r
1106 if (PcdGetBool (PcdConInConnectOnDemand)) {\r
1107 BdsDxeOnConnectConInCallBack (NULL, NULL);\r
1108 }\r
1109\r
1110 //\r
1634214d
RN
1111 // Directly enter the setup page.\r
1112 // BootManagerMenu always contains the correct information even call fails.\r
f4cd24da 1113 //\r
1634214d
RN
1114 EfiBootManagerGetBootManagerMenu (&BootManagerMenu);\r
1115 EfiBootManagerBoot (&BootManagerMenu);\r
1116 EfiBootManagerFreeLoadOption (&BootManagerMenu);\r
f4cd24da
RN
1117 }\r
1118\r
1634214d
RN
1119 //\r
1120 // Execute SysPrep####\r
1121 //\r
1122 LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypeSysPrep);\r
1123 ProcessLoadOptions (LoadOptions, LoadOptionCount);\r
1124 EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);\r
1125\r
1126 //\r
1127 // Execute Key####\r
1128 //\r
1129 PERF_START (NULL, "BdsWait", "BDS", 0);\r
1130 BdsWait (HotkeyTriggered);\r
1131 PERF_END (NULL, "BdsWait", "BDS", 0);\r
1132\r
1133 //\r
1134 // BdsReadKeys() be removed after all keyboard drivers invoke callback in timer callback.\r
1135 //\r
1136 BdsReadKeys ();\r
1137\r
1138 EfiBootManagerHotkeyBoot ();\r
1139\r
f4cd24da
RN
1140 //\r
1141 // Boot to "BootNext"\r
1142 //\r
1143 if (BootNext != NULL) {\r
1144 UnicodeSPrint (BootNextVariableName, sizeof (BootNextVariableName), L"Boot%04x", *BootNext);\r
d175f4e6 1145 Status = EfiBootManagerVariableToLoadOption (BootNextVariableName, &LoadOption);\r
f4cd24da 1146 if (!EFI_ERROR (Status)) {\r
d175f4e6
RN
1147 EfiBootManagerBoot (&LoadOption);\r
1148 EfiBootManagerFreeLoadOption (&LoadOption);\r
1149 if (LoadOption.Status == EFI_SUCCESS) {\r
f4cd24da
RN
1150 //\r
1151 // Boot to Boot Manager Menu upon EFI_SUCCESS\r
1152 //\r
d175f4e6
RN
1153 EfiBootManagerGetBootManagerMenu (&LoadOption);\r
1154 EfiBootManagerBoot (&LoadOption);\r
1155 EfiBootManagerFreeLoadOption (&LoadOption);\r
f4cd24da
RN
1156 }\r
1157 }\r
1158 }\r
1159\r
1160 while (TRUE) {\r
1161 //\r
1162 // BDS select the boot device to load OS\r
1163 // Try next upon boot failure\r
1164 // Show Boot Manager Menu upon boot success\r
1165 //\r
1166 DefaultBootBehavior ();\r
1167 }\r
1168}\r
1169\r
1170/**\r
1171 Set the variable and report the error through status code upon failure.\r
1172\r
1173 @param VariableName A Null-terminated string that is the name of the vendor's variable.\r
1174 Each VariableName is unique for each VendorGuid. VariableName must\r
1175 contain 1 or more characters. If VariableName is an empty string,\r
1176 then EFI_INVALID_PARAMETER is returned.\r
1177 @param VendorGuid A unique identifier for the vendor.\r
1178 @param Attributes Attributes bitmask to set for the variable.\r
1179 @param DataSize The size in bytes of the Data buffer. Unless the EFI_VARIABLE_APPEND_WRITE, \r
1180 EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, or \r
1181 EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute is set, a size of zero \r
1182 causes the variable to be deleted. When the EFI_VARIABLE_APPEND_WRITE attribute is \r
1183 set, then a SetVariable() call with a DataSize of zero will not cause any change to \r
1184 the variable value (the timestamp associated with the variable may be updated however \r
1185 even if no new data value is provided,see the description of the \r
1186 EFI_VARIABLE_AUTHENTICATION_2 descriptor below. In this case the DataSize will not \r
1187 be zero since the EFI_VARIABLE_AUTHENTICATION_2 descriptor will be populated). \r
1188 @param Data The contents for the variable.\r
1189\r
1190 @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as\r
1191 defined by the Attributes.\r
1192 @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits, name, and GUID was supplied, or the\r
1193 DataSize exceeds the maximum allowed.\r
1194 @retval EFI_INVALID_PARAMETER VariableName is an empty string.\r
1195 @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data.\r
1196 @retval EFI_DEVICE_ERROR The variable could not be retrieved due to a hardware error.\r
1197 @retval EFI_WRITE_PROTECTED The variable in question is read-only.\r
1198 @retval EFI_WRITE_PROTECTED The variable in question cannot be deleted.\r
1199 @retval EFI_SECURITY_VIOLATION The variable could not be written due to EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS \r
1200 or EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACESS being set, but the AuthInfo \r
1201 does NOT pass the validation check carried out by the firmware.\r
1202\r
1203 @retval EFI_NOT_FOUND The variable trying to be updated or deleted was not found.\r
1204**/\r
1205EFI_STATUS\r
1206BdsDxeSetVariableAndReportStatusCodeOnError (\r
1207 IN CHAR16 *VariableName,\r
1208 IN EFI_GUID *VendorGuid,\r
1209 IN UINT32 Attributes,\r
1210 IN UINTN DataSize,\r
1211 IN VOID *Data\r
1212 )\r
1213{\r
1214 EFI_STATUS Status;\r
1215 EDKII_SET_VARIABLE_STATUS *SetVariableStatus;\r
1216 UINTN NameSize;\r
1217\r
1218 Status = gRT->SetVariable (\r
1219 VariableName,\r
1220 VendorGuid,\r
1221 Attributes,\r
1222 DataSize,\r
1223 Data\r
1224 );\r
1225 if (EFI_ERROR (Status)) {\r
1226 NameSize = StrSize (VariableName);\r
1227 SetVariableStatus = AllocatePool (sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + DataSize);\r
1228 if (SetVariableStatus != NULL) {\r
1229 CopyGuid (&SetVariableStatus->Guid, VendorGuid);\r
1230 SetVariableStatus->NameSize = NameSize;\r
1231 SetVariableStatus->DataSize = DataSize;\r
1232 SetVariableStatus->SetStatus = Status;\r
1233 SetVariableStatus->Attributes = Attributes;\r
1234 CopyMem (SetVariableStatus + 1, VariableName, NameSize);\r
1235 CopyMem (((UINT8 *) (SetVariableStatus + 1)) + NameSize, Data, DataSize);\r
1236\r
1237 REPORT_STATUS_CODE_EX (\r
1238 EFI_ERROR_CODE,\r
1239 PcdGet32 (PcdErrorCodeSetVariable),\r
1240 0,\r
1241 NULL,\r
1242 &gEdkiiStatusCodeDataTypeVariableGuid,\r
1243 SetVariableStatus,\r
1244 sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + DataSize\r
1245 );\r
1246\r
1247 FreePool (SetVariableStatus);\r
1248 }\r
1249 }\r
1250\r
1251 return Status;\r
1252}\r