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