2 Sample platform variable cleanup library implementation.
4 Copyright (c) 2015 - 2017, 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 EFI_EVENT mPlatVarCleanupLibEndOfDxeEvent
= NULL
;
27 LIST_ENTRY mUserVariableList
= INITIALIZE_LIST_HEAD_VARIABLE (mUserVariableList
);
28 UINT16 mUserVariableCount
= 0;
29 UINT16 mMarkedUserVariableCount
= 0;
31 EFI_GUID mVariableCleanupHiiGuid
= VARIABLE_CLEANUP_HII_GUID
;
32 CHAR16 mVarStoreName
[] = L
"VariableCleanup";
34 HII_VENDOR_DEVICE_PATH mVarCleanupHiiVendorDevicePath
= {
40 (UINT8
) (sizeof (VENDOR_DEVICE_PATH
)),
41 (UINT8
) ((sizeof (VENDOR_DEVICE_PATH
)) >> 8)
44 VARIABLE_CLEANUP_HII_GUID
48 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
50 (UINT8
) (sizeof (EFI_DEVICE_PATH_PROTOCOL
)),
51 (UINT8
) ((sizeof (EFI_DEVICE_PATH_PROTOCOL
)) >> 8)
57 Internal get variable error flag.
59 @return Variable error flag.
63 InternalGetVarErrorFlag (
69 VAR_ERROR_FLAG ErrorFlag
;
71 Size
= sizeof (ErrorFlag
);
72 Status
= gRT
->GetVariable (
74 &gEdkiiVarErrorFlagGuid
,
79 if (EFI_ERROR (Status
)) {
80 DEBUG ((EFI_D_INFO
, "%s - not found\n", VAR_ERROR_FLAG_NAME
));
81 return VAR_ERROR_FLAG_NO_ERROR
;
89 @param[in] Name Pointer to variable name.
90 @param[in] Guid Pointer to vendor guid.
92 @retval TRUE User variable.
93 @retval FALSE System variable.
103 VAR_CHECK_VARIABLE_PROPERTY Property
;
105 if (mVarCheck
== NULL
) {
106 gBS
->LocateProtocol (
107 &gEdkiiVarCheckProtocolGuid
,
112 ASSERT (mVarCheck
!= NULL
);
114 ZeroMem (&Property
, sizeof (Property
));
115 Status
= mVarCheck
->VariablePropertyGet (
120 if (EFI_ERROR (Status
)) {
122 // No property, it is user variable.
124 DEBUG ((EFI_D_INFO
, "PlatformVarCleanup - User variable: %g:%s\n", Guid
, Name
));
128 // DEBUG ((EFI_D_INFO, "PlatformVarCleanup - Variable Property: %g:%s\n", Guid, Name));
129 // DEBUG ((EFI_D_INFO, " Revision - 0x%04x\n", Property.Revision));
130 // DEBUG ((EFI_D_INFO, " Property - 0x%04x\n", Property.Property));
131 // DEBUG ((EFI_D_INFO, " Attribute - 0x%08x\n", Property.Attributes));
132 // DEBUG ((EFI_D_INFO, " MinSize - 0x%x\n", Property.MinSize));
133 // DEBUG ((EFI_D_INFO, " MaxSize - 0x%x\n", Property.MaxSize));
139 Find user variable node by variable GUID.
141 @param[in] Guid Pointer to vendor guid.
143 @return Pointer to user variable node.
147 FindUserVariableNodeByGuid (
151 USER_VARIABLE_NODE
*UserVariableNode
;
154 for (Link
= mUserVariableList
.ForwardLink
155 ;Link
!= &mUserVariableList
156 ;Link
= Link
->ForwardLink
) {
157 UserVariableNode
= USER_VARIABLE_FROM_LINK (Link
);
159 if (CompareGuid (Guid
, &UserVariableNode
->Guid
)) {
163 return UserVariableNode
;
168 // Create new one if not found.
170 UserVariableNode
= AllocateZeroPool (sizeof (*UserVariableNode
));
171 ASSERT (UserVariableNode
!= NULL
);
172 UserVariableNode
->Signature
= USER_VARIABLE_NODE_SIGNATURE
;
173 CopyGuid (&UserVariableNode
->Guid
, Guid
);
175 // (36 chars of "########-####-####-####-############" + 1 space + 1 terminator) * sizeof (CHAR16).
177 UserVariableNode
->PromptString
= AllocatePool ((36 + 2) * sizeof (CHAR16
));
178 ASSERT (UserVariableNode
->PromptString
!= NULL
);
179 UnicodeSPrint (UserVariableNode
->PromptString
, (36 + 2) * sizeof (CHAR16
), L
" %g", &UserVariableNode
->Guid
);
180 InitializeListHead (&UserVariableNode
->NameLink
);
181 InsertTailList (&mUserVariableList
, &UserVariableNode
->Link
);
182 return UserVariableNode
;
186 Create user variable node.
190 CreateUserVariableNode (
195 EFI_STATUS GetVariableStatus
;
197 UINTN MaxVarNameSize
;
204 USER_VARIABLE_NODE
*UserVariableNode
;
205 USER_VARIABLE_NAME_NODE
*UserVariableNameNode
;
210 // Initialize 128 * sizeof (CHAR16) variable name size.
212 MaxVarNameSize
= 128 * sizeof (CHAR16
);
213 VarName
= AllocateZeroPool (MaxVarNameSize
);
214 ASSERT (VarName
!= NULL
);
217 // Initialize 0x1000 variable data size.
219 MaxDataSize
= 0x1000;
220 Data
= AllocateZeroPool (MaxDataSize
);
221 ASSERT (Data
!= NULL
);
225 VarNameSize
= MaxVarNameSize
;
226 Status
= gRT
->GetNextVariableName (&VarNameSize
, VarName
, &Guid
);
227 if (Status
== EFI_BUFFER_TOO_SMALL
) {
228 VarName
= ReallocatePool (MaxVarNameSize
, VarNameSize
, VarName
);
229 ASSERT (VarName
!= NULL
);
230 MaxVarNameSize
= VarNameSize
;
231 Status
= gRT
->GetNextVariableName (&VarNameSize
, VarName
, &Guid
);
234 if (!EFI_ERROR (Status
)) {
235 if (IsUserVariable (VarName
, &Guid
)) {
236 DataSize
= MaxDataSize
;
237 GetVariableStatus
= gRT
->GetVariable (VarName
, &Guid
, &Attributes
, &DataSize
, Data
);
238 if (GetVariableStatus
== EFI_BUFFER_TOO_SMALL
) {
239 Data
= ReallocatePool (MaxDataSize
, DataSize
, Data
);
240 ASSERT (Data
!= NULL
);
241 MaxDataSize
= DataSize
;
242 GetVariableStatus
= gRT
->GetVariable (VarName
, &Guid
, &Attributes
, &DataSize
, Data
);
244 ASSERT_EFI_ERROR (GetVariableStatus
);
246 if ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) != 0) {
247 UserVariableNode
= FindUserVariableNodeByGuid (&Guid
);
248 ASSERT (UserVariableNode
!= NULL
);
251 // Different variables that have same variable GUID share same user variable node.
253 UserVariableNameNode
= AllocateZeroPool (sizeof (*UserVariableNameNode
));
254 ASSERT (UserVariableNameNode
!= NULL
);
255 UserVariableNameNode
->Signature
= USER_VARIABLE_NAME_NODE_SIGNATURE
;
256 UserVariableNameNode
->Name
= AllocateCopyPool (VarNameSize
, VarName
);
257 UserVariableNameNode
->Attributes
= Attributes
;
258 UserVariableNameNode
->DataSize
= DataSize
;
259 UserVariableNameNode
->Index
= Index
;
260 UserVariableNameNode
->QuestionId
= (EFI_QUESTION_ID
) (USER_VARIABLE_QUESTION_ID
+ Index
);
262 // 2 space * sizeof (CHAR16) + StrSize.
264 StringSize
= 2 * sizeof (CHAR16
) + StrSize (UserVariableNameNode
->Name
);
265 UserVariableNameNode
->PromptString
= AllocatePool (StringSize
);
266 ASSERT (UserVariableNameNode
->PromptString
!= NULL
);
267 UnicodeSPrint (UserVariableNameNode
->PromptString
, StringSize
, L
" %s", UserVariableNameNode
->Name
);
269 // (33 chars of "Attribtues = 0x and DataSize = 0x" + 1 terminator + (sizeof (UINT32) + sizeof (UINTN)) * 2) * sizeof (CHAR16).
271 StringSize
= (33 + 1 + (sizeof (UINT32
) + sizeof (UINTN
)) * 2) * sizeof (CHAR16
);
272 UserVariableNameNode
->HelpString
= AllocatePool (StringSize
);
273 ASSERT (UserVariableNameNode
->HelpString
!= NULL
);
274 UnicodeSPrint (UserVariableNameNode
->HelpString
, StringSize
, L
"Attribtues = 0x%08x and DataSize = 0x%x", UserVariableNameNode
->Attributes
, UserVariableNameNode
->DataSize
);
275 UserVariableNameNode
->Deleted
= FALSE
;
276 InsertTailList (&UserVariableNode
->NameLink
, &UserVariableNameNode
->Link
);
281 } while (Status
!= EFI_NOT_FOUND
);
283 mUserVariableCount
= Index
;
284 ASSERT (mUserVariableCount
<= MAX_USER_VARIABLE_COUNT
);
285 DEBUG ((EFI_D_INFO
, "PlatformVarCleanup - User variable count: 0x%04x\n", mUserVariableCount
));
292 Destroy user variable nodes.
296 DestroyUserVariableNode (
300 USER_VARIABLE_NODE
*UserVariableNode
;
302 USER_VARIABLE_NAME_NODE
*UserVariableNameNode
;
303 LIST_ENTRY
*NameLink
;
305 while (mUserVariableList
.ForwardLink
!= &mUserVariableList
) {
306 Link
= mUserVariableList
.ForwardLink
;
307 UserVariableNode
= USER_VARIABLE_FROM_LINK (Link
);
309 RemoveEntryList (&UserVariableNode
->Link
);
311 while (UserVariableNode
->NameLink
.ForwardLink
!= &UserVariableNode
->NameLink
) {
312 NameLink
= UserVariableNode
->NameLink
.ForwardLink
;
313 UserVariableNameNode
= USER_VARIABLE_NAME_FROM_LINK (NameLink
);
315 RemoveEntryList (&UserVariableNameNode
->Link
);
317 FreePool (UserVariableNameNode
->Name
);
318 FreePool (UserVariableNameNode
->PromptString
);
319 FreePool (UserVariableNameNode
->HelpString
);
320 FreePool (UserVariableNameNode
);
323 FreePool (UserVariableNode
->PromptString
);
324 FreePool (UserVariableNode
);
329 Create a time based data payload by concatenating the EFI_VARIABLE_AUTHENTICATION_2
330 descriptor with the input data. NO authentication is required in this function.
332 @param[in, out] DataSize On input, the size of Data buffer in bytes.
333 On output, the size of data returned in Data
335 @param[in, out] Data On input, Pointer to data buffer to be wrapped or
336 pointer to NULL to wrap an empty payload.
337 On output, Pointer to the new payload date buffer allocated from pool,
338 it's caller's responsibility to free the memory after using it.
340 @retval EFI_SUCCESS Create time based payload successfully.
341 @retval EFI_OUT_OF_RESOURCES There are not enough memory resourses to create time based payload.
342 @retval EFI_INVALID_PARAMETER The parameter is invalid.
343 @retval Others Unexpected error happens.
347 CreateTimeBasedPayload (
348 IN OUT UINTN
*DataSize
,
356 EFI_VARIABLE_AUTHENTICATION_2
*DescriptorData
;
357 UINTN DescriptorSize
;
360 if (Data
== NULL
|| DataSize
== NULL
) {
361 return EFI_INVALID_PARAMETER
;
365 // At user physical presence, the variable does not need to be signed but the
366 // parameters to the SetVariable() call still need to be prepared as authenticated
367 // variable. So we create EFI_VARIABLE_AUTHENTICATED_2 descriptor without certificate
371 PayloadSize
= *DataSize
;
373 DescriptorSize
= OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2
, AuthInfo
) + OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID
, CertData
);
374 NewData
= (UINT8
*) AllocateZeroPool (DescriptorSize
+ PayloadSize
);
375 if (NewData
== NULL
) {
376 return EFI_OUT_OF_RESOURCES
;
379 if ((Payload
!= NULL
) && (PayloadSize
!= 0)) {
380 CopyMem (NewData
+ DescriptorSize
, Payload
, PayloadSize
);
383 DescriptorData
= (EFI_VARIABLE_AUTHENTICATION_2
*) (NewData
);
385 ZeroMem (&Time
, sizeof (EFI_TIME
));
386 Status
= gRT
->GetTime (&Time
, NULL
);
387 if (EFI_ERROR (Status
)) {
396 CopyMem (&DescriptorData
->TimeStamp
, &Time
, sizeof (EFI_TIME
));
398 DescriptorData
->AuthInfo
.Hdr
.dwLength
= OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID
, CertData
);
399 DescriptorData
->AuthInfo
.Hdr
.wRevision
= 0x0200;
400 DescriptorData
->AuthInfo
.Hdr
.wCertificateType
= WIN_CERT_TYPE_EFI_GUID
;
401 CopyGuid (&DescriptorData
->AuthInfo
.CertType
, &gEfiCertPkcs7Guid
);
403 if (Payload
!= NULL
) {
407 *DataSize
= DescriptorSize
+ PayloadSize
;
413 Create a counter based data payload by concatenating the EFI_VARIABLE_AUTHENTICATION
414 descriptor with the input data. NO authentication is required in this function.
416 @param[in, out] DataSize On input, the size of Data buffer in bytes.
417 On output, the size of data returned in Data
419 @param[in, out] Data On input, Pointer to data buffer to be wrapped or
420 pointer to NULL to wrap an empty payload.
421 On output, Pointer to the new payload date buffer allocated from pool,
422 it's caller's responsibility to free the memory after using it.
424 @retval EFI_SUCCESS Create counter based payload successfully.
425 @retval EFI_OUT_OF_RESOURCES There are not enough memory resourses to create time based payload.
426 @retval EFI_INVALID_PARAMETER The parameter is invalid.
427 @retval Others Unexpected error happens.
431 CreateCounterBasedPayload (
432 IN OUT UINTN
*DataSize
,
440 EFI_VARIABLE_AUTHENTICATION
*DescriptorData
;
441 UINTN DescriptorSize
;
442 UINT64 MonotonicCount
;
444 if (Data
== NULL
|| DataSize
== NULL
) {
445 return EFI_INVALID_PARAMETER
;
449 // At user physical presence, the variable does not need to be signed but the
450 // parameters to the SetVariable() call still need to be prepared as authenticated
451 // variable. So we create EFI_VARIABLE_AUTHENTICATED descriptor without certificate
455 PayloadSize
= *DataSize
;
457 DescriptorSize
= (OFFSET_OF (EFI_VARIABLE_AUTHENTICATION
, AuthInfo
)) + \
458 (OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID
, CertData
)) + \
459 sizeof (EFI_CERT_BLOCK_RSA_2048_SHA256
);
460 NewData
= (UINT8
*) AllocateZeroPool (DescriptorSize
+ PayloadSize
);
461 if (NewData
== NULL
) {
462 return EFI_OUT_OF_RESOURCES
;
465 if ((Payload
!= NULL
) && (PayloadSize
!= 0)) {
466 CopyMem (NewData
+ DescriptorSize
, Payload
, PayloadSize
);
469 DescriptorData
= (EFI_VARIABLE_AUTHENTICATION
*) (NewData
);
471 Status
= gBS
->GetNextMonotonicCount (&MonotonicCount
);
472 if (EFI_ERROR (Status
)) {
476 DescriptorData
->MonotonicCount
= MonotonicCount
;
478 DescriptorData
->AuthInfo
.Hdr
.dwLength
= OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID
, CertData
) + sizeof (EFI_CERT_BLOCK_RSA_2048_SHA256
);
479 DescriptorData
->AuthInfo
.Hdr
.wRevision
= 0x0200;
480 DescriptorData
->AuthInfo
.Hdr
.wCertificateType
= WIN_CERT_TYPE_EFI_GUID
;
481 CopyGuid (&DescriptorData
->AuthInfo
.CertType
, &gEfiCertTypeRsa2048Sha256Guid
);
483 if (Payload
!= NULL
) {
487 *DataSize
= DescriptorSize
+ PayloadSize
;
493 Delete user variable.
495 @param[in] DeleteAll Delete all user variables.
496 @param[in] VariableCleanupData Pointer to variable cleanup data.
501 IN BOOLEAN DeleteAll
,
502 IN VARIABLE_CLEANUP_DATA
*VariableCleanupData OPTIONAL
506 USER_VARIABLE_NODE
*UserVariableNode
;
508 USER_VARIABLE_NAME_NODE
*UserVariableNameNode
;
509 LIST_ENTRY
*NameLink
;
513 for (Link
= mUserVariableList
.ForwardLink
514 ;Link
!= &mUserVariableList
515 ;Link
= Link
->ForwardLink
) {
516 UserVariableNode
= USER_VARIABLE_FROM_LINK (Link
);
518 for (NameLink
= UserVariableNode
->NameLink
.ForwardLink
519 ;NameLink
!= &UserVariableNode
->NameLink
520 ;NameLink
= NameLink
->ForwardLink
) {
521 UserVariableNameNode
= USER_VARIABLE_NAME_FROM_LINK (NameLink
);
523 if (!UserVariableNameNode
->Deleted
&& (DeleteAll
|| ((VariableCleanupData
!= NULL
) && (VariableCleanupData
->UserVariable
[UserVariableNameNode
->Index
] == TRUE
)))) {
524 DEBUG ((EFI_D_INFO
, "PlatformVarCleanup - Delete variable: %g:%s\n", &UserVariableNode
->Guid
, UserVariableNameNode
->Name
));
525 if ((UserVariableNameNode
->Attributes
& EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) != 0) {
528 Status
= CreateTimeBasedPayload (&DataSize
, &Data
);
529 if (!EFI_ERROR (Status
)) {
530 Status
= gRT
->SetVariable (UserVariableNameNode
->Name
, &UserVariableNode
->Guid
, UserVariableNameNode
->Attributes
, DataSize
, Data
);
533 } else if ((UserVariableNameNode
->Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) != 0) {
536 Status
= CreateCounterBasedPayload (&DataSize
, &Data
);
537 if (!EFI_ERROR (Status
)) {
538 Status
= gRT
->SetVariable (UserVariableNameNode
->Name
, &UserVariableNode
->Guid
, UserVariableNameNode
->Attributes
, DataSize
, Data
);
542 Status
= gRT
->SetVariable (UserVariableNameNode
->Name
, &UserVariableNode
->Guid
, 0, 0, NULL
);
544 if (!EFI_ERROR (Status
)) {
545 UserVariableNameNode
->Deleted
= TRUE
;
547 DEBUG ((EFI_D_INFO
, "PlatformVarCleanup - Delete variable fail: %g:%s\n", &UserVariableNode
->Guid
, UserVariableNameNode
->Name
));
555 This function allows a caller to extract the current configuration for one
556 or more named elements from the target driver.
558 @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
559 @param[in] Request A null-terminated Unicode string in <ConfigRequest> format.
560 @param[out] Progress On return, points to a character in the Request string.
561 Points to the string's null terminator if request was successful.
562 Points to the most recent '&' before the first failing name/value
563 pair (or the beginning of the string if the failure is in the
564 first name/value pair) if the request was not successful.
565 @param[out] Results A null-terminated Unicode string in <ConfigAltResp> format which
566 has all values filled in for the names in the Request string.
567 String to be allocated by the called function.
569 @retval EFI_SUCCESS The Results is filled with the requested values.
570 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results.
571 @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name.
572 @retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver.
577 VariableCleanupHiiExtractConfig (
578 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL
*This
,
579 IN CONST EFI_STRING Request
,
580 OUT EFI_STRING
*Progress
,
581 OUT EFI_STRING
*Results
585 VARIABLE_CLEANUP_HII_PRIVATE_DATA
*Private
;
587 EFI_STRING ConfigRequestHdr
;
588 EFI_STRING ConfigRequest
;
589 BOOLEAN AllocatedRequest
;
592 if (Progress
== NULL
|| Results
== NULL
) {
593 return EFI_INVALID_PARAMETER
;
597 if ((Request
!= NULL
) && !HiiIsConfigHdrMatch (Request
, &mVariableCleanupHiiGuid
, mVarStoreName
)) {
598 return EFI_NOT_FOUND
;
601 ConfigRequestHdr
= NULL
;
602 ConfigRequest
= NULL
;
603 AllocatedRequest
= FALSE
;
606 Private
= VARIABLE_CLEANUP_HII_PRIVATE_FROM_THIS (This
);
608 // Convert buffer data to <ConfigResp> by helper function BlockToConfig().
610 BufferSize
= sizeof (VARIABLE_CLEANUP_DATA
);
611 ConfigRequest
= Request
;
612 if ((Request
== NULL
) || (StrStr (Request
, L
"OFFSET") == NULL
)) {
614 // Request has no request element, construct full request string.
615 // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
616 // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator.
618 ConfigRequestHdr
= HiiConstructConfigHdr (&mVariableCleanupHiiGuid
, mVarStoreName
, Private
->HiiHandle
);
619 Size
= (StrLen (ConfigRequestHdr
) + 32 + 1) * sizeof (CHAR16
);
620 ConfigRequest
= AllocateZeroPool (Size
);
621 ASSERT (ConfigRequest
!= NULL
);
622 AllocatedRequest
= TRUE
;
623 UnicodeSPrint (ConfigRequest
, Size
, L
"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr
, (UINT64
)BufferSize
);
624 FreePool (ConfigRequestHdr
);
627 Status
= Private
->ConfigRouting
->BlockToConfig (
628 Private
->ConfigRouting
,
630 (UINT8
*) &Private
->VariableCleanupData
,
635 ASSERT_EFI_ERROR (Status
);
638 // Free the allocated config request string.
640 if (AllocatedRequest
) {
641 FreePool (ConfigRequest
);
642 ConfigRequest
= NULL
;
645 // Set Progress string to the original request string or the string's null terminator.
647 if (Request
== NULL
) {
649 } else if (StrStr (Request
, L
"OFFSET") == NULL
) {
650 *Progress
= Request
+ StrLen (Request
);
657 Update user variable form.
659 @param[in] Private Points to the VARIABLE_CLEANUP_HII_PRIVATE_DATA.
663 UpdateUserVariableForm (
664 IN VARIABLE_CLEANUP_HII_PRIVATE_DATA
*Private
667 EFI_STRING_ID PromptStringToken
;
668 EFI_STRING_ID HelpStringToken
;
669 VOID
*StartOpCodeHandle
;
670 VOID
*EndOpCodeHandle
;
671 EFI_IFR_GUID_LABEL
*StartLabel
;
672 EFI_IFR_GUID_LABEL
*EndLabel
;
673 USER_VARIABLE_NODE
*UserVariableNode
;
675 USER_VARIABLE_NAME_NODE
*UserVariableNameNode
;
676 LIST_ENTRY
*NameLink
;
680 // Init OpCode Handle.
682 StartOpCodeHandle
= HiiAllocateOpCodeHandle ();
683 ASSERT (StartOpCodeHandle
!= NULL
);
685 EndOpCodeHandle
= HiiAllocateOpCodeHandle ();
686 ASSERT (EndOpCodeHandle
!= NULL
);
689 // Create Hii Extend Label OpCode as the start opcode.
691 StartLabel
= (EFI_IFR_GUID_LABEL
*) HiiCreateGuidOpCode (StartOpCodeHandle
, &gEfiIfrTianoGuid
, NULL
, sizeof (EFI_IFR_GUID_LABEL
));
692 StartLabel
->ExtendOpCode
= EFI_IFR_EXTEND_OP_LABEL
;
693 StartLabel
->Number
= LABEL_START
;
696 // Create Hii Extend Label OpCode as the end opcode.
698 EndLabel
= (EFI_IFR_GUID_LABEL
*) HiiCreateGuidOpCode (EndOpCodeHandle
, &gEfiIfrTianoGuid
, NULL
, sizeof (EFI_IFR_GUID_LABEL
));
699 EndLabel
->ExtendOpCode
= EFI_IFR_EXTEND_OP_LABEL
;
700 EndLabel
->Number
= LABEL_END
;
704 &mVariableCleanupHiiGuid
,
705 FORM_ID_VARIABLE_CLEANUP
,
706 StartOpCodeHandle
, // LABEL_START
707 EndOpCodeHandle
// LABEL_END
710 for (Link
= mUserVariableList
.ForwardLink
711 ;Link
!= &mUserVariableList
712 ;Link
= Link
->ForwardLink
) {
713 UserVariableNode
= USER_VARIABLE_FROM_LINK (Link
);
716 // Create checkbox opcode for variables in the same variable GUID space.
719 for (NameLink
= UserVariableNode
->NameLink
.ForwardLink
720 ;NameLink
!= &UserVariableNode
->NameLink
721 ;NameLink
= NameLink
->ForwardLink
) {
722 UserVariableNameNode
= USER_VARIABLE_NAME_FROM_LINK (NameLink
);
724 if (!UserVariableNameNode
->Deleted
) {
727 // Create subtitle opcode for variable GUID.
729 PromptStringToken
= HiiSetString (Private
->HiiHandle
, 0, UserVariableNode
->PromptString
, NULL
);
730 HiiCreateSubTitleOpCode (StartOpCodeHandle
, PromptStringToken
, 0, 0, 0);
735 // Only create opcode for the non-deleted variables.
737 PromptStringToken
= HiiSetString (Private
->HiiHandle
, 0, UserVariableNameNode
->PromptString
, NULL
);
738 HelpStringToken
= HiiSetString (Private
->HiiHandle
, 0, UserVariableNameNode
->HelpString
, NULL
);
739 HiiCreateCheckBoxOpCode (
741 UserVariableNameNode
->QuestionId
,
742 VARIABLE_CLEANUP_VARSTORE_ID
,
743 (UINT16
) (USER_VARIABLE_VAR_OFFSET
+ UserVariableNameNode
->Index
),
746 EFI_IFR_FLAG_CALLBACK
,
747 Private
->VariableCleanupData
.UserVariable
[UserVariableNameNode
->Index
],
754 HiiCreateSubTitleOpCode (
756 STRING_TOKEN (STR_NULL_STRING
),
763 // Create the "Apply changes" and "Discard changes" tags.
765 HiiCreateActionOpCode (
767 SAVE_AND_EXIT_QUESTION_ID
,
768 STRING_TOKEN (STR_SAVE_AND_EXIT
),
769 STRING_TOKEN (STR_NULL_STRING
),
770 EFI_IFR_FLAG_CALLBACK
,
773 HiiCreateActionOpCode (
775 NO_SAVE_AND_EXIT_QUESTION_ID
,
776 STRING_TOKEN (STR_NO_SAVE_AND_EXIT
),
777 STRING_TOKEN (STR_NULL_STRING
),
778 EFI_IFR_FLAG_CALLBACK
,
784 &mVariableCleanupHiiGuid
,
785 FORM_ID_VARIABLE_CLEANUP
,
786 StartOpCodeHandle
, // LABEL_START
787 EndOpCodeHandle
// LABEL_END
790 HiiFreeOpCodeHandle (StartOpCodeHandle
);
791 HiiFreeOpCodeHandle (EndOpCodeHandle
);
795 This function applies changes in a driver's configuration.
796 Input is a Configuration, which has the routing data for this
797 driver followed by name / value configuration pairs. The driver
798 must apply those pairs to its configurable storage. If the
799 driver's configuration is stored in a linear block of data
800 and the driver's name / value pairs are in <BlockConfig>
801 format, it may use the ConfigToBlock helper function (above) to
802 simplify the job. Currently not implemented.
804 @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
805 @param[in] Configuration A null-terminated Unicode string in
806 <ConfigString> format.
807 @param[out] Progress A pointer to a string filled in with the
808 offset of the most recent '&' before the
809 first failing name / value pair (or the
810 beginn ing of the string if the failure
811 is in the first name / value pair) or
812 the terminating NULL if all was
815 @retval EFI_SUCCESS The results have been distributed or are
816 awaiting distribution.
817 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the
818 parts of the results that must be
819 stored awaiting possible future
821 @retval EFI_INVALID_PARAMETERS Passing in a NULL for the
822 Results parameter would result
823 in this type of error.
824 @retval EFI_NOT_FOUND Target for the specified routing data
830 VariableCleanupHiiRouteConfig (
831 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL
*This
,
832 IN CONST EFI_STRING Configuration
,
833 OUT EFI_STRING
*Progress
837 VARIABLE_CLEANUP_HII_PRIVATE_DATA
*Private
;
840 if (Progress
== NULL
) {
841 return EFI_INVALID_PARAMETER
;
843 *Progress
= Configuration
;
845 if (Configuration
== NULL
) {
846 return EFI_INVALID_PARAMETER
;
850 // Check routing data in <ConfigHdr>.
851 // Note: there is no name for Name/Value storage, only GUID will be checked.
853 if (!HiiIsConfigHdrMatch (Configuration
, &mVariableCleanupHiiGuid
, mVarStoreName
)) {
854 return EFI_NOT_FOUND
;
857 Private
= VARIABLE_CLEANUP_HII_PRIVATE_FROM_THIS (This
);
859 // Get Buffer Storage data.
861 BufferSize
= sizeof (VARIABLE_CLEANUP_DATA
);
863 // Convert <ConfigResp> to buffer data by helper function ConfigToBlock().
865 Status
= Private
->ConfigRouting
->ConfigToBlock (
866 Private
->ConfigRouting
,
868 (UINT8
*) &Private
->VariableCleanupData
,
872 ASSERT_EFI_ERROR (Status
);
874 DeleteUserVariable (FALSE
, &Private
->VariableCleanupData
);
876 // For "F10" hotkey to refresh the form.
878 // UpdateUserVariableForm (Private);
884 This function is called to provide results data to the driver.
885 This data consists of a unique key that is used to identify
886 which data is either being passed back or being asked for.
888 @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
889 @param[in] Action Specifies the type of action taken by the browser.
890 @param[in] QuestionId A unique value which is sent to the original
891 exporting driver so that it can identify the type
892 of data to expect. The format of the data tends to
893 vary based on the opcode that generated the callback.
894 @param[in] Type The type of value for the question.
895 @param[in] Value A pointer to the data being sent to the original
897 @param[out] ActionRequest On return, points to the action requested by the
900 @retval EFI_SUCCESS The callback successfully handled the action.
901 @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the
902 variable and its data.
903 @retval EFI_DEVICE_ERROR The variable could not be saved.
904 @retval EFI_UNSUPPORTED The specified Action is not supported by the
909 VariableCleanupHiiCallback (
910 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL
*This
,
911 IN EFI_BROWSER_ACTION Action
,
912 IN EFI_QUESTION_ID QuestionId
,
914 IN EFI_IFR_TYPE_VALUE
*Value
,
915 OUT EFI_BROWSER_ACTION_REQUEST
*ActionRequest
918 VARIABLE_CLEANUP_HII_PRIVATE_DATA
*Private
;
919 VARIABLE_CLEANUP_DATA
*VariableCleanupData
;
921 Private
= VARIABLE_CLEANUP_HII_PRIVATE_FROM_THIS (This
);
923 if ((Action
!= EFI_BROWSER_ACTION_CHANGING
) && (Action
!= EFI_BROWSER_ACTION_CHANGED
)) {
925 // All other action return unsupported.
927 return EFI_UNSUPPORTED
;
931 // Retrieve uncommitted data from Form Browser.
933 VariableCleanupData
= &Private
->VariableCleanupData
;
934 HiiGetBrowserData (&mVariableCleanupHiiGuid
, mVarStoreName
, sizeof (VARIABLE_CLEANUP_DATA
), (UINT8
*) VariableCleanupData
);
935 if (Action
== EFI_BROWSER_ACTION_CHANGING
) {
937 return EFI_INVALID_PARAMETER
;
939 } else if (Action
== EFI_BROWSER_ACTION_CHANGED
) {
940 if ((Value
== NULL
) || (ActionRequest
== NULL
)) {
941 return EFI_INVALID_PARAMETER
;
943 if ((QuestionId
>= USER_VARIABLE_QUESTION_ID
) && (QuestionId
< USER_VARIABLE_QUESTION_ID
+ MAX_USER_VARIABLE_COUNT
)) {
946 // Means one user variable checkbox is marked to delete but not press F10 or "Commit Changes and Exit" menu.
948 mMarkedUserVariableCount
++;
949 ASSERT (mMarkedUserVariableCount
<= mUserVariableCount
);
950 if (mMarkedUserVariableCount
== mUserVariableCount
) {
952 // All user variables have been marked, then also mark the SelectAll checkbox.
954 VariableCleanupData
->SelectAll
= TRUE
;
958 // Means one user variable checkbox is unmarked.
960 mMarkedUserVariableCount
--;
962 // Also unmark the SelectAll checkbox.
964 VariableCleanupData
->SelectAll
= FALSE
;
967 switch (QuestionId
) {
968 case SELECT_ALL_QUESTION_ID
:
971 // Means the SelectAll checkbox is marked to delete all user variables but not press F10 or "Commit Changes and Exit" menu.
973 SetMem (VariableCleanupData
->UserVariable
, sizeof (VariableCleanupData
->UserVariable
), TRUE
);
974 mMarkedUserVariableCount
= mUserVariableCount
;
977 // Means the SelectAll checkbox is unmarked.
979 SetMem (VariableCleanupData
->UserVariable
, sizeof (VariableCleanupData
->UserVariable
), FALSE
);
980 mMarkedUserVariableCount
= 0;
983 case SAVE_AND_EXIT_QUESTION_ID
:
984 DeleteUserVariable (FALSE
, VariableCleanupData
);
985 *ActionRequest
= EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT
;
988 case NO_SAVE_AND_EXIT_QUESTION_ID
:
990 // Restore local maintain data.
992 *ActionRequest
= EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT
;
1002 // Pass changed uncommitted data back to Form Browser.
1004 HiiSetBrowserData (&mVariableCleanupHiiGuid
, mVarStoreName
, sizeof (VARIABLE_CLEANUP_DATA
), (UINT8
*) VariableCleanupData
, NULL
);
1009 Platform variable cleanup.
1011 @param[in] Flag Variable error flag.
1012 @param[in] Type Variable cleanup type.
1013 If it is VarCleanupManually, the interface must be called after console connected.
1015 @retval EFI_SUCCESS No error or error processed.
1016 @retval EFI_UNSUPPORTED The specified Flag or Type is not supported.
1017 For example, system error may be not supported to process and Platform should have mechanism to reset system to manufacture mode.
1018 Another, if system and user variables are wanted to be distinguished to process, the interface must be called after EndOfDxe.
1019 @retval EFI_OUT_OF_RESOURCES Not enough resource to process the error.
1020 @retval EFI_INVALID_PARAMETER The specified Flag or Type is an invalid value.
1021 @retval Others Other failure occurs.
1026 PlatformVarCleanup (
1027 IN VAR_ERROR_FLAG Flag
,
1028 IN VAR_CLEANUP_TYPE Type
1032 EFI_FORM_BROWSER2_PROTOCOL
*FormBrowser2
;
1033 VARIABLE_CLEANUP_HII_PRIVATE_DATA
*Private
;
1037 // This implementation must be called after EndOfDxe.
1039 return EFI_UNSUPPORTED
;
1042 if ((Type
>= VarCleanupMax
) || ((Flag
& ((VAR_ERROR_FLAG
) (VAR_ERROR_FLAG_SYSTEM_ERROR
& VAR_ERROR_FLAG_USER_ERROR
))) == 0)) {
1043 return EFI_INVALID_PARAMETER
;
1046 if (Flag
== VAR_ERROR_FLAG_NO_ERROR
) {
1048 // Just return success if no error.
1053 if ((Flag
& (~((VAR_ERROR_FLAG
) VAR_ERROR_FLAG_SYSTEM_ERROR
))) == 0) {
1055 // This sample does not support system variables cleanup.
1057 DEBUG ((EFI_D_ERROR
, "NOTICE - VAR_ERROR_FLAG_SYSTEM_ERROR\n"));
1058 DEBUG ((EFI_D_ERROR
, "Platform should have mechanism to reset system to manufacture mode\n"));
1059 return EFI_UNSUPPORTED
;
1063 // Continue to process VAR_ERROR_FLAG_USER_ERROR.
1067 // Create user variable nodes for the following processing.
1069 CreateUserVariableNode ();
1073 DeleteUserVariable (TRUE
, NULL
);
1075 // Destroyed the created user variable nodes
1077 DestroyUserVariableNode ();
1081 case VarCleanupManually
:
1083 // Locate FormBrowser2 protocol.
1085 Status
= gBS
->LocateProtocol (&gEfiFormBrowser2ProtocolGuid
, NULL
, (VOID
**) &FormBrowser2
);
1086 if (EFI_ERROR (Status
)) {
1090 Private
= AllocateZeroPool (sizeof (VARIABLE_CLEANUP_HII_PRIVATE_DATA
));
1091 if (Private
== NULL
) {
1092 return EFI_OUT_OF_RESOURCES
;
1095 Private
->Signature
= VARIABLE_CLEANUP_HII_PRIVATE_SIGNATURE
;
1096 Private
->ConfigAccess
.ExtractConfig
= VariableCleanupHiiExtractConfig
;
1097 Private
->ConfigAccess
.RouteConfig
= VariableCleanupHiiRouteConfig
;
1098 Private
->ConfigAccess
.Callback
= VariableCleanupHiiCallback
;
1100 Status
= gBS
->LocateProtocol (
1101 &gEfiHiiConfigRoutingProtocolGuid
,
1103 (VOID
**) &Private
->ConfigRouting
1105 if (EFI_ERROR (Status
)) {
1110 // Install Device Path Protocol and Config Access protocol to driver handle.
1112 Status
= gBS
->InstallMultipleProtocolInterfaces (
1113 &Private
->DriverHandle
,
1114 &gEfiDevicePathProtocolGuid
,
1115 &mVarCleanupHiiVendorDevicePath
,
1116 &gEfiHiiConfigAccessProtocolGuid
,
1117 &Private
->ConfigAccess
,
1120 if (EFI_ERROR (Status
)) {
1125 // Publish our HII data.
1127 Private
->HiiHandle
= HiiAddPackages (
1128 &mVariableCleanupHiiGuid
,
1129 Private
->DriverHandle
,
1130 PlatformVarCleanupLibStrings
,
1134 if (Private
->HiiHandle
== NULL
) {
1135 Status
= EFI_OUT_OF_RESOURCES
;
1139 UpdateUserVariableForm (Private
);
1141 Status
= FormBrowser2
->SendForm (
1143 &Private
->HiiHandle
,
1153 return EFI_UNSUPPORTED
;
1158 if (Private
->DriverHandle
!= NULL
) {
1159 gBS
->UninstallMultipleProtocolInterfaces (
1160 Private
->DriverHandle
,
1161 &gEfiDevicePathProtocolGuid
,
1162 &mVarCleanupHiiVendorDevicePath
,
1163 &gEfiHiiConfigAccessProtocolGuid
,
1164 &Private
->ConfigAccess
,
1168 if (Private
->HiiHandle
!= NULL
) {
1169 HiiRemovePackages (Private
->HiiHandle
);
1175 // Destroyed the created user variable nodes
1177 DestroyUserVariableNode ();
1182 Get last boot variable error flag.
1184 @return Last boot variable error flag.
1189 GetLastBootVarErrorFlag (
1192 return mLastVarErrorFlag
;
1196 Notification function of END_OF_DXE.
1198 This is a notification function registered on END_OF_DXE event.
1200 @param[in] Event Event whose notification function is being invoked.
1201 @param[in] Context Pointer to the notification function's context.
1206 PlatformVarCleanupEndOfDxeEvent (
1215 The constructor function caches the pointer to VarCheck protocol and last boot variable error flag.
1217 The constructor function locates VarCheck protocol from protocol database.
1218 It will ASSERT() if that operation fails and it will always return EFI_SUCCESS.
1220 @param ImageHandle The firmware allocated handle for the EFI image.
1221 @param SystemTable A pointer to the EFI System Table.
1223 @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
1228 PlatformVarCleanupLibConstructor (
1229 IN EFI_HANDLE ImageHandle
,
1230 IN EFI_SYSTEM_TABLE
*SystemTable
1235 mLastVarErrorFlag
= InternalGetVarErrorFlag ();
1236 DEBUG ((EFI_D_INFO
, "mLastVarErrorFlag - 0x%02x\n", mLastVarErrorFlag
));
1239 // Register EFI_END_OF_DXE_EVENT_GROUP_GUID event.
1241 Status
= gBS
->CreateEventEx (
1244 PlatformVarCleanupEndOfDxeEvent
,
1246 &gEfiEndOfDxeEventGroupGuid
,
1247 &mPlatVarCleanupLibEndOfDxeEvent
1249 ASSERT_EFI_ERROR (Status
);
1255 The destructor function closes the End of DXE event.
1257 @param ImageHandle The firmware allocated handle for the EFI image.
1258 @param SystemTable A pointer to the EFI System Table.
1260 @retval EFI_SUCCESS The destructor completed successfully.
1265 PlatformVarCleanupLibDestructor (
1266 IN EFI_HANDLE ImageHandle
,
1267 IN EFI_SYSTEM_TABLE
*SystemTable
1273 // Close the End of DXE event.
1275 Status
= gBS
->CloseEvent (mPlatVarCleanupLibEndOfDxeEvent
);
1276 ASSERT_EFI_ERROR (Status
);