]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkModulePkg/Library/GenericBdsLib/BdsMisc.c
Remove the RT attribute for HDDP variable and validate the variable content before...
[mirror_edk2.git] / IntelFrameworkModulePkg / Library / GenericBdsLib / BdsMisc.c
1 /** @file
2 Misc BDS library function
3
4 Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "InternalBdsLib.h"
16
17
18 #define MAX_STRING_LEN 200
19
20 BOOLEAN mFeaturerSwitch = TRUE;
21 BOOLEAN mResetRequired = FALSE;
22
23 extern UINT16 gPlatformBootTimeOutDefault;
24
25 /**
26 The function will go through the driver option link list, load and start
27 every driver the driver option device path point to.
28
29 @param BdsDriverLists The header of the current driver option link list
30
31 **/
32 VOID
33 EFIAPI
34 BdsLibLoadDrivers (
35 IN LIST_ENTRY *BdsDriverLists
36 )
37 {
38 EFI_STATUS Status;
39 LIST_ENTRY *Link;
40 BDS_COMMON_OPTION *Option;
41 EFI_HANDLE ImageHandle;
42 EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;
43 UINTN ExitDataSize;
44 CHAR16 *ExitData;
45 BOOLEAN ReconnectAll;
46
47 ReconnectAll = FALSE;
48
49 //
50 // Process the driver option
51 //
52 for (Link = BdsDriverLists->ForwardLink; Link != BdsDriverLists; Link = Link->ForwardLink) {
53 Option = CR (Link, BDS_COMMON_OPTION, Link, BDS_LOAD_OPTION_SIGNATURE);
54
55 //
56 // If a load option is not marked as LOAD_OPTION_ACTIVE,
57 // the boot manager will not automatically load the option.
58 //
59 if (!IS_LOAD_OPTION_TYPE (Option->Attribute, LOAD_OPTION_ACTIVE)) {
60 continue;
61 }
62
63 //
64 // If a driver load option is marked as LOAD_OPTION_FORCE_RECONNECT,
65 // then all of the EFI drivers in the system will be disconnected and
66 // reconnected after the last driver load option is processed.
67 //
68 if (IS_LOAD_OPTION_TYPE (Option->Attribute, LOAD_OPTION_FORCE_RECONNECT)) {
69 ReconnectAll = TRUE;
70 }
71
72 //
73 // Make sure the driver path is connected.
74 //
75 BdsLibConnectDevicePath (Option->DevicePath);
76
77 //
78 // Load and start the image that Driver#### describes
79 //
80 Status = gBS->LoadImage (
81 FALSE,
82 gImageHandle,
83 Option->DevicePath,
84 NULL,
85 0,
86 &ImageHandle
87 );
88
89 if (!EFI_ERROR (Status)) {
90 gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);
91
92 //
93 // Verify whether this image is a driver, if not,
94 // exit it and continue to parse next load option
95 //
96 if (ImageInfo->ImageCodeType != EfiBootServicesCode && ImageInfo->ImageCodeType != EfiRuntimeServicesCode) {
97 gBS->Exit (ImageHandle, EFI_INVALID_PARAMETER, 0, NULL);
98 continue;
99 }
100
101 if (Option->LoadOptionsSize != 0) {
102 ImageInfo->LoadOptionsSize = Option->LoadOptionsSize;
103 ImageInfo->LoadOptions = Option->LoadOptions;
104 }
105 //
106 // Before calling the image, enable the Watchdog Timer for
107 // the 5 Minute period
108 //
109 gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);
110
111 Status = gBS->StartImage (ImageHandle, &ExitDataSize, &ExitData);
112 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Driver Return Status = %r\n", Status));
113
114 //
115 // Clear the Watchdog Timer after the image returns
116 //
117 gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
118 }
119 }
120
121 //
122 // Process the LOAD_OPTION_FORCE_RECONNECT driver option
123 //
124 if (ReconnectAll) {
125 BdsLibDisconnectAllEfi ();
126 BdsLibConnectAll ();
127 }
128
129 }
130
131 /**
132 Get the Option Number that does not used.
133 Try to locate the specific option variable one by one utile find a free number.
134
135 @param VariableName Indicate if the boot#### or driver#### option
136
137 @return The Minimal Free Option Number
138
139 **/
140 UINT16
141 BdsLibGetFreeOptionNumber (
142 IN CHAR16 *VariableName
143 )
144 {
145 UINTN Index;
146 CHAR16 StrTemp[10];
147 UINT16 *OptionBuffer;
148 UINTN OptionSize;
149
150 //
151 // Try to find the minimum free number from 0, 1, 2, 3....
152 //
153 Index = 0;
154 do {
155 if (*VariableName == 'B') {
156 UnicodeSPrint (StrTemp, sizeof (StrTemp), L"Boot%04x", Index);
157 } else {
158 UnicodeSPrint (StrTemp, sizeof (StrTemp), L"Driver%04x", Index);
159 }
160 //
161 // try if the option number is used
162 //
163 OptionBuffer = BdsLibGetVariableAndSize (
164 StrTemp,
165 &gEfiGlobalVariableGuid,
166 &OptionSize
167 );
168 if (OptionBuffer == NULL) {
169 break;
170 }
171 Index++;
172 } while (TRUE);
173
174 return ((UINT16) Index);
175 }
176
177
178 /**
179 This function will register the new boot#### or driver#### option base on
180 the VariableName. The new registered boot#### or driver#### will be linked
181 to BdsOptionList and also update to the VariableName. After the boot#### or
182 driver#### updated, the BootOrder or DriverOrder will also be updated.
183
184 @param BdsOptionList The header of the boot#### or driver#### link list
185 @param DevicePath The device path which the boot#### or driver####
186 option present
187 @param String The description of the boot#### or driver####
188 @param VariableName Indicate if the boot#### or driver#### option
189
190 @retval EFI_SUCCESS The boot#### or driver#### have been success
191 registered
192 @retval EFI_STATUS Return the status of gRT->SetVariable ().
193
194 **/
195 EFI_STATUS
196 EFIAPI
197 BdsLibRegisterNewOption (
198 IN LIST_ENTRY *BdsOptionList,
199 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
200 IN CHAR16 *String,
201 IN CHAR16 *VariableName
202 )
203 {
204 EFI_STATUS Status;
205 UINTN Index;
206 UINT16 RegisterOptionNumber;
207 UINT16 *TempOptionPtr;
208 UINTN TempOptionSize;
209 UINT16 *OptionOrderPtr;
210 VOID *OptionPtr;
211 UINTN OptionSize;
212 UINT8 *TempPtr;
213 EFI_DEVICE_PATH_PROTOCOL *OptionDevicePath;
214 CHAR16 *Description;
215 CHAR16 OptionName[10];
216 BOOLEAN UpdateDescription;
217 UINT16 BootOrderEntry;
218 UINTN OrderItemNum;
219
220 if (DevicePath == NULL) {
221 return EFI_INVALID_PARAMETER;
222 }
223
224 OptionPtr = NULL;
225 OptionSize = 0;
226 TempPtr = NULL;
227 OptionDevicePath = NULL;
228 Description = NULL;
229 OptionOrderPtr = NULL;
230 UpdateDescription = FALSE;
231 Status = EFI_SUCCESS;
232 ZeroMem (OptionName, sizeof (OptionName));
233
234 TempOptionSize = 0;
235 TempOptionPtr = BdsLibGetVariableAndSize (
236 VariableName,
237 &gEfiGlobalVariableGuid,
238 &TempOptionSize
239 );
240 //
241 // Compare with current option variable if the previous option is set in global variable.
242 //
243 for (Index = 0; Index < TempOptionSize / sizeof (UINT16); Index++) {
244 //
245 // TempOptionPtr must not be NULL if we have non-zero TempOptionSize.
246 //
247 ASSERT (TempOptionPtr != NULL);
248
249 if (*VariableName == 'B') {
250 UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", TempOptionPtr[Index]);
251 } else {
252 UnicodeSPrint (OptionName, sizeof (OptionName), L"Driver%04x", TempOptionPtr[Index]);
253 }
254
255 OptionPtr = BdsLibGetVariableAndSize (
256 OptionName,
257 &gEfiGlobalVariableGuid,
258 &OptionSize
259 );
260 if (OptionPtr == NULL) {
261 continue;
262 }
263
264 //
265 // Validate the variable.
266 //
267 if (!ValidateOption(OptionPtr, OptionSize)) {
268 continue;
269 }
270
271 TempPtr = OptionPtr;
272 TempPtr += sizeof (UINT32) + sizeof (UINT16);
273 Description = (CHAR16 *) TempPtr;
274 TempPtr += StrSize ((CHAR16 *) TempPtr);
275 OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
276
277 //
278 // Notes: the description may will change base on the GetStringToken
279 //
280 if (CompareMem (OptionDevicePath, DevicePath, GetDevicePathSize (OptionDevicePath)) == 0) {
281 if (CompareMem (Description, String, StrSize (Description)) == 0) {
282 //
283 // Got the option, so just return
284 //
285 FreePool (OptionPtr);
286 FreePool (TempOptionPtr);
287 return EFI_SUCCESS;
288 } else {
289 //
290 // Option description changed, need update.
291 //
292 UpdateDescription = TRUE;
293 FreePool (OptionPtr);
294 break;
295 }
296 }
297
298 FreePool (OptionPtr);
299 }
300
301 OptionSize = sizeof (UINT32) + sizeof (UINT16) + StrSize (String);
302 OptionSize += GetDevicePathSize (DevicePath);
303 OptionPtr = AllocateZeroPool (OptionSize);
304 ASSERT (OptionPtr != NULL);
305
306 TempPtr = OptionPtr;
307 *(UINT32 *) TempPtr = LOAD_OPTION_ACTIVE;
308 TempPtr += sizeof (UINT32);
309 *(UINT16 *) TempPtr = (UINT16) GetDevicePathSize (DevicePath);
310 TempPtr += sizeof (UINT16);
311 CopyMem (TempPtr, String, StrSize (String));
312 TempPtr += StrSize (String);
313 CopyMem (TempPtr, DevicePath, GetDevicePathSize (DevicePath));
314
315 if (UpdateDescription) {
316 //
317 // The number in option#### to be updated.
318 // In this case, we must have non-NULL TempOptionPtr.
319 //
320 ASSERT (TempOptionPtr != NULL);
321 RegisterOptionNumber = TempOptionPtr[Index];
322 } else {
323 //
324 // The new option#### number
325 //
326 RegisterOptionNumber = BdsLibGetFreeOptionNumber(VariableName);
327 }
328
329 if (*VariableName == 'B') {
330 UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", RegisterOptionNumber);
331 } else {
332 UnicodeSPrint (OptionName, sizeof (OptionName), L"Driver%04x", RegisterOptionNumber);
333 }
334
335 Status = gRT->SetVariable (
336 OptionName,
337 &gEfiGlobalVariableGuid,
338 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
339 OptionSize,
340 OptionPtr
341 );
342 //
343 // Return if only need to update a changed description or fail to set option.
344 //
345 if (EFI_ERROR (Status) || UpdateDescription) {
346 FreePool (OptionPtr);
347 if (TempOptionPtr != NULL) {
348 FreePool (TempOptionPtr);
349 }
350 return Status;
351 }
352
353 FreePool (OptionPtr);
354
355 //
356 // Update the option order variable
357 //
358
359 //
360 // If no option order
361 //
362 if (TempOptionSize == 0) {
363 BootOrderEntry = 0;
364 Status = gRT->SetVariable (
365 VariableName,
366 &gEfiGlobalVariableGuid,
367 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
368 sizeof (UINT16),
369 &BootOrderEntry
370 );
371 if (TempOptionPtr != NULL) {
372 FreePool (TempOptionPtr);
373 }
374 return Status;
375 }
376
377 //
378 // TempOptionPtr must not be NULL if TempOptionSize is not zero.
379 //
380 ASSERT (TempOptionPtr != NULL);
381 //
382 // Append the new option number to the original option order
383 //
384 OrderItemNum = (TempOptionSize / sizeof (UINT16)) + 1 ;
385 OptionOrderPtr = AllocateZeroPool ( OrderItemNum * sizeof (UINT16));
386 ASSERT (OptionOrderPtr!= NULL);
387 CopyMem (OptionOrderPtr, TempOptionPtr, (OrderItemNum - 1) * sizeof (UINT16));
388
389 OptionOrderPtr[Index] = RegisterOptionNumber;
390
391 Status = gRT->SetVariable (
392 VariableName,
393 &gEfiGlobalVariableGuid,
394 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
395 OrderItemNum * sizeof (UINT16),
396 OptionOrderPtr
397 );
398 FreePool (TempOptionPtr);
399 FreePool (OptionOrderPtr);
400
401 return Status;
402 }
403
404 /**
405 Returns the size of a device path in bytes.
406
407 This function returns the size, in bytes, of the device path data structure
408 specified by DevicePath including the end of device path node. If DevicePath
409 is NULL, then 0 is returned. If the length of the device path is bigger than
410 MaxSize, also return 0 to indicate this is an invalidate device path.
411
412 @param DevicePath A pointer to a device path data structure.
413 @param MaxSize Max valid device path size. If big than this size,
414 return error.
415
416 @retval 0 An invalid device path.
417 @retval Others The size of a device path in bytes.
418
419 **/
420 UINTN
421 GetDevicePathSizeEx (
422 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,
423 IN UINTN MaxSize
424 )
425 {
426 UINTN Size;
427 UINTN NodeSize;
428
429 if (DevicePath == NULL) {
430 return 0;
431 }
432
433 //
434 // Search for the end of the device path structure
435 //
436 Size = 0;
437 while (!IsDevicePathEnd (DevicePath)) {
438 NodeSize = DevicePathNodeLength (DevicePath);
439 if (NodeSize < END_DEVICE_PATH_LENGTH) {
440 return 0;
441 }
442 Size += NodeSize;
443 if (Size > MaxSize) {
444 return 0;
445 }
446 DevicePath = NextDevicePathNode (DevicePath);
447 }
448 Size += DevicePathNodeLength (DevicePath);
449 if (Size > MaxSize) {
450 return 0;
451 }
452
453 return Size;
454 }
455
456 /**
457 Returns the length of a Null-terminated Unicode string. If the length is
458 bigger than MaxStringLen, return length 0 to indicate that this is an
459 invalidate string.
460
461 This function returns the byte length of Unicode characters in the Null-terminated
462 Unicode string specified by String.
463
464 If String is NULL, then ASSERT().
465 If String is not aligned on a 16-bit boundary, then ASSERT().
466
467 @param String A pointer to a Null-terminated Unicode string.
468 @param MaxStringLen Max string len in this string.
469
470 @retval 0 An invalid string.
471 @retval Others The length of String.
472
473 **/
474 UINTN
475 StrSizeEx (
476 IN CONST CHAR16 *String,
477 IN UINTN MaxStringLen
478 )
479 {
480 UINTN Length;
481
482 ASSERT (String != NULL && MaxStringLen != 0);
483 ASSERT (((UINTN) String & BIT0) == 0);
484
485 for (Length = 0; *String != L'\0' && MaxStringLen != Length; String++, Length+=2);
486
487 if (*String != L'\0' && MaxStringLen == Length) {
488 return 0;
489 }
490
491 return Length + 2;
492 }
493
494 /**
495 Validate the EFI Boot#### variable (VendorGuid/Name)
496
497 @param Variable Boot#### variable data.
498 @param VariableSize Returns the size of the EFI variable that was read
499
500 @retval TRUE The variable data is correct.
501 @retval FALSE The variable data is corrupted.
502
503 **/
504 BOOLEAN
505 ValidateOption (
506 UINT8 *Variable,
507 UINTN VariableSize
508 )
509 {
510 UINT16 FilePathSize;
511 UINT8 *TempPtr;
512 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
513 UINTN TempSize;
514
515 if (VariableSize <= sizeof (UINT16) + sizeof (UINT32)) {
516 return FALSE;
517 }
518
519 //
520 // Skip the option attribute
521 //
522 TempPtr = Variable;
523 TempPtr += sizeof (UINT32);
524
525 //
526 // Get the option's device path size
527 //
528 FilePathSize = *(UINT16 *) TempPtr;
529 TempPtr += sizeof (UINT16);
530
531 //
532 // Get the option's description string size
533 //
534 TempSize = StrSizeEx ((CHAR16 *) TempPtr, VariableSize - sizeof (UINT16) - sizeof (UINT32));
535 TempPtr += TempSize;
536
537 //
538 // Get the option's device path
539 //
540 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
541 TempPtr += FilePathSize;
542
543 //
544 // Validation boot option variable.
545 //
546 if ((FilePathSize == 0) || (TempSize == 0)) {
547 return FALSE;
548 }
549
550 if (TempSize + FilePathSize + sizeof (UINT16) + sizeof (UINT32) > VariableSize) {
551 return FALSE;
552 }
553
554 return (BOOLEAN) (GetDevicePathSizeEx (DevicePath, FilePathSize) != 0);
555 }
556
557 /**
558 Convert a single character to number.
559 It assumes the input Char is in the scope of L'0' ~ L'9' and L'A' ~ L'F'
560
561 @param Char The input char which need to change to a hex number.
562
563 **/
564 UINTN
565 CharToUint (
566 IN CHAR16 Char
567 )
568 {
569 if ((Char >= L'0') && (Char <= L'9')) {
570 return (UINTN) (Char - L'0');
571 }
572
573 if ((Char >= L'A') && (Char <= L'F')) {
574 return (UINTN) (Char - L'A' + 0xA);
575 }
576
577 ASSERT (FALSE);
578 return 0;
579 }
580
581 /**
582 Build the boot#### or driver#### option from the VariableName, the
583 build boot#### or driver#### will also be linked to BdsCommonOptionList.
584
585 @param BdsCommonOptionList The header of the boot#### or driver#### option
586 link list
587 @param VariableName EFI Variable name indicate if it is boot#### or
588 driver####
589
590 @retval BDS_COMMON_OPTION Get the option just been created
591 @retval NULL Failed to get the new option
592
593 **/
594 BDS_COMMON_OPTION *
595 EFIAPI
596 BdsLibVariableToOption (
597 IN OUT LIST_ENTRY *BdsCommonOptionList,
598 IN CHAR16 *VariableName
599 )
600 {
601 UINT32 Attribute;
602 UINT16 FilePathSize;
603 UINT8 *Variable;
604 UINT8 *TempPtr;
605 UINTN VariableSize;
606 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
607 BDS_COMMON_OPTION *Option;
608 VOID *LoadOptions;
609 UINT32 LoadOptionsSize;
610 CHAR16 *Description;
611 UINT8 NumOff;
612
613 //
614 // Read the variable. We will never free this data.
615 //
616 Variable = BdsLibGetVariableAndSize (
617 VariableName,
618 &gEfiGlobalVariableGuid,
619 &VariableSize
620 );
621 if (Variable == NULL) {
622 return NULL;
623 }
624
625 //
626 // Validate Boot#### variable data.
627 //
628 if (!ValidateOption(Variable, VariableSize)) {
629 return NULL;
630 }
631
632 //
633 // Notes: careful defined the variable of Boot#### or
634 // Driver####, consider use some macro to abstract the code
635 //
636 //
637 // Get the option attribute
638 //
639 TempPtr = Variable;
640 Attribute = *(UINT32 *) Variable;
641 TempPtr += sizeof (UINT32);
642
643 //
644 // Get the option's device path size
645 //
646 FilePathSize = *(UINT16 *) TempPtr;
647 TempPtr += sizeof (UINT16);
648
649 //
650 // Get the option's description string
651 //
652 Description = (CHAR16 *) TempPtr;
653
654 //
655 // Get the option's description string size
656 //
657 TempPtr += StrSize((CHAR16 *) TempPtr);
658
659 //
660 // Get the option's device path
661 //
662 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
663 TempPtr += FilePathSize;
664
665 //
666 // Get load opion data.
667 //
668 LoadOptions = TempPtr;
669 LoadOptionsSize = (UINT32) (VariableSize - (UINTN) (TempPtr - Variable));
670
671 //
672 // The Console variables may have multiple device paths, so make
673 // an Entry for each one.
674 //
675 Option = AllocateZeroPool (sizeof (BDS_COMMON_OPTION));
676 if (Option == NULL) {
677 return NULL;
678 }
679
680 Option->Signature = BDS_LOAD_OPTION_SIGNATURE;
681 Option->DevicePath = AllocateZeroPool (GetDevicePathSize (DevicePath));
682 ASSERT(Option->DevicePath != NULL);
683 CopyMem (Option->DevicePath, DevicePath, GetDevicePathSize (DevicePath));
684
685 Option->Attribute = Attribute;
686 Option->Description = AllocateZeroPool (StrSize (Description));
687 ASSERT(Option->Description != NULL);
688 CopyMem (Option->Description, Description, StrSize (Description));
689
690 Option->LoadOptions = AllocateZeroPool (LoadOptionsSize);
691 ASSERT(Option->LoadOptions != NULL);
692 CopyMem (Option->LoadOptions, LoadOptions, LoadOptionsSize);
693 Option->LoadOptionsSize = LoadOptionsSize;
694
695 //
696 // Get the value from VariableName Unicode string
697 // since the ISO standard assumes ASCII equivalent abbreviations, we can be safe in converting this
698 // Unicode stream to ASCII without any loss in meaning.
699 //
700 if (*VariableName == 'B') {
701 NumOff = (UINT8) (sizeof (L"Boot") / sizeof (CHAR16) - 1);
702 Option->BootCurrent = (UINT16) (CharToUint (VariableName[NumOff+0]) * 0x1000)
703 + (UINT16) (CharToUint (VariableName[NumOff+1]) * 0x100)
704 + (UINT16) (CharToUint (VariableName[NumOff+2]) * 0x10)
705 + (UINT16) (CharToUint (VariableName[NumOff+3]) * 0x1);
706 }
707 InsertTailList (BdsCommonOptionList, &Option->Link);
708 FreePool (Variable);
709 return Option;
710 }
711
712 /**
713 Process BootOrder, or DriverOrder variables, by calling
714 BdsLibVariableToOption () for each UINT16 in the variables.
715
716 @param BdsCommonOptionList The header of the option list base on variable
717 VariableName
718 @param VariableName EFI Variable name indicate the BootOrder or
719 DriverOrder
720
721 @retval EFI_SUCCESS Success create the boot option or driver option
722 list
723 @retval EFI_OUT_OF_RESOURCES Failed to get the boot option or driver option list
724
725 **/
726 EFI_STATUS
727 EFIAPI
728 BdsLibBuildOptionFromVar (
729 IN LIST_ENTRY *BdsCommonOptionList,
730 IN CHAR16 *VariableName
731 )
732 {
733 UINT16 *OptionOrder;
734 UINTN OptionOrderSize;
735 UINTN Index;
736 BDS_COMMON_OPTION *Option;
737 CHAR16 OptionName[20];
738
739 //
740 // Zero Buffer in order to get all BOOT#### variables
741 //
742 ZeroMem (OptionName, sizeof (OptionName));
743
744 //
745 // Read the BootOrder, or DriverOrder variable.
746 //
747 OptionOrder = BdsLibGetVariableAndSize (
748 VariableName,
749 &gEfiGlobalVariableGuid,
750 &OptionOrderSize
751 );
752 if (OptionOrder == NULL) {
753 return EFI_OUT_OF_RESOURCES;
754 }
755
756 for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) {
757 if (*VariableName == 'B') {
758 UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", OptionOrder[Index]);
759 } else {
760 UnicodeSPrint (OptionName, sizeof (OptionName), L"Driver%04x", OptionOrder[Index]);
761 }
762
763 Option = BdsLibVariableToOption (BdsCommonOptionList, OptionName);
764 if (Option != NULL) {
765 Option->BootCurrent = OptionOrder[Index];
766 }
767 }
768
769 FreePool (OptionOrder);
770
771 return EFI_SUCCESS;
772 }
773
774 /**
775 Get boot mode by looking up configuration table and parsing HOB list
776
777 @param BootMode Boot mode from PEI handoff HOB.
778
779 @retval EFI_SUCCESS Successfully get boot mode
780
781 **/
782 EFI_STATUS
783 EFIAPI
784 BdsLibGetBootMode (
785 OUT EFI_BOOT_MODE *BootMode
786 )
787 {
788 *BootMode = GetBootModeHob ();
789
790 return EFI_SUCCESS;
791 }
792
793 /**
794 Read the EFI variable (VendorGuid/Name) and return a dynamically allocated
795 buffer, and the size of the buffer. If failure return NULL.
796
797 @param Name String part of EFI variable name
798 @param VendorGuid GUID part of EFI variable name
799 @param VariableSize Returns the size of the EFI variable that was read
800
801 @return Dynamically allocated memory that contains a copy of the EFI variable
802 Caller is responsible freeing the buffer.
803 @retval NULL Variable was not read
804
805 **/
806 VOID *
807 EFIAPI
808 BdsLibGetVariableAndSize (
809 IN CHAR16 *Name,
810 IN EFI_GUID *VendorGuid,
811 OUT UINTN *VariableSize
812 )
813 {
814 EFI_STATUS Status;
815 UINTN BufferSize;
816 VOID *Buffer;
817
818 Buffer = NULL;
819
820 //
821 // Pass in a zero size buffer to find the required buffer size.
822 //
823 BufferSize = 0;
824 Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer);
825 if (Status == EFI_BUFFER_TOO_SMALL) {
826 //
827 // Allocate the buffer to return
828 //
829 Buffer = AllocateZeroPool (BufferSize);
830 if (Buffer == NULL) {
831 *VariableSize = 0;
832 return NULL;
833 }
834 //
835 // Read variable into the allocated buffer.
836 //
837 Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer);
838 if (EFI_ERROR (Status)) {
839 FreePool (Buffer);
840 BufferSize = 0;
841 Buffer = NULL;
842 }
843 }
844
845 ASSERT (((Buffer == NULL) && (BufferSize == 0)) ||
846 ((Buffer != NULL) && (BufferSize != 0))
847 );
848 *VariableSize = BufferSize;
849 return Buffer;
850 }
851
852 /**
853 Delete the instance in Multi which matches partly with Single instance
854
855 @param Multi A pointer to a multi-instance device path data
856 structure.
857 @param Single A pointer to a single-instance device path data
858 structure.
859
860 @return This function will remove the device path instances in Multi which partly
861 match with the Single, and return the result device path. If there is no
862 remaining device path as a result, this function will return NULL.
863
864 **/
865 EFI_DEVICE_PATH_PROTOCOL *
866 EFIAPI
867 BdsLibDelPartMatchInstance (
868 IN EFI_DEVICE_PATH_PROTOCOL *Multi,
869 IN EFI_DEVICE_PATH_PROTOCOL *Single
870 )
871 {
872 EFI_DEVICE_PATH_PROTOCOL *Instance;
873 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
874 EFI_DEVICE_PATH_PROTOCOL *TempNewDevicePath;
875 UINTN InstanceSize;
876 UINTN SingleDpSize;
877 UINTN Size;
878
879 NewDevicePath = NULL;
880 TempNewDevicePath = NULL;
881
882 if (Multi == NULL || Single == NULL) {
883 return Multi;
884 }
885
886 Instance = GetNextDevicePathInstance (&Multi, &InstanceSize);
887 SingleDpSize = GetDevicePathSize (Single) - END_DEVICE_PATH_LENGTH;
888 InstanceSize -= END_DEVICE_PATH_LENGTH;
889
890 while (Instance != NULL) {
891
892 Size = (SingleDpSize < InstanceSize) ? SingleDpSize : InstanceSize;
893
894 if ((CompareMem (Instance, Single, Size) != 0)) {
895 //
896 // Append the device path instance which does not match with Single
897 //
898 TempNewDevicePath = NewDevicePath;
899 NewDevicePath = AppendDevicePathInstance (NewDevicePath, Instance);
900 if (TempNewDevicePath != NULL) {
901 FreePool(TempNewDevicePath);
902 }
903 }
904 FreePool(Instance);
905 Instance = GetNextDevicePathInstance (&Multi, &InstanceSize);
906 InstanceSize -= END_DEVICE_PATH_LENGTH;
907 }
908
909 return NewDevicePath;
910 }
911
912 /**
913 Function compares a device path data structure to that of all the nodes of a
914 second device path instance.
915
916 @param Multi A pointer to a multi-instance device path data
917 structure.
918 @param Single A pointer to a single-instance device path data
919 structure.
920
921 @retval TRUE If the Single device path is contained within Multi device path.
922 @retval FALSE The Single device path is not match within Multi device path.
923
924 **/
925 BOOLEAN
926 EFIAPI
927 BdsLibMatchDevicePaths (
928 IN EFI_DEVICE_PATH_PROTOCOL *Multi,
929 IN EFI_DEVICE_PATH_PROTOCOL *Single
930 )
931 {
932 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
933 EFI_DEVICE_PATH_PROTOCOL *DevicePathInst;
934 UINTN Size;
935
936 if (Multi == NULL || Single == NULL) {
937 return FALSE;
938 }
939
940 DevicePath = Multi;
941 DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);
942
943 //
944 // Search for the match of 'Single' in 'Multi'
945 //
946 while (DevicePathInst != NULL) {
947 //
948 // If the single device path is found in multiple device paths,
949 // return success
950 //
951 if (CompareMem (Single, DevicePathInst, Size) == 0) {
952 FreePool (DevicePathInst);
953 return TRUE;
954 }
955
956 FreePool (DevicePathInst);
957 DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);
958 }
959
960 return FALSE;
961 }
962
963 /**
964 This function prints a series of strings.
965
966 @param ConOut Pointer to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
967 @param ... A variable argument list containing series of
968 strings, the last string must be NULL.
969
970 @retval EFI_SUCCESS Success print out the string using ConOut.
971 @retval EFI_STATUS Return the status of the ConOut->OutputString ().
972
973 **/
974 EFI_STATUS
975 EFIAPI
976 BdsLibOutputStrings (
977 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut,
978 ...
979 )
980 {
981 VA_LIST Args;
982 EFI_STATUS Status;
983 CHAR16 *String;
984
985 Status = EFI_SUCCESS;
986 VA_START (Args, ConOut);
987
988 while (!EFI_ERROR (Status)) {
989 //
990 // If String is NULL, then it's the end of the list
991 //
992 String = VA_ARG (Args, CHAR16 *);
993 if (String == NULL) {
994 break;
995 }
996
997 Status = ConOut->OutputString (ConOut, String);
998
999 if (EFI_ERROR (Status)) {
1000 break;
1001 }
1002 }
1003
1004 VA_END(Args);
1005 return Status;
1006 }
1007
1008 //
1009 // Following are BDS Lib functions which contain all the code about setup browser reset reminder feature.
1010 // Setup Browser reset reminder feature is that an reset reminder will be given before user leaves the setup browser if
1011 // user change any option setting which needs a reset to be effective, and the reset will be applied according to the user selection.
1012 //
1013
1014
1015 /**
1016 Enable the setup browser reset reminder feature.
1017 This routine is used in platform tip. If the platform policy need the feature, use the routine to enable it.
1018
1019 **/
1020 VOID
1021 EFIAPI
1022 EnableResetReminderFeature (
1023 VOID
1024 )
1025 {
1026 mFeaturerSwitch = TRUE;
1027 }
1028
1029
1030 /**
1031 Disable the setup browser reset reminder feature.
1032 This routine is used in platform tip. If the platform policy do not want the feature, use the routine to disable it.
1033
1034 **/
1035 VOID
1036 EFIAPI
1037 DisableResetReminderFeature (
1038 VOID
1039 )
1040 {
1041 mFeaturerSwitch = FALSE;
1042 }
1043
1044
1045 /**
1046 Record the info that a reset is required.
1047 A module boolean variable is used to record whether a reset is required.
1048
1049 **/
1050 VOID
1051 EFIAPI
1052 EnableResetRequired (
1053 VOID
1054 )
1055 {
1056 mResetRequired = TRUE;
1057 }
1058
1059
1060 /**
1061 Record the info that no reset is required.
1062 A module boolean variable is used to record whether a reset is required.
1063
1064 **/
1065 VOID
1066 EFIAPI
1067 DisableResetRequired (
1068 VOID
1069 )
1070 {
1071 mResetRequired = FALSE;
1072 }
1073
1074
1075 /**
1076 Check whether platform policy enable the reset reminder feature. The default is enabled.
1077
1078 **/
1079 BOOLEAN
1080 EFIAPI
1081 IsResetReminderFeatureEnable (
1082 VOID
1083 )
1084 {
1085 return mFeaturerSwitch;
1086 }
1087
1088
1089 /**
1090 Check if user changed any option setting which needs a system reset to be effective.
1091
1092 **/
1093 BOOLEAN
1094 EFIAPI
1095 IsResetRequired (
1096 VOID
1097 )
1098 {
1099 return mResetRequired;
1100 }
1101
1102
1103 /**
1104 Check whether a reset is needed, and finish the reset reminder feature.
1105 If a reset is needed, Popup a menu to notice user, and finish the feature
1106 according to the user selection.
1107
1108 **/
1109 VOID
1110 EFIAPI
1111 SetupResetReminder (
1112 VOID
1113 )
1114 {
1115 EFI_INPUT_KEY Key;
1116 CHAR16 *StringBuffer1;
1117 CHAR16 *StringBuffer2;
1118
1119
1120 //
1121 //check any reset required change is applied? if yes, reset system
1122 //
1123 if (IsResetReminderFeatureEnable ()) {
1124 if (IsResetRequired ()) {
1125
1126 StringBuffer1 = AllocateZeroPool (MAX_STRING_LEN * sizeof (CHAR16));
1127 ASSERT (StringBuffer1 != NULL);
1128 StringBuffer2 = AllocateZeroPool (MAX_STRING_LEN * sizeof (CHAR16));
1129 ASSERT (StringBuffer2 != NULL);
1130 StrCpy (StringBuffer1, L"Configuration changed. Reset to apply it Now.");
1131 StrCpy (StringBuffer2, L"Press ENTER to reset");
1132 //
1133 // Popup a menu to notice user
1134 //
1135 do {
1136 CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, StringBuffer1, StringBuffer2, NULL);
1137 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
1138
1139 FreePool (StringBuffer1);
1140 FreePool (StringBuffer2);
1141
1142 gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);
1143 }
1144 }
1145 }
1146
1147 /**
1148 Get the headers (dos, image, optional header) from an image
1149
1150 @param Device SimpleFileSystem device handle
1151 @param FileName File name for the image
1152 @param DosHeader Pointer to dos header
1153 @param Hdr The buffer in which to return the PE32, PE32+, or TE header.
1154
1155 @retval EFI_SUCCESS Successfully get the machine type.
1156 @retval EFI_NOT_FOUND The file is not found.
1157 @retval EFI_LOAD_ERROR File is not a valid image file.
1158
1159 **/
1160 EFI_STATUS
1161 EFIAPI
1162 BdsLibGetImageHeader (
1163 IN EFI_HANDLE Device,
1164 IN CHAR16 *FileName,
1165 OUT EFI_IMAGE_DOS_HEADER *DosHeader,
1166 OUT EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
1167 )
1168 {
1169 EFI_STATUS Status;
1170 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume;
1171 EFI_FILE_HANDLE Root;
1172 EFI_FILE_HANDLE ThisFile;
1173 UINTN BufferSize;
1174 UINT64 FileSize;
1175 EFI_FILE_INFO *Info;
1176
1177 Root = NULL;
1178 ThisFile = NULL;
1179 //
1180 // Handle the file system interface to the device
1181 //
1182 Status = gBS->HandleProtocol (
1183 Device,
1184 &gEfiSimpleFileSystemProtocolGuid,
1185 (VOID *) &Volume
1186 );
1187 if (EFI_ERROR (Status)) {
1188 goto Done;
1189 }
1190
1191 Status = Volume->OpenVolume (
1192 Volume,
1193 &Root
1194 );
1195 if (EFI_ERROR (Status)) {
1196 Root = NULL;
1197 goto Done;
1198 }
1199 ASSERT (Root != NULL);
1200 Status = Root->Open (Root, &ThisFile, FileName, EFI_FILE_MODE_READ, 0);
1201 if (EFI_ERROR (Status)) {
1202 goto Done;
1203 }
1204 ASSERT (ThisFile != NULL);
1205
1206 //
1207 // Get file size
1208 //
1209 BufferSize = SIZE_OF_EFI_FILE_INFO + 200;
1210 do {
1211 Info = NULL;
1212 Status = gBS->AllocatePool (EfiBootServicesData, BufferSize, (VOID **) &Info);
1213 if (EFI_ERROR (Status)) {
1214 goto Done;
1215 }
1216 Status = ThisFile->GetInfo (
1217 ThisFile,
1218 &gEfiFileInfoGuid,
1219 &BufferSize,
1220 Info
1221 );
1222 if (!EFI_ERROR (Status)) {
1223 break;
1224 }
1225 if (Status != EFI_BUFFER_TOO_SMALL) {
1226 FreePool (Info);
1227 goto Done;
1228 }
1229 FreePool (Info);
1230 } while (TRUE);
1231
1232 FileSize = Info->FileSize;
1233 FreePool (Info);
1234
1235 //
1236 // Read dos header
1237 //
1238 BufferSize = sizeof (EFI_IMAGE_DOS_HEADER);
1239 Status = ThisFile->Read (ThisFile, &BufferSize, DosHeader);
1240 if (EFI_ERROR (Status) ||
1241 BufferSize < sizeof (EFI_IMAGE_DOS_HEADER) ||
1242 FileSize <= DosHeader->e_lfanew ||
1243 DosHeader->e_magic != EFI_IMAGE_DOS_SIGNATURE) {
1244 Status = EFI_LOAD_ERROR;
1245 goto Done;
1246 }
1247
1248 //
1249 // Move to PE signature
1250 //
1251 Status = ThisFile->SetPosition (ThisFile, DosHeader->e_lfanew);
1252 if (EFI_ERROR (Status)) {
1253 Status = EFI_LOAD_ERROR;
1254 goto Done;
1255 }
1256
1257 //
1258 // Read and check PE signature
1259 //
1260 BufferSize = sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION);
1261 Status = ThisFile->Read (ThisFile, &BufferSize, Hdr.Pe32);
1262 if (EFI_ERROR (Status) ||
1263 BufferSize < sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION) ||
1264 Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {
1265 Status = EFI_LOAD_ERROR;
1266 goto Done;
1267 }
1268
1269 //
1270 // Check PE32 or PE32+ magic
1271 //
1272 if (Hdr.Pe32->OptionalHeader.Magic != EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC &&
1273 Hdr.Pe32->OptionalHeader.Magic != EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
1274 Status = EFI_LOAD_ERROR;
1275 goto Done;
1276 }
1277
1278 Done:
1279 if (ThisFile != NULL) {
1280 ThisFile->Close (ThisFile);
1281 }
1282 if (Root != NULL) {
1283 Root->Close (Root);
1284 }
1285 return Status;
1286 }
1287
1288 /**
1289 This routine adjust the memory information for different memory type and
1290 save them into the variables for next boot.
1291 **/
1292 VOID
1293 BdsSetMemoryTypeInformationVariable (
1294 VOID
1295 )
1296 {
1297 EFI_STATUS Status;
1298 EFI_MEMORY_TYPE_INFORMATION *PreviousMemoryTypeInformation;
1299 EFI_MEMORY_TYPE_INFORMATION *CurrentMemoryTypeInformation;
1300 UINTN VariableSize;
1301 UINTN Index;
1302 UINTN Index1;
1303 UINT32 Previous;
1304 UINT32 Current;
1305 UINT32 Next;
1306 EFI_HOB_GUID_TYPE *GuidHob;
1307 BOOLEAN MemoryTypeInformationModified;
1308 BOOLEAN MemoryTypeInformationVariableExists;
1309 EFI_BOOT_MODE BootMode;
1310
1311 MemoryTypeInformationModified = FALSE;
1312 MemoryTypeInformationVariableExists = FALSE;
1313
1314
1315 BootMode = GetBootModeHob ();
1316 //
1317 // In BOOT_IN_RECOVERY_MODE, Variable region is not reliable.
1318 //
1319 if (BootMode == BOOT_IN_RECOVERY_MODE) {
1320 return;
1321 }
1322
1323 //
1324 // Only check the the Memory Type Information variable in the boot mode
1325 // other than BOOT_WITH_DEFAULT_SETTINGS because the Memory Type
1326 // Information is not valid in this boot mode.
1327 //
1328 if (BootMode != BOOT_WITH_DEFAULT_SETTINGS) {
1329 VariableSize = 0;
1330 Status = gRT->GetVariable (
1331 EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME,
1332 &gEfiMemoryTypeInformationGuid,
1333 NULL,
1334 &VariableSize,
1335 NULL
1336 );
1337 if (Status == EFI_BUFFER_TOO_SMALL) {
1338 MemoryTypeInformationVariableExists = TRUE;
1339 }
1340 }
1341
1342 //
1343 // Retrieve the current memory usage statistics. If they are not found, then
1344 // no adjustments can be made to the Memory Type Information variable.
1345 //
1346 Status = EfiGetSystemConfigurationTable (
1347 &gEfiMemoryTypeInformationGuid,
1348 (VOID **) &CurrentMemoryTypeInformation
1349 );
1350 if (EFI_ERROR (Status) || CurrentMemoryTypeInformation == NULL) {
1351 return;
1352 }
1353
1354 //
1355 // Get the Memory Type Information settings from Hob if they exist,
1356 // PEI is responsible for getting them from variable and build a Hob to save them.
1357 // If the previous Memory Type Information is not available, then set defaults
1358 //
1359 GuidHob = GetFirstGuidHob (&gEfiMemoryTypeInformationGuid);
1360 if (GuidHob == NULL) {
1361 //
1362 // If Platform has not built Memory Type Info into the Hob, just return.
1363 //
1364 return;
1365 }
1366 PreviousMemoryTypeInformation = GET_GUID_HOB_DATA (GuidHob);
1367 VariableSize = GET_GUID_HOB_DATA_SIZE (GuidHob);
1368
1369 //
1370 // Use a heuristic to adjust the Memory Type Information for the next boot
1371 //
1372 DEBUG ((EFI_D_INFO, "Memory Previous Current Next \n"));
1373 DEBUG ((EFI_D_INFO, " Type Pages Pages Pages \n"));
1374 DEBUG ((EFI_D_INFO, "====== ======== ======== ========\n"));
1375
1376 for (Index = 0; PreviousMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
1377
1378 for (Index1 = 0; CurrentMemoryTypeInformation[Index1].Type != EfiMaxMemoryType; Index1++) {
1379 if (PreviousMemoryTypeInformation[Index].Type == CurrentMemoryTypeInformation[Index1].Type) {
1380 break;
1381 }
1382 }
1383 if (CurrentMemoryTypeInformation[Index1].Type == EfiMaxMemoryType) {
1384 continue;
1385 }
1386
1387 //
1388 // Previous is the number of pages pre-allocated
1389 // Current is the number of pages actually needed
1390 //
1391 Previous = PreviousMemoryTypeInformation[Index].NumberOfPages;
1392 Current = CurrentMemoryTypeInformation[Index1].NumberOfPages;
1393 Next = Previous;
1394
1395 //
1396 // Inconsistent Memory Reserved across bootings may lead to S4 fail
1397 // Write next varible to 125% * current when the pre-allocated memory is:
1398 // 1. More than 150% of needed memory and boot mode is BOOT_WITH_DEFAULT_SETTING
1399 // 2. Less than the needed memory
1400 //
1401 if ((Current + (Current >> 1)) < Previous) {
1402 if (BootMode == BOOT_WITH_DEFAULT_SETTINGS) {
1403 Next = Current + (Current >> 2);
1404 }
1405 } else if (Current > Previous) {
1406 Next = Current + (Current >> 2);
1407 }
1408 if (Next > 0 && Next < 4) {
1409 Next = 4;
1410 }
1411
1412 if (Next != Previous) {
1413 PreviousMemoryTypeInformation[Index].NumberOfPages = Next;
1414 MemoryTypeInformationModified = TRUE;
1415 }
1416
1417 DEBUG ((EFI_D_INFO, " %02x %08x %08x %08x\n", PreviousMemoryTypeInformation[Index].Type, Previous, Current, Next));
1418 }
1419
1420 //
1421 // If any changes were made to the Memory Type Information settings, then set the new variable value;
1422 // Or create the variable in first boot.
1423 //
1424 if (MemoryTypeInformationModified || !MemoryTypeInformationVariableExists) {
1425 Status = SetVariableAndReportStatusCodeOnError (
1426 EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME,
1427 &gEfiMemoryTypeInformationGuid,
1428 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
1429 VariableSize,
1430 PreviousMemoryTypeInformation
1431 );
1432
1433 if (!EFI_ERROR (Status)) {
1434 //
1435 // If the Memory Type Information settings have been modified, then reset the platform
1436 // so the new Memory Type Information setting will be used to guarantee that an S4
1437 // entry/resume cycle will not fail.
1438 //
1439 if (MemoryTypeInformationModified && PcdGetBool (PcdResetOnMemoryTypeInformationChange)) {
1440 DEBUG ((EFI_D_INFO, "Memory Type Information settings change. Warm Reset!!!\n"));
1441 gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);
1442 }
1443 } else {
1444 DEBUG ((EFI_D_ERROR, "Memory Type Information settings cannot be saved. OS S4 may fail!\n"));
1445 }
1446 }
1447 }
1448
1449 /**
1450 This routine is kept for backward compatibility.
1451 **/
1452 VOID
1453 EFIAPI
1454 BdsLibSaveMemoryTypeInformation (
1455 VOID
1456 )
1457 {
1458 }
1459
1460
1461 /**
1462 Identify a user and, if authenticated, returns the current user profile handle.
1463
1464 @param[out] User Point to user profile handle.
1465
1466 @retval EFI_SUCCESS User is successfully identified, or user identification
1467 is not supported.
1468 @retval EFI_ACCESS_DENIED User is not successfully identified
1469
1470 **/
1471 EFI_STATUS
1472 EFIAPI
1473 BdsLibUserIdentify (
1474 OUT EFI_USER_PROFILE_HANDLE *User
1475 )
1476 {
1477 EFI_STATUS Status;
1478 EFI_USER_MANAGER_PROTOCOL *Manager;
1479
1480 Status = gBS->LocateProtocol (
1481 &gEfiUserManagerProtocolGuid,
1482 NULL,
1483 (VOID **) &Manager
1484 );
1485 if (EFI_ERROR (Status)) {
1486 return EFI_SUCCESS;
1487 }
1488
1489 return Manager->Identify (Manager, User);
1490 }
1491
1492 /**
1493 Set the variable and report the error through status code upon failure.
1494
1495 @param VariableName A Null-terminated string that is the name of the vendor's variable.
1496 Each VariableName is unique for each VendorGuid. VariableName must
1497 contain 1 or more characters. If VariableName is an empty string,
1498 then EFI_INVALID_PARAMETER is returned.
1499 @param VendorGuid A unique identifier for the vendor.
1500 @param Attributes Attributes bitmask to set for the variable.
1501 @param DataSize The size in bytes of the Data buffer. Unless the EFI_VARIABLE_APPEND_WRITE,
1502 EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, or
1503 EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute is set, a size of zero
1504 causes the variable to be deleted. When the EFI_VARIABLE_APPEND_WRITE attribute is
1505 set, then a SetVariable() call with a DataSize of zero will not cause any change to
1506 the variable value (the timestamp associated with the variable may be updated however
1507 even if no new data value is provided,see the description of the
1508 EFI_VARIABLE_AUTHENTICATION_2 descriptor below. In this case the DataSize will not
1509 be zero since the EFI_VARIABLE_AUTHENTICATION_2 descriptor will be populated).
1510 @param Data The contents for the variable.
1511
1512 @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as
1513 defined by the Attributes.
1514 @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits, name, and GUID was supplied, or the
1515 DataSize exceeds the maximum allowed.
1516 @retval EFI_INVALID_PARAMETER VariableName is an empty string.
1517 @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data.
1518 @retval EFI_DEVICE_ERROR The variable could not be retrieved due to a hardware error.
1519 @retval EFI_WRITE_PROTECTED The variable in question is read-only.
1520 @retval EFI_WRITE_PROTECTED The variable in question cannot be deleted.
1521 @retval EFI_SECURITY_VIOLATION The variable could not be written due to EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
1522 or EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACESS being set, but the AuthInfo
1523 does NOT pass the validation check carried out by the firmware.
1524
1525 @retval EFI_NOT_FOUND The variable trying to be updated or deleted was not found.
1526 **/
1527 EFI_STATUS
1528 SetVariableAndReportStatusCodeOnError (
1529 IN CHAR16 *VariableName,
1530 IN EFI_GUID *VendorGuid,
1531 IN UINT32 Attributes,
1532 IN UINTN DataSize,
1533 IN VOID *Data
1534 )
1535 {
1536 EFI_STATUS Status;
1537 EDKII_SET_VARIABLE_STATUS *SetVariableStatus;
1538 UINTN NameSize;
1539
1540 Status = gRT->SetVariable (
1541 VariableName,
1542 VendorGuid,
1543 Attributes,
1544 DataSize,
1545 Data
1546 );
1547 if (EFI_ERROR (Status)) {
1548 NameSize = StrSize (VariableName);
1549 SetVariableStatus = AllocatePool (sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + DataSize);
1550 if (SetVariableStatus != NULL) {
1551 CopyGuid (&SetVariableStatus->Guid, VendorGuid);
1552 SetVariableStatus->NameSize = NameSize;
1553 SetVariableStatus->DataSize = DataSize;
1554 SetVariableStatus->SetStatus = Status;
1555 SetVariableStatus->Attributes = Attributes;
1556 CopyMem (SetVariableStatus + 1, VariableName, NameSize);
1557 if ((Data != NULL) && (DataSize != 0)) {
1558 CopyMem (((UINT8 *) (SetVariableStatus + 1)) + NameSize, Data, DataSize);
1559 }
1560
1561 REPORT_STATUS_CODE_EX (
1562 EFI_ERROR_CODE,
1563 PcdGet32 (PcdErrorCodeSetVariable),
1564 0,
1565 NULL,
1566 &gEdkiiStatusCodeDataTypeVariableGuid,
1567 SetVariableStatus,
1568 sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + DataSize
1569 );
1570
1571 FreePool (SetVariableStatus);
1572 }
1573 }
1574
1575 return Status;
1576 }
1577