2 Sample platform variable cleanup library implementation.
4 Copyright (c) 2015, 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
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.
15 #include "PlatVarCleanup.h"
17 VAR_ERROR_FLAG mLastVarErrorFlag
= VAR_ERROR_FLAG_NO_ERROR
;
18 EDKII_VAR_CHECK_PROTOCOL
*mVarCheck
= NULL
;
21 /// The flag to indicate whether the platform has left the DXE phase of execution.
23 BOOLEAN mEndOfDxe
= FALSE
;
25 LIST_ENTRY mUserVariableList
= INITIALIZE_LIST_HEAD_VARIABLE (mUserVariableList
);
26 UINT16 mUserVariableCount
= 0;
27 UINT16 mMarkedUserVariableCount
= 0;
29 EFI_GUID mVariableCleanupHiiGuid
= VARIABLE_CLEANUP_HII_GUID
;
30 CHAR16 mVarStoreName
[] = L
"VariableCleanup";
32 HII_VENDOR_DEVICE_PATH mVarCleanupHiiVendorDevicePath
= {
38 (UINT8
) (sizeof (VENDOR_DEVICE_PATH
)),
39 (UINT8
) ((sizeof (VENDOR_DEVICE_PATH
)) >> 8)
42 VARIABLE_CLEANUP_HII_GUID
46 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
48 (UINT8
) (sizeof (EFI_DEVICE_PATH_PROTOCOL
)),
49 (UINT8
) ((sizeof (EFI_DEVICE_PATH_PROTOCOL
)) >> 8)
55 Internal get variable error flag.
57 @return Variable error flag.
61 InternalGetVarErrorFlag (
67 VAR_ERROR_FLAG ErrorFlag
;
69 Size
= sizeof (ErrorFlag
);
70 Status
= gRT
->GetVariable (
72 &gEdkiiVarErrorFlagGuid
,
77 if (EFI_ERROR (Status
)) {
78 DEBUG ((EFI_D_INFO
, "%s - not found\n", VAR_ERROR_FLAG_NAME
));
79 return VAR_ERROR_FLAG_NO_ERROR
;
87 @param[in] Name Pointer to variable name.
88 @param[in] Guid Pointer to vendor guid.
90 @retval TRUE User variable.
91 @retval FALSE System variable.
101 VAR_CHECK_VARIABLE_PROPERTY Property
;
103 ZeroMem (&Property
, sizeof (Property
));
104 Status
= mVarCheck
->VariablePropertyGet (
109 if (EFI_ERROR (Status
)) {
111 // No property, it is user variable.
113 DEBUG ((EFI_D_INFO
, "PlatformVarCleanup - User variable: %g:%s\n", Guid
, Name
));
117 // DEBUG ((EFI_D_INFO, "PlatformVarCleanup - Variable Property: %g:%s\n", Guid, Name));
118 // DEBUG ((EFI_D_INFO, " Revision - 0x%04x\n", Property.Revision));
119 // DEBUG ((EFI_D_INFO, " Property - 0x%04x\n", Property.Property));
120 // DEBUG ((EFI_D_INFO, " Attribute - 0x%08x\n", Property.Attributes));
121 // DEBUG ((EFI_D_INFO, " MinSize - 0x%x\n", Property.MinSize));
122 // DEBUG ((EFI_D_INFO, " MaxSize - 0x%x\n", Property.MaxSize));
128 Find user variable node by variable GUID.
130 @param[in] Guid Pointer to vendor guid.
132 @return Pointer to user variable node.
136 FindUserVariableNodeByGuid (
140 USER_VARIABLE_NODE
*UserVariableNode
;
143 for (Link
= mUserVariableList
.ForwardLink
144 ;Link
!= &mUserVariableList
145 ;Link
= Link
->ForwardLink
) {
146 UserVariableNode
= USER_VARIABLE_FROM_LINK (Link
);
148 if (CompareGuid (Guid
, &UserVariableNode
->Guid
)) {
152 return UserVariableNode
;
157 // Create new one if not found.
159 UserVariableNode
= AllocateZeroPool (sizeof (*UserVariableNode
));
160 ASSERT (UserVariableNode
!= NULL
);
161 UserVariableNode
->Signature
= USER_VARIABLE_NODE_SIGNATURE
;
162 CopyGuid (&UserVariableNode
->Guid
, Guid
);
164 // (36 chars of "########-####-####-####-############" + 1 space + 1 terminator) * sizeof (CHAR16).
166 UserVariableNode
->PromptString
= AllocatePool ((36 + 2) * sizeof (CHAR16
));
167 ASSERT (UserVariableNode
->PromptString
!= NULL
);
168 UnicodeSPrint (UserVariableNode
->PromptString
, (36 + 2) * sizeof (CHAR16
), L
" %g", &UserVariableNode
->Guid
);
169 InitializeListHead (&UserVariableNode
->NameLink
);
170 InsertTailList (&mUserVariableList
, &UserVariableNode
->Link
);
171 return UserVariableNode
;
175 Create user variable node.
179 CreateUserVariableNode (
184 EFI_STATUS GetVariableStatus
;
186 UINTN MaxVarNameSize
;
193 USER_VARIABLE_NODE
*UserVariableNode
;
194 USER_VARIABLE_NAME_NODE
*UserVariableNameNode
;
199 // Initialize 128 * sizeof (CHAR16) variable name size.
201 MaxVarNameSize
= 128 * sizeof (CHAR16
);
202 VarName
= AllocateZeroPool (MaxVarNameSize
);
203 ASSERT (VarName
!= NULL
);
206 // Initialize 0x1000 variable data size.
208 MaxDataSize
= 0x1000;
209 Data
= AllocateZeroPool (MaxDataSize
);
210 ASSERT (Data
!= NULL
);
214 VarNameSize
= MaxVarNameSize
;
215 Status
= gRT
->GetNextVariableName (&VarNameSize
, VarName
, &Guid
);
216 if (Status
== EFI_BUFFER_TOO_SMALL
) {
217 VarName
= ReallocatePool (MaxVarNameSize
, VarNameSize
, VarName
);
218 ASSERT (VarName
!= NULL
);
219 MaxVarNameSize
= VarNameSize
;
220 Status
= gRT
->GetNextVariableName (&VarNameSize
, VarName
, &Guid
);
223 if (!EFI_ERROR (Status
)) {
224 if (IsUserVariable (VarName
, &Guid
)) {
225 DataSize
= MaxDataSize
;
226 GetVariableStatus
= gRT
->GetVariable (VarName
, &Guid
, &Attributes
, &DataSize
, Data
);
227 if (GetVariableStatus
== EFI_BUFFER_TOO_SMALL
) {
228 Data
= ReallocatePool (MaxDataSize
, DataSize
, Data
);
229 ASSERT (Data
!= NULL
);
230 MaxDataSize
= DataSize
;
231 GetVariableStatus
= gRT
->GetVariable (VarName
, &Guid
, &Attributes
, &DataSize
, Data
);
233 ASSERT_EFI_ERROR (GetVariableStatus
);
235 if ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) != 0) {
236 UserVariableNode
= FindUserVariableNodeByGuid (&Guid
);
237 ASSERT (UserVariableNode
!= NULL
);
240 // Different variables that have same variable GUID share same user variable node.
242 UserVariableNameNode
= AllocateZeroPool (sizeof (*UserVariableNameNode
));
243 ASSERT (UserVariableNameNode
!= NULL
);
244 UserVariableNameNode
->Signature
= USER_VARIABLE_NAME_NODE_SIGNATURE
;
245 UserVariableNameNode
->Name
= AllocateCopyPool (VarNameSize
, VarName
);
246 UserVariableNameNode
->Attributes
= Attributes
;
247 UserVariableNameNode
->DataSize
= DataSize
;
248 UserVariableNameNode
->Index
= Index
;
249 UserVariableNameNode
->QuestionId
= (EFI_QUESTION_ID
) (USER_VARIABLE_QUESTION_ID
+ Index
);
251 // 2 space * sizeof (CHAR16) + StrSize.
253 StringSize
= 2 * sizeof (CHAR16
) + StrSize (UserVariableNameNode
->Name
);
254 UserVariableNameNode
->PromptString
= AllocatePool (StringSize
);
255 ASSERT (UserVariableNameNode
->PromptString
!= NULL
);
256 UnicodeSPrint (UserVariableNameNode
->PromptString
, StringSize
, L
" %s", UserVariableNameNode
->Name
);
258 // (33 chars of "Attribtues = 0x and DataSize = 0x" + 1 terminator + (sizeof (UINT32) + sizeof (UINTN)) * 2) * sizeof (CHAR16).
260 StringSize
= (33 + 1 + (sizeof (UINT32
) + sizeof (UINTN
)) * 2) * sizeof (CHAR16
);
261 UserVariableNameNode
->HelpString
= AllocatePool (StringSize
);
262 ASSERT (UserVariableNameNode
->HelpString
!= NULL
);
263 UnicodeSPrint (UserVariableNameNode
->HelpString
, StringSize
, L
"Attribtues = 0x%08x and DataSize = 0x%x", UserVariableNameNode
->Attributes
, UserVariableNameNode
->DataSize
);
264 UserVariableNameNode
->Deleted
= FALSE
;
265 InsertTailList (&UserVariableNode
->NameLink
, &UserVariableNameNode
->Link
);
270 } while (Status
!= EFI_NOT_FOUND
);
272 mUserVariableCount
= Index
;
273 ASSERT (mUserVariableCount
<= MAX_USER_VARIABLE_COUNT
);
274 DEBUG ((EFI_D_INFO
, "PlatformVarCleanup - User variable count: 0x%04x\n", mUserVariableCount
));
281 Destroy user variable nodes.
285 DestroyUserVariableNode (
289 USER_VARIABLE_NODE
*UserVariableNode
;
291 USER_VARIABLE_NAME_NODE
*UserVariableNameNode
;
292 LIST_ENTRY
*NameLink
;
294 while (mUserVariableList
.ForwardLink
!= &mUserVariableList
) {
295 Link
= mUserVariableList
.ForwardLink
;
296 UserVariableNode
= USER_VARIABLE_FROM_LINK (Link
);
298 RemoveEntryList (&UserVariableNode
->Link
);
300 while (UserVariableNode
->NameLink
.ForwardLink
!= &UserVariableNode
->NameLink
) {
301 NameLink
= UserVariableNode
->NameLink
.ForwardLink
;
302 UserVariableNameNode
= USER_VARIABLE_NAME_FROM_LINK (NameLink
);
304 RemoveEntryList (&UserVariableNameNode
->Link
);
306 FreePool (UserVariableNameNode
->Name
);
307 FreePool (UserVariableNameNode
->PromptString
);
308 FreePool (UserVariableNameNode
->HelpString
);
309 FreePool (UserVariableNameNode
);
312 FreePool (UserVariableNode
->PromptString
);
313 FreePool (UserVariableNode
);
318 Create a time based data payload by concatenating the EFI_VARIABLE_AUTHENTICATION_2
319 descriptor with the input data. NO authentication is required in this function.
321 @param[in, out] DataSize On input, the size of Data buffer in bytes.
322 On output, the size of data returned in Data
324 @param[in, out] Data On input, Pointer to data buffer to be wrapped or
325 pointer to NULL to wrap an empty payload.
326 On output, Pointer to the new payload date buffer allocated from pool,
327 it's caller's responsibility to free the memory after using it.
329 @retval EFI_SUCCESS Create time based payload successfully.
330 @retval EFI_OUT_OF_RESOURCES There are not enough memory resourses to create time based payload.
331 @retval EFI_INVALID_PARAMETER The parameter is invalid.
332 @retval Others Unexpected error happens.
336 CreateTimeBasedPayload (
337 IN OUT UINTN
*DataSize
,
345 EFI_VARIABLE_AUTHENTICATION_2
*DescriptorData
;
346 UINTN DescriptorSize
;
349 if (Data
== NULL
|| DataSize
== NULL
) {
350 return EFI_INVALID_PARAMETER
;
354 // At user physical presence, the variable does not need to be signed but the
355 // parameters to the SetVariable() call still need to be prepared as authenticated
356 // variable. So we create EFI_VARIABLE_AUTHENTICATED_2 descriptor without certificate
360 PayloadSize
= *DataSize
;
362 DescriptorSize
= OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2
, AuthInfo
) + OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID
, CertData
);
363 NewData
= (UINT8
*) AllocateZeroPool (DescriptorSize
+ PayloadSize
);
364 if (NewData
== NULL
) {
365 return EFI_OUT_OF_RESOURCES
;
368 if ((Payload
!= NULL
) && (PayloadSize
!= 0)) {
369 CopyMem (NewData
+ DescriptorSize
, Payload
, PayloadSize
);
372 DescriptorData
= (EFI_VARIABLE_AUTHENTICATION_2
*) (NewData
);
374 ZeroMem (&Time
, sizeof (EFI_TIME
));
375 Status
= gRT
->GetTime (&Time
, NULL
);
376 if (EFI_ERROR (Status
)) {
385 CopyMem (&DescriptorData
->TimeStamp
, &Time
, sizeof (EFI_TIME
));
387 DescriptorData
->AuthInfo
.Hdr
.dwLength
= OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID
, CertData
);
388 DescriptorData
->AuthInfo
.Hdr
.wRevision
= 0x0200;
389 DescriptorData
->AuthInfo
.Hdr
.wCertificateType
= WIN_CERT_TYPE_EFI_GUID
;
390 CopyGuid (&DescriptorData
->AuthInfo
.CertType
, &gEfiCertPkcs7Guid
);
392 if (Payload
!= NULL
) {
396 *DataSize
= DescriptorSize
+ PayloadSize
;
402 Create a counter based data payload by concatenating the EFI_VARIABLE_AUTHENTICATION
403 descriptor with the input data. NO authentication is required in this function.
405 @param[in, out] DataSize On input, the size of Data buffer in bytes.
406 On output, the size of data returned in Data
408 @param[in, out] Data On input, Pointer to data buffer to be wrapped or
409 pointer to NULL to wrap an empty payload.
410 On output, Pointer to the new payload date buffer allocated from pool,
411 it's caller's responsibility to free the memory after using it.
413 @retval EFI_SUCCESS Create counter based payload successfully.
414 @retval EFI_OUT_OF_RESOURCES There are not enough memory resourses to create time based payload.
415 @retval EFI_INVALID_PARAMETER The parameter is invalid.
416 @retval Others Unexpected error happens.
420 CreateCounterBasedPayload (
421 IN OUT UINTN
*DataSize
,
429 EFI_VARIABLE_AUTHENTICATION
*DescriptorData
;
430 UINTN DescriptorSize
;
431 UINT64 MonotonicCount
;
433 if (Data
== NULL
|| DataSize
== NULL
) {
434 return EFI_INVALID_PARAMETER
;
438 // At user physical presence, the variable does not need to be signed but the
439 // parameters to the SetVariable() call still need to be prepared as authenticated
440 // variable. So we create EFI_VARIABLE_AUTHENTICATED descriptor without certificate
444 PayloadSize
= *DataSize
;
446 DescriptorSize
= (OFFSET_OF (EFI_VARIABLE_AUTHENTICATION
, AuthInfo
)) + \
447 (OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID
, CertData
)) + \
448 sizeof (EFI_CERT_BLOCK_RSA_2048_SHA256
);
449 NewData
= (UINT8
*) AllocateZeroPool (DescriptorSize
+ PayloadSize
);
450 if (NewData
== NULL
) {
451 return EFI_OUT_OF_RESOURCES
;
454 if ((Payload
!= NULL
) && (PayloadSize
!= 0)) {
455 CopyMem (NewData
+ DescriptorSize
, Payload
, PayloadSize
);
458 DescriptorData
= (EFI_VARIABLE_AUTHENTICATION
*) (NewData
);
460 Status
= gBS
->GetNextMonotonicCount (&MonotonicCount
);
461 if (EFI_ERROR (Status
)) {
465 DescriptorData
->MonotonicCount
= MonotonicCount
;
467 DescriptorData
->AuthInfo
.Hdr
.dwLength
= OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID
, CertData
) + sizeof (EFI_CERT_BLOCK_RSA_2048_SHA256
);
468 DescriptorData
->AuthInfo
.Hdr
.wRevision
= 0x0200;
469 DescriptorData
->AuthInfo
.Hdr
.wCertificateType
= WIN_CERT_TYPE_EFI_GUID
;
470 CopyGuid (&DescriptorData
->AuthInfo
.CertType
, &gEfiCertTypeRsa2048Sha256Guid
);
472 if (Payload
!= NULL
) {
476 *DataSize
= DescriptorSize
+ PayloadSize
;
482 Delete user variable.
484 @param[in] DeleteAll Delete all user variables.
485 @param[in] VariableCleanupData Pointer to variable cleanup data.
490 IN BOOLEAN DeleteAll
,
491 IN VARIABLE_CLEANUP_DATA
*VariableCleanupData OPTIONAL
495 USER_VARIABLE_NODE
*UserVariableNode
;
497 USER_VARIABLE_NAME_NODE
*UserVariableNameNode
;
498 LIST_ENTRY
*NameLink
;
502 for (Link
= mUserVariableList
.ForwardLink
503 ;Link
!= &mUserVariableList
504 ;Link
= Link
->ForwardLink
) {
505 UserVariableNode
= USER_VARIABLE_FROM_LINK (Link
);
507 for (NameLink
= UserVariableNode
->NameLink
.ForwardLink
508 ;NameLink
!= &UserVariableNode
->NameLink
509 ;NameLink
= NameLink
->ForwardLink
) {
510 UserVariableNameNode
= USER_VARIABLE_NAME_FROM_LINK (NameLink
);
512 if (!UserVariableNameNode
->Deleted
&& (DeleteAll
|| ((VariableCleanupData
!= NULL
) && (VariableCleanupData
->UserVariable
[UserVariableNameNode
->Index
] == TRUE
)))) {
513 DEBUG ((EFI_D_INFO
, "PlatformVarCleanup - Delete variable: %g:%s\n", &UserVariableNode
->Guid
, UserVariableNameNode
->Name
));
514 if ((UserVariableNameNode
->Attributes
& EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) != 0) {
517 Status
= CreateTimeBasedPayload (&DataSize
, &Data
);
518 if (!EFI_ERROR (Status
)) {
519 Status
= gRT
->SetVariable (UserVariableNameNode
->Name
, &UserVariableNode
->Guid
, UserVariableNameNode
->Attributes
, DataSize
, Data
);
522 } else if ((UserVariableNameNode
->Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) != 0) {
525 Status
= CreateCounterBasedPayload (&DataSize
, &Data
);
526 if (!EFI_ERROR (Status
)) {
527 Status
= gRT
->SetVariable (UserVariableNameNode
->Name
, &UserVariableNode
->Guid
, UserVariableNameNode
->Attributes
, DataSize
, Data
);
531 Status
= gRT
->SetVariable (UserVariableNameNode
->Name
, &UserVariableNode
->Guid
, 0, 0, NULL
);
533 if (!EFI_ERROR (Status
)) {
534 UserVariableNameNode
->Deleted
= TRUE
;
536 DEBUG ((EFI_D_INFO
, "PlatformVarCleanup - Delete variable fail: %g:%s\n", &UserVariableNode
->Guid
, UserVariableNameNode
->Name
));
544 This function allows a caller to extract the current configuration for one
545 or more named elements from the target driver.
547 @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
548 @param[in] Request A null-terminated Unicode string in <ConfigRequest> format.
549 @param[out] Progress On return, points to a character in the Request string.
550 Points to the string's null terminator if request was successful.
551 Points to the most recent '&' before the first failing name/value
552 pair (or the beginning of the string if the failure is in the
553 first name/value pair) if the request was not successful.
554 @param[out] Results A null-terminated Unicode string in <ConfigAltResp> format which
555 has all values filled in for the names in the Request string.
556 String to be allocated by the called function.
558 @retval EFI_SUCCESS The Results is filled with the requested values.
559 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results.
560 @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name.
561 @retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver.
566 VariableCleanupHiiExtractConfig (
567 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL
*This
,
568 IN CONST EFI_STRING Request
,
569 OUT EFI_STRING
*Progress
,
570 OUT EFI_STRING
*Results
574 VARIABLE_CLEANUP_HII_PRIVATE_DATA
*Private
;
576 EFI_STRING ConfigRequestHdr
;
577 EFI_STRING ConfigRequest
;
578 BOOLEAN AllocatedRequest
;
581 if (Progress
== NULL
|| Results
== NULL
) {
582 return EFI_INVALID_PARAMETER
;
586 if ((Request
!= NULL
) && !HiiIsConfigHdrMatch (Request
, &mVariableCleanupHiiGuid
, mVarStoreName
)) {
587 return EFI_NOT_FOUND
;
590 ConfigRequestHdr
= NULL
;
591 ConfigRequest
= NULL
;
592 AllocatedRequest
= FALSE
;
595 Private
= VARIABLE_CLEANUP_HII_PRIVATE_FROM_THIS (This
);
597 // Convert buffer data to <ConfigResp> by helper function BlockToConfig().
599 BufferSize
= sizeof (VARIABLE_CLEANUP_DATA
);
600 ConfigRequest
= Request
;
601 if ((Request
== NULL
) || (StrStr (Request
, L
"OFFSET") == NULL
)) {
603 // Request has no request element, construct full request string.
604 // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
605 // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator.
607 ConfigRequestHdr
= HiiConstructConfigHdr (&mVariableCleanupHiiGuid
, mVarStoreName
, Private
->HiiHandle
);
608 Size
= (StrLen (ConfigRequestHdr
) + 32 + 1) * sizeof (CHAR16
);
609 ConfigRequest
= AllocateZeroPool (Size
);
610 ASSERT (ConfigRequest
!= NULL
);
611 AllocatedRequest
= TRUE
;
612 UnicodeSPrint (ConfigRequest
, Size
, L
"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr
, (UINT64
)BufferSize
);
613 FreePool (ConfigRequestHdr
);
616 Status
= Private
->ConfigRouting
->BlockToConfig (
617 Private
->ConfigRouting
,
619 (UINT8
*) &Private
->VariableCleanupData
,
624 ASSERT_EFI_ERROR (Status
);
627 // Free the allocated config request string.
629 if (AllocatedRequest
) {
630 FreePool (ConfigRequest
);
631 ConfigRequest
= NULL
;
634 // Set Progress string to the original request string or the string's null terminator.
636 if (Request
== NULL
) {
638 } else if (StrStr (Request
, L
"OFFSET") == NULL
) {
639 *Progress
= Request
+ StrLen (Request
);
646 Update user variable form.
648 @param[in] Private Points to the VARIABLE_CLEANUP_HII_PRIVATE_DATA.
652 UpdateUserVariableForm (
653 IN VARIABLE_CLEANUP_HII_PRIVATE_DATA
*Private
656 EFI_STRING_ID PromptStringToken
;
657 EFI_STRING_ID HelpStringToken
;
658 VOID
*StartOpCodeHandle
;
659 VOID
*EndOpCodeHandle
;
660 EFI_IFR_GUID_LABEL
*StartLabel
;
661 EFI_IFR_GUID_LABEL
*EndLabel
;
662 USER_VARIABLE_NODE
*UserVariableNode
;
664 USER_VARIABLE_NAME_NODE
*UserVariableNameNode
;
665 LIST_ENTRY
*NameLink
;
669 // Init OpCode Handle.
671 StartOpCodeHandle
= HiiAllocateOpCodeHandle ();
672 ASSERT (StartOpCodeHandle
!= NULL
);
674 EndOpCodeHandle
= HiiAllocateOpCodeHandle ();
675 ASSERT (EndOpCodeHandle
!= NULL
);
678 // Create Hii Extend Label OpCode as the start opcode.
680 StartLabel
= (EFI_IFR_GUID_LABEL
*) HiiCreateGuidOpCode (StartOpCodeHandle
, &gEfiIfrTianoGuid
, NULL
, sizeof (EFI_IFR_GUID_LABEL
));
681 StartLabel
->ExtendOpCode
= EFI_IFR_EXTEND_OP_LABEL
;
682 StartLabel
->Number
= LABEL_START
;
685 // Create Hii Extend Label OpCode as the end opcode.
687 EndLabel
= (EFI_IFR_GUID_LABEL
*) HiiCreateGuidOpCode (EndOpCodeHandle
, &gEfiIfrTianoGuid
, NULL
, sizeof (EFI_IFR_GUID_LABEL
));
688 EndLabel
->ExtendOpCode
= EFI_IFR_EXTEND_OP_LABEL
;
689 EndLabel
->Number
= LABEL_END
;
693 &mVariableCleanupHiiGuid
,
694 FORM_ID_VARIABLE_CLEANUP
,
695 StartOpCodeHandle
, // LABEL_START
696 EndOpCodeHandle
// LABEL_END
699 for (Link
= mUserVariableList
.ForwardLink
700 ;Link
!= &mUserVariableList
701 ;Link
= Link
->ForwardLink
) {
702 UserVariableNode
= USER_VARIABLE_FROM_LINK (Link
);
705 // Create checkbox opcode for variables in the same variable GUID space.
708 for (NameLink
= UserVariableNode
->NameLink
.ForwardLink
709 ;NameLink
!= &UserVariableNode
->NameLink
710 ;NameLink
= NameLink
->ForwardLink
) {
711 UserVariableNameNode
= USER_VARIABLE_NAME_FROM_LINK (NameLink
);
713 if (!UserVariableNameNode
->Deleted
) {
716 // Create subtitle opcode for variable GUID.
718 PromptStringToken
= HiiSetString (Private
->HiiHandle
, 0, UserVariableNode
->PromptString
, NULL
);
719 HiiCreateSubTitleOpCode (StartOpCodeHandle
, PromptStringToken
, 0, 0, 0);
724 // Only create opcode for the non-deleted variables.
726 PromptStringToken
= HiiSetString (Private
->HiiHandle
, 0, UserVariableNameNode
->PromptString
, NULL
);
727 HelpStringToken
= HiiSetString (Private
->HiiHandle
, 0, UserVariableNameNode
->HelpString
, NULL
);
728 HiiCreateCheckBoxOpCode (
730 UserVariableNameNode
->QuestionId
,
731 VARIABLE_CLEANUP_VARSTORE_ID
,
732 (UINT16
) (USER_VARIABLE_VAR_OFFSET
+ UserVariableNameNode
->Index
),
735 EFI_IFR_FLAG_CALLBACK
,
736 Private
->VariableCleanupData
.UserVariable
[UserVariableNameNode
->Index
],
743 HiiCreateSubTitleOpCode (
745 STRING_TOKEN (STR_NULL_STRING
),
752 // Create the "Apply changes" and "Discard changes" tags.
754 HiiCreateActionOpCode (
756 SAVE_AND_EXIT_QUESTION_ID
,
757 STRING_TOKEN (STR_SAVE_AND_EXIT
),
758 STRING_TOKEN (STR_NULL_STRING
),
759 EFI_IFR_FLAG_CALLBACK
,
762 HiiCreateActionOpCode (
764 NO_SAVE_AND_EXIT_QUESTION_ID
,
765 STRING_TOKEN (STR_NO_SAVE_AND_EXIT
),
766 STRING_TOKEN (STR_NULL_STRING
),
767 EFI_IFR_FLAG_CALLBACK
,
773 &mVariableCleanupHiiGuid
,
774 FORM_ID_VARIABLE_CLEANUP
,
775 StartOpCodeHandle
, // LABEL_START
776 EndOpCodeHandle
// LABEL_END
779 HiiFreeOpCodeHandle (StartOpCodeHandle
);
780 HiiFreeOpCodeHandle (EndOpCodeHandle
);
784 This function applies changes in a driver's configuration.
785 Input is a Configuration, which has the routing data for this
786 driver followed by name / value configuration pairs. The driver
787 must apply those pairs to its configurable storage. If the
788 driver's configuration is stored in a linear block of data
789 and the driver's name / value pairs are in <BlockConfig>
790 format, it may use the ConfigToBlock helper function (above) to
791 simplify the job. Currently not implemented.
793 @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
794 @param[in] Configuration A null-terminated Unicode string in
795 <ConfigString> format.
796 @param[out] Progress A pointer to a string filled in with the
797 offset of the most recent '&' before the
798 first failing name / value pair (or the
799 beginn ing of the string if the failure
800 is in the first name / value pair) or
801 the terminating NULL if all was
804 @retval EFI_SUCCESS The results have been distributed or are
805 awaiting distribution.
806 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the
807 parts of the results that must be
808 stored awaiting possible future
810 @retval EFI_INVALID_PARAMETERS Passing in a NULL for the
811 Results parameter would result
812 in this type of error.
813 @retval EFI_NOT_FOUND Target for the specified routing data
819 VariableCleanupHiiRouteConfig (
820 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL
*This
,
821 IN CONST EFI_STRING Configuration
,
822 OUT EFI_STRING
*Progress
826 VARIABLE_CLEANUP_HII_PRIVATE_DATA
*Private
;
829 if (Progress
== NULL
) {
830 return EFI_INVALID_PARAMETER
;
832 *Progress
= Configuration
;
834 if (Configuration
== NULL
) {
835 return EFI_INVALID_PARAMETER
;
839 // Check routing data in <ConfigHdr>.
840 // Note: there is no name for Name/Value storage, only GUID will be checked.
842 if (!HiiIsConfigHdrMatch (Configuration
, &mVariableCleanupHiiGuid
, mVarStoreName
)) {
843 return EFI_NOT_FOUND
;
846 Private
= VARIABLE_CLEANUP_HII_PRIVATE_FROM_THIS (This
);
848 // Get Buffer Storage data.
850 BufferSize
= sizeof (VARIABLE_CLEANUP_DATA
);
852 // Convert <ConfigResp> to buffer data by helper function ConfigToBlock().
854 Status
= Private
->ConfigRouting
->ConfigToBlock (
855 Private
->ConfigRouting
,
857 (UINT8
*) &Private
->VariableCleanupData
,
861 ASSERT_EFI_ERROR (Status
);
863 DeleteUserVariable (FALSE
, &Private
->VariableCleanupData
);
865 // For "F10" hotkey to refresh the form.
867 // UpdateUserVariableForm (Private);
873 This function is called to provide results data to the driver.
874 This data consists of a unique key that is used to identify
875 which data is either being passed back or being asked for.
877 @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
878 @param[in] Action Specifies the type of action taken by the browser.
879 @param[in] QuestionId A unique value which is sent to the original
880 exporting driver so that it can identify the type
881 of data to expect. The format of the data tends to
882 vary based on the opcode that generated the callback.
883 @param[in] Type The type of value for the question.
884 @param[in] Value A pointer to the data being sent to the original
886 @param[out] ActionRequest On return, points to the action requested by the
889 @retval EFI_SUCCESS The callback successfully handled the action.
890 @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the
891 variable and its data.
892 @retval EFI_DEVICE_ERROR The variable could not be saved.
893 @retval EFI_UNSUPPORTED The specified Action is not supported by the
898 VariableCleanupHiiCallback (
899 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL
*This
,
900 IN EFI_BROWSER_ACTION Action
,
901 IN EFI_QUESTION_ID QuestionId
,
903 IN EFI_IFR_TYPE_VALUE
*Value
,
904 OUT EFI_BROWSER_ACTION_REQUEST
*ActionRequest
907 VARIABLE_CLEANUP_HII_PRIVATE_DATA
*Private
;
908 VARIABLE_CLEANUP_DATA
*VariableCleanupData
;
910 Private
= VARIABLE_CLEANUP_HII_PRIVATE_FROM_THIS (This
);
912 if ((Action
!= EFI_BROWSER_ACTION_CHANGING
) && (Action
!= EFI_BROWSER_ACTION_CHANGED
)) {
914 // All other action return unsupported.
916 return EFI_UNSUPPORTED
;
920 // Retrive uncommitted data from Form Browser.
922 VariableCleanupData
= &Private
->VariableCleanupData
;
923 HiiGetBrowserData (&mVariableCleanupHiiGuid
, mVarStoreName
, sizeof (VARIABLE_CLEANUP_DATA
), (UINT8
*) VariableCleanupData
);
924 if (Action
== EFI_BROWSER_ACTION_CHANGING
) {
926 return EFI_INVALID_PARAMETER
;
928 } else if (Action
== EFI_BROWSER_ACTION_CHANGED
) {
929 if ((Value
== NULL
) || (ActionRequest
== NULL
)) {
930 return EFI_INVALID_PARAMETER
;
932 if ((QuestionId
>= USER_VARIABLE_QUESTION_ID
) && (QuestionId
< USER_VARIABLE_QUESTION_ID
+ MAX_USER_VARIABLE_COUNT
)) {
935 // Means one user variable checkbox is marked to delete but not press F10 or "Commit Changes and Exit" menu.
937 mMarkedUserVariableCount
++;
938 ASSERT (mMarkedUserVariableCount
<= mUserVariableCount
);
939 if (mMarkedUserVariableCount
== mUserVariableCount
) {
941 // All user variables have been marked, then also mark the SelectAll checkbox.
943 VariableCleanupData
->SelectAll
= TRUE
;
947 // Means one user variable checkbox is unmarked.
949 mMarkedUserVariableCount
--;
951 // Also unmark the SelectAll checkbox.
953 VariableCleanupData
->SelectAll
= FALSE
;
956 switch (QuestionId
) {
957 case SELECT_ALL_QUESTION_ID
:
960 // Means the SelectAll checkbox is marked to delete all user variables but not press F10 or "Commit Changes and Exit" menu.
962 SetMem (VariableCleanupData
->UserVariable
, sizeof (VariableCleanupData
->UserVariable
), TRUE
);
963 mMarkedUserVariableCount
= mUserVariableCount
;
966 // Means the SelectAll checkbox is unmarked.
968 SetMem (VariableCleanupData
->UserVariable
, sizeof (VariableCleanupData
->UserVariable
), FALSE
);
969 mMarkedUserVariableCount
= 0;
972 case SAVE_AND_EXIT_QUESTION_ID
:
973 DeleteUserVariable (FALSE
, VariableCleanupData
);
974 *ActionRequest
= EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT
;
977 case NO_SAVE_AND_EXIT_QUESTION_ID
:
979 // Restore local maintain data.
981 *ActionRequest
= EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT
;
991 // Pass changed uncommitted data back to Form Browser.
993 HiiSetBrowserData (&mVariableCleanupHiiGuid
, mVarStoreName
, sizeof (VARIABLE_CLEANUP_DATA
), (UINT8
*) VariableCleanupData
, NULL
);
998 Platform variable cleanup.
1000 @param[in] Flag Variable error flag.
1001 @param[in] Type Variable cleanup type.
1002 If it is VarCleanupManually, the interface must be called after console connected.
1004 @retval EFI_SUCCESS No error or error processed.
1005 @retval EFI_UNSUPPORTED The specified Flag or Type is not supported.
1006 For example, system error may be not supported to process and Platform should have mechanism to reset system to manufacture mode.
1007 Another, if system and user variables are wanted to be distinguished to process, the interface must be called after EndOfDxe.
1008 @retval EFI_OUT_OF_RESOURCES Not enough resource to process the error.
1009 @retval EFI_INVALID_PARAMETER The specified Flag or Type is an invalid value.
1010 @retval Others Other failure occurs.
1015 PlatformVarCleanup (
1016 IN VAR_ERROR_FLAG Flag
,
1017 IN VAR_CLEANUP_TYPE Type
1021 EFI_FORM_BROWSER2_PROTOCOL
*FormBrowser2
;
1022 VARIABLE_CLEANUP_HII_PRIVATE_DATA
*Private
;
1026 // This implementation must be called after EndOfDxe.
1028 return EFI_UNSUPPORTED
;
1031 if ((Type
>= VarCleanupMax
) || ((Flag
& ((VAR_ERROR_FLAG
) (VAR_ERROR_FLAG_SYSTEM_ERROR
& VAR_ERROR_FLAG_USER_ERROR
))) == 0)) {
1032 return EFI_INVALID_PARAMETER
;
1035 if (Flag
== VAR_ERROR_FLAG_NO_ERROR
) {
1037 // Just return success if no error.
1042 if ((Flag
& (~((VAR_ERROR_FLAG
) VAR_ERROR_FLAG_SYSTEM_ERROR
))) == 0) {
1044 // This sample does not support system variables cleanup.
1046 DEBUG ((EFI_D_ERROR
, "NOTICE - VAR_ERROR_FLAG_SYSTEM_ERROR\n"));
1047 DEBUG ((EFI_D_ERROR
, "Platform should have mechanism to reset system to manufacture mode\n"));
1048 return EFI_UNSUPPORTED
;
1052 // Continue to process VAR_ERROR_FLAG_USER_ERROR.
1056 // Create user variable nodes for the following processing.
1058 CreateUserVariableNode ();
1062 DeleteUserVariable (TRUE
, NULL
);
1064 // Destroyed the created user variable nodes
1066 DestroyUserVariableNode ();
1070 case VarCleanupManually
:
1072 // Locate FormBrowser2 protocol.
1074 Status
= gBS
->LocateProtocol (&gEfiFormBrowser2ProtocolGuid
, NULL
, (VOID
**) &FormBrowser2
);
1075 if (EFI_ERROR (Status
)) {
1079 Private
= AllocateZeroPool (sizeof (VARIABLE_CLEANUP_HII_PRIVATE_DATA
));
1080 if (Private
== NULL
) {
1081 return EFI_OUT_OF_RESOURCES
;
1084 Private
->Signature
= VARIABLE_CLEANUP_HII_PRIVATE_SIGNATURE
;
1085 Private
->ConfigAccess
.ExtractConfig
= VariableCleanupHiiExtractConfig
;
1086 Private
->ConfigAccess
.RouteConfig
= VariableCleanupHiiRouteConfig
;
1087 Private
->ConfigAccess
.Callback
= VariableCleanupHiiCallback
;
1089 Status
= gBS
->LocateProtocol (
1090 &gEfiHiiConfigRoutingProtocolGuid
,
1092 (VOID
**) &Private
->ConfigRouting
1094 if (EFI_ERROR (Status
)) {
1099 // Install Device Path Protocol and Config Access protocol to driver handle.
1101 Status
= gBS
->InstallMultipleProtocolInterfaces (
1102 &Private
->DriverHandle
,
1103 &gEfiDevicePathProtocolGuid
,
1104 &mVarCleanupHiiVendorDevicePath
,
1105 &gEfiHiiConfigAccessProtocolGuid
,
1106 &Private
->ConfigAccess
,
1109 if (EFI_ERROR (Status
)) {
1114 // Publish our HII data.
1116 Private
->HiiHandle
= HiiAddPackages (
1117 &mVariableCleanupHiiGuid
,
1118 Private
->DriverHandle
,
1119 PlatformVarCleanupLibStrings
,
1123 if (Private
->HiiHandle
== NULL
) {
1124 Status
= EFI_OUT_OF_RESOURCES
;
1128 UpdateUserVariableForm (Private
);
1130 Status
= FormBrowser2
->SendForm (
1132 &Private
->HiiHandle
,
1142 return EFI_UNSUPPORTED
;
1147 if (Private
->DriverHandle
!= NULL
) {
1148 gBS
->UninstallMultipleProtocolInterfaces (
1149 Private
->DriverHandle
,
1150 &gEfiDevicePathProtocolGuid
,
1151 &mVarCleanupHiiVendorDevicePath
,
1152 &gEfiHiiConfigAccessProtocolGuid
,
1153 &Private
->ConfigAccess
,
1157 if (Private
->HiiHandle
!= NULL
) {
1158 HiiRemovePackages (Private
->HiiHandle
);
1164 // Destroyed the created user variable nodes
1166 DestroyUserVariableNode ();
1171 Get last boot variable error flag.
1173 @return Last boot variable error flag.
1178 GetLastBootVarErrorFlag (
1181 return mLastVarErrorFlag
;
1185 Notification function of END_OF_DXE.
1187 This is a notification function registered on END_OF_DXE event.
1189 @param[in] Event Event whose notification function is being invoked.
1190 @param[in] Context Pointer to the notification function's context.
1195 PlatformVarCleanupEndOfDxeEvent (
1204 The constructor function caches the pointer to VarCheck protocol and last boot variable error flag.
1206 The constructor function locates VarCheck protocol from protocol database.
1207 It will ASSERT() if that operation fails and it will always return EFI_SUCCESS.
1209 @param ImageHandle The firmware allocated handle for the EFI image.
1210 @param SystemTable A pointer to the EFI System Table.
1212 @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
1217 PlatformVarCleanupLibConstructor (
1218 IN EFI_HANDLE ImageHandle
,
1219 IN EFI_SYSTEM_TABLE
*SystemTable
1225 mLastVarErrorFlag
= InternalGetVarErrorFlag ();
1226 DEBUG ((EFI_D_INFO
, "mLastVarErrorFlag - 0x%02x\n", mLastVarErrorFlag
));
1228 Status
= gBS
->LocateProtocol (
1229 &gEdkiiVarCheckProtocolGuid
,
1231 (VOID
**) &mVarCheck
1233 ASSERT_EFI_ERROR (Status
);
1236 // Register EFI_END_OF_DXE_EVENT_GROUP_GUID event.
1238 Status
= gBS
->CreateEventEx (
1241 PlatformVarCleanupEndOfDxeEvent
,
1243 &gEfiEndOfDxeEventGroupGuid
,
1246 ASSERT_EFI_ERROR (Status
);