• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2   Sample platform variable cleanup library implementation.
3 
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
9 
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 
13 **/
14 
15 #include "PlatVarCleanup.h"
16 
17 VAR_ERROR_FLAG              mLastVarErrorFlag = VAR_ERROR_FLAG_NO_ERROR;
18 EDKII_VAR_CHECK_PROTOCOL    *mVarCheck = NULL;
19 
20 ///
21 /// The flag to indicate whether the platform has left the DXE phase of execution.
22 ///
23 BOOLEAN                     mEndOfDxe = FALSE;
24 
25 LIST_ENTRY                  mUserVariableList = INITIALIZE_LIST_HEAD_VARIABLE (mUserVariableList);
26 UINT16                      mUserVariableCount = 0;
27 UINT16                      mMarkedUserVariableCount = 0;
28 
29 EFI_GUID                    mVariableCleanupHiiGuid = VARIABLE_CLEANUP_HII_GUID;
30 CHAR16                      mVarStoreName[] = L"VariableCleanup";
31 
32 HII_VENDOR_DEVICE_PATH      mVarCleanupHiiVendorDevicePath = {
33   {
34     {
35       HARDWARE_DEVICE_PATH,
36       HW_VENDOR_DP,
37       {
38         (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
39         (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
40       }
41     },
42     VARIABLE_CLEANUP_HII_GUID
43   },
44   {
45     END_DEVICE_PATH_TYPE,
46     END_ENTIRE_DEVICE_PATH_SUBTYPE,
47     {
48       (UINT8) (sizeof (EFI_DEVICE_PATH_PROTOCOL)),
49       (UINT8) ((sizeof (EFI_DEVICE_PATH_PROTOCOL)) >> 8)
50     }
51   }
52 };
53 
54 /**
55   Internal get variable error flag.
56 
57   @return   Variable error flag.
58 
59 **/
60 VAR_ERROR_FLAG
InternalGetVarErrorFlag(VOID)61 InternalGetVarErrorFlag (
62   VOID
63   )
64 {
65   EFI_STATUS        Status;
66   UINTN             Size;
67   VAR_ERROR_FLAG    ErrorFlag;
68 
69   Size = sizeof (ErrorFlag);
70   Status = gRT->GetVariable (
71                   VAR_ERROR_FLAG_NAME,
72                   &gEdkiiVarErrorFlagGuid,
73                   NULL,
74                   &Size,
75                   &ErrorFlag
76                   );
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;
80   }
81   return ErrorFlag;
82 }
83 
84 /**
85   Is user variable?
86 
87   @param[in] Name   Pointer to variable name.
88   @param[in] Guid   Pointer to vendor guid.
89 
90   @retval TRUE      User variable.
91   @retval FALSE     System variable.
92 
93 **/
94 BOOLEAN
IsUserVariable(IN CHAR16 * Name,IN EFI_GUID * Guid)95 IsUserVariable (
96   IN CHAR16                     *Name,
97   IN EFI_GUID                   *Guid
98   )
99 {
100   EFI_STATUS                    Status;
101   VAR_CHECK_VARIABLE_PROPERTY   Property;
102 
103   ZeroMem (&Property, sizeof (Property));
104   Status = mVarCheck->VariablePropertyGet (
105                         Name,
106                         Guid,
107                         &Property
108                         );
109   if (EFI_ERROR (Status)) {
110     //
111     // No property, it is user variable.
112     //
113     DEBUG ((EFI_D_INFO, "PlatformVarCleanup - User variable: %g:%s\n", Guid, Name));
114     return TRUE;
115   }
116 
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));
123 
124   return FALSE;
125 }
126 
127 /**
128   Find user variable node by variable GUID.
129 
130   @param[in] Guid   Pointer to vendor guid.
131 
132   @return Pointer to user variable node.
133 
134 **/
135 USER_VARIABLE_NODE *
FindUserVariableNodeByGuid(IN EFI_GUID * Guid)136 FindUserVariableNodeByGuid (
137   IN EFI_GUID   *Guid
138   )
139 {
140   USER_VARIABLE_NODE    *UserVariableNode;
141   LIST_ENTRY            *Link;
142 
143   for (Link = mUserVariableList.ForwardLink
144        ;Link != &mUserVariableList
145        ;Link = Link->ForwardLink) {
146     UserVariableNode = USER_VARIABLE_FROM_LINK (Link);
147 
148     if (CompareGuid (Guid, &UserVariableNode->Guid)) {
149       //
150       // Found it.
151       //
152       return UserVariableNode;
153     }
154   }
155 
156   //
157   // Create new one if not found.
158   //
159   UserVariableNode = AllocateZeroPool (sizeof (*UserVariableNode));
160   ASSERT (UserVariableNode != NULL);
161   UserVariableNode->Signature = USER_VARIABLE_NODE_SIGNATURE;
162   CopyGuid (&UserVariableNode->Guid, Guid);
163   //
164   // (36 chars of "########-####-####-####-############" + 1 space + 1 terminator) * sizeof (CHAR16).
165   //
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;
172 }
173 
174 /**
175   Create user variable node.
176 
177 **/
178 VOID
CreateUserVariableNode(VOID)179 CreateUserVariableNode (
180   VOID
181   )
182 {
183   EFI_STATUS                    Status;
184   EFI_STATUS                    GetVariableStatus;
185   CHAR16                        *VarName;
186   UINTN                         MaxVarNameSize;
187   UINTN                         VarNameSize;
188   UINTN                         MaxDataSize;
189   UINTN                         DataSize;
190   VOID                          *Data;
191   UINT32                        Attributes;
192   EFI_GUID                      Guid;
193   USER_VARIABLE_NODE            *UserVariableNode;
194   USER_VARIABLE_NAME_NODE       *UserVariableNameNode;
195   UINT16                        Index;
196   UINTN                         StringSize;
197 
198   //
199   // Initialize 128 * sizeof (CHAR16) variable name size.
200   //
201   MaxVarNameSize = 128 * sizeof (CHAR16);
202   VarName = AllocateZeroPool (MaxVarNameSize);
203   ASSERT (VarName != NULL);
204 
205   //
206   // Initialize 0x1000 variable data size.
207   //
208   MaxDataSize = 0x1000;
209   Data = AllocateZeroPool (MaxDataSize);
210   ASSERT (Data != NULL);
211 
212   Index = 0;
213   do {
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);
221     }
222 
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);
232         }
233         ASSERT_EFI_ERROR (GetVariableStatus);
234 
235         if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
236           UserVariableNode = FindUserVariableNodeByGuid (&Guid);
237           ASSERT (UserVariableNode != NULL);
238 
239           //
240           // Different variables that have same variable GUID share same user variable node.
241           //
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);
250           //
251           // 2 space * sizeof (CHAR16) + StrSize.
252           //
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);
257           //
258           // (33 chars of "Attribtues = 0x and DataSize = 0x" + 1 terminator + (sizeof (UINT32) + sizeof (UINTN)) * 2) * sizeof (CHAR16).
259           //
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);
266           Index++;
267         }
268       }
269     }
270   } while (Status != EFI_NOT_FOUND);
271 
272   mUserVariableCount = Index;
273   ASSERT (mUserVariableCount <= MAX_USER_VARIABLE_COUNT);
274   DEBUG ((EFI_D_INFO, "PlatformVarCleanup - User variable count: 0x%04x\n", mUserVariableCount));
275 
276   FreePool (VarName);
277   FreePool (Data);
278 }
279 
280 /**
281   Destroy user variable nodes.
282 
283 **/
284 VOID
DestroyUserVariableNode(VOID)285 DestroyUserVariableNode (
286   VOID
287   )
288 {
289   USER_VARIABLE_NODE        *UserVariableNode;
290   LIST_ENTRY                *Link;
291   USER_VARIABLE_NAME_NODE   *UserVariableNameNode;
292   LIST_ENTRY                *NameLink;
293 
294   while (mUserVariableList.ForwardLink != &mUserVariableList) {
295     Link = mUserVariableList.ForwardLink;
296     UserVariableNode = USER_VARIABLE_FROM_LINK (Link);
297 
298     RemoveEntryList (&UserVariableNode->Link);
299 
300     while (UserVariableNode->NameLink.ForwardLink != &UserVariableNode->NameLink) {
301       NameLink = UserVariableNode->NameLink.ForwardLink;
302       UserVariableNameNode = USER_VARIABLE_NAME_FROM_LINK (NameLink);
303 
304       RemoveEntryList (&UserVariableNameNode->Link);
305 
306       FreePool (UserVariableNameNode->Name);
307       FreePool (UserVariableNameNode->PromptString);
308       FreePool (UserVariableNameNode->HelpString);
309       FreePool (UserVariableNameNode);
310     }
311 
312     FreePool (UserVariableNode->PromptString);
313     FreePool (UserVariableNode);
314   }
315 }
316 
317 /**
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.
320 
321   @param[in, out] DataSize          On input, the size of Data buffer in bytes.
322                                     On output, the size of data returned in Data
323                                     buffer in bytes.
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.
328 
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.
333 
334 **/
335 EFI_STATUS
CreateTimeBasedPayload(IN OUT UINTN * DataSize,IN OUT UINT8 ** Data)336 CreateTimeBasedPayload (
337   IN OUT UINTN      *DataSize,
338   IN OUT UINT8      **Data
339   )
340 {
341   EFI_STATUS                        Status;
342   UINT8                             *NewData;
343   UINT8                             *Payload;
344   UINTN                             PayloadSize;
345   EFI_VARIABLE_AUTHENTICATION_2     *DescriptorData;
346   UINTN                             DescriptorSize;
347   EFI_TIME                          Time;
348 
349   if (Data == NULL || DataSize == NULL) {
350     return EFI_INVALID_PARAMETER;
351   }
352 
353   //
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
357   // data in it.
358   //
359   Payload     = *Data;
360   PayloadSize = *DataSize;
361 
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;
366   }
367 
368   if ((Payload != NULL) && (PayloadSize != 0)) {
369     CopyMem (NewData + DescriptorSize, Payload, PayloadSize);
370   }
371 
372   DescriptorData = (EFI_VARIABLE_AUTHENTICATION_2 *) (NewData);
373 
374   ZeroMem (&Time, sizeof (EFI_TIME));
375   Status = gRT->GetTime (&Time, NULL);
376   if (EFI_ERROR (Status)) {
377     FreePool (NewData);
378     return Status;
379   }
380   Time.Pad1       = 0;
381   Time.Nanosecond = 0;
382   Time.TimeZone   = 0;
383   Time.Daylight   = 0;
384   Time.Pad2       = 0;
385   CopyMem (&DescriptorData->TimeStamp, &Time, sizeof (EFI_TIME));
386 
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);
391 
392   if (Payload != NULL) {
393     FreePool (Payload);
394   }
395 
396   *DataSize = DescriptorSize + PayloadSize;
397   *Data     = NewData;
398   return EFI_SUCCESS;
399 }
400 
401 /**
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.
404 
405   @param[in, out] DataSize          On input, the size of Data buffer in bytes.
406                                     On output, the size of data returned in Data
407                                     buffer in bytes.
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.
412 
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.
417 
418 **/
419 EFI_STATUS
CreateCounterBasedPayload(IN OUT UINTN * DataSize,IN OUT UINT8 ** Data)420 CreateCounterBasedPayload (
421   IN OUT UINTN      *DataSize,
422   IN OUT UINT8      **Data
423   )
424 {
425   EFI_STATUS                        Status;
426   UINT8                             *NewData;
427   UINT8                             *Payload;
428   UINTN                             PayloadSize;
429   EFI_VARIABLE_AUTHENTICATION       *DescriptorData;
430   UINTN                             DescriptorSize;
431   UINT64                            MonotonicCount;
432 
433   if (Data == NULL || DataSize == NULL) {
434     return EFI_INVALID_PARAMETER;
435   }
436 
437   //
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
441   // data in it.
442   //
443   Payload     = *Data;
444   PayloadSize = *DataSize;
445 
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;
452   }
453 
454   if ((Payload != NULL) && (PayloadSize != 0)) {
455     CopyMem (NewData + DescriptorSize, Payload, PayloadSize);
456   }
457 
458   DescriptorData = (EFI_VARIABLE_AUTHENTICATION *) (NewData);
459 
460   Status = gBS->GetNextMonotonicCount (&MonotonicCount);
461   if (EFI_ERROR (Status)) {
462     FreePool (NewData);
463     return Status;
464   }
465   DescriptorData->MonotonicCount = MonotonicCount;
466 
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);
471 
472   if (Payload != NULL) {
473     FreePool (Payload);
474   }
475 
476   *DataSize = DescriptorSize + PayloadSize;
477   *Data     = NewData;
478   return EFI_SUCCESS;
479 }
480 
481 /**
482   Delete user variable.
483 
484   @param[in] DeleteAll              Delete all user variables.
485   @param[in] VariableCleanupData    Pointer to variable cleanup data.
486 
487 **/
488 VOID
DeleteUserVariable(IN BOOLEAN DeleteAll,IN VARIABLE_CLEANUP_DATA * VariableCleanupData OPTIONAL)489 DeleteUserVariable (
490   IN BOOLEAN                DeleteAll,
491   IN VARIABLE_CLEANUP_DATA  *VariableCleanupData OPTIONAL
492   )
493 {
494   EFI_STATUS                Status;
495   USER_VARIABLE_NODE        *UserVariableNode;
496   LIST_ENTRY                *Link;
497   USER_VARIABLE_NAME_NODE   *UserVariableNameNode;
498   LIST_ENTRY                *NameLink;
499   UINTN                     DataSize;
500   UINT8                     *Data;
501 
502   for (Link = mUserVariableList.ForwardLink
503        ;Link != &mUserVariableList
504        ;Link = Link->ForwardLink) {
505     UserVariableNode = USER_VARIABLE_FROM_LINK (Link);
506 
507     for (NameLink = UserVariableNode->NameLink.ForwardLink
508         ;NameLink != &UserVariableNode->NameLink
509         ;NameLink = NameLink->ForwardLink) {
510       UserVariableNameNode = USER_VARIABLE_NAME_FROM_LINK (NameLink);
511 
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) {
515           DataSize = 0;
516           Data = NULL;
517           Status = CreateTimeBasedPayload (&DataSize, &Data);
518           if (!EFI_ERROR (Status)) {
519             Status = gRT->SetVariable (UserVariableNameNode->Name, &UserVariableNode->Guid, UserVariableNameNode->Attributes, DataSize, Data);
520             FreePool (Data);
521           }
522         } else if ((UserVariableNameNode->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
523           DataSize = 0;
524           Data = NULL;
525           Status = CreateCounterBasedPayload (&DataSize, &Data);
526           if (!EFI_ERROR (Status)) {
527             Status = gRT->SetVariable (UserVariableNameNode->Name, &UserVariableNode->Guid, UserVariableNameNode->Attributes, DataSize, Data);
528             FreePool (Data);
529           }
530         } else {
531           Status = gRT->SetVariable (UserVariableNameNode->Name, &UserVariableNode->Guid, 0, 0, NULL);
532         }
533         if (!EFI_ERROR (Status)) {
534           UserVariableNameNode->Deleted = TRUE;
535         } else {
536           DEBUG ((EFI_D_INFO, "PlatformVarCleanup - Delete variable fail: %g:%s\n", &UserVariableNode->Guid, UserVariableNameNode->Name));
537         }
538       }
539     }
540   }
541 }
542 
543 /**
544   This function allows a caller to extract the current configuration for one
545   or more named elements from the target driver.
546 
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.
557 
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.
562 
563 **/
564 EFI_STATUS
565 EFIAPI
VariableCleanupHiiExtractConfig(IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL * This,IN CONST EFI_STRING Request,OUT EFI_STRING * Progress,OUT EFI_STRING * Results)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
571   )
572 {
573   EFI_STATUS                        Status;
574   VARIABLE_CLEANUP_HII_PRIVATE_DATA *Private;
575   UINTN                             BufferSize;
576   EFI_STRING                        ConfigRequestHdr;
577   EFI_STRING                        ConfigRequest;
578   BOOLEAN                           AllocatedRequest;
579   UINTN                             Size;
580 
581   if (Progress == NULL || Results == NULL) {
582     return EFI_INVALID_PARAMETER;
583   }
584 
585   *Progress = Request;
586   if ((Request != NULL) && !HiiIsConfigHdrMatch (Request, &mVariableCleanupHiiGuid, mVarStoreName)) {
587     return EFI_NOT_FOUND;
588   }
589 
590   ConfigRequestHdr = NULL;
591   ConfigRequest    = NULL;
592   AllocatedRequest = FALSE;
593   Size             = 0;
594 
595   Private = VARIABLE_CLEANUP_HII_PRIVATE_FROM_THIS (This);
596   //
597   // Convert buffer data to <ConfigResp> by helper function BlockToConfig().
598   //
599   BufferSize = sizeof (VARIABLE_CLEANUP_DATA);
600   ConfigRequest = Request;
601   if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) {
602     //
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.
606     //
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);
614   }
615 
616   Status = Private->ConfigRouting->BlockToConfig (
617                                      Private->ConfigRouting,
618                                      ConfigRequest,
619                                      (UINT8 *) &Private->VariableCleanupData,
620                                      BufferSize,
621                                      Results,
622                                      Progress
623                                      );
624   ASSERT_EFI_ERROR (Status);
625 
626   //
627   // Free the allocated config request string.
628   //
629   if (AllocatedRequest) {
630     FreePool (ConfigRequest);
631     ConfigRequest = NULL;
632   }
633   //
634   // Set Progress string to the original request string or the string's null terminator.
635   //
636   if (Request == NULL) {
637     *Progress = NULL;
638   } else if (StrStr (Request, L"OFFSET") == NULL) {
639     *Progress = Request + StrLen (Request);
640   }
641 
642   return Status;
643 }
644 
645 /**
646   Update user variable form.
647 
648   @param[in] Private    Points to the VARIABLE_CLEANUP_HII_PRIVATE_DATA.
649 
650 **/
651 VOID
UpdateUserVariableForm(IN VARIABLE_CLEANUP_HII_PRIVATE_DATA * Private)652 UpdateUserVariableForm (
653   IN VARIABLE_CLEANUP_HII_PRIVATE_DATA  *Private
654   )
655 {
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;
663   LIST_ENTRY                *Link;
664   USER_VARIABLE_NAME_NODE   *UserVariableNameNode;
665   LIST_ENTRY                *NameLink;
666   BOOLEAN                   Created;
667 
668   //
669   // Init OpCode Handle.
670   //
671   StartOpCodeHandle = HiiAllocateOpCodeHandle ();
672   ASSERT (StartOpCodeHandle != NULL);
673 
674   EndOpCodeHandle = HiiAllocateOpCodeHandle ();
675   ASSERT (EndOpCodeHandle != NULL);
676 
677   //
678   // Create Hii Extend Label OpCode as the start opcode.
679   //
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;
683 
684   //
685   // Create Hii Extend Label OpCode as the end opcode.
686   //
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;
690 
691   HiiUpdateForm (
692     Private->HiiHandle,
693     &mVariableCleanupHiiGuid,
694     FORM_ID_VARIABLE_CLEANUP,
695     StartOpCodeHandle, // LABEL_START
696     EndOpCodeHandle    // LABEL_END
697     );
698 
699   for (Link = mUserVariableList.ForwardLink
700       ;Link != &mUserVariableList
701       ;Link = Link->ForwardLink) {
702     UserVariableNode = USER_VARIABLE_FROM_LINK (Link);
703 
704     //
705     // Create checkbox opcode for variables in the same variable GUID space.
706     //
707     Created = FALSE;
708     for (NameLink = UserVariableNode->NameLink.ForwardLink
709         ;NameLink != &UserVariableNode->NameLink
710         ;NameLink = NameLink->ForwardLink) {
711       UserVariableNameNode = USER_VARIABLE_NAME_FROM_LINK (NameLink);
712 
713       if (!UserVariableNameNode->Deleted) {
714         if (!Created) {
715           //
716           // Create subtitle opcode for variable GUID.
717           //
718           PromptStringToken = HiiSetString (Private->HiiHandle, 0, UserVariableNode->PromptString, NULL);
719           HiiCreateSubTitleOpCode (StartOpCodeHandle, PromptStringToken, 0, 0, 0);
720           Created = TRUE;
721         }
722 
723         //
724         // Only create opcode for the non-deleted variables.
725         //
726         PromptStringToken = HiiSetString (Private->HiiHandle, 0, UserVariableNameNode->PromptString, NULL);
727         HelpStringToken = HiiSetString (Private->HiiHandle, 0, UserVariableNameNode->HelpString, NULL);
728         HiiCreateCheckBoxOpCode (
729           StartOpCodeHandle,
730           UserVariableNameNode->QuestionId,
731           VARIABLE_CLEANUP_VARSTORE_ID,
732           (UINT16) (USER_VARIABLE_VAR_OFFSET + UserVariableNameNode->Index),
733           PromptStringToken,
734           HelpStringToken,
735           EFI_IFR_FLAG_CALLBACK,
736           Private->VariableCleanupData.UserVariable[UserVariableNameNode->Index],
737           NULL
738           );
739       }
740     }
741   }
742 
743   HiiCreateSubTitleOpCode (
744     StartOpCodeHandle,
745     STRING_TOKEN (STR_NULL_STRING),
746     0,
747     0,
748     0
749     );
750 
751   //
752   // Create the "Apply changes" and "Discard changes" tags.
753   //
754   HiiCreateActionOpCode (
755     StartOpCodeHandle,
756     SAVE_AND_EXIT_QUESTION_ID,
757     STRING_TOKEN (STR_SAVE_AND_EXIT),
758     STRING_TOKEN (STR_NULL_STRING),
759     EFI_IFR_FLAG_CALLBACK,
760     0
761     );
762   HiiCreateActionOpCode (
763     StartOpCodeHandle,
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,
768     0
769     );
770 
771   HiiUpdateForm (
772     Private->HiiHandle,
773     &mVariableCleanupHiiGuid,
774     FORM_ID_VARIABLE_CLEANUP,
775     StartOpCodeHandle, // LABEL_START
776     EndOpCodeHandle    // LABEL_END
777     );
778 
779   HiiFreeOpCodeHandle (StartOpCodeHandle);
780   HiiFreeOpCodeHandle (EndOpCodeHandle);
781 }
782 
783 /**
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.
792 
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
802                                     successful.
803 
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
809                                     protocols.
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
814                                     was not found.
815 
816 **/
817 EFI_STATUS
818 EFIAPI
VariableCleanupHiiRouteConfig(IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL * This,IN CONST EFI_STRING Configuration,OUT EFI_STRING * Progress)819 VariableCleanupHiiRouteConfig (
820   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL      *This,
821   IN  CONST EFI_STRING                          Configuration,
822   OUT EFI_STRING                                *Progress
823   )
824 {
825   EFI_STATUS                        Status;
826   VARIABLE_CLEANUP_HII_PRIVATE_DATA *Private;
827   UINTN                             BufferSize;
828 
829   if (Progress == NULL) {
830     return EFI_INVALID_PARAMETER;
831   }
832   *Progress = Configuration;
833 
834   if (Configuration == NULL) {
835     return EFI_INVALID_PARAMETER;
836   }
837 
838   //
839   // Check routing data in <ConfigHdr>.
840   // Note: there is no name for Name/Value storage, only GUID will be checked.
841   //
842   if (!HiiIsConfigHdrMatch (Configuration, &mVariableCleanupHiiGuid, mVarStoreName)) {
843     return EFI_NOT_FOUND;
844   }
845 
846   Private = VARIABLE_CLEANUP_HII_PRIVATE_FROM_THIS (This);
847   //
848   // Get Buffer Storage data.
849   //
850   BufferSize = sizeof (VARIABLE_CLEANUP_DATA);
851   //
852   // Convert <ConfigResp> to buffer data by helper function ConfigToBlock().
853   //
854   Status = Private->ConfigRouting->ConfigToBlock (
855                             Private->ConfigRouting,
856                             Configuration,
857                             (UINT8 *) &Private->VariableCleanupData,
858                             &BufferSize,
859                             Progress
860                             );
861   ASSERT_EFI_ERROR (Status);
862 
863   DeleteUserVariable (FALSE, &Private->VariableCleanupData);
864   //
865   // For "F10" hotkey to refresh the form.
866   //
867 //  UpdateUserVariableForm (Private);
868 
869   return EFI_SUCCESS;
870 }
871 
872 /**
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.
876 
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
885                                     exporting driver.
886   @param[out] ActionRequest         On return, points to the action requested by the
887                                     callback function.
888 
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
894                                     callback.
895 **/
896 EFI_STATUS
897 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)898 VariableCleanupHiiCallback (
899   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
900   IN  EFI_BROWSER_ACTION                     Action,
901   IN  EFI_QUESTION_ID                        QuestionId,
902   IN  UINT8                                  Type,
903   IN  EFI_IFR_TYPE_VALUE                     *Value,
904   OUT EFI_BROWSER_ACTION_REQUEST             *ActionRequest
905   )
906 {
907   VARIABLE_CLEANUP_HII_PRIVATE_DATA *Private;
908   VARIABLE_CLEANUP_DATA             *VariableCleanupData;
909 
910   Private = VARIABLE_CLEANUP_HII_PRIVATE_FROM_THIS (This);
911 
912   if ((Action != EFI_BROWSER_ACTION_CHANGING) && (Action != EFI_BROWSER_ACTION_CHANGED)) {
913     //
914     // All other action return unsupported.
915     //
916     return EFI_UNSUPPORTED;
917   }
918 
919   //
920   // Retrive uncommitted data from Form Browser.
921   //
922   VariableCleanupData = &Private->VariableCleanupData;
923   HiiGetBrowserData (&mVariableCleanupHiiGuid, mVarStoreName, sizeof (VARIABLE_CLEANUP_DATA), (UINT8 *) VariableCleanupData);
924   if (Action == EFI_BROWSER_ACTION_CHANGING) {
925     if (Value == NULL) {
926       return EFI_INVALID_PARAMETER;
927     }
928   } else if (Action == EFI_BROWSER_ACTION_CHANGED) {
929     if ((Value == NULL) || (ActionRequest == NULL)) {
930       return EFI_INVALID_PARAMETER;
931     }
932     if ((QuestionId >= USER_VARIABLE_QUESTION_ID) && (QuestionId < USER_VARIABLE_QUESTION_ID + MAX_USER_VARIABLE_COUNT)) {
933       if (Value->b){
934         //
935         // Means one user variable checkbox is marked to delete but not press F10 or "Commit Changes and Exit" menu.
936         //
937         mMarkedUserVariableCount++;
938         ASSERT (mMarkedUserVariableCount <= mUserVariableCount);
939         if (mMarkedUserVariableCount == mUserVariableCount) {
940           //
941           // All user variables have been marked, then also mark the SelectAll checkbox.
942           //
943           VariableCleanupData->SelectAll = TRUE;
944         }
945       } else {
946         //
947         // Means one user variable checkbox is unmarked.
948         //
949         mMarkedUserVariableCount--;
950         //
951         // Also unmark the SelectAll checkbox.
952         //
953         VariableCleanupData->SelectAll = FALSE;
954       }
955     } else {
956       switch (QuestionId) {
957         case SELECT_ALL_QUESTION_ID:
958          if (Value->b){
959             //
960             // Means the SelectAll checkbox is marked to delete all user variables but not press F10 or "Commit Changes and Exit" menu.
961             //
962             SetMem (VariableCleanupData->UserVariable, sizeof (VariableCleanupData->UserVariable), TRUE);
963             mMarkedUserVariableCount = mUserVariableCount;
964           } else {
965             //
966             // Means the SelectAll checkbox is unmarked.
967             //
968             SetMem (VariableCleanupData->UserVariable, sizeof (VariableCleanupData->UserVariable), FALSE);
969             mMarkedUserVariableCount = 0;
970           }
971           break;
972         case SAVE_AND_EXIT_QUESTION_ID:
973           DeleteUserVariable (FALSE, VariableCleanupData);
974           *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT;
975           break;
976 
977         case NO_SAVE_AND_EXIT_QUESTION_ID:
978           //
979           // Restore local maintain data.
980           //
981           *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT;
982           break;
983 
984         default:
985           break;
986       }
987     }
988   }
989 
990   //
991   // Pass changed uncommitted data back to Form Browser.
992   //
993   HiiSetBrowserData (&mVariableCleanupHiiGuid, mVarStoreName, sizeof (VARIABLE_CLEANUP_DATA), (UINT8 *) VariableCleanupData, NULL);
994   return EFI_SUCCESS;
995 }
996 
997 /**
998   Platform variable cleanup.
999 
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.
1003 
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.
1011 
1012 **/
1013 EFI_STATUS
1014 EFIAPI
PlatformVarCleanup(IN VAR_ERROR_FLAG Flag,IN VAR_CLEANUP_TYPE Type)1015 PlatformVarCleanup (
1016   IN VAR_ERROR_FLAG     Flag,
1017   IN VAR_CLEANUP_TYPE   Type
1018   )
1019 {
1020   EFI_STATUS                            Status;
1021   EFI_FORM_BROWSER2_PROTOCOL            *FormBrowser2;
1022   VARIABLE_CLEANUP_HII_PRIVATE_DATA     *Private;
1023 
1024   if (!mEndOfDxe) {
1025     //
1026     // This implementation must be called after EndOfDxe.
1027     //
1028     return EFI_UNSUPPORTED;
1029   }
1030 
1031   if ((Type >= VarCleanupMax) || ((Flag & ((VAR_ERROR_FLAG) (VAR_ERROR_FLAG_SYSTEM_ERROR & VAR_ERROR_FLAG_USER_ERROR))) == 0)) {
1032     return EFI_INVALID_PARAMETER;
1033   }
1034 
1035   if (Flag == VAR_ERROR_FLAG_NO_ERROR) {
1036     //
1037     // Just return success if no error.
1038     //
1039     return EFI_SUCCESS;
1040   }
1041 
1042   if ((Flag & (~((VAR_ERROR_FLAG) VAR_ERROR_FLAG_SYSTEM_ERROR))) == 0) {
1043     //
1044     // This sample does not support system variables cleanup.
1045     //
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;
1049   }
1050 
1051   //
1052   // Continue to process VAR_ERROR_FLAG_USER_ERROR.
1053   //
1054 
1055   //
1056   // Create user variable nodes for the following processing.
1057   //
1058   CreateUserVariableNode ();
1059 
1060   switch (Type) {
1061     case VarCleanupAll:
1062       DeleteUserVariable (TRUE, NULL);
1063       //
1064       // Destroyed the created user variable nodes
1065       //
1066       DestroyUserVariableNode ();
1067       return EFI_SUCCESS;
1068       break;
1069 
1070     case VarCleanupManually:
1071       //
1072       // Locate FormBrowser2 protocol.
1073       //
1074       Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &FormBrowser2);
1075       if (EFI_ERROR (Status)) {
1076         return Status;
1077       }
1078 
1079       Private = AllocateZeroPool (sizeof (VARIABLE_CLEANUP_HII_PRIVATE_DATA));
1080       if (Private == NULL) {
1081         return EFI_OUT_OF_RESOURCES;
1082       }
1083 
1084       Private->Signature = VARIABLE_CLEANUP_HII_PRIVATE_SIGNATURE;
1085       Private->ConfigAccess.ExtractConfig = VariableCleanupHiiExtractConfig;
1086       Private->ConfigAccess.RouteConfig   = VariableCleanupHiiRouteConfig;
1087       Private->ConfigAccess.Callback      = VariableCleanupHiiCallback;
1088 
1089       Status = gBS->LocateProtocol (
1090                       &gEfiHiiConfigRoutingProtocolGuid,
1091                       NULL,
1092                       (VOID **) &Private->ConfigRouting
1093                       );
1094       if (EFI_ERROR (Status)) {
1095         goto Done;
1096       }
1097 
1098       //
1099       // Install Device Path Protocol and Config Access protocol to driver handle.
1100       //
1101       Status = gBS->InstallMultipleProtocolInterfaces (
1102                       &Private->DriverHandle,
1103                       &gEfiDevicePathProtocolGuid,
1104                       &mVarCleanupHiiVendorDevicePath,
1105                       &gEfiHiiConfigAccessProtocolGuid,
1106                       &Private->ConfigAccess,
1107                       NULL
1108                       );
1109       if (EFI_ERROR (Status)) {
1110         goto Done;
1111       }
1112 
1113       //
1114       // Publish our HII data.
1115       //
1116       Private->HiiHandle = HiiAddPackages (
1117                              &mVariableCleanupHiiGuid,
1118                              Private->DriverHandle,
1119                              PlatformVarCleanupLibStrings,
1120                              PlatVarCleanupBin,
1121                              NULL
1122                              );
1123       if (Private->HiiHandle == NULL) {
1124         Status = EFI_OUT_OF_RESOURCES;
1125         goto Done;
1126       }
1127 
1128       UpdateUserVariableForm (Private);
1129 
1130       Status = FormBrowser2->SendForm (
1131                                FormBrowser2,
1132                                &Private->HiiHandle,
1133                                1,
1134                                NULL,
1135                                0,
1136                                NULL,
1137                                NULL
1138                                );
1139       break;
1140 
1141     default:
1142       return EFI_UNSUPPORTED;
1143       break;
1144   }
1145 
1146 Done:
1147   if (Private->DriverHandle != NULL) {
1148     gBS->UninstallMultipleProtocolInterfaces (
1149            Private->DriverHandle,
1150            &gEfiDevicePathProtocolGuid,
1151            &mVarCleanupHiiVendorDevicePath,
1152            &gEfiHiiConfigAccessProtocolGuid,
1153            &Private->ConfigAccess,
1154            NULL
1155            );
1156   }
1157   if (Private->HiiHandle != NULL) {
1158     HiiRemovePackages (Private->HiiHandle);
1159   }
1160 
1161   FreePool (Private);
1162 
1163   //
1164   // Destroyed the created user variable nodes
1165   //
1166   DestroyUserVariableNode ();
1167   return Status;
1168 }
1169 
1170 /**
1171   Get last boot variable error flag.
1172 
1173   @return   Last boot variable error flag.
1174 
1175 **/
1176 VAR_ERROR_FLAG
1177 EFIAPI
GetLastBootVarErrorFlag()1178 GetLastBootVarErrorFlag (
1179   )
1180 {
1181   return mLastVarErrorFlag;
1182 }
1183 
1184 /**
1185   Notification function of END_OF_DXE.
1186 
1187   This is a notification function registered on END_OF_DXE event.
1188 
1189   @param[in] Event      Event whose notification function is being invoked.
1190   @param[in] Context    Pointer to the notification function's context.
1191 
1192 **/
1193 VOID
1194 EFIAPI
PlatformVarCleanupEndOfDxeEvent(IN EFI_EVENT Event,IN VOID * Context)1195 PlatformVarCleanupEndOfDxeEvent (
1196   IN EFI_EVENT  Event,
1197   IN VOID       *Context
1198   )
1199 {
1200   mEndOfDxe = TRUE;
1201 }
1202 
1203 /**
1204   The constructor function caches the pointer to VarCheck protocol and last boot variable error flag.
1205 
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.
1208 
1209   @param  ImageHandle   The firmware allocated handle for the EFI image.
1210   @param  SystemTable   A pointer to the EFI System Table.
1211 
1212   @retval EFI_SUCCESS   The constructor always returns EFI_SUCCESS.
1213 
1214 **/
1215 EFI_STATUS
1216 EFIAPI
PlatformVarCleanupLibConstructor(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)1217 PlatformVarCleanupLibConstructor (
1218   IN EFI_HANDLE         ImageHandle,
1219   IN EFI_SYSTEM_TABLE   *SystemTable
1220   )
1221 {
1222   EFI_STATUS    Status;
1223   EFI_EVENT     Event;
1224 
1225   mLastVarErrorFlag = InternalGetVarErrorFlag ();
1226   DEBUG ((EFI_D_INFO, "mLastVarErrorFlag - 0x%02x\n", mLastVarErrorFlag));
1227 
1228   Status = gBS->LocateProtocol (
1229                   &gEdkiiVarCheckProtocolGuid,
1230                   NULL,
1231                   (VOID **) &mVarCheck
1232                   );
1233   ASSERT_EFI_ERROR (Status);
1234 
1235   //
1236   // Register EFI_END_OF_DXE_EVENT_GROUP_GUID event.
1237   //
1238   Status = gBS->CreateEventEx (
1239                   EVT_NOTIFY_SIGNAL,
1240                   TPL_CALLBACK,
1241                   PlatformVarCleanupEndOfDxeEvent,
1242                   NULL,
1243                   &gEfiEndOfDxeEventGroupGuid,
1244                   &Event
1245                   );
1246   ASSERT_EFI_ERROR (Status);
1247 
1248   return EFI_SUCCESS;
1249 }
1250 
1251