1 /** @file
2   Sample platform variable cleanup library implementation.
3 
4 Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6 
7 **/
8 
9 #include "PlatVarCleanup.h"
10 
11 VAR_ERROR_FLAG              mLastVarErrorFlag = VAR_ERROR_FLAG_NO_ERROR;
12 EDKII_VAR_CHECK_PROTOCOL    *mVarCheck = NULL;
13 
14 ///
15 /// The flag to indicate whether the platform has left the DXE phase of execution.
16 ///
17 BOOLEAN                     mEndOfDxe = FALSE;
18 
19 EFI_EVENT                   mPlatVarCleanupLibEndOfDxeEvent = NULL;
20 
21 LIST_ENTRY                  mUserVariableList = INITIALIZE_LIST_HEAD_VARIABLE (mUserVariableList);
22 UINT16                      mUserVariableCount = 0;
23 UINT16                      mMarkedUserVariableCount = 0;
24 
25 EFI_GUID                    mVariableCleanupHiiGuid = VARIABLE_CLEANUP_HII_GUID;
26 CHAR16                      mVarStoreName[] = L"VariableCleanup";
27 
28 HII_VENDOR_DEVICE_PATH      mVarCleanupHiiVendorDevicePath = {
29   {
30     {
31       HARDWARE_DEVICE_PATH,
32       HW_VENDOR_DP,
33       {
34         (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
35         (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
36       }
37     },
38     VARIABLE_CLEANUP_HII_GUID
39   },
40   {
41     END_DEVICE_PATH_TYPE,
42     END_ENTIRE_DEVICE_PATH_SUBTYPE,
43     {
44       (UINT8) (sizeof (EFI_DEVICE_PATH_PROTOCOL)),
45       (UINT8) ((sizeof (EFI_DEVICE_PATH_PROTOCOL)) >> 8)
46     }
47   }
48 };
49 
50 /**
51   Internal get variable error flag.
52 
53   @return   Variable error flag.
54 
55 **/
56 VAR_ERROR_FLAG
InternalGetVarErrorFlag(VOID)57 InternalGetVarErrorFlag (
58   VOID
59   )
60 {
61   EFI_STATUS        Status;
62   UINTN             Size;
63   VAR_ERROR_FLAG    ErrorFlag;
64 
65   Size = sizeof (ErrorFlag);
66   Status = gRT->GetVariable (
67                   VAR_ERROR_FLAG_NAME,
68                   &gEdkiiVarErrorFlagGuid,
69                   NULL,
70                   &Size,
71                   &ErrorFlag
72                   );
73   if (EFI_ERROR (Status)) {
74     DEBUG ((EFI_D_INFO, "%s - not found\n", VAR_ERROR_FLAG_NAME));
75     return VAR_ERROR_FLAG_NO_ERROR;
76   }
77   return ErrorFlag;
78 }
79 
80 /**
81   Is user variable?
82 
83   @param[in] Name   Pointer to variable name.
84   @param[in] Guid   Pointer to vendor guid.
85 
86   @retval TRUE      User variable.
87   @retval FALSE     System variable.
88 
89 **/
90 BOOLEAN
IsUserVariable(IN CHAR16 * Name,IN EFI_GUID * Guid)91 IsUserVariable (
92   IN CHAR16                     *Name,
93   IN EFI_GUID                   *Guid
94   )
95 {
96   EFI_STATUS                    Status;
97   VAR_CHECK_VARIABLE_PROPERTY   Property;
98 
99   if (mVarCheck == NULL) {
100     gBS->LocateProtocol (
101            &gEdkiiVarCheckProtocolGuid,
102            NULL,
103            (VOID **) &mVarCheck
104            );
105   }
106   ASSERT (mVarCheck != NULL);
107 
108   ZeroMem (&Property, sizeof (Property));
109   Status = mVarCheck->VariablePropertyGet (
110                         Name,
111                         Guid,
112                         &Property
113                         );
114   if (EFI_ERROR (Status)) {
115     //
116     // No property, it is user variable.
117     //
118     DEBUG ((EFI_D_INFO, "PlatformVarCleanup - User variable: %g:%s\n", Guid, Name));
119     return TRUE;
120   }
121 
122 //  DEBUG ((EFI_D_INFO, "PlatformVarCleanup - Variable Property: %g:%s\n", Guid, Name));
123 //  DEBUG ((EFI_D_INFO, "  Revision  - 0x%04x\n", Property.Revision));
124 //  DEBUG ((EFI_D_INFO, "  Property  - 0x%04x\n", Property.Property));
125 //  DEBUG ((EFI_D_INFO, "  Attribute - 0x%08x\n", Property.Attributes));
126 //  DEBUG ((EFI_D_INFO, "  MinSize   - 0x%x\n", Property.MinSize));
127 //  DEBUG ((EFI_D_INFO, "  MaxSize   - 0x%x\n", Property.MaxSize));
128 
129   return FALSE;
130 }
131 
132 /**
133   Find user variable node by variable GUID.
134 
135   @param[in] Guid   Pointer to vendor guid.
136 
137   @return Pointer to user variable node.
138 
139 **/
140 USER_VARIABLE_NODE *
FindUserVariableNodeByGuid(IN EFI_GUID * Guid)141 FindUserVariableNodeByGuid (
142   IN EFI_GUID   *Guid
143   )
144 {
145   USER_VARIABLE_NODE    *UserVariableNode;
146   LIST_ENTRY            *Link;
147 
148   for (Link = mUserVariableList.ForwardLink
149        ;Link != &mUserVariableList
150        ;Link = Link->ForwardLink) {
151     UserVariableNode = USER_VARIABLE_FROM_LINK (Link);
152 
153     if (CompareGuid (Guid, &UserVariableNode->Guid)) {
154       //
155       // Found it.
156       //
157       return UserVariableNode;
158     }
159   }
160 
161   //
162   // Create new one if not found.
163   //
164   UserVariableNode = AllocateZeroPool (sizeof (*UserVariableNode));
165   ASSERT (UserVariableNode != NULL);
166   UserVariableNode->Signature = USER_VARIABLE_NODE_SIGNATURE;
167   CopyGuid (&UserVariableNode->Guid, Guid);
168   //
169   // (36 chars of "########-####-####-####-############" + 1 space + 1 terminator) * sizeof (CHAR16).
170   //
171   UserVariableNode->PromptString = AllocatePool ((36 + 2) * sizeof (CHAR16));
172   ASSERT (UserVariableNode->PromptString != NULL);
173   UnicodeSPrint (UserVariableNode->PromptString, (36 + 2) * sizeof (CHAR16), L" %g", &UserVariableNode->Guid);
174   InitializeListHead (&UserVariableNode->NameLink);
175   InsertTailList (&mUserVariableList, &UserVariableNode->Link);
176   return UserVariableNode;
177 }
178 
179 /**
180   Create user variable node.
181 
182 **/
183 VOID
CreateUserVariableNode(VOID)184 CreateUserVariableNode (
185   VOID
186   )
187 {
188   EFI_STATUS                    Status;
189   EFI_STATUS                    GetVariableStatus;
190   CHAR16                        *VarName;
191   UINTN                         MaxVarNameSize;
192   UINTN                         VarNameSize;
193   UINTN                         MaxDataSize;
194   UINTN                         DataSize;
195   VOID                          *Data;
196   UINT32                        Attributes;
197   EFI_GUID                      Guid;
198   USER_VARIABLE_NODE            *UserVariableNode;
199   USER_VARIABLE_NAME_NODE       *UserVariableNameNode;
200   UINT16                        Index;
201   UINTN                         StringSize;
202 
203   //
204   // Initialize 128 * sizeof (CHAR16) variable name size.
205   //
206   MaxVarNameSize = 128 * sizeof (CHAR16);
207   VarName = AllocateZeroPool (MaxVarNameSize);
208   ASSERT (VarName != NULL);
209 
210   //
211   // Initialize 0x1000 variable data size.
212   //
213   MaxDataSize = 0x1000;
214   Data = AllocateZeroPool (MaxDataSize);
215   ASSERT (Data != NULL);
216 
217   Index = 0;
218   do {
219     VarNameSize = MaxVarNameSize;
220     Status = gRT->GetNextVariableName (&VarNameSize, VarName, &Guid);
221     if (Status == EFI_BUFFER_TOO_SMALL) {
222       VarName = ReallocatePool (MaxVarNameSize, VarNameSize, VarName);
223       ASSERT (VarName != NULL);
224       MaxVarNameSize = VarNameSize;
225       Status = gRT->GetNextVariableName (&VarNameSize, VarName, &Guid);
226     }
227 
228     if (!EFI_ERROR (Status)) {
229       if (IsUserVariable (VarName, &Guid)) {
230         DataSize = MaxDataSize;
231         GetVariableStatus = gRT->GetVariable (VarName, &Guid, &Attributes, &DataSize, Data);
232         if (GetVariableStatus == EFI_BUFFER_TOO_SMALL) {
233           Data = ReallocatePool (MaxDataSize, DataSize, Data);
234           ASSERT (Data != NULL);
235           MaxDataSize = DataSize;
236           GetVariableStatus = gRT->GetVariable (VarName, &Guid, &Attributes, &DataSize, Data);
237         }
238         ASSERT_EFI_ERROR (GetVariableStatus);
239 
240         if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
241           UserVariableNode = FindUserVariableNodeByGuid (&Guid);
242           ASSERT (UserVariableNode != NULL);
243 
244           //
245           // Different variables that have same variable GUID share same user variable node.
246           //
247           UserVariableNameNode = AllocateZeroPool (sizeof (*UserVariableNameNode));
248           ASSERT (UserVariableNameNode != NULL);
249           UserVariableNameNode->Signature = USER_VARIABLE_NAME_NODE_SIGNATURE;
250           UserVariableNameNode->Name = AllocateCopyPool (VarNameSize, VarName);
251           UserVariableNameNode->Attributes = Attributes;
252           UserVariableNameNode->DataSize = DataSize;
253           UserVariableNameNode->Index = Index;
254           UserVariableNameNode->QuestionId = (EFI_QUESTION_ID) (USER_VARIABLE_QUESTION_ID + Index);
255           //
256           // 2 space * sizeof (CHAR16) + StrSize.
257           //
258           StringSize = 2 * sizeof (CHAR16) + StrSize (UserVariableNameNode->Name);
259           UserVariableNameNode->PromptString = AllocatePool (StringSize);
260           ASSERT (UserVariableNameNode->PromptString != NULL);
261           UnicodeSPrint (UserVariableNameNode->PromptString, StringSize, L"  %s", UserVariableNameNode->Name);
262           //
263           // (33 chars of "Attribtues = 0x and DataSize = 0x" + 1 terminator + (sizeof (UINT32) + sizeof (UINTN)) * 2) * sizeof (CHAR16).
264           //
265           StringSize = (33 + 1 + (sizeof (UINT32) + sizeof (UINTN)) * 2) * sizeof (CHAR16);
266           UserVariableNameNode->HelpString = AllocatePool (StringSize);
267           ASSERT (UserVariableNameNode->HelpString != NULL);
268           UnicodeSPrint (UserVariableNameNode->HelpString, StringSize, L"Attribtues = 0x%08x and DataSize = 0x%x", UserVariableNameNode->Attributes, UserVariableNameNode->DataSize);
269           UserVariableNameNode->Deleted = FALSE;
270           InsertTailList (&UserVariableNode->NameLink, &UserVariableNameNode->Link);
271           Index++;
272         }
273       }
274     }
275   } while (Status != EFI_NOT_FOUND);
276 
277   mUserVariableCount = Index;
278   ASSERT (mUserVariableCount <= MAX_USER_VARIABLE_COUNT);
279   DEBUG ((EFI_D_INFO, "PlatformVarCleanup - User variable count: 0x%04x\n", mUserVariableCount));
280 
281   FreePool (VarName);
282   FreePool (Data);
283 }
284 
285 /**
286   Destroy user variable nodes.
287 
288 **/
289 VOID
DestroyUserVariableNode(VOID)290 DestroyUserVariableNode (
291   VOID
292   )
293 {
294   USER_VARIABLE_NODE        *UserVariableNode;
295   LIST_ENTRY                *Link;
296   USER_VARIABLE_NAME_NODE   *UserVariableNameNode;
297   LIST_ENTRY                *NameLink;
298 
299   while (mUserVariableList.ForwardLink != &mUserVariableList) {
300     Link = mUserVariableList.ForwardLink;
301     UserVariableNode = USER_VARIABLE_FROM_LINK (Link);
302 
303     RemoveEntryList (&UserVariableNode->Link);
304 
305     while (UserVariableNode->NameLink.ForwardLink != &UserVariableNode->NameLink) {
306       NameLink = UserVariableNode->NameLink.ForwardLink;
307       UserVariableNameNode = USER_VARIABLE_NAME_FROM_LINK (NameLink);
308 
309       RemoveEntryList (&UserVariableNameNode->Link);
310 
311       FreePool (UserVariableNameNode->Name);
312       FreePool (UserVariableNameNode->PromptString);
313       FreePool (UserVariableNameNode->HelpString);
314       FreePool (UserVariableNameNode);
315     }
316 
317     FreePool (UserVariableNode->PromptString);
318     FreePool (UserVariableNode);
319   }
320 }
321 
322 /**
323   Create a time based data payload by concatenating the EFI_VARIABLE_AUTHENTICATION_2
324   descriptor with the input data. NO authentication is required in this function.
325 
326   @param[in, out] DataSize          On input, the size of Data buffer in bytes.
327                                     On output, the size of data returned in Data
328                                     buffer in bytes.
329   @param[in, out] Data              On input, Pointer to data buffer to be wrapped or
330                                     pointer to NULL to wrap an empty payload.
331                                     On output, Pointer to the new payload date buffer allocated from pool,
332                                     it's caller's responsibility to free the memory after using it.
333 
334   @retval EFI_SUCCESS               Create time based payload successfully.
335   @retval EFI_OUT_OF_RESOURCES      There are not enough memory resourses to create time based payload.
336   @retval EFI_INVALID_PARAMETER     The parameter is invalid.
337   @retval Others                    Unexpected error happens.
338 
339 **/
340 EFI_STATUS
CreateTimeBasedPayload(IN OUT UINTN * DataSize,IN OUT UINT8 ** Data)341 CreateTimeBasedPayload (
342   IN OUT UINTN      *DataSize,
343   IN OUT UINT8      **Data
344   )
345 {
346   EFI_STATUS                        Status;
347   UINT8                             *NewData;
348   UINT8                             *Payload;
349   UINTN                             PayloadSize;
350   EFI_VARIABLE_AUTHENTICATION_2     *DescriptorData;
351   UINTN                             DescriptorSize;
352   EFI_TIME                          Time;
353 
354   if (Data == NULL || DataSize == NULL) {
355     return EFI_INVALID_PARAMETER;
356   }
357 
358   //
359   // At user physical presence, the variable does not need to be signed but the
360   // parameters to the SetVariable() call still need to be prepared as authenticated
361   // variable. So we create EFI_VARIABLE_AUTHENTICATED_2 descriptor without certificate
362   // data in it.
363   //
364   Payload     = *Data;
365   PayloadSize = *DataSize;
366 
367   DescriptorSize = OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2, AuthInfo) + OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData);
368   NewData = (UINT8 *) AllocateZeroPool (DescriptorSize + PayloadSize);
369   if (NewData == NULL) {
370     return EFI_OUT_OF_RESOURCES;
371   }
372 
373   if ((Payload != NULL) && (PayloadSize != 0)) {
374     CopyMem (NewData + DescriptorSize, Payload, PayloadSize);
375   }
376 
377   DescriptorData = (EFI_VARIABLE_AUTHENTICATION_2 *) (NewData);
378 
379   ZeroMem (&Time, sizeof (EFI_TIME));
380   Status = gRT->GetTime (&Time, NULL);
381   if (EFI_ERROR (Status)) {
382     FreePool (NewData);
383     return Status;
384   }
385   Time.Pad1       = 0;
386   Time.Nanosecond = 0;
387   Time.TimeZone   = 0;
388   Time.Daylight   = 0;
389   Time.Pad2       = 0;
390   CopyMem (&DescriptorData->TimeStamp, &Time, sizeof (EFI_TIME));
391 
392   DescriptorData->AuthInfo.Hdr.dwLength         = OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData);
393   DescriptorData->AuthInfo.Hdr.wRevision        = 0x0200;
394   DescriptorData->AuthInfo.Hdr.wCertificateType = WIN_CERT_TYPE_EFI_GUID;
395   CopyGuid (&DescriptorData->AuthInfo.CertType, &gEfiCertPkcs7Guid);
396 
397   if (Payload != NULL) {
398     FreePool (Payload);
399   }
400 
401   *DataSize = DescriptorSize + PayloadSize;
402   *Data     = NewData;
403   return EFI_SUCCESS;
404 }
405 
406 /**
407   Create a counter based data payload by concatenating the EFI_VARIABLE_AUTHENTICATION
408   descriptor with the input data. NO authentication is required in this function.
409 
410   @param[in, out] DataSize          On input, the size of Data buffer in bytes.
411                                     On output, the size of data returned in Data
412                                     buffer in bytes.
413   @param[in, out] Data              On input, Pointer to data buffer to be wrapped or
414                                     pointer to NULL to wrap an empty payload.
415                                     On output, Pointer to the new payload date buffer allocated from pool,
416                                     it's caller's responsibility to free the memory after using it.
417 
418   @retval EFI_SUCCESS               Create counter based payload successfully.
419   @retval EFI_OUT_OF_RESOURCES      There are not enough memory resourses to create time based payload.
420   @retval EFI_INVALID_PARAMETER     The parameter is invalid.
421   @retval Others                    Unexpected error happens.
422 
423 **/
424 EFI_STATUS
CreateCounterBasedPayload(IN OUT UINTN * DataSize,IN OUT UINT8 ** Data)425 CreateCounterBasedPayload (
426   IN OUT UINTN      *DataSize,
427   IN OUT UINT8      **Data
428   )
429 {
430   EFI_STATUS                        Status;
431   UINT8                             *NewData;
432   UINT8                             *Payload;
433   UINTN                             PayloadSize;
434   EFI_VARIABLE_AUTHENTICATION       *DescriptorData;
435   UINTN                             DescriptorSize;
436   UINT64                            MonotonicCount;
437 
438   if (Data == NULL || DataSize == NULL) {
439     return EFI_INVALID_PARAMETER;
440   }
441 
442   //
443   // At user physical presence, the variable does not need to be signed but the
444   // parameters to the SetVariable() call still need to be prepared as authenticated
445   // variable. So we create EFI_VARIABLE_AUTHENTICATED descriptor without certificate
446   // data in it.
447   //
448   Payload     = *Data;
449   PayloadSize = *DataSize;
450 
451   DescriptorSize = (OFFSET_OF (EFI_VARIABLE_AUTHENTICATION, AuthInfo)) + \
452                    (OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData)) + \
453                    sizeof (EFI_CERT_BLOCK_RSA_2048_SHA256);
454   NewData = (UINT8 *) AllocateZeroPool (DescriptorSize + PayloadSize);
455   if (NewData == NULL) {
456     return EFI_OUT_OF_RESOURCES;
457   }
458 
459   if ((Payload != NULL) && (PayloadSize != 0)) {
460     CopyMem (NewData + DescriptorSize, Payload, PayloadSize);
461   }
462 
463   DescriptorData = (EFI_VARIABLE_AUTHENTICATION *) (NewData);
464 
465   Status = gBS->GetNextMonotonicCount (&MonotonicCount);
466   if (EFI_ERROR (Status)) {
467     FreePool (NewData);
468     return Status;
469   }
470   DescriptorData->MonotonicCount = MonotonicCount;
471 
472   DescriptorData->AuthInfo.Hdr.dwLength         = OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData) + sizeof (EFI_CERT_BLOCK_RSA_2048_SHA256);
473   DescriptorData->AuthInfo.Hdr.wRevision        = 0x0200;
474   DescriptorData->AuthInfo.Hdr.wCertificateType = WIN_CERT_TYPE_EFI_GUID;
475   CopyGuid (&DescriptorData->AuthInfo.CertType, &gEfiCertTypeRsa2048Sha256Guid);
476 
477   if (Payload != NULL) {
478     FreePool (Payload);
479   }
480 
481   *DataSize = DescriptorSize + PayloadSize;
482   *Data     = NewData;
483   return EFI_SUCCESS;
484 }
485 
486 /**
487   Delete user variable.
488 
489   @param[in] DeleteAll              Delete all user variables.
490   @param[in] VariableCleanupData    Pointer to variable cleanup data.
491 
492 **/
493 VOID
DeleteUserVariable(IN BOOLEAN DeleteAll,IN VARIABLE_CLEANUP_DATA * VariableCleanupData OPTIONAL)494 DeleteUserVariable (
495   IN BOOLEAN                DeleteAll,
496   IN VARIABLE_CLEANUP_DATA  *VariableCleanupData OPTIONAL
497   )
498 {
499   EFI_STATUS                Status;
500   USER_VARIABLE_NODE        *UserVariableNode;
501   LIST_ENTRY                *Link;
502   USER_VARIABLE_NAME_NODE   *UserVariableNameNode;
503   LIST_ENTRY                *NameLink;
504   UINTN                     DataSize;
505   UINT8                     *Data;
506 
507   for (Link = mUserVariableList.ForwardLink
508        ;Link != &mUserVariableList
509        ;Link = Link->ForwardLink) {
510     UserVariableNode = USER_VARIABLE_FROM_LINK (Link);
511 
512     for (NameLink = UserVariableNode->NameLink.ForwardLink
513         ;NameLink != &UserVariableNode->NameLink
514         ;NameLink = NameLink->ForwardLink) {
515       UserVariableNameNode = USER_VARIABLE_NAME_FROM_LINK (NameLink);
516 
517       if (!UserVariableNameNode->Deleted && (DeleteAll || ((VariableCleanupData != NULL) && (VariableCleanupData->UserVariable[UserVariableNameNode->Index] == TRUE)))) {
518         DEBUG ((EFI_D_INFO, "PlatformVarCleanup - Delete variable: %g:%s\n", &UserVariableNode->Guid, UserVariableNameNode->Name));
519         if ((UserVariableNameNode->Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {
520           DataSize = 0;
521           Data = NULL;
522           Status = CreateTimeBasedPayload (&DataSize, &Data);
523           if (!EFI_ERROR (Status)) {
524             Status = gRT->SetVariable (UserVariableNameNode->Name, &UserVariableNode->Guid, UserVariableNameNode->Attributes, DataSize, Data);
525             FreePool (Data);
526           }
527         } else if ((UserVariableNameNode->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
528           DataSize = 0;
529           Data = NULL;
530           Status = CreateCounterBasedPayload (&DataSize, &Data);
531           if (!EFI_ERROR (Status)) {
532             Status = gRT->SetVariable (UserVariableNameNode->Name, &UserVariableNode->Guid, UserVariableNameNode->Attributes, DataSize, Data);
533             FreePool (Data);
534           }
535         } else {
536           Status = gRT->SetVariable (UserVariableNameNode->Name, &UserVariableNode->Guid, 0, 0, NULL);
537         }
538         if (!EFI_ERROR (Status)) {
539           UserVariableNameNode->Deleted = TRUE;
540         } else {
541           DEBUG ((EFI_D_INFO, "PlatformVarCleanup - Delete variable fail: %g:%s\n", &UserVariableNode->Guid, UserVariableNameNode->Name));
542         }
543       }
544     }
545   }
546 }
547 
548 /**
549   This function allows a caller to extract the current configuration for one
550   or more named elements from the target driver.
551 
552   @param[in]  This          Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
553   @param[in]  Request       A null-terminated Unicode string in <ConfigRequest> format.
554   @param[out] Progress      On return, points to a character in the Request string.
555                             Points to the string's null terminator if request was successful.
556                             Points to the most recent '&' before the first failing name/value
557                             pair (or the beginning of the string if the failure is in the
558                             first name/value pair) if the request was not successful.
559   @param[out] Results       A null-terminated Unicode string in <ConfigAltResp> format which
560                             has all values filled in for the names in the Request string.
561                             String to be allocated by the called function.
562 
563   @retval EFI_SUCCESS               The Results is filled with the requested values.
564   @retval EFI_OUT_OF_RESOURCES      Not enough memory to store the results.
565   @retval EFI_INVALID_PARAMETER     Request is illegal syntax, or unknown name.
566   @retval EFI_NOT_FOUND             Routing data doesn't match any storage in this driver.
567 
568 **/
569 EFI_STATUS
570 EFIAPI
VariableCleanupHiiExtractConfig(IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL * This,IN CONST EFI_STRING Request,OUT EFI_STRING * Progress,OUT EFI_STRING * Results)571 VariableCleanupHiiExtractConfig (
572   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL      *This,
573   IN  CONST EFI_STRING                          Request,
574   OUT EFI_STRING                                *Progress,
575   OUT EFI_STRING                                *Results
576   )
577 {
578   EFI_STATUS                        Status;
579   VARIABLE_CLEANUP_HII_PRIVATE_DATA *Private;
580   UINTN                             BufferSize;
581   EFI_STRING                        ConfigRequestHdr;
582   EFI_STRING                        ConfigRequest;
583   BOOLEAN                           AllocatedRequest;
584   UINTN                             Size;
585 
586   if (Progress == NULL || Results == NULL) {
587     return EFI_INVALID_PARAMETER;
588   }
589 
590   *Progress = Request;
591   if ((Request != NULL) && !HiiIsConfigHdrMatch (Request, &mVariableCleanupHiiGuid, mVarStoreName)) {
592     return EFI_NOT_FOUND;
593   }
594 
595   ConfigRequestHdr = NULL;
596   ConfigRequest    = NULL;
597   AllocatedRequest = FALSE;
598   Size             = 0;
599 
600   Private = VARIABLE_CLEANUP_HII_PRIVATE_FROM_THIS (This);
601   //
602   // Convert buffer data to <ConfigResp> by helper function BlockToConfig().
603   //
604   BufferSize = sizeof (VARIABLE_CLEANUP_DATA);
605   ConfigRequest = Request;
606   if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) {
607     //
608     // Request has no request element, construct full request string.
609     // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
610     // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator.
611     //
612     ConfigRequestHdr = HiiConstructConfigHdr (
613                          &mVariableCleanupHiiGuid,
614                          mVarStoreName,
615                          Private->DriverHandle
616                          );
617     Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16);
618     ConfigRequest = AllocateZeroPool (Size);
619     ASSERT (ConfigRequest != NULL);
620     AllocatedRequest = TRUE;
621     UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr, (UINT64)BufferSize);
622     FreePool (ConfigRequestHdr);
623   }
624 
625   Status = Private->ConfigRouting->BlockToConfig (
626                                      Private->ConfigRouting,
627                                      ConfigRequest,
628                                      (UINT8 *) &Private->VariableCleanupData,
629                                      BufferSize,
630                                      Results,
631                                      Progress
632                                      );
633   ASSERT_EFI_ERROR (Status);
634 
635   //
636   // Free the allocated config request string.
637   //
638   if (AllocatedRequest) {
639     FreePool (ConfigRequest);
640     ConfigRequest = NULL;
641   }
642   //
643   // Set Progress string to the original request string or the string's null terminator.
644   //
645   if (Request == NULL) {
646     *Progress = NULL;
647   } else if (StrStr (Request, L"OFFSET") == NULL) {
648     *Progress = Request + StrLen (Request);
649   }
650 
651   return Status;
652 }
653 
654 /**
655   Update user variable form.
656 
657   @param[in] Private    Points to the VARIABLE_CLEANUP_HII_PRIVATE_DATA.
658 
659 **/
660 VOID
UpdateUserVariableForm(IN VARIABLE_CLEANUP_HII_PRIVATE_DATA * Private)661 UpdateUserVariableForm (
662   IN VARIABLE_CLEANUP_HII_PRIVATE_DATA  *Private
663   )
664 {
665   EFI_STRING_ID             PromptStringToken;
666   EFI_STRING_ID             HelpStringToken;
667   VOID                      *StartOpCodeHandle;
668   VOID                      *EndOpCodeHandle;
669   EFI_IFR_GUID_LABEL        *StartLabel;
670   EFI_IFR_GUID_LABEL        *EndLabel;
671   USER_VARIABLE_NODE        *UserVariableNode;
672   LIST_ENTRY                *Link;
673   USER_VARIABLE_NAME_NODE   *UserVariableNameNode;
674   LIST_ENTRY                *NameLink;
675   BOOLEAN                   Created;
676 
677   //
678   // Init OpCode Handle.
679   //
680   StartOpCodeHandle = HiiAllocateOpCodeHandle ();
681   ASSERT (StartOpCodeHandle != NULL);
682 
683   EndOpCodeHandle = HiiAllocateOpCodeHandle ();
684   ASSERT (EndOpCodeHandle != NULL);
685 
686   //
687   // Create Hii Extend Label OpCode as the start opcode.
688   //
689   StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
690   StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
691   StartLabel->Number = LABEL_START;
692 
693   //
694   // Create Hii Extend Label OpCode as the end opcode.
695   //
696   EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
697   EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
698   EndLabel->Number = LABEL_END;
699 
700   HiiUpdateForm (
701     Private->HiiHandle,
702     &mVariableCleanupHiiGuid,
703     FORM_ID_VARIABLE_CLEANUP,
704     StartOpCodeHandle, // LABEL_START
705     EndOpCodeHandle    // LABEL_END
706     );
707 
708   for (Link = mUserVariableList.ForwardLink
709       ;Link != &mUserVariableList
710       ;Link = Link->ForwardLink) {
711     UserVariableNode = USER_VARIABLE_FROM_LINK (Link);
712 
713     //
714     // Create checkbox opcode for variables in the same variable GUID space.
715     //
716     Created = FALSE;
717     for (NameLink = UserVariableNode->NameLink.ForwardLink
718         ;NameLink != &UserVariableNode->NameLink
719         ;NameLink = NameLink->ForwardLink) {
720       UserVariableNameNode = USER_VARIABLE_NAME_FROM_LINK (NameLink);
721 
722       if (!UserVariableNameNode->Deleted) {
723         if (!Created) {
724           //
725           // Create subtitle opcode for variable GUID.
726           //
727           PromptStringToken = HiiSetString (Private->HiiHandle, 0, UserVariableNode->PromptString, NULL);
728           HiiCreateSubTitleOpCode (StartOpCodeHandle, PromptStringToken, 0, 0, 0);
729           Created = TRUE;
730         }
731 
732         //
733         // Only create opcode for the non-deleted variables.
734         //
735         PromptStringToken = HiiSetString (Private->HiiHandle, 0, UserVariableNameNode->PromptString, NULL);
736         HelpStringToken = HiiSetString (Private->HiiHandle, 0, UserVariableNameNode->HelpString, NULL);
737         HiiCreateCheckBoxOpCode (
738           StartOpCodeHandle,
739           UserVariableNameNode->QuestionId,
740           VARIABLE_CLEANUP_VARSTORE_ID,
741           (UINT16) (USER_VARIABLE_VAR_OFFSET + UserVariableNameNode->Index),
742           PromptStringToken,
743           HelpStringToken,
744           EFI_IFR_FLAG_CALLBACK,
745           Private->VariableCleanupData.UserVariable[UserVariableNameNode->Index],
746           NULL
747           );
748       }
749     }
750   }
751 
752   HiiCreateSubTitleOpCode (
753     StartOpCodeHandle,
754     STRING_TOKEN (STR_NULL_STRING),
755     0,
756     0,
757     0
758     );
759 
760   //
761   // Create the "Apply changes" and "Discard changes" tags.
762   //
763   HiiCreateActionOpCode (
764     StartOpCodeHandle,
765     SAVE_AND_EXIT_QUESTION_ID,
766     STRING_TOKEN (STR_SAVE_AND_EXIT),
767     STRING_TOKEN (STR_NULL_STRING),
768     EFI_IFR_FLAG_CALLBACK,
769     0
770     );
771   HiiCreateActionOpCode (
772     StartOpCodeHandle,
773     NO_SAVE_AND_EXIT_QUESTION_ID,
774     STRING_TOKEN (STR_NO_SAVE_AND_EXIT),
775     STRING_TOKEN (STR_NULL_STRING),
776     EFI_IFR_FLAG_CALLBACK,
777     0
778     );
779 
780   HiiUpdateForm (
781     Private->HiiHandle,
782     &mVariableCleanupHiiGuid,
783     FORM_ID_VARIABLE_CLEANUP,
784     StartOpCodeHandle, // LABEL_START
785     EndOpCodeHandle    // LABEL_END
786     );
787 
788   HiiFreeOpCodeHandle (StartOpCodeHandle);
789   HiiFreeOpCodeHandle (EndOpCodeHandle);
790 }
791 
792 /**
793   This function applies changes in a driver's configuration.
794   Input is a Configuration, which has the routing data for this
795   driver followed by name / value configuration pairs. The driver
796   must apply those pairs to its configurable storage. If the
797   driver's configuration is stored in a linear block of data
798   and the driver's name / value pairs are in <BlockConfig>
799   format, it may use the ConfigToBlock helper function (above) to
800   simplify the job. Currently not implemented.
801 
802   @param[in]  This                  Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
803   @param[in]  Configuration         A null-terminated Unicode string in
804                                     <ConfigString> format.
805   @param[out] Progress              A pointer to a string filled in with the
806                                     offset of the most recent '&' before the
807                                     first failing name / value pair (or the
808                                     beginn ing of the string if the failure
809                                     is in the first name / value pair) or
810                                     the terminating NULL if all was
811                                     successful.
812 
813   @retval EFI_SUCCESS               The results have been distributed or are
814                                     awaiting distribution.
815   @retval EFI_OUT_OF_RESOURCES      Not enough memory to store the
816                                     parts of the results that must be
817                                     stored awaiting possible future
818                                     protocols.
819   @retval EFI_INVALID_PARAMETERS    Passing in a NULL for the
820                                     Results parameter would result
821                                     in this type of error.
822   @retval EFI_NOT_FOUND             Target for the specified routing data
823                                     was not found.
824 
825 **/
826 EFI_STATUS
827 EFIAPI
VariableCleanupHiiRouteConfig(IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL * This,IN CONST EFI_STRING Configuration,OUT EFI_STRING * Progress)828 VariableCleanupHiiRouteConfig (
829   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL      *This,
830   IN  CONST EFI_STRING                          Configuration,
831   OUT EFI_STRING                                *Progress
832   )
833 {
834   EFI_STATUS                        Status;
835   VARIABLE_CLEANUP_HII_PRIVATE_DATA *Private;
836   UINTN                             BufferSize;
837 
838   if (Progress == NULL) {
839     return EFI_INVALID_PARAMETER;
840   }
841   *Progress = Configuration;
842 
843   if (Configuration == NULL) {
844     return EFI_INVALID_PARAMETER;
845   }
846 
847   //
848   // Check routing data in <ConfigHdr>.
849   // Note: there is no name for Name/Value storage, only GUID will be checked.
850   //
851   if (!HiiIsConfigHdrMatch (Configuration, &mVariableCleanupHiiGuid, mVarStoreName)) {
852     return EFI_NOT_FOUND;
853   }
854 
855   Private = VARIABLE_CLEANUP_HII_PRIVATE_FROM_THIS (This);
856   //
857   // Get Buffer Storage data.
858   //
859   BufferSize = sizeof (VARIABLE_CLEANUP_DATA);
860   //
861   // Convert <ConfigResp> to buffer data by helper function ConfigToBlock().
862   //
863   Status = Private->ConfigRouting->ConfigToBlock (
864                             Private->ConfigRouting,
865                             Configuration,
866                             (UINT8 *) &Private->VariableCleanupData,
867                             &BufferSize,
868                             Progress
869                             );
870   ASSERT_EFI_ERROR (Status);
871 
872   DeleteUserVariable (FALSE, &Private->VariableCleanupData);
873   //
874   // For "F10" hotkey to refresh the form.
875   //
876 //  UpdateUserVariableForm (Private);
877 
878   return EFI_SUCCESS;
879 }
880 
881 /**
882   This function is called to provide results data to the driver.
883   This data consists of a unique key that is used to identify
884   which data is either being passed back or being asked for.
885 
886   @param[in]  This                  Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
887   @param[in]  Action                Specifies the type of action taken by the browser.
888   @param[in]  QuestionId            A unique value which is sent to the original
889                                     exporting driver so that it can identify the type
890                                     of data to expect. The format of the data tends to
891                                     vary based on the opcode that generated the callback.
892   @param[in]  Type                  The type of value for the question.
893   @param[in]  Value                 A pointer to the data being sent to the original
894                                     exporting driver.
895   @param[out] ActionRequest         On return, points to the action requested by the
896                                     callback function.
897 
898   @retval EFI_SUCCESS               The callback successfully handled the action.
899   @retval EFI_OUT_OF_RESOURCES      Not enough storage is available to hold the
900                                     variable and its data.
901   @retval EFI_DEVICE_ERROR          The variable could not be saved.
902   @retval EFI_UNSUPPORTED           The specified Action is not supported by the
903                                     callback.
904 **/
905 EFI_STATUS
906 EFIAPI
VariableCleanupHiiCallback(IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL * This,IN EFI_BROWSER_ACTION Action,IN EFI_QUESTION_ID QuestionId,IN UINT8 Type,IN EFI_IFR_TYPE_VALUE * Value,OUT EFI_BROWSER_ACTION_REQUEST * ActionRequest)907 VariableCleanupHiiCallback (
908   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
909   IN  EFI_BROWSER_ACTION                     Action,
910   IN  EFI_QUESTION_ID                        QuestionId,
911   IN  UINT8                                  Type,
912   IN  EFI_IFR_TYPE_VALUE                     *Value,
913   OUT EFI_BROWSER_ACTION_REQUEST             *ActionRequest
914   )
915 {
916   VARIABLE_CLEANUP_HII_PRIVATE_DATA *Private;
917   VARIABLE_CLEANUP_DATA             *VariableCleanupData;
918 
919   Private = VARIABLE_CLEANUP_HII_PRIVATE_FROM_THIS (This);
920 
921   if ((Action != EFI_BROWSER_ACTION_CHANGING) && (Action != EFI_BROWSER_ACTION_CHANGED)) {
922     //
923     // All other action return unsupported.
924     //
925     return EFI_UNSUPPORTED;
926   }
927 
928   //
929   // Retrieve uncommitted data from Form Browser.
930   //
931   VariableCleanupData = &Private->VariableCleanupData;
932   HiiGetBrowserData (&mVariableCleanupHiiGuid, mVarStoreName, sizeof (VARIABLE_CLEANUP_DATA), (UINT8 *) VariableCleanupData);
933   if (Action == EFI_BROWSER_ACTION_CHANGING) {
934     if (Value == NULL) {
935       return EFI_INVALID_PARAMETER;
936     }
937   } else if (Action == EFI_BROWSER_ACTION_CHANGED) {
938     if ((Value == NULL) || (ActionRequest == NULL)) {
939       return EFI_INVALID_PARAMETER;
940     }
941     if ((QuestionId >= USER_VARIABLE_QUESTION_ID) && (QuestionId < USER_VARIABLE_QUESTION_ID + MAX_USER_VARIABLE_COUNT)) {
942       if (Value->b){
943         //
944         // Means one user variable checkbox is marked to delete but not press F10 or "Commit Changes and Exit" menu.
945         //
946         mMarkedUserVariableCount++;
947         ASSERT (mMarkedUserVariableCount <= mUserVariableCount);
948         if (mMarkedUserVariableCount == mUserVariableCount) {
949           //
950           // All user variables have been marked, then also mark the SelectAll checkbox.
951           //
952           VariableCleanupData->SelectAll = TRUE;
953         }
954       } else {
955         //
956         // Means one user variable checkbox is unmarked.
957         //
958         mMarkedUserVariableCount--;
959         //
960         // Also unmark the SelectAll checkbox.
961         //
962         VariableCleanupData->SelectAll = FALSE;
963       }
964     } else {
965       switch (QuestionId) {
966         case SELECT_ALL_QUESTION_ID:
967          if (Value->b){
968             //
969             // Means the SelectAll checkbox is marked to delete all user variables but not press F10 or "Commit Changes and Exit" menu.
970             //
971             SetMem (VariableCleanupData->UserVariable, sizeof (VariableCleanupData->UserVariable), TRUE);
972             mMarkedUserVariableCount = mUserVariableCount;
973           } else {
974             //
975             // Means the SelectAll checkbox is unmarked.
976             //
977             SetMem (VariableCleanupData->UserVariable, sizeof (VariableCleanupData->UserVariable), FALSE);
978             mMarkedUserVariableCount = 0;
979           }
980           break;
981         case SAVE_AND_EXIT_QUESTION_ID:
982           DeleteUserVariable (FALSE, VariableCleanupData);
983           *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT;
984           break;
985 
986         case NO_SAVE_AND_EXIT_QUESTION_ID:
987           //
988           // Restore local maintain data.
989           //
990           *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT;
991           break;
992 
993         default:
994           break;
995       }
996     }
997   }
998 
999   //
1000   // Pass changed uncommitted data back to Form Browser.
1001   //
1002   HiiSetBrowserData (&mVariableCleanupHiiGuid, mVarStoreName, sizeof (VARIABLE_CLEANUP_DATA), (UINT8 *) VariableCleanupData, NULL);
1003   return EFI_SUCCESS;
1004 }
1005 
1006 /**
1007   Platform variable cleanup.
1008 
1009   @param[in] Flag                   Variable error flag.
1010   @param[in] Type                   Variable cleanup type.
1011                                     If it is VarCleanupManually, the interface must be called after console connected.
1012 
1013   @retval EFI_SUCCESS               No error or error processed.
1014   @retval EFI_UNSUPPORTED           The specified Flag or Type is not supported.
1015                                     For example, system error may be not supported to process and Platform should have mechanism to reset system to manufacture mode.
1016                                     Another, if system and user variables are wanted to be distinguished to process, the interface must be called after EndOfDxe.
1017   @retval EFI_OUT_OF_RESOURCES      Not enough resource to process the error.
1018   @retval EFI_INVALID_PARAMETER     The specified Flag or Type is an invalid value.
1019   @retval Others                    Other failure occurs.
1020 
1021 **/
1022 EFI_STATUS
1023 EFIAPI
PlatformVarCleanup(IN VAR_ERROR_FLAG Flag,IN VAR_CLEANUP_TYPE Type)1024 PlatformVarCleanup (
1025   IN VAR_ERROR_FLAG     Flag,
1026   IN VAR_CLEANUP_TYPE   Type
1027   )
1028 {
1029   EFI_STATUS                            Status;
1030   EFI_FORM_BROWSER2_PROTOCOL            *FormBrowser2;
1031   VARIABLE_CLEANUP_HII_PRIVATE_DATA     *Private;
1032 
1033   if (!mEndOfDxe) {
1034     //
1035     // This implementation must be called after EndOfDxe.
1036     //
1037     return EFI_UNSUPPORTED;
1038   }
1039 
1040   if ((Type >= VarCleanupMax) || ((Flag & ((VAR_ERROR_FLAG) (VAR_ERROR_FLAG_SYSTEM_ERROR & VAR_ERROR_FLAG_USER_ERROR))) == 0)) {
1041     return EFI_INVALID_PARAMETER;
1042   }
1043 
1044   if (Flag == VAR_ERROR_FLAG_NO_ERROR) {
1045     //
1046     // Just return success if no error.
1047     //
1048     return EFI_SUCCESS;
1049   }
1050 
1051   if ((Flag & (~((VAR_ERROR_FLAG) VAR_ERROR_FLAG_SYSTEM_ERROR))) == 0) {
1052     //
1053     // This sample does not support system variables cleanup.
1054     //
1055     DEBUG ((EFI_D_ERROR, "NOTICE - VAR_ERROR_FLAG_SYSTEM_ERROR\n"));
1056     DEBUG ((EFI_D_ERROR, "Platform should have mechanism to reset system to manufacture mode\n"));
1057     return EFI_UNSUPPORTED;
1058   }
1059 
1060   //
1061   // Continue to process VAR_ERROR_FLAG_USER_ERROR.
1062   //
1063 
1064   //
1065   // Create user variable nodes for the following processing.
1066   //
1067   CreateUserVariableNode ();
1068 
1069   switch (Type) {
1070     case VarCleanupAll:
1071       DeleteUserVariable (TRUE, NULL);
1072       //
1073       // Destroyed the created user variable nodes
1074       //
1075       DestroyUserVariableNode ();
1076       return EFI_SUCCESS;
1077       break;
1078 
1079     case VarCleanupManually:
1080       //
1081       // Locate FormBrowser2 protocol.
1082       //
1083       Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &FormBrowser2);
1084       if (EFI_ERROR (Status)) {
1085         return Status;
1086       }
1087 
1088       Private = AllocateZeroPool (sizeof (VARIABLE_CLEANUP_HII_PRIVATE_DATA));
1089       if (Private == NULL) {
1090         return EFI_OUT_OF_RESOURCES;
1091       }
1092 
1093       Private->Signature = VARIABLE_CLEANUP_HII_PRIVATE_SIGNATURE;
1094       Private->ConfigAccess.ExtractConfig = VariableCleanupHiiExtractConfig;
1095       Private->ConfigAccess.RouteConfig   = VariableCleanupHiiRouteConfig;
1096       Private->ConfigAccess.Callback      = VariableCleanupHiiCallback;
1097 
1098       Status = gBS->LocateProtocol (
1099                       &gEfiHiiConfigRoutingProtocolGuid,
1100                       NULL,
1101                       (VOID **) &Private->ConfigRouting
1102                       );
1103       if (EFI_ERROR (Status)) {
1104         goto Done;
1105       }
1106 
1107       //
1108       // Install Device Path Protocol and Config Access protocol to driver handle.
1109       //
1110       Status = gBS->InstallMultipleProtocolInterfaces (
1111                       &Private->DriverHandle,
1112                       &gEfiDevicePathProtocolGuid,
1113                       &mVarCleanupHiiVendorDevicePath,
1114                       &gEfiHiiConfigAccessProtocolGuid,
1115                       &Private->ConfigAccess,
1116                       NULL
1117                       );
1118       if (EFI_ERROR (Status)) {
1119         goto Done;
1120       }
1121 
1122       //
1123       // Publish our HII data.
1124       //
1125       Private->HiiHandle = HiiAddPackages (
1126                              &mVariableCleanupHiiGuid,
1127                              Private->DriverHandle,
1128                              PlatformVarCleanupLibStrings,
1129                              PlatVarCleanupBin,
1130                              NULL
1131                              );
1132       if (Private->HiiHandle == NULL) {
1133         Status = EFI_OUT_OF_RESOURCES;
1134         goto Done;
1135       }
1136 
1137       UpdateUserVariableForm (Private);
1138 
1139       Status = FormBrowser2->SendForm (
1140                                FormBrowser2,
1141                                &Private->HiiHandle,
1142                                1,
1143                                NULL,
1144                                0,
1145                                NULL,
1146                                NULL
1147                                );
1148       break;
1149 
1150     default:
1151       return EFI_UNSUPPORTED;
1152       break;
1153   }
1154 
1155 Done:
1156   if (Private->DriverHandle != NULL) {
1157     gBS->UninstallMultipleProtocolInterfaces (
1158            Private->DriverHandle,
1159            &gEfiDevicePathProtocolGuid,
1160            &mVarCleanupHiiVendorDevicePath,
1161            &gEfiHiiConfigAccessProtocolGuid,
1162            &Private->ConfigAccess,
1163            NULL
1164            );
1165   }
1166   if (Private->HiiHandle != NULL) {
1167     HiiRemovePackages (Private->HiiHandle);
1168   }
1169 
1170   FreePool (Private);
1171 
1172   //
1173   // Destroyed the created user variable nodes
1174   //
1175   DestroyUserVariableNode ();
1176   return Status;
1177 }
1178 
1179 /**
1180   Get last boot variable error flag.
1181 
1182   @return   Last boot variable error flag.
1183 
1184 **/
1185 VAR_ERROR_FLAG
1186 EFIAPI
GetLastBootVarErrorFlag(VOID)1187 GetLastBootVarErrorFlag (
1188   VOID
1189   )
1190 {
1191   return mLastVarErrorFlag;
1192 }
1193 
1194 /**
1195   Notification function of END_OF_DXE.
1196 
1197   This is a notification function registered on END_OF_DXE event.
1198 
1199   @param[in] Event      Event whose notification function is being invoked.
1200   @param[in] Context    Pointer to the notification function's context.
1201 
1202 **/
1203 VOID
1204 EFIAPI
PlatformVarCleanupEndOfDxeEvent(IN EFI_EVENT Event,IN VOID * Context)1205 PlatformVarCleanupEndOfDxeEvent (
1206   IN EFI_EVENT  Event,
1207   IN VOID       *Context
1208   )
1209 {
1210   mEndOfDxe = TRUE;
1211 }
1212 
1213 /**
1214   The constructor function caches the pointer to VarCheck protocol and last boot variable error flag.
1215 
1216   The constructor function locates VarCheck protocol from protocol database.
1217   It will ASSERT() if that operation fails and it will always return EFI_SUCCESS.
1218 
1219   @param  ImageHandle   The firmware allocated handle for the EFI image.
1220   @param  SystemTable   A pointer to the EFI System Table.
1221 
1222   @retval EFI_SUCCESS   The constructor always returns EFI_SUCCESS.
1223 
1224 **/
1225 EFI_STATUS
1226 EFIAPI
PlatformVarCleanupLibConstructor(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)1227 PlatformVarCleanupLibConstructor (
1228   IN EFI_HANDLE         ImageHandle,
1229   IN EFI_SYSTEM_TABLE   *SystemTable
1230   )
1231 {
1232   EFI_STATUS    Status;
1233 
1234   mLastVarErrorFlag = InternalGetVarErrorFlag ();
1235   DEBUG ((EFI_D_INFO, "mLastVarErrorFlag - 0x%02x\n", mLastVarErrorFlag));
1236 
1237   //
1238   // Register EFI_END_OF_DXE_EVENT_GROUP_GUID event.
1239   //
1240   Status = gBS->CreateEventEx (
1241                   EVT_NOTIFY_SIGNAL,
1242                   TPL_CALLBACK,
1243                   PlatformVarCleanupEndOfDxeEvent,
1244                   NULL,
1245                   &gEfiEndOfDxeEventGroupGuid,
1246                   &mPlatVarCleanupLibEndOfDxeEvent
1247                   );
1248   ASSERT_EFI_ERROR (Status);
1249 
1250   return EFI_SUCCESS;
1251 }
1252 
1253 /**
1254   The destructor function closes the End of DXE event.
1255 
1256   @param  ImageHandle   The firmware allocated handle for the EFI image.
1257   @param  SystemTable   A pointer to the EFI System Table.
1258 
1259   @retval EFI_SUCCESS   The destructor completed successfully.
1260 
1261 **/
1262 EFI_STATUS
1263 EFIAPI
PlatformVarCleanupLibDestructor(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)1264 PlatformVarCleanupLibDestructor (
1265   IN EFI_HANDLE         ImageHandle,
1266   IN EFI_SYSTEM_TABLE   *SystemTable
1267   )
1268 {
1269   EFI_STATUS    Status;
1270 
1271   //
1272   // Close the End of DXE event.
1273   //
1274   Status = gBS->CloseEvent (mPlatVarCleanupLibEndOfDxeEvent);
1275   ASSERT_EFI_ERROR (Status);
1276 
1277   return EFI_SUCCESS;
1278 }
1279