1 /** @file
2   Sample platform variable cleanup library implementation.
3 
4 Copyright (c) 2015 - 2016, 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   if (mVarCheck == NULL) {
104     gBS->LocateProtocol (
105            &gEdkiiVarCheckProtocolGuid,
106            NULL,
107            (VOID **) &mVarCheck
108            );
109   }
110   ASSERT (mVarCheck != NULL);
111 
112   ZeroMem (&Property, sizeof (Property));
113   Status = mVarCheck->VariablePropertyGet (
114                         Name,
115                         Guid,
116                         &Property
117                         );
118   if (EFI_ERROR (Status)) {
119     //
120     // No property, it is user variable.
121     //
122     DEBUG ((EFI_D_INFO, "PlatformVarCleanup - User variable: %g:%s\n", Guid, Name));
123     return TRUE;
124   }
125 
126 //  DEBUG ((EFI_D_INFO, "PlatformVarCleanup - Variable Property: %g:%s\n", Guid, Name));
127 //  DEBUG ((EFI_D_INFO, "  Revision  - 0x%04x\n", Property.Revision));
128 //  DEBUG ((EFI_D_INFO, "  Property  - 0x%04x\n", Property.Property));
129 //  DEBUG ((EFI_D_INFO, "  Attribute - 0x%08x\n", Property.Attributes));
130 //  DEBUG ((EFI_D_INFO, "  MinSize   - 0x%x\n", Property.MinSize));
131 //  DEBUG ((EFI_D_INFO, "  MaxSize   - 0x%x\n", Property.MaxSize));
132 
133   return FALSE;
134 }
135 
136 /**
137   Find user variable node by variable GUID.
138 
139   @param[in] Guid   Pointer to vendor guid.
140 
141   @return Pointer to user variable node.
142 
143 **/
144 USER_VARIABLE_NODE *
FindUserVariableNodeByGuid(IN EFI_GUID * Guid)145 FindUserVariableNodeByGuid (
146   IN EFI_GUID   *Guid
147   )
148 {
149   USER_VARIABLE_NODE    *UserVariableNode;
150   LIST_ENTRY            *Link;
151 
152   for (Link = mUserVariableList.ForwardLink
153        ;Link != &mUserVariableList
154        ;Link = Link->ForwardLink) {
155     UserVariableNode = USER_VARIABLE_FROM_LINK (Link);
156 
157     if (CompareGuid (Guid, &UserVariableNode->Guid)) {
158       //
159       // Found it.
160       //
161       return UserVariableNode;
162     }
163   }
164 
165   //
166   // Create new one if not found.
167   //
168   UserVariableNode = AllocateZeroPool (sizeof (*UserVariableNode));
169   ASSERT (UserVariableNode != NULL);
170   UserVariableNode->Signature = USER_VARIABLE_NODE_SIGNATURE;
171   CopyGuid (&UserVariableNode->Guid, Guid);
172   //
173   // (36 chars of "########-####-####-####-############" + 1 space + 1 terminator) * sizeof (CHAR16).
174   //
175   UserVariableNode->PromptString = AllocatePool ((36 + 2) * sizeof (CHAR16));
176   ASSERT (UserVariableNode->PromptString != NULL);
177   UnicodeSPrint (UserVariableNode->PromptString, (36 + 2) * sizeof (CHAR16), L" %g", &UserVariableNode->Guid);
178   InitializeListHead (&UserVariableNode->NameLink);
179   InsertTailList (&mUserVariableList, &UserVariableNode->Link);
180   return UserVariableNode;
181 }
182 
183 /**
184   Create user variable node.
185 
186 **/
187 VOID
CreateUserVariableNode(VOID)188 CreateUserVariableNode (
189   VOID
190   )
191 {
192   EFI_STATUS                    Status;
193   EFI_STATUS                    GetVariableStatus;
194   CHAR16                        *VarName;
195   UINTN                         MaxVarNameSize;
196   UINTN                         VarNameSize;
197   UINTN                         MaxDataSize;
198   UINTN                         DataSize;
199   VOID                          *Data;
200   UINT32                        Attributes;
201   EFI_GUID                      Guid;
202   USER_VARIABLE_NODE            *UserVariableNode;
203   USER_VARIABLE_NAME_NODE       *UserVariableNameNode;
204   UINT16                        Index;
205   UINTN                         StringSize;
206 
207   //
208   // Initialize 128 * sizeof (CHAR16) variable name size.
209   //
210   MaxVarNameSize = 128 * sizeof (CHAR16);
211   VarName = AllocateZeroPool (MaxVarNameSize);
212   ASSERT (VarName != NULL);
213 
214   //
215   // Initialize 0x1000 variable data size.
216   //
217   MaxDataSize = 0x1000;
218   Data = AllocateZeroPool (MaxDataSize);
219   ASSERT (Data != NULL);
220 
221   Index = 0;
222   do {
223     VarNameSize = MaxVarNameSize;
224     Status = gRT->GetNextVariableName (&VarNameSize, VarName, &Guid);
225     if (Status == EFI_BUFFER_TOO_SMALL) {
226       VarName = ReallocatePool (MaxVarNameSize, VarNameSize, VarName);
227       ASSERT (VarName != NULL);
228       MaxVarNameSize = VarNameSize;
229       Status = gRT->GetNextVariableName (&VarNameSize, VarName, &Guid);
230     }
231 
232     if (!EFI_ERROR (Status)) {
233       if (IsUserVariable (VarName, &Guid)) {
234         DataSize = MaxDataSize;
235         GetVariableStatus = gRT->GetVariable (VarName, &Guid, &Attributes, &DataSize, Data);
236         if (GetVariableStatus == EFI_BUFFER_TOO_SMALL) {
237           Data = ReallocatePool (MaxDataSize, DataSize, Data);
238           ASSERT (Data != NULL);
239           MaxDataSize = DataSize;
240           GetVariableStatus = gRT->GetVariable (VarName, &Guid, &Attributes, &DataSize, Data);
241         }
242         ASSERT_EFI_ERROR (GetVariableStatus);
243 
244         if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
245           UserVariableNode = FindUserVariableNodeByGuid (&Guid);
246           ASSERT (UserVariableNode != NULL);
247 
248           //
249           // Different variables that have same variable GUID share same user variable node.
250           //
251           UserVariableNameNode = AllocateZeroPool (sizeof (*UserVariableNameNode));
252           ASSERT (UserVariableNameNode != NULL);
253           UserVariableNameNode->Signature = USER_VARIABLE_NAME_NODE_SIGNATURE;
254           UserVariableNameNode->Name = AllocateCopyPool (VarNameSize, VarName);
255           UserVariableNameNode->Attributes = Attributes;
256           UserVariableNameNode->DataSize = DataSize;
257           UserVariableNameNode->Index = Index;
258           UserVariableNameNode->QuestionId = (EFI_QUESTION_ID) (USER_VARIABLE_QUESTION_ID + Index);
259           //
260           // 2 space * sizeof (CHAR16) + StrSize.
261           //
262           StringSize = 2 * sizeof (CHAR16) + StrSize (UserVariableNameNode->Name);
263           UserVariableNameNode->PromptString = AllocatePool (StringSize);
264           ASSERT (UserVariableNameNode->PromptString != NULL);
265           UnicodeSPrint (UserVariableNameNode->PromptString, StringSize, L"  %s", UserVariableNameNode->Name);
266           //
267           // (33 chars of "Attribtues = 0x and DataSize = 0x" + 1 terminator + (sizeof (UINT32) + sizeof (UINTN)) * 2) * sizeof (CHAR16).
268           //
269           StringSize = (33 + 1 + (sizeof (UINT32) + sizeof (UINTN)) * 2) * sizeof (CHAR16);
270           UserVariableNameNode->HelpString = AllocatePool (StringSize);
271           ASSERT (UserVariableNameNode->HelpString != NULL);
272           UnicodeSPrint (UserVariableNameNode->HelpString, StringSize, L"Attribtues = 0x%08x and DataSize = 0x%x", UserVariableNameNode->Attributes, UserVariableNameNode->DataSize);
273           UserVariableNameNode->Deleted = FALSE;
274           InsertTailList (&UserVariableNode->NameLink, &UserVariableNameNode->Link);
275           Index++;
276         }
277       }
278     }
279   } while (Status != EFI_NOT_FOUND);
280 
281   mUserVariableCount = Index;
282   ASSERT (mUserVariableCount <= MAX_USER_VARIABLE_COUNT);
283   DEBUG ((EFI_D_INFO, "PlatformVarCleanup - User variable count: 0x%04x\n", mUserVariableCount));
284 
285   FreePool (VarName);
286   FreePool (Data);
287 }
288 
289 /**
290   Destroy user variable nodes.
291 
292 **/
293 VOID
DestroyUserVariableNode(VOID)294 DestroyUserVariableNode (
295   VOID
296   )
297 {
298   USER_VARIABLE_NODE        *UserVariableNode;
299   LIST_ENTRY                *Link;
300   USER_VARIABLE_NAME_NODE   *UserVariableNameNode;
301   LIST_ENTRY                *NameLink;
302 
303   while (mUserVariableList.ForwardLink != &mUserVariableList) {
304     Link = mUserVariableList.ForwardLink;
305     UserVariableNode = USER_VARIABLE_FROM_LINK (Link);
306 
307     RemoveEntryList (&UserVariableNode->Link);
308 
309     while (UserVariableNode->NameLink.ForwardLink != &UserVariableNode->NameLink) {
310       NameLink = UserVariableNode->NameLink.ForwardLink;
311       UserVariableNameNode = USER_VARIABLE_NAME_FROM_LINK (NameLink);
312 
313       RemoveEntryList (&UserVariableNameNode->Link);
314 
315       FreePool (UserVariableNameNode->Name);
316       FreePool (UserVariableNameNode->PromptString);
317       FreePool (UserVariableNameNode->HelpString);
318       FreePool (UserVariableNameNode);
319     }
320 
321     FreePool (UserVariableNode->PromptString);
322     FreePool (UserVariableNode);
323   }
324 }
325 
326 /**
327   Create a time based data payload by concatenating the EFI_VARIABLE_AUTHENTICATION_2
328   descriptor with the input data. NO authentication is required in this function.
329 
330   @param[in, out] DataSize          On input, the size of Data buffer in bytes.
331                                     On output, the size of data returned in Data
332                                     buffer in bytes.
333   @param[in, out] Data              On input, Pointer to data buffer to be wrapped or
334                                     pointer to NULL to wrap an empty payload.
335                                     On output, Pointer to the new payload date buffer allocated from pool,
336                                     it's caller's responsibility to free the memory after using it.
337 
338   @retval EFI_SUCCESS               Create time based payload successfully.
339   @retval EFI_OUT_OF_RESOURCES      There are not enough memory resourses to create time based payload.
340   @retval EFI_INVALID_PARAMETER     The parameter is invalid.
341   @retval Others                    Unexpected error happens.
342 
343 **/
344 EFI_STATUS
CreateTimeBasedPayload(IN OUT UINTN * DataSize,IN OUT UINT8 ** Data)345 CreateTimeBasedPayload (
346   IN OUT UINTN      *DataSize,
347   IN OUT UINT8      **Data
348   )
349 {
350   EFI_STATUS                        Status;
351   UINT8                             *NewData;
352   UINT8                             *Payload;
353   UINTN                             PayloadSize;
354   EFI_VARIABLE_AUTHENTICATION_2     *DescriptorData;
355   UINTN                             DescriptorSize;
356   EFI_TIME                          Time;
357 
358   if (Data == NULL || DataSize == NULL) {
359     return EFI_INVALID_PARAMETER;
360   }
361 
362   //
363   // At user physical presence, the variable does not need to be signed but the
364   // parameters to the SetVariable() call still need to be prepared as authenticated
365   // variable. So we create EFI_VARIABLE_AUTHENTICATED_2 descriptor without certificate
366   // data in it.
367   //
368   Payload     = *Data;
369   PayloadSize = *DataSize;
370 
371   DescriptorSize = OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2, AuthInfo) + OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData);
372   NewData = (UINT8 *) AllocateZeroPool (DescriptorSize + PayloadSize);
373   if (NewData == NULL) {
374     return EFI_OUT_OF_RESOURCES;
375   }
376 
377   if ((Payload != NULL) && (PayloadSize != 0)) {
378     CopyMem (NewData + DescriptorSize, Payload, PayloadSize);
379   }
380 
381   DescriptorData = (EFI_VARIABLE_AUTHENTICATION_2 *) (NewData);
382 
383   ZeroMem (&Time, sizeof (EFI_TIME));
384   Status = gRT->GetTime (&Time, NULL);
385   if (EFI_ERROR (Status)) {
386     FreePool (NewData);
387     return Status;
388   }
389   Time.Pad1       = 0;
390   Time.Nanosecond = 0;
391   Time.TimeZone   = 0;
392   Time.Daylight   = 0;
393   Time.Pad2       = 0;
394   CopyMem (&DescriptorData->TimeStamp, &Time, sizeof (EFI_TIME));
395 
396   DescriptorData->AuthInfo.Hdr.dwLength         = OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData);
397   DescriptorData->AuthInfo.Hdr.wRevision        = 0x0200;
398   DescriptorData->AuthInfo.Hdr.wCertificateType = WIN_CERT_TYPE_EFI_GUID;
399   CopyGuid (&DescriptorData->AuthInfo.CertType, &gEfiCertPkcs7Guid);
400 
401   if (Payload != NULL) {
402     FreePool (Payload);
403   }
404 
405   *DataSize = DescriptorSize + PayloadSize;
406   *Data     = NewData;
407   return EFI_SUCCESS;
408 }
409 
410 /**
411   Create a counter based data payload by concatenating the EFI_VARIABLE_AUTHENTICATION
412   descriptor with the input data. NO authentication is required in this function.
413 
414   @param[in, out] DataSize          On input, the size of Data buffer in bytes.
415                                     On output, the size of data returned in Data
416                                     buffer in bytes.
417   @param[in, out] Data              On input, Pointer to data buffer to be wrapped or
418                                     pointer to NULL to wrap an empty payload.
419                                     On output, Pointer to the new payload date buffer allocated from pool,
420                                     it's caller's responsibility to free the memory after using it.
421 
422   @retval EFI_SUCCESS               Create counter based payload successfully.
423   @retval EFI_OUT_OF_RESOURCES      There are not enough memory resourses to create time based payload.
424   @retval EFI_INVALID_PARAMETER     The parameter is invalid.
425   @retval Others                    Unexpected error happens.
426 
427 **/
428 EFI_STATUS
CreateCounterBasedPayload(IN OUT UINTN * DataSize,IN OUT UINT8 ** Data)429 CreateCounterBasedPayload (
430   IN OUT UINTN      *DataSize,
431   IN OUT UINT8      **Data
432   )
433 {
434   EFI_STATUS                        Status;
435   UINT8                             *NewData;
436   UINT8                             *Payload;
437   UINTN                             PayloadSize;
438   EFI_VARIABLE_AUTHENTICATION       *DescriptorData;
439   UINTN                             DescriptorSize;
440   UINT64                            MonotonicCount;
441 
442   if (Data == NULL || DataSize == NULL) {
443     return EFI_INVALID_PARAMETER;
444   }
445 
446   //
447   // At user physical presence, the variable does not need to be signed but the
448   // parameters to the SetVariable() call still need to be prepared as authenticated
449   // variable. So we create EFI_VARIABLE_AUTHENTICATED descriptor without certificate
450   // data in it.
451   //
452   Payload     = *Data;
453   PayloadSize = *DataSize;
454 
455   DescriptorSize = (OFFSET_OF (EFI_VARIABLE_AUTHENTICATION, AuthInfo)) + \
456                    (OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData)) + \
457                    sizeof (EFI_CERT_BLOCK_RSA_2048_SHA256);
458   NewData = (UINT8 *) AllocateZeroPool (DescriptorSize + PayloadSize);
459   if (NewData == NULL) {
460     return EFI_OUT_OF_RESOURCES;
461   }
462 
463   if ((Payload != NULL) && (PayloadSize != 0)) {
464     CopyMem (NewData + DescriptorSize, Payload, PayloadSize);
465   }
466 
467   DescriptorData = (EFI_VARIABLE_AUTHENTICATION *) (NewData);
468 
469   Status = gBS->GetNextMonotonicCount (&MonotonicCount);
470   if (EFI_ERROR (Status)) {
471     FreePool (NewData);
472     return Status;
473   }
474   DescriptorData->MonotonicCount = MonotonicCount;
475 
476   DescriptorData->AuthInfo.Hdr.dwLength         = OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData) + sizeof (EFI_CERT_BLOCK_RSA_2048_SHA256);
477   DescriptorData->AuthInfo.Hdr.wRevision        = 0x0200;
478   DescriptorData->AuthInfo.Hdr.wCertificateType = WIN_CERT_TYPE_EFI_GUID;
479   CopyGuid (&DescriptorData->AuthInfo.CertType, &gEfiCertTypeRsa2048Sha256Guid);
480 
481   if (Payload != NULL) {
482     FreePool (Payload);
483   }
484 
485   *DataSize = DescriptorSize + PayloadSize;
486   *Data     = NewData;
487   return EFI_SUCCESS;
488 }
489 
490 /**
491   Delete user variable.
492 
493   @param[in] DeleteAll              Delete all user variables.
494   @param[in] VariableCleanupData    Pointer to variable cleanup data.
495 
496 **/
497 VOID
DeleteUserVariable(IN BOOLEAN DeleteAll,IN VARIABLE_CLEANUP_DATA * VariableCleanupData OPTIONAL)498 DeleteUserVariable (
499   IN BOOLEAN                DeleteAll,
500   IN VARIABLE_CLEANUP_DATA  *VariableCleanupData OPTIONAL
501   )
502 {
503   EFI_STATUS                Status;
504   USER_VARIABLE_NODE        *UserVariableNode;
505   LIST_ENTRY                *Link;
506   USER_VARIABLE_NAME_NODE   *UserVariableNameNode;
507   LIST_ENTRY                *NameLink;
508   UINTN                     DataSize;
509   UINT8                     *Data;
510 
511   for (Link = mUserVariableList.ForwardLink
512        ;Link != &mUserVariableList
513        ;Link = Link->ForwardLink) {
514     UserVariableNode = USER_VARIABLE_FROM_LINK (Link);
515 
516     for (NameLink = UserVariableNode->NameLink.ForwardLink
517         ;NameLink != &UserVariableNode->NameLink
518         ;NameLink = NameLink->ForwardLink) {
519       UserVariableNameNode = USER_VARIABLE_NAME_FROM_LINK (NameLink);
520 
521       if (!UserVariableNameNode->Deleted && (DeleteAll || ((VariableCleanupData != NULL) && (VariableCleanupData->UserVariable[UserVariableNameNode->Index] == TRUE)))) {
522         DEBUG ((EFI_D_INFO, "PlatformVarCleanup - Delete variable: %g:%s\n", &UserVariableNode->Guid, UserVariableNameNode->Name));
523         if ((UserVariableNameNode->Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {
524           DataSize = 0;
525           Data = NULL;
526           Status = CreateTimeBasedPayload (&DataSize, &Data);
527           if (!EFI_ERROR (Status)) {
528             Status = gRT->SetVariable (UserVariableNameNode->Name, &UserVariableNode->Guid, UserVariableNameNode->Attributes, DataSize, Data);
529             FreePool (Data);
530           }
531         } else if ((UserVariableNameNode->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
532           DataSize = 0;
533           Data = NULL;
534           Status = CreateCounterBasedPayload (&DataSize, &Data);
535           if (!EFI_ERROR (Status)) {
536             Status = gRT->SetVariable (UserVariableNameNode->Name, &UserVariableNode->Guid, UserVariableNameNode->Attributes, DataSize, Data);
537             FreePool (Data);
538           }
539         } else {
540           Status = gRT->SetVariable (UserVariableNameNode->Name, &UserVariableNode->Guid, 0, 0, NULL);
541         }
542         if (!EFI_ERROR (Status)) {
543           UserVariableNameNode->Deleted = TRUE;
544         } else {
545           DEBUG ((EFI_D_INFO, "PlatformVarCleanup - Delete variable fail: %g:%s\n", &UserVariableNode->Guid, UserVariableNameNode->Name));
546         }
547       }
548     }
549   }
550 }
551 
552 /**
553   This function allows a caller to extract the current configuration for one
554   or more named elements from the target driver.
555 
556   @param[in]  This          Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
557   @param[in]  Request       A null-terminated Unicode string in <ConfigRequest> format.
558   @param[out] Progress      On return, points to a character in the Request string.
559                             Points to the string's null terminator if request was successful.
560                             Points to the most recent '&' before the first failing name/value
561                             pair (or the beginning of the string if the failure is in the
562                             first name/value pair) if the request was not successful.
563   @param[out] Results       A null-terminated Unicode string in <ConfigAltResp> format which
564                             has all values filled in for the names in the Request string.
565                             String to be allocated by the called function.
566 
567   @retval EFI_SUCCESS               The Results is filled with the requested values.
568   @retval EFI_OUT_OF_RESOURCES      Not enough memory to store the results.
569   @retval EFI_INVALID_PARAMETER     Request is illegal syntax, or unknown name.
570   @retval EFI_NOT_FOUND             Routing data doesn't match any storage in this driver.
571 
572 **/
573 EFI_STATUS
574 EFIAPI
VariableCleanupHiiExtractConfig(IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL * This,IN CONST EFI_STRING Request,OUT EFI_STRING * Progress,OUT EFI_STRING * Results)575 VariableCleanupHiiExtractConfig (
576   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL      *This,
577   IN  CONST EFI_STRING                          Request,
578   OUT EFI_STRING                                *Progress,
579   OUT EFI_STRING                                *Results
580   )
581 {
582   EFI_STATUS                        Status;
583   VARIABLE_CLEANUP_HII_PRIVATE_DATA *Private;
584   UINTN                             BufferSize;
585   EFI_STRING                        ConfigRequestHdr;
586   EFI_STRING                        ConfigRequest;
587   BOOLEAN                           AllocatedRequest;
588   UINTN                             Size;
589 
590   if (Progress == NULL || Results == NULL) {
591     return EFI_INVALID_PARAMETER;
592   }
593 
594   *Progress = Request;
595   if ((Request != NULL) && !HiiIsConfigHdrMatch (Request, &mVariableCleanupHiiGuid, mVarStoreName)) {
596     return EFI_NOT_FOUND;
597   }
598 
599   ConfigRequestHdr = NULL;
600   ConfigRequest    = NULL;
601   AllocatedRequest = FALSE;
602   Size             = 0;
603 
604   Private = VARIABLE_CLEANUP_HII_PRIVATE_FROM_THIS (This);
605   //
606   // Convert buffer data to <ConfigResp> by helper function BlockToConfig().
607   //
608   BufferSize = sizeof (VARIABLE_CLEANUP_DATA);
609   ConfigRequest = Request;
610   if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) {
611     //
612     // Request has no request element, construct full request string.
613     // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
614     // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator.
615     //
616     ConfigRequestHdr = HiiConstructConfigHdr (&mVariableCleanupHiiGuid, mVarStoreName, Private->HiiHandle);
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()1187 GetLastBootVarErrorFlag (
1188   )
1189 {
1190   return mLastVarErrorFlag;
1191 }
1192 
1193 /**
1194   Notification function of END_OF_DXE.
1195 
1196   This is a notification function registered on END_OF_DXE event.
1197 
1198   @param[in] Event      Event whose notification function is being invoked.
1199   @param[in] Context    Pointer to the notification function's context.
1200 
1201 **/
1202 VOID
1203 EFIAPI
PlatformVarCleanupEndOfDxeEvent(IN EFI_EVENT Event,IN VOID * Context)1204 PlatformVarCleanupEndOfDxeEvent (
1205   IN EFI_EVENT  Event,
1206   IN VOID       *Context
1207   )
1208 {
1209   mEndOfDxe = TRUE;
1210 }
1211 
1212 /**
1213   The constructor function caches the pointer to VarCheck protocol and last boot variable error flag.
1214 
1215   The constructor function locates VarCheck protocol from protocol database.
1216   It will ASSERT() if that operation fails and it will always return EFI_SUCCESS.
1217 
1218   @param  ImageHandle   The firmware allocated handle for the EFI image.
1219   @param  SystemTable   A pointer to the EFI System Table.
1220 
1221   @retval EFI_SUCCESS   The constructor always returns EFI_SUCCESS.
1222 
1223 **/
1224 EFI_STATUS
1225 EFIAPI
PlatformVarCleanupLibConstructor(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)1226 PlatformVarCleanupLibConstructor (
1227   IN EFI_HANDLE         ImageHandle,
1228   IN EFI_SYSTEM_TABLE   *SystemTable
1229   )
1230 {
1231   EFI_STATUS    Status;
1232   EFI_EVENT     Event;
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                   &Event
1247                   );
1248   ASSERT_EFI_ERROR (Status);
1249 
1250   return EFI_SUCCESS;
1251 }
1252 
1253