1 /** @file
2   Function and Macro defintions for to extract default values from UEFI Form package.
3 
4   Copyright (c) 2008 - 2010, 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 "HiiDatabase.h"
16 #include "UefiIfrParser.h"
17 #include "UefiIfrDefault.h"
18 
19 //
20 // Extern Variables
21 //
22 extern CONST EFI_HII_DATABASE_PROTOCOL            *mHiiDatabase;
23 extern CONST EFI_HII_IMAGE_PROTOCOL               *mHiiImageProtocol;
24 extern CONST EFI_HII_STRING_PROTOCOL              *mHiiStringProtocol;
25 extern CONST EFI_HII_CONFIG_ROUTING_PROTOCOL      *mHiiConfigRoutingProtocol;
26 
27 /**
28   Set the data position at Offset with Width in Node->Buffer based
29   the value passed in.
30 
31   @param  Node                    The Buffer Storage Node.
32   @param Value                    The input value.
33   @param Offset                   The offset in Node->Buffer for the update.
34   @param Width                    The length of the Value.
35 
36 **/
37 VOID
SetNodeBuffer(OUT UEFI_IFR_BUFFER_STORAGE_NODE * Node,IN CONST EFI_HII_VALUE * Value,IN UINTN Offset,IN UINTN Width)38 SetNodeBuffer (
39   OUT UEFI_IFR_BUFFER_STORAGE_NODE        *Node,
40   IN  CONST   EFI_HII_VALUE               *Value,
41   IN  UINTN                               Offset,
42   IN  UINTN                               Width
43   )
44 {
45   ASSERT (Node->Signature == UEFI_IFR_BUFFER_STORAGE_NODE_SIGNATURE);
46   ASSERT (Offset + Width <= Node->Size);
47 
48   CopyMem (Node->Buffer + Offset, &Value->Value.u8, Width);
49 }
50 
51 
52 /**
53   Get question default value, and set it into the match var storage.
54 
55   Note Framework 0.92's HII Implementation does not support for default value for these opcodes:
56   EFI_IFR_ORDERED_LIST_OP:
57   EFI_IFR_PASSWORD_OP:
58   EFI_IFR_STRING_OP:
59 
60   @param  Question               Question to be set to its default value.
61   @param  DefaultId              The Class of the default.
62   @param  VarStoreId             Id of var storage.
63   @param  Node                   Var storage buffer to store the got default value.
64 
65   @retval EFI_SUCCESS            Question is reset to default value.
66 
67 **/
68 EFI_STATUS
GetQuestionDefault(IN FORM_BROWSER_STATEMENT * Question,IN UINT16 DefaultId,IN UINT16 VarStoreId,OUT UEFI_IFR_BUFFER_STORAGE_NODE * Node)69 GetQuestionDefault (
70   IN FORM_BROWSER_STATEMENT           *Question,
71   IN UINT16                           DefaultId,
72   IN UINT16                           VarStoreId,
73   OUT UEFI_IFR_BUFFER_STORAGE_NODE    *Node
74   )
75 {
76   EFI_STATUS              Status;
77   LIST_ENTRY              *Link;
78   QUESTION_DEFAULT        *Default;
79   QUESTION_OPTION         *Option;
80   EFI_HII_VALUE           *HiiValue;
81 
82   Status = EFI_SUCCESS;
83 
84   //
85   // Statement don't have storage, skip them
86   //
87   if (Question->QuestionId == 0) {
88     return Status;
89   }
90 
91   if (Question->VarStoreId != VarStoreId) {
92     return Status;
93   }
94 
95   ASSERT (Question->Storage->Type == EFI_HII_VARSTORE_BUFFER);
96 
97   //
98   // There are three ways to specify default value for a Question:
99   //  1, use nested EFI_IFR_DEFAULT (highest priority)
100   //  2, set flags of EFI_ONE_OF_OPTION (provide Standard and Manufacturing default)
101   //  3, set flags of EFI_IFR_CHECKBOX (provide Standard and Manufacturing default) (lowest priority)
102   //
103   HiiValue = &Question->HiiValue;
104 
105   //
106   // EFI_IFR_DEFAULT has highest priority
107   //
108   if (!IsListEmpty (&Question->DefaultListHead)) {
109     Link = GetFirstNode (&Question->DefaultListHead);
110     while (!IsNull (&Question->DefaultListHead, Link)) {
111       Default = QUESTION_DEFAULT_FROM_LINK (Link);
112 
113       if (Default->DefaultId == DefaultId) {
114         //
115         // Default value is embedded in EFI_IFR_DEFAULT
116         //
117         CopyMem (HiiValue, &Default->Value, sizeof (EFI_HII_VALUE));
118 
119         SetNodeBuffer (Node, HiiValue, Question->VarStoreInfo.VarOffset, Question->StorageWidth);
120         return EFI_SUCCESS;
121       }
122 
123       Link = GetNextNode (&Question->DefaultListHead, Link);
124     }
125   }
126 
127   //
128   // EFI_ONE_OF_OPTION
129   //
130   if ((Question->Operand == EFI_IFR_ONE_OF_OP) && !IsListEmpty (&Question->OptionListHead)) {
131     if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING)  {
132       //
133       // OneOfOption could only provide Standard and Manufacturing default
134       //
135       Link = GetFirstNode (&Question->OptionListHead);
136       while (!IsNull (&Question->OptionListHead, Link)) {
137         Option = QUESTION_OPTION_FROM_LINK (Link);
138 
139         if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT) == EFI_IFR_OPTION_DEFAULT)) ||
140             ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT_MFG) == EFI_IFR_OPTION_DEFAULT_MFG))
141            ) {
142           CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE));
143 
144           SetNodeBuffer (Node, HiiValue, Question->VarStoreInfo.VarOffset, Question->StorageWidth);
145           return EFI_SUCCESS;
146         }
147 
148         Link = GetNextNode (&Question->OptionListHead, Link);
149       }
150     }
151   }
152 
153   //
154   // EFI_IFR_CHECKBOX - lowest priority
155   //
156   if (Question->Operand == EFI_IFR_CHECKBOX_OP) {
157     if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING)  {
158       //
159       // Checkbox could only provide Standard and Manufacturing default
160       //
161       if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT) == EFI_IFR_CHECKBOX_DEFAULT)) ||
162           ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT_MFG) == EFI_IFR_CHECKBOX_DEFAULT_MFG))
163          ) {
164         HiiValue->Value.b = TRUE;
165       } else {
166         HiiValue->Value.b = FALSE;
167       }
168 
169       SetNodeBuffer (Node, HiiValue, Question->VarStoreInfo.VarOffset, Question->StorageWidth);
170       return EFI_SUCCESS;
171     }
172   }
173 
174   return Status;
175 }
176 
177 
178 /**
179   Extract the default values from all questions in the input Form,
180   and set default value into the matched var storage.
181 
182   @param  Form                   The Form which to be reset.
183   @param  DefaultId              The Class of the default.
184   @param  VarStoreId             Id of var storage.
185   @param  Node                   Var storage buffer to store the got default value.
186 
187   @retval EFI_SUCCESS            The function completed successfully.
188 
189 **/
190 EFI_STATUS
ExtractFormDefault(IN FORM_BROWSER_FORM * Form,IN UINT16 DefaultId,IN UINT16 VarStoreId,OUT UEFI_IFR_BUFFER_STORAGE_NODE * Node)191 ExtractFormDefault (
192   IN FORM_BROWSER_FORM                *Form,
193   IN UINT16                           DefaultId,
194   IN UINT16                           VarStoreId,
195   OUT UEFI_IFR_BUFFER_STORAGE_NODE    *Node
196   )
197 {
198   EFI_STATUS              Status;
199   LIST_ENTRY              *Link;
200   FORM_BROWSER_STATEMENT  *Question;
201 
202   Link = GetFirstNode (&Form->StatementListHead);
203   while (!IsNull (&Form->StatementListHead, Link)) {
204     Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
205     //
206     // Reset Question to its default value
207     //
208     Status = GetQuestionDefault (Question, DefaultId, VarStoreId, Node);
209     if (EFI_ERROR (Status)) {
210       continue;
211     }
212 
213     Link = GetNextNode (&Form->StatementListHead, Link);
214   }
215   return EFI_SUCCESS;
216 }
217 
218 
219 /**
220   Destroy all the buffer allocated for the fileds of
221   UEFI_IFR_BUFFER_STORAGE_NODE. The Node itself
222   will be freed too.
223 
224   @param  Node                Var storage buffer.
225 
226 **/
227 VOID
DestroyDefaultNode(IN UEFI_IFR_BUFFER_STORAGE_NODE * Node)228 DestroyDefaultNode (
229   IN UEFI_IFR_BUFFER_STORAGE_NODE        *Node
230   )
231 {
232   FreePool (Node->Buffer);
233   FreePool (Node->Name);
234   FreePool (Node);
235 }
236 
237 
238 /**
239   Get the default value for Buffer Type storage named by
240   a Default Store and a Storage Store from a FormSet.
241   The result is in the a instance of UEFI_IFR_BUFFER_STORAGE_NODE
242   allocated by this function. It is inserted to the link list.
243 
244   @param  DefaultStore           The Default Store.
245   @param  Storage                The Storage.
246   @param  FormSet                The Form Set.
247   @param  UefiDefaultsListHead   The head of link list for the output.
248 
249   @retval   EFI_SUCCESS          Successful.
250 
251 **/
252 EFI_STATUS
GetBufferTypeDefaultIdAndStorageId(IN FORMSET_DEFAULTSTORE * DefaultStore,IN FORMSET_STORAGE * Storage,IN FORM_BROWSER_FORMSET * FormSet,OUT LIST_ENTRY * UefiDefaultsListHead)253 GetBufferTypeDefaultIdAndStorageId (
254   IN        FORMSET_DEFAULTSTORE        *DefaultStore,
255   IN        FORMSET_STORAGE             *Storage,
256   IN        FORM_BROWSER_FORMSET        *FormSet,
257   OUT       LIST_ENTRY                  *UefiDefaultsListHead
258  )
259 {
260   UEFI_IFR_BUFFER_STORAGE_NODE        *Node;
261   LIST_ENTRY              *Link;
262   FORM_BROWSER_FORM       *Form;
263   EFI_STATUS              Status;
264 
265   Node = AllocateZeroPool (sizeof (UEFI_IFR_BUFFER_STORAGE_NODE));
266   ASSERT (Node != NULL);
267 
268   Node->Signature = UEFI_IFR_BUFFER_STORAGE_NODE_SIGNATURE;
269   Node->Name      = AllocateCopyPool (StrSize (Storage->Name), Storage->Name);
270   Node->DefaultId = DefaultStore->DefaultId;
271   Node->StoreId   = Storage->VarStoreId;
272   CopyGuid (&Node->Guid, &Storage->Guid);
273   Node->Size      = Storage->Size;
274   Node->Buffer    = AllocateZeroPool (Node->Size);
275   //
276   // Extract default from IFR binary
277   //
278   Link = GetFirstNode (&FormSet->FormListHead);
279   while (!IsNull (&FormSet->FormListHead, Link)) {
280     Form = FORM_BROWSER_FORM_FROM_LINK (Link);
281 
282     Status = ExtractFormDefault (Form, DefaultStore->DefaultId, Storage->VarStoreId, Node);
283     ASSERT_EFI_ERROR (Status);
284 
285     Link = GetNextNode (&FormSet->FormListHead, Link);
286   }
287 
288   InsertTailList (UefiDefaultsListHead, &Node->List);
289 
290   return EFI_SUCCESS;
291 }
292 
293 
294 /**
295   Get the default value for Buffer Type storage named by
296   a Default Store from a FormSet.
297   The result is in the a instance of UEFI_IFR_BUFFER_STORAGE_NODE
298   allocated by this function. The output can be multiple instances
299   of UEFI_IFR_BUFFER_STORAGE_NODE. It is inserted to the link list.
300 
301   @param  DefaultStore            The Default Store.
302   @param  FormSet                  The Form Set.
303   @param  UefiDefaultsListHead The head of link list for the output.
304 
305   @retval   EFI_SUCCESS          Successful.
306 
307 **/
308 EFI_STATUS
GetBufferTypeDefaultId(IN FORMSET_DEFAULTSTORE * DefaultStore,IN FORM_BROWSER_FORMSET * FormSet,OUT LIST_ENTRY * UefiDefaultsListHead)309 GetBufferTypeDefaultId (
310   IN  FORMSET_DEFAULTSTORE  *DefaultStore,
311   IN  FORM_BROWSER_FORMSET  *FormSet,
312   OUT       LIST_ENTRY      *UefiDefaultsListHead
313   )
314 {
315   LIST_ENTRY                  *StorageLink;
316   FORMSET_STORAGE             *Storage;
317   EFI_STATUS                  Status;
318 
319   StorageLink = GetFirstNode (&FormSet->StorageListHead);
320 
321   while (!IsNull (&FormSet->StorageListHead, StorageLink)) {
322     Storage = FORMSET_STORAGE_FROM_LINK(StorageLink);
323 
324     if (Storage->Type == EFI_HII_VARSTORE_BUFFER) {
325       Status = GetBufferTypeDefaultIdAndStorageId (DefaultStore, Storage, FormSet, UefiDefaultsListHead);
326       ASSERT_EFI_ERROR (Status);
327     }
328 
329     StorageLink = GetNextNode (&FormSet->StorageListHead, StorageLink);
330   }
331 
332   return EFI_SUCCESS;
333 }
334 
335 
336 /**
337   Get the default value for Buffer Type storage from the FormSet in ThunkContext.
338 
339   The results can be multiple instances of UEFI_IFR_BUFFER_STORAGE_NODE.
340   They are inserted to the link list.
341 
342   @param  ThunkContext  Hii thunk context.
343   @param  UefiDefaults  The head of link list for the output.
344 
345   @retval   EFI_SUCCESS          Successful.
346 
347 **/
348 EFI_STATUS
UefiIfrGetBufferTypeDefaults(IN HII_THUNK_CONTEXT * ThunkContext,OUT LIST_ENTRY ** UefiDefaults)349 UefiIfrGetBufferTypeDefaults (
350   IN  HII_THUNK_CONTEXT   *ThunkContext,
351   OUT LIST_ENTRY          **UefiDefaults
352   )
353 {
354   LIST_ENTRY            *DefaultLink;
355   FORMSET_DEFAULTSTORE  *DefaultStore;
356   EFI_STATUS            Status;
357 
358   ASSERT (UefiDefaults != NULL);
359 
360   *UefiDefaults = AllocateZeroPool (sizeof (LIST_ENTRY));
361   ASSERT (*UefiDefaults != NULL);
362   InitializeListHead (*UefiDefaults);
363 
364   DefaultLink = GetFirstNode (&ThunkContext->FormSet->DefaultStoreListHead);
365   while (!IsNull (&ThunkContext->FormSet->DefaultStoreListHead, DefaultLink)) {
366     DefaultStore = FORMSET_DEFAULTSTORE_FROM_LINK(DefaultLink);
367 
368     Status = GetBufferTypeDefaultId (DefaultStore, ThunkContext->FormSet, *UefiDefaults);
369     ASSERT_EFI_ERROR (Status);
370 
371     DefaultLink = GetNextNode (&ThunkContext->FormSet->DefaultStoreListHead, DefaultLink);
372   }
373 
374   return EFI_SUCCESS;
375 }
376 
377 
378 /**
379   Convert the UEFI Buffer Type default values to a Framework HII default
380   values specified by a EFI_HII_VARIABLE_PACK_LIST structure.
381 
382   @param  ListHead             The link list of UEFI_IFR_BUFFER_STORAGE_NODE
383                                which contains the default values retrived from a UEFI form set.
384   @param  DefaultMask          The default mask.
385                                The valid values are EFI_IFR_FLAG_DEFAULT and EFI_IFR_FLAG_MANUFACTURING.
386                                UEFI spec only map EFI_IFR_FLAG_DEFAULT and EFI_IFR_FLAG_MANUFACTURING
387                                from specification to valid default class.
388   @param  UefiFormSetDefaultVarStoreId
389                                ID of the default varstore in FormSet.
390   @param  VariablePackList     The output default value in a format defined in Framework.
391 
392   @retval   EFI_SUCCESS                Successful.
393   @retval   EFI_INVALID_PARAMETER      The default mask is not EFI_IFR_FLAG_DEFAULT or
394                                        EFI_IFR_FLAG_MANUFACTURING.
395 **/
396 EFI_STATUS
UefiDefaultsToFwDefaults(IN LIST_ENTRY * ListHead,IN UINTN DefaultMask,IN EFI_VARSTORE_ID UefiFormSetDefaultVarStoreId,OUT EFI_HII_VARIABLE_PACK_LIST ** VariablePackList)397 UefiDefaultsToFwDefaults (
398   IN     LIST_ENTRY                  *ListHead,
399   IN     UINTN                       DefaultMask,
400   IN     EFI_VARSTORE_ID             UefiFormSetDefaultVarStoreId,
401   OUT    EFI_HII_VARIABLE_PACK_LIST  **VariablePackList
402   )
403 {
404   LIST_ENTRY                        *List;
405   UEFI_IFR_BUFFER_STORAGE_NODE      *Node;
406   UINTN                             Size;
407   UINTN                             Count;
408   UINT16                            DefaultId;
409   EFI_HII_VARIABLE_PACK             *Pack;
410   EFI_HII_VARIABLE_PACK_LIST        *PackList;
411   UINTN                             Index;
412 
413   if (DefaultMask == EFI_IFR_FLAG_DEFAULT) {
414     DefaultId = EFI_HII_DEFAULT_CLASS_STANDARD;
415   } else if (DefaultMask == EFI_IFR_FLAG_MANUFACTURING) {
416     DefaultId = EFI_HII_DEFAULT_CLASS_MANUFACTURING;
417   } else {
418     //
419     // UEFI spec only map EFI_IFR_FLAG_DEFAULT and EFI_IFR_FLAG_MANUFACTURING
420     // from specification to valid default class.
421     //
422     ASSERT (FALSE);
423     return EFI_INVALID_PARAMETER;
424   }
425 
426   //
427   // Calculate the size of the output EFI_HII_VARIABLE_PACK_LIST structure
428   //
429   Size = 0;
430   Count = 0;
431   List = GetFirstNode (ListHead);
432   while (!IsNull (ListHead, List)) {
433     Node = UEFI_IFR_BUFFER_STORAGE_NODE_FROM_LIST(List);
434 
435     if (Node->DefaultId == DefaultId) {
436       Size += Node->Size;
437       Size += StrSize (Node->Name);
438 
439       Count++;
440     }
441 
442     List = GetNextNode (ListHead, List);
443   }
444 
445   if (Count == 0) {
446     *VariablePackList = NULL;
447     return EFI_NOT_FOUND;
448   }
449 
450   Size = Size + Count * (sizeof (EFI_HII_VARIABLE_PACK_LIST) + sizeof (EFI_HII_VARIABLE_PACK));
451 
452   *VariablePackList = AllocateZeroPool (Size);
453   ASSERT (*VariablePackList != NULL);
454 
455   List = GetFirstNode (ListHead);
456 
457   PackList = (EFI_HII_VARIABLE_PACK_LIST *) *VariablePackList;
458   Pack     = (EFI_HII_VARIABLE_PACK *) (PackList + 1);
459   Index = 0;
460   while (!IsNull (ListHead, List)) {
461     Node = UEFI_IFR_BUFFER_STORAGE_NODE_FROM_LIST(List);
462 
463     Size = 0;
464     if (Node->DefaultId == DefaultId) {
465       Size += Node->Size;
466       Size += sizeof (EFI_HII_VARIABLE_PACK);
467 
468       Pack->VariableNameLength = (UINT32) StrSize (Node->Name);
469 
470       if (Node->StoreId == UefiFormSetDefaultVarStoreId) {
471         //
472         // The default VARSTORE in VFR from a Framework module has Varstore ID of 0.
473         //
474         Pack->VariableId = 0;
475       } else {
476         Pack->VariableId = Node->StoreId;
477       }
478 
479       CopyMem ((UINT8 *) Pack + sizeof (EFI_HII_VARIABLE_PACK), Node->Name, StrSize (Node->Name));
480       Size += Pack->VariableNameLength;
481 
482       //
483       // Initialize EFI_HII_VARIABLE_PACK
484       //
485       Pack->Header.Type   = 0;
486       Pack->Header.Length = (UINT32) Size;
487       CopyMem (&Pack->VariableGuid, &Node->Guid, sizeof (EFI_GUID));
488 
489       CopyMem ((UINT8 *) Pack + sizeof (EFI_HII_VARIABLE_PACK) + Pack->VariableNameLength, Node->Buffer, Node->Size);
490 
491       Size += sizeof (EFI_HII_VARIABLE_PACK_LIST);
492 
493       //
494       // Initialize EFI_HII_VARIABLE_PACK_LIST
495       //
496       PackList->VariablePack = Pack;
497       Index++;
498       if (Index < Count) {
499         PackList->NextVariablePack = (EFI_HII_VARIABLE_PACK_LIST *)((UINT8 *) PackList + Size);
500 
501         PackList = PackList->NextVariablePack;
502         Pack     = (EFI_HII_VARIABLE_PACK *) (PackList + 1);
503       }
504 
505     }
506 
507     List = GetNextNode (ListHead, List);
508   }
509 
510 
511   return EFI_SUCCESS;
512 }
513 
514 
515 /**
516   Free up all buffer allocated for the link list of UEFI_IFR_BUFFER_STORAGE_NODE.
517 
518   @param  ListHead                  The link list of UEFI_IFR_BUFFER_STORAGE_NODE
519                                     which contains the default values retrived from
520                                     a UEFI form set.
521 
522 **/
523 VOID
FreeDefaultList(IN LIST_ENTRY * ListHead)524 FreeDefaultList (
525   IN     LIST_ENTRY                  *ListHead
526   )
527 {
528   LIST_ENTRY *Link;
529   UEFI_IFR_BUFFER_STORAGE_NODE *Default;
530 
531   while (!IsListEmpty (ListHead)) {
532     Link = GetFirstNode (ListHead);
533 
534     Default = UEFI_IFR_BUFFER_STORAGE_NODE_FROM_LIST(Link);
535 
536     RemoveEntryList (Link);
537 
538     DestroyDefaultNode (Default);
539   }
540 
541   FreePool (ListHead);
542 }
543 
544