• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*++
2 
3 Copyright (c) 2007 - 2012, Intel Corporation. All rights reserved.<BR>
4 This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution.  The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8 
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11 
12 Module Name:
13 
14   UefiIfrForm.c
15 
16 Abstract:
17 
18   Common Library Routines to assist handle HII elements.
19 
20 --*/
21 
22 #include "UefiIfrLibrary.h"
23 
24 //
25 // Fake <ConfigHdr>
26 //
27 UINT16 mFakeConfigHdr[] = L"GUID=00000000000000000000000000000000&NAME=0000&PATH=0";
28 
29 EFI_STATUS
GetPackageDataFromPackageList(IN EFI_HII_PACKAGE_LIST_HEADER * HiiPackageList,IN UINT32 PackageIndex,OUT UINT32 * BufferLen,OUT EFI_HII_PACKAGE_HEADER ** Buffer)30 GetPackageDataFromPackageList (
31   IN  EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList,
32   IN  UINT32                      PackageIndex,
33   OUT UINT32                      *BufferLen,
34   OUT EFI_HII_PACKAGE_HEADER      **Buffer
35   )
36 {
37   UINT32                        Index;
38   EFI_HII_PACKAGE_HEADER        *Package;
39   UINT32                        Offset;
40   UINT32                        PackageListLength;
41   EFI_HII_PACKAGE_HEADER        PackageHeader = {0, 0};
42 
43   ASSERT(HiiPackageList != NULL);
44 
45   if ((BufferLen == NULL) || (Buffer == NULL)) {
46     return EFI_INVALID_PARAMETER;
47   }
48 
49   Package = NULL;
50   Index   = 0;
51   Offset  = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
52   EfiCopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32));
53   while (Offset < PackageListLength) {
54     Package = (EFI_HII_PACKAGE_HEADER *) (((UINT8 *) HiiPackageList) + Offset);
55     EfiCopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
56     if (Index == PackageIndex) {
57       break;
58     }
59     Offset += PackageHeader.Length;
60     Index++;
61   }
62   if (Offset >= PackageListLength) {
63     //
64     // no package found in this Package List
65     //
66     return EFI_NOT_FOUND;
67   }
68 
69   *BufferLen = PackageHeader.Length;
70   *Buffer    = Package;
71   return EFI_SUCCESS;
72 }
73 
74 EFI_STATUS
UpdateFormPackageData(IN EFI_GUID * FormSetGuid,IN EFI_FORM_ID FormId,IN EFI_HII_PACKAGE_HEADER * Package,IN UINT32 PackageLength,IN UINT16 Label,IN BOOLEAN Insert,IN EFI_HII_UPDATE_DATA * Data,OUT UINT8 ** TempBuffer,OUT UINT32 * TempBufferSize)75 UpdateFormPackageData (
76   IN  EFI_GUID               *FormSetGuid,
77   IN  EFI_FORM_ID            FormId,
78   IN  EFI_HII_PACKAGE_HEADER *Package,
79   IN  UINT32                 PackageLength,
80   IN  UINT16                 Label,
81   IN  BOOLEAN                Insert,
82   IN  EFI_HII_UPDATE_DATA    *Data,
83   OUT UINT8                  **TempBuffer,
84   OUT UINT32                 *TempBufferSize
85   )
86 {
87   UINT8                     *BufferPos;
88   EFI_HII_PACKAGE_HEADER    PackageHeader;
89   UINT32                    Offset;
90   EFI_IFR_OP_HEADER         *IfrOpHdr;
91   BOOLEAN                   GetFormSet;
92   BOOLEAN                   GetForm;
93   UINT8                     ExtendOpCode;
94   UINT16                    LabelNumber;
95   BOOLEAN                   Updated;
96 
97   if ((TempBuffer == NULL) || (TempBufferSize == NULL)) {
98     return EFI_INVALID_PARAMETER;
99   }
100 
101   *TempBufferSize = PackageLength;
102   if (Data != NULL) {
103     *TempBufferSize += Data->Offset;
104   }
105   *TempBuffer = EfiLibAllocateZeroPool (*TempBufferSize);
106   if (*TempBuffer == NULL) {
107     return EFI_OUT_OF_RESOURCES;
108   }
109 
110   EfiCopyMem (*TempBuffer, Package, sizeof (EFI_HII_PACKAGE_HEADER));
111   *TempBufferSize = sizeof (EFI_HII_PACKAGE_HEADER);
112   BufferPos = *TempBuffer + sizeof (EFI_HII_PACKAGE_HEADER);
113 
114   EfiCopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
115   IfrOpHdr   = (EFI_IFR_OP_HEADER *)((UINT8 *) Package + sizeof (EFI_HII_PACKAGE_HEADER));
116   Offset     = sizeof (EFI_HII_PACKAGE_HEADER);
117   GetFormSet = (BOOLEAN)((FormSetGuid == NULL) ? TRUE : FALSE);
118   GetForm    = FALSE;
119   Updated    = FALSE;
120 
121   while (!Updated && Offset < PackageHeader.Length) {
122     EfiCopyMem (BufferPos, IfrOpHdr, IfrOpHdr->Length);
123     BufferPos += IfrOpHdr->Length;
124     *TempBufferSize += IfrOpHdr->Length;
125 
126     switch (IfrOpHdr->OpCode) {
127     case EFI_IFR_FORM_SET_OP :
128       if (FormSetGuid != NULL) {
129         if (EfiCompareMem (&((EFI_IFR_FORM_SET *) IfrOpHdr)->Guid, FormSetGuid, sizeof (EFI_GUID)) == 0) {
130           GetFormSet = TRUE;
131         } else {
132           GetFormSet = FALSE;
133         }
134       }
135       break;
136 
137     case EFI_IFR_FORM_OP:
138       if (EfiCompareMem (&((EFI_IFR_FORM *) IfrOpHdr)->FormId, &FormId, sizeof (EFI_FORM_ID)) == 0) {
139         GetForm = TRUE;
140       } else {
141         GetForm = FALSE;
142       }
143       break;
144 
145     case EFI_IFR_GUID_OP :
146       if (!GetFormSet || !GetForm) {
147         //
148         // Go to the next Op-Code
149         //
150         break;
151       }
152 
153       if (!EfiCompareGuid (&((EFI_IFR_GUID *) IfrOpHdr)->Guid, &mIfrVendorGuid)) {
154         //
155         // GUID mismatch, skip this op-code
156         //
157         break;
158       }
159 
160       ExtendOpCode = ((EFI_IFR_GUID_LABEL *) IfrOpHdr)->ExtendOpCode;
161       EfiCopyMem (&LabelNumber, &((EFI_IFR_GUID_LABEL *)IfrOpHdr)->Number, sizeof (UINT16));
162       if ((ExtendOpCode != EFI_IFR_EXTEND_OP_LABEL) || (LabelNumber != Label)) {
163         //
164         // Go to the next Op-Code
165         //
166         break;
167       }
168 
169       if (Insert) {
170         //
171         // Insert data after current Label, skip myself
172         //
173         Offset   += IfrOpHdr->Length;
174         IfrOpHdr = (EFI_IFR_OP_HEADER *) ((CHAR8 *) (IfrOpHdr) + IfrOpHdr->Length);
175       } else {
176         //
177         // Replace data between two paired Label, try to find the next Label.
178         //
179         while (TRUE) {
180           Offset   += IfrOpHdr->Length;
181           //
182           // Search the next label and Fail if not label found.
183           //
184           if (Offset >= PackageHeader.Length) {
185             goto Fail;
186           }
187           IfrOpHdr = (EFI_IFR_OP_HEADER *) ((CHAR8 *) (IfrOpHdr) + IfrOpHdr->Length);
188           if (IfrOpHdr->OpCode == EFI_IFR_GUID_OP) {
189             ExtendOpCode = ((EFI_IFR_GUID_LABEL *) IfrOpHdr)->ExtendOpCode;
190             if (EfiCompareGuid (&((EFI_IFR_GUID *) IfrOpHdr)->Guid, &mIfrVendorGuid) && ExtendOpCode == EFI_IFR_EXTEND_OP_LABEL) {
191               break;
192             }
193           }
194         }
195       }
196 
197       //
198       // Fill in the update data
199       //
200       if (Data != NULL) {
201         EfiCopyMem (BufferPos, Data->Data, Data->Offset);
202         BufferPos += Data->Offset;
203         *TempBufferSize += Data->Offset;
204       }
205 
206       //
207       // Copy the reset data
208       //
209       EfiCopyMem (BufferPos, IfrOpHdr, PackageHeader.Length - Offset);
210       *TempBufferSize += PackageHeader.Length - Offset;
211 
212       Updated = TRUE;
213       break;
214     default :
215       break;
216     }
217 
218     //
219     // Go to the next Op-Code
220     //
221     Offset   += IfrOpHdr->Length;
222     IfrOpHdr = (EFI_IFR_OP_HEADER *) ((CHAR8 *) (IfrOpHdr) + IfrOpHdr->Length);
223   }
224 
225   //
226   // Update the package length.
227   //
228   PackageHeader.Length = *TempBufferSize;
229   EfiCopyMem (*TempBuffer, &PackageHeader, sizeof (EFI_HII_PACKAGE_HEADER));
230 
231 Fail:
232   if (!Updated) {
233     gBS->FreePool (*TempBuffer);
234     *TempBufferSize = 0;
235     return EFI_NOT_FOUND;
236   }
237 
238   return EFI_SUCCESS;
239 }
240 
241 EFI_STATUS
IfrLibInitUpdateData(IN OUT EFI_HII_UPDATE_DATA * UpdateData,IN UINT32 BufferSize)242 IfrLibInitUpdateData (
243   IN OUT EFI_HII_UPDATE_DATA   *UpdateData,
244   IN UINT32                    BufferSize
245   )
246 /*++
247 
248 Routine Description:
249   This function initialize the data structure for dynamic opcode.
250 
251 Arguments:
252   UpdateData     - The adding data;
253   BufferSize     - Length of the buffer to fill dynamic opcodes.
254 
255 Returns:
256   EFI_SUCCESS           - Update data is initialized.
257   EFI_INVALID_PARAMETER - UpdateData is NULL.
258   EFI_OUT_OF_RESOURCES  - No enough memory to allocate.
259 
260 --*/
261 {
262   if (UpdateData == NULL) {
263     return EFI_INVALID_PARAMETER;
264   }
265 
266   UpdateData->BufferSize = BufferSize;
267   UpdateData->Offset = 0;
268   UpdateData->Data = EfiLibAllocatePool (BufferSize);
269 
270   return (UpdateData->Data != NULL) ? EFI_SUCCESS : EFI_OUT_OF_RESOURCES;
271 }
272 
273 EFI_STATUS
IfrLibFreeUpdateData(IN EFI_HII_UPDATE_DATA * UpdateData)274 IfrLibFreeUpdateData (
275   IN EFI_HII_UPDATE_DATA       *UpdateData
276   )
277 /*++
278 
279 Routine Description:
280   This function free the resource of update data.
281 
282 Arguments:
283   UpdateData     - The adding data;
284 
285 Returns:
286   EFI_SUCCESS           - Resource in UpdateData is released.
287   EFI_INVALID_PARAMETER - UpdateData is NULL.
288 
289 --*/
290 {
291   EFI_STATUS  Status;
292 
293   if (UpdateData == NULL) {
294     return EFI_INVALID_PARAMETER;
295   }
296 
297   Status = gBS->FreePool (UpdateData->Data);
298   UpdateData->Data = NULL;
299 
300   return Status;
301 }
302 
303 EFI_STATUS
IfrLibUpdateForm(IN EFI_HII_HANDLE Handle,IN EFI_GUID * FormSetGuid,OPTIONAL IN EFI_FORM_ID FormId,IN UINT16 Label,IN BOOLEAN Insert,IN EFI_HII_UPDATE_DATA * Data)304 IfrLibUpdateForm (
305   IN EFI_HII_HANDLE            Handle,
306   IN EFI_GUID                  *FormSetGuid, OPTIONAL
307   IN EFI_FORM_ID               FormId,
308   IN UINT16                    Label,
309   IN BOOLEAN                   Insert,
310   IN EFI_HII_UPDATE_DATA       *Data
311   )
312 /*++
313 
314 Routine Description:
315   This function allows the caller to update a form that has
316   previously been registered with the EFI HII database.
317 
318 Arguments:
319   Handle       - Hii Handle
320   FormSetGuid  - The formset should be updated.
321   FormId       - The form should be updated.
322   Label        - Update information starting immediately after this label in the IFR
323   Insert       - If TRUE and Data is not NULL, insert data after Label.
324                  If FALSE, replace opcodes between two labels with Data
325   Data         - The adding data; If NULL, remove opcodes between two Label.
326 
327 Returns:
328   EFI_SUCCESS  - Update success.
329   Other        - Update fail.
330 
331 --*/
332 {
333   EFI_STATUS                   Status;
334   EFI_HII_DATABASE_PROTOCOL    *HiiDatabase;
335   EFI_HII_PACKAGE_LIST_HEADER  *HiiPackageList;
336   UINT32                       Index;
337   EFI_HII_PACKAGE_LIST_HEADER  *UpdateBuffer;
338   UINTN                        BufferSize;
339   UINT8                        *UpdateBufferPos;
340   EFI_HII_PACKAGE_HEADER       PackageHeader;
341   EFI_HII_PACKAGE_HEADER       *Package;
342   UINT32                       PackageLength;
343   EFI_HII_PACKAGE_HEADER       *TempBuffer;
344   UINT32                       TempBufferSize;
345   BOOLEAN                      Updated;
346 
347   if (Data == NULL) {
348     return EFI_INVALID_PARAMETER;
349   }
350 
351   LocateHiiProtocols ();
352   HiiDatabase = gIfrLibHiiDatabase;
353 
354   //
355   // Get the orginal package list
356   //
357   BufferSize = 0;
358   HiiPackageList   = NULL;
359   Status = HiiDatabase->ExportPackageLists (HiiDatabase, Handle, &BufferSize, HiiPackageList);
360   if (Status == EFI_BUFFER_TOO_SMALL) {
361     HiiPackageList = EfiLibAllocatePool (BufferSize);
362     ASSERT (HiiPackageList != NULL);
363 
364     Status = HiiDatabase->ExportPackageLists (HiiDatabase, Handle, &BufferSize, HiiPackageList);
365     if (EFI_ERROR (Status)) {
366       gBS->FreePool (HiiPackageList);
367       return Status;
368     }
369   }
370 
371   //
372   // Calculate and allocate space for retrieval of IFR data
373   //
374   BufferSize += Data->Offset;
375   UpdateBuffer = EfiLibAllocateZeroPool (BufferSize);
376   if (UpdateBuffer == NULL) {
377     return EFI_OUT_OF_RESOURCES;
378   }
379 
380   UpdateBufferPos = (UINT8 *) UpdateBuffer;
381 
382   //
383   // copy the package list header
384   //
385   EfiCopyMem (UpdateBufferPos, HiiPackageList, sizeof (EFI_HII_PACKAGE_LIST_HEADER));
386   UpdateBufferPos += sizeof (EFI_HII_PACKAGE_LIST_HEADER);
387 
388   Updated = FALSE;
389   for (Index = 0; ; Index++) {
390     Status = GetPackageDataFromPackageList (HiiPackageList, Index, &PackageLength, &Package);
391     if (Status == EFI_SUCCESS) {
392       EfiCopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
393       if ((PackageHeader.Type == EFI_HII_PACKAGE_FORMS) && !Updated) {
394         Status = UpdateFormPackageData (FormSetGuid, FormId, Package, PackageLength, Label, Insert, Data, (UINT8 **)&TempBuffer, &TempBufferSize);
395         if (!EFI_ERROR(Status)) {
396           if (FormSetGuid == NULL) {
397             Updated = TRUE;
398           }
399           EfiCopyMem (UpdateBufferPos, TempBuffer, TempBufferSize);
400           UpdateBufferPos += TempBufferSize;
401           gBS->FreePool (TempBuffer);
402           continue;
403         }
404       }
405 
406       EfiCopyMem (UpdateBufferPos, Package, PackageLength);
407       UpdateBufferPos += PackageLength;
408     } else if (Status == EFI_NOT_FOUND) {
409       break;
410     } else {
411       gBS->FreePool (HiiPackageList);
412       return Status;
413     }
414   }
415 
416   //
417   // Update package list length
418   //
419   BufferSize = UpdateBufferPos - (UINT8 *) UpdateBuffer;
420   EfiCopyMem (&UpdateBuffer->PackageLength, &BufferSize, sizeof (UINT32));
421 
422   gBS->FreePool (HiiPackageList);
423 
424   return HiiDatabase->UpdatePackageList (HiiDatabase, Handle, UpdateBuffer);
425 }
426 
427 EFI_STATUS
IfrLibCreatePopUp(IN UINTN NumberOfLines,OUT EFI_INPUT_KEY * KeyValue,IN CHAR16 * String,...)428 IfrLibCreatePopUp (
429   IN  UINTN                       NumberOfLines,
430   OUT EFI_INPUT_KEY               *KeyValue,
431   IN  CHAR16                      *String,
432   ...
433   )
434 /*++
435 
436 Routine Description:
437   Draw a dialog and return the selected key.
438 
439 Arguments:
440   NumberOfLines     - The number of lines for the dialog box
441   KeyValue          - The EFI_KEY value returned if HotKey is TRUE..
442   String            - Pointer to the first string in the list
443   ...               - A series of (quantity == NumberOfLines) text strings which
444                       will be used to construct the dialog box
445 
446 Returns:
447   EFI_SUCCESS           - Displayed dialog and received user interaction
448   EFI_INVALID_PARAMETER - One of the parameters was invalid.
449 
450 --*/
451 {
452   UINTN                         Index;
453   UINTN                         Count;
454   UINTN                         Start;
455   UINTN                         Top;
456   CHAR16                        *StringPtr;
457   UINTN                         LeftColumn;
458   UINTN                         RightColumn;
459   UINTN                         TopRow;
460   UINTN                         BottomRow;
461   UINTN                         DimensionsWidth;
462   UINTN                         DimensionsHeight;
463   VA_LIST                       Marker;
464   EFI_INPUT_KEY                 Key;
465   UINTN                         LargestString;
466   CHAR16                        *StackString;
467   EFI_STATUS                    Status;
468   UINTN                         StringLen;
469   CHAR16                        *LineBuffer;
470   CHAR16                        **StringArray;
471   EFI_EVENT                     TimerEvent;
472   EFI_EVENT                     WaitList[2];
473   UINTN                         CurrentAttribute;
474   EFI_SIMPLE_TEXT_OUT_PROTOCOL  *ConOut;
475 
476   if ((KeyValue == NULL) || (String == NULL)) {
477     return EFI_INVALID_PARAMETER;
478   }
479 
480   TopRow      = 0;
481   BottomRow   = 0;
482   LeftColumn  = 0;
483   RightColumn = 0;
484 
485   ConOut = gST->ConOut;
486   ConOut->QueryMode (ConOut, ConOut->Mode->Mode, &RightColumn, &BottomRow);
487 
488   DimensionsWidth  = RightColumn - LeftColumn;
489   DimensionsHeight = BottomRow - TopRow;
490 
491   CurrentAttribute = ConOut->Mode->Attribute;
492 
493   LineBuffer = EfiLibAllocateZeroPool (DimensionsWidth * sizeof (CHAR16));
494   ASSERT (LineBuffer != NULL);
495 
496   //
497   // Determine the largest string in the dialog box
498   // Notice we are starting with 1 since String is the first string
499   //
500   StringArray = EfiLibAllocateZeroPool (NumberOfLines * sizeof (CHAR16 *));
501   LargestString = EfiStrLen (String);
502   StringArray[0] = String;
503 
504   VA_START (Marker, String);
505   for (Index = 1; Index < NumberOfLines; Index++) {
506     StackString = VA_ARG (Marker, CHAR16 *);
507 
508     if (StackString == NULL) {
509       VA_END (Marker);
510       return EFI_INVALID_PARAMETER;
511     }
512 
513     StringArray[Index] = StackString;
514     StringLen = EfiStrLen (StackString);
515     if (StringLen > LargestString) {
516       LargestString = StringLen;
517     }
518   }
519   VA_END (Marker);
520 
521   if ((LargestString + 2) > DimensionsWidth) {
522     LargestString = DimensionsWidth - 2;
523   }
524 
525   //
526   // Subtract the PopUp width from total Columns, allow for one space extra on
527   // each end plus a border.
528   //
529   Start     = (DimensionsWidth - LargestString - 2) / 2 + LeftColumn + 1;
530 
531   Top       = ((DimensionsHeight - NumberOfLines - 2) / 2) + TopRow - 1;
532 
533   //
534   // Disable cursor
535   //
536   ConOut->EnableCursor (ConOut, FALSE);
537   ConOut->SetAttribute (ConOut, EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE);
538 
539   StringPtr = &LineBuffer[0];
540   *StringPtr++ = BOXDRAW_DOWN_RIGHT;
541   for (Index = 0; Index < LargestString; Index++) {
542     *StringPtr++ = BOXDRAW_HORIZONTAL;
543   }
544   *StringPtr++ = BOXDRAW_DOWN_LEFT;
545   *StringPtr = L'\0';
546 
547   ConOut->SetCursorPosition (ConOut, Start, Top);
548   ConOut->OutputString (ConOut, LineBuffer);
549 
550   for (Index = 0; Index < NumberOfLines; Index++) {
551     StringPtr = &LineBuffer[0];
552     *StringPtr++ = BOXDRAW_VERTICAL;
553 
554     for (Count = 0; Count < LargestString; Count++) {
555       StringPtr[Count] = L' ';
556     }
557 
558     StringLen = EfiStrLen (StringArray[Index]);
559     if (StringLen > LargestString) {
560       StringLen = LargestString;
561     }
562     EfiCopyMem (
563       StringPtr + ((LargestString - StringLen) / 2),
564       StringArray[Index],
565       StringLen * sizeof (CHAR16)
566       );
567     StringPtr += LargestString;
568 
569     *StringPtr++ = BOXDRAW_VERTICAL;
570     *StringPtr = L'\0';
571 
572     ConOut->SetCursorPosition (ConOut, Start, Top + 1 + Index);
573     ConOut->OutputString (ConOut, LineBuffer);
574   }
575 
576   StringPtr = &LineBuffer[0];
577   *StringPtr++ = BOXDRAW_UP_RIGHT;
578   for (Index = 0; Index < LargestString; Index++) {
579     *StringPtr++ = BOXDRAW_HORIZONTAL;
580   }
581   *StringPtr++ = BOXDRAW_UP_LEFT;
582   *StringPtr = L'\0';
583 
584   ConOut->SetCursorPosition (ConOut, Start, Top + NumberOfLines + 1);
585   ConOut->OutputString (ConOut, LineBuffer);
586 
587   do {
588     Status = gBS->CreateEvent (EFI_EVENT_TIMER, 0, NULL, NULL, &TimerEvent);
589 
590     //
591     // Set a timer event of 1 second expiration
592     //
593     gBS->SetTimer (
594           TimerEvent,
595           TimerRelative,
596           10000000
597           );
598 
599     //
600     // Wait for the keystroke event or the timer
601     //
602     WaitList[0] = gST->ConIn->WaitForKey;
603     WaitList[1] = TimerEvent;
604     Status      = gBS->WaitForEvent (2, WaitList, &Index);
605 
606     //
607     // Check for the timer expiration
608     //
609     if (!EFI_ERROR (Status) && Index == 1) {
610       Status = EFI_TIMEOUT;
611     }
612 
613     gBS->CloseEvent (TimerEvent);
614   } while (Status == EFI_TIMEOUT);
615 
616   Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
617   EfiCopyMem (KeyValue, &Key, sizeof (EFI_INPUT_KEY));
618 
619   ConOut->SetAttribute (ConOut, CurrentAttribute);
620   ConOut->EnableCursor (ConOut, TRUE);
621 
622   return Status;
623 }
624 
625 EFI_STATUS
ExtractDefault(IN VOID * Buffer,IN UINTN * BufferSize,UINTN Number,...)626 ExtractDefault(
627   IN VOID                         *Buffer,
628   IN UINTN                        *BufferSize,
629   UINTN                           Number,
630   ...
631   )
632 /*++
633 
634   Routine Description:
635 
636     Configure the buffer accrording to ConfigBody strings.
637 
638   Arguments:
639     DefaultId             - the ID of default.
640     Buffer                - the start address of buffer.
641     BufferSize            - the size of buffer.
642     Number                - the number of the strings.
643 
644   Returns:
645     EFI_BUFFER_TOO_SMALL  - the BufferSize is too small to operate.
646     EFI_INVALID_PARAMETER - Buffer is NULL or BufferSize is 0.
647     EFI_SUCCESS           - Operation successful.
648 
649 --*/
650 {
651   VA_LIST                         Args;
652   UINTN                           Index;
653   UINT32                          TotalLen;
654   UINT8                           *BufCfgArray;
655   UINT8                           *BufferPos;
656   UINT16                          Offset;
657   UINT16                          Width;
658   UINT8                           *Value;
659 
660   if ((Buffer == NULL) || (BufferSize == NULL)) {
661     return EFI_INVALID_PARAMETER;
662   }
663 
664   Offset = 0;
665   Width  = 0;
666   Value  = NULL;
667 
668   VA_START (Args, Number);
669   for (Index = 0; Index < Number; Index++) {
670     BufCfgArray = (UINT8 *) VA_ARG (Args, VOID *);
671     EfiCopyMem (&TotalLen, BufCfgArray, sizeof (UINT32));
672     BufferPos = BufCfgArray + sizeof (UINT32);
673 
674     while ((UINT32)(BufferPos - BufCfgArray) < TotalLen) {
675       EfiCopyMem (&Offset, BufferPos, sizeof (UINT16));
676       BufferPos += sizeof (UINT16);
677       EfiCopyMem (&Width, BufferPos, sizeof (UINT16));
678       BufferPos += sizeof (UINT16);
679       Value = BufferPos;
680       BufferPos += Width;
681 
682       if ((UINTN)(Offset + Width) > *BufferSize) {
683         VA_END (Args);
684         return EFI_BUFFER_TOO_SMALL;
685       }
686 
687       EfiCopyMem ((UINT8 *)Buffer + Offset, Value, Width);
688     }
689   }
690   VA_END (Args);
691 
692   *BufferSize = (UINTN)Offset;
693 
694   return EFI_SUCCESS;
695 }
696 
697 EFI_STATUS
ExtractBlockName(IN UINT8 * Buffer,OUT CHAR16 ** BlockName)698 ExtractBlockName (
699   IN UINT8                        *Buffer,
700   OUT CHAR16                      **BlockName
701   )
702 /*++
703 
704   Routine Description:
705 
706     Extract block name from the array generated by VFR compiler. The name of
707   this array is "Vfr + <StorageName> + BlockName", e.g. "VfrMyIfrNVDataBlockName".
708   Format of this array is:
709      Array length | 4-bytes
710        Offset     | 2-bytes
711        Width      | 2-bytes
712        Offset     | 2-bytes
713        Width      | 2-bytes
714        ... ...
715 
716   Arguments:
717     Buffer                - Array generated by VFR compiler.
718     BlockName             - The returned <BlockName>
719 
720   Returns:
721     EFI_OUT_OF_RESOURCES  - Run out of memory resource.
722     EFI_INVALID_PARAMETER - Buffer is NULL or BlockName is NULL.
723     EFI_SUCCESS           - Operation successful.
724 
725 --*/
726 {
727   UINTN       Index;
728   UINT32      Length;
729   UINT32      BlockNameNumber;
730   UINTN       HexStringBufferLen;
731   CHAR16      *StringPtr;
732 
733   if ((Buffer == NULL) || (BlockName == NULL)) {
734     return EFI_INVALID_PARAMETER;
735   }
736 
737   //
738   // Calculate number of Offset/Width pair
739   //
740   EfiCopyMem (&Length, Buffer, sizeof (UINT32));
741   BlockNameNumber = (Length - sizeof (UINT32)) / (sizeof (UINT16) * 2);
742 
743   //
744   // <BlockName> ::= &OFFSET=1234&WIDTH=1234
745   //                 |   8  | 4 |  7   | 4 |
746   //
747   StringPtr = EfiLibAllocateZeroPool ((BlockNameNumber * (8 + 4 + 7 + 4) + 1) * sizeof (CHAR16));
748   *BlockName = StringPtr;
749   if (StringPtr == NULL) {
750     return EFI_OUT_OF_RESOURCES;
751   }
752 
753   Buffer += sizeof (UINT32);
754   for (Index = 0; Index < BlockNameNumber; Index++) {
755     EfiStrCpy (StringPtr, L"&OFFSET=");
756     StringPtr += 8;
757 
758     HexStringBufferLen = 5;
759     BufToHexString (StringPtr, &HexStringBufferLen, Buffer, sizeof (UINT16));
760     Buffer += sizeof (UINT16);
761     StringPtr += 4;
762 
763     EfiStrCpy (StringPtr, L"&WIDTH=");
764     StringPtr += 7;
765 
766     HexStringBufferLen = 5;
767     BufToHexString (StringPtr, &HexStringBufferLen, Buffer, sizeof (UINT16));
768     Buffer += sizeof (UINT16);
769     StringPtr += 4;
770   }
771 
772   return EFI_SUCCESS;
773 }
774 
775 EFI_STATUS
ExtractBlockConfig(IN UINT8 * Buffer,OUT CHAR16 ** BlockConfig)776 ExtractBlockConfig (
777   IN UINT8                        *Buffer,
778   OUT CHAR16                      **BlockConfig
779   )
780 /*++
781 
782   Routine Description:
783 
784     Extract block config from the array generated by VFR compiler. The name of
785   this array is "Vfr + <StorageName> + Default<HexCh>4", e.g. "VfrMyIfrNVDataDefault0000".
786 
787   Arguments:
788     Buffer                - Array generated by VFR compiler.
789     BlockConfig           - The returned <BlockConfig>
790 
791   Returns:
792     EFI_OUT_OF_RESOURCES  - Run out of memory resource.
793     EFI_INVALID_PARAMETER - Buffer is NULL or BlockConfig is NULL.
794     EFI_SUCCESS           - Operation successful.
795 
796 --*/
797 {
798   UINT32      Length;
799   UINT16      Width;
800   UINTN       HexStringBufferLen;
801   CHAR16      *StringPtr;
802   UINT8       *BufferEnd;
803   CHAR16      *StringEnd;
804   EFI_STATUS  Status;
805 
806   if ((Buffer == NULL) || (BlockConfig == NULL)) {
807     return EFI_INVALID_PARAMETER;
808   }
809 
810   //
811   // Calculate length of AltResp string
812   // Format of Default value array is:
813   //  Array length | 4-bytes
814   //        Offset | 2-bytes
815   //        Width  | 2-bytes
816   //        Value  | Variable length
817   //        Offset | 2-bytes
818   //        Width  | 2-bytes
819   //        Value  | Variable length
820   //        ... ...
821   // When value is 1 byte in length, overhead of AltResp string will be maximum,
822   //  BlockConfig ::= <&OFFSET=1234&WIDTH=1234&VALUE=12>+
823   //                   |   8   | 4  |  7   | 4 |  7  |2|
824   // so the maximum length of BlockConfig could be calculated as:
825   // (ArrayLength / 5) * (8 + 4 + 7 + 4 + 7 + 2) = ArrayLength * 6.4 < ArrayLength * 7
826   //
827   EfiCopyMem (&Length, Buffer, sizeof (UINT32));
828   BufferEnd = Buffer + Length;
829   StringPtr = EfiLibAllocatePool (Length * 7 * sizeof (CHAR16));
830   *BlockConfig = StringPtr;
831   if (StringPtr == NULL) {
832       return EFI_OUT_OF_RESOURCES;
833   }
834   StringEnd = StringPtr + (Length * 7);
835 
836   Buffer += sizeof (UINT32);
837   while (Buffer < BufferEnd) {
838     EfiStrCpy (StringPtr, L"&OFFSET=");
839     StringPtr += 8;
840 
841     HexStringBufferLen = 5;
842     BufToHexString (StringPtr, &HexStringBufferLen, Buffer, sizeof (UINT16));
843     Buffer += sizeof (UINT16);
844     StringPtr += 4;
845 
846     EfiStrCpy (StringPtr, L"&WIDTH=");
847     StringPtr += 7;
848 
849     HexStringBufferLen = 5;
850     BufToHexString (StringPtr, &HexStringBufferLen, Buffer, sizeof (UINT16));
851     EfiCopyMem (&Width, Buffer, sizeof (UINT16));
852     Buffer += sizeof (UINT16);
853     StringPtr += 4;
854 
855     EfiStrCpy (StringPtr, L"&VALUE=");
856     StringPtr += 7;
857 
858     HexStringBufferLen = StringEnd - StringPtr;
859     Status = BufToHexString (StringPtr, &HexStringBufferLen, Buffer, Width);
860     if (EFI_ERROR (Status)) {
861       return Status;
862     }
863     Buffer += Width;
864     StringPtr += (Width * 2);
865   }
866 
867   return EFI_SUCCESS;
868 }
869 
870 EFI_STATUS
ConstructConfigAltResp(IN EFI_STRING ConfigRequest,OPTIONAL OUT EFI_STRING * Progress,OUT EFI_STRING * ConfigAltResp,IN EFI_GUID * Guid,IN CHAR16 * Name,IN EFI_HANDLE * DriverHandle,IN VOID * BufferStorage,IN UINTN BufferStorageSize,IN VOID * BlockNameArray,OPTIONAL IN UINTN NumberAltCfg,...)871 ConstructConfigAltResp (
872   IN  EFI_STRING                  ConfigRequest,  OPTIONAL
873   OUT EFI_STRING                  *Progress,
874   OUT EFI_STRING                  *ConfigAltResp,
875   IN  EFI_GUID                    *Guid,
876   IN  CHAR16                      *Name,
877   IN  EFI_HANDLE                  *DriverHandle,
878   IN  VOID                        *BufferStorage,
879   IN  UINTN                       BufferStorageSize,
880   IN  VOID                        *BlockNameArray, OPTIONAL
881   IN  UINTN                       NumberAltCfg,
882   ...
883 //IN  UINT16                      AltCfgId,
884 //IN  VOID                        *DefaultValueArray,
885   )
886 /*++
887 
888   Routine Description:
889 
890   Construct <ConfigAltResp> for a buffer storage.
891 
892   Arguments:
893     ConfigRequest         - The Config request string. If set to NULL, all the
894                             configurable elements will be extracted from BlockNameArray.
895     ConfigAltResp         - The returned <ConfigAltResp>.
896     Progress              - On return, points to a character in the Request.
897     Guid                  - GUID of the buffer storage.
898     Name                  - Name of the buffer storage.
899     DriverHandle          - The DriverHandle which is used to invoke HiiDatabase
900                             protocol interface NewPackageList().
901     BufferStorage         - Content of the buffer storage.
902     BufferStorageSize     - Length in bytes of the buffer storage.
903     BlockNameArray        - Array generated by VFR compiler.
904     NumberAltCfg          - Number of Default value array generated by VFR compiler.
905                             The sequential input parameters will be number of
906                             AltCfgId and DefaultValueArray pairs. When set to 0,
907                             there will be no <AltResp>.
908 
909   Returns:
910     EFI_OUT_OF_RESOURCES  - Run out of memory resource.
911     EFI_INVALID_PARAMETER - ConfigAltResp is NULL.
912     EFI_SUCCESS           - Operation successful.
913 
914 --*/
915 {
916   EFI_STATUS                      Status;
917   CHAR16                          *ConfigHdr;
918   CHAR16                          *BlockName;
919   CHAR16                          *DescHdr;
920   CHAR16                          *StringPtr;
921   CHAR16                          **AltCfg;
922   UINT16                          AltCfgId;
923   VOID                            *DefaultValueArray;
924   UINTN                           StrBufferLen;
925   EFI_STRING                      ConfigResp;
926   EFI_STRING                      TempStr;
927   VA_LIST                         Args;
928   UINTN                           AltRespLen;
929   UINTN                           Index;
930   BOOLEAN                         NeedFreeConfigRequest;
931   EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
932 
933   if (ConfigAltResp == NULL) {
934     return EFI_INVALID_PARAMETER;
935   }
936 
937   //
938   // Construct <ConfigHdr> : "GUID=...&NAME=...&PATH=..."
939   //
940   ConfigHdr = NULL;
941   StrBufferLen = 0;
942   Status = ConstructConfigHdr (
943              ConfigHdr,
944              &StrBufferLen,
945              Guid,
946              Name,
947              DriverHandle
948              );
949   if (Status == EFI_BUFFER_TOO_SMALL) {
950     ConfigHdr = EfiLibAllocateZeroPool (StrBufferLen);
951     Status = ConstructConfigHdr (
952                ConfigHdr,
953                &StrBufferLen,
954                Guid,
955                Name,
956                DriverHandle
957                );
958   }
959 
960   if (EFI_ERROR (Status) || (ConfigHdr == NULL)) {
961     return Status;
962   }
963 
964   //
965   // Construct <ConfigResp>
966   //
967   NeedFreeConfigRequest = FALSE;
968   if (ConfigRequest == NULL) {
969     //
970     // If ConfigRequest is set to NULL, export all configurable elements in BlockNameArray
971     //
972     Status = ExtractBlockName (BlockNameArray, &BlockName);
973     if (EFI_ERROR (Status)) {
974       return Status;
975     }
976 
977     StrBufferLen = EfiStrSize (ConfigHdr);
978     StrBufferLen = StrBufferLen + EfiStrSize (BlockName) - sizeof (CHAR16);
979     ConfigRequest = EfiLibAllocateZeroPool (StrBufferLen);
980     EfiStrCpy (ConfigRequest, ConfigHdr);
981     EfiStrCat (ConfigRequest, BlockName);
982     NeedFreeConfigRequest = TRUE;
983   }
984 
985   Status = gBS->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid, NULL, (VOID **) &HiiConfigRouting);
986   if (EFI_ERROR (Status)) {
987     return Status;
988   }
989 
990   Status = HiiConfigRouting->BlockToConfig (
991                                HiiConfigRouting,
992                                ConfigRequest,
993                                BufferStorage,
994                                BufferStorageSize,
995                                &ConfigResp,
996                                (Progress == NULL) ? &TempStr : Progress
997                                );
998   if (EFI_ERROR (Status)) {
999     return Status;
1000   }
1001 
1002   //
1003   // Construct <AltResp>
1004   //
1005   DescHdr = EfiLibAllocateZeroPool (NumberAltCfg * 16 * sizeof (CHAR16));
1006   StringPtr = DescHdr;
1007   AltCfg = EfiLibAllocateZeroPool (NumberAltCfg * sizeof (CHAR16 *));
1008   AltRespLen = 0;
1009   VA_START (Args, NumberAltCfg);
1010   for (Index = 0; Index < NumberAltCfg; Index++) {
1011     AltCfgId = (UINT16) VA_ARG (Args, UINT16);
1012     DefaultValueArray = (UINT8 *) VA_ARG (Args, VOID *);
1013 
1014     //
1015     // '&' <ConfigHdr>
1016     //
1017     AltRespLen += (EfiStrLen (ConfigHdr) + 1);
1018 
1019     StringPtr = DescHdr + Index * 16;
1020     EfiStrCpy (StringPtr, L"&ALTCFG=");
1021     AltRespLen += (8 + sizeof (UINT16) * 2);
1022 
1023     StrBufferLen = 5;
1024     BufToHexString (StringPtr + 8, &StrBufferLen, (UINT8 *) &AltCfgId, sizeof (UINT16));
1025     Status = ExtractBlockConfig (DefaultValueArray, &AltCfg[Index]);
1026     if (EFI_ERROR (Status)) {
1027       VA_END (Args);
1028       return Status;
1029     }
1030     AltRespLen += EfiStrLen (AltCfg[Index]);
1031   }
1032   VA_END (Args);
1033 
1034   //
1035   // Generate the final <ConfigAltResp>
1036   //
1037   StrBufferLen = (EfiStrLen ((CHAR16 *) ConfigResp) + AltRespLen + 1) * sizeof (CHAR16);
1038   TempStr = EfiLibAllocateZeroPool (StrBufferLen);
1039   *ConfigAltResp = TempStr;
1040   if (TempStr == NULL) {
1041     return EFI_OUT_OF_RESOURCES;
1042   }
1043 
1044   //
1045   // <ConfigAltResp> ::= <ConfigResp> ['&' <AltResp>]*
1046   //
1047   EfiStrCpy (TempStr, ConfigResp);
1048   for (Index = 0; Index < NumberAltCfg; Index++) {
1049     EfiStrCat (TempStr, L"&");
1050     EfiStrCat (TempStr, ConfigHdr);
1051     EfiStrCat (TempStr, DescHdr + Index * 16);
1052     EfiStrCat (TempStr, AltCfg[Index]);
1053 
1054     gBS->FreePool (AltCfg[Index]);
1055   }
1056 
1057   if (NeedFreeConfigRequest) {
1058     gBS->FreePool (ConfigRequest);
1059   }
1060   gBS->FreePool (ConfigHdr);
1061   gBS->FreePool (ConfigResp);
1062   gBS->FreePool (DescHdr);
1063   gBS->FreePool (AltCfg);
1064 
1065   return EFI_SUCCESS;
1066 }
1067 
1068 VOID
SwapBuffer(IN OUT UINT8 * Buffer,IN UINTN BufferSize)1069 SwapBuffer (
1070   IN OUT UINT8     *Buffer,
1071   IN UINTN         BufferSize
1072   )
1073 /*++
1074 
1075 Routine Description:
1076   Swap bytes in the buffer.
1077 
1078 Arguments:
1079   Buffer     -  Binary buffer.
1080   BufferSize -  Size of the buffer in bytes.
1081 
1082 Returns:
1083   None.
1084 
1085 --*/
1086 {
1087   UINTN  Index;
1088   UINT8  Temp;
1089   UINTN  SwapCount;
1090 
1091   SwapCount = BufferSize / 2;
1092   for (Index = 0; Index < SwapCount; Index++) {
1093     Temp = Buffer[Index];
1094     Buffer[Index] = Buffer[BufferSize - 1 - Index];
1095     Buffer[BufferSize - 1 - Index] = Temp;
1096   }
1097 }
1098 
1099 VOID
ToLower(IN OUT CHAR16 * Str)1100 ToLower (
1101   IN OUT CHAR16    *Str
1102   )
1103 /*++
1104 
1105 Routine Description:
1106   Converts the unicode character of the string from uppercase to lowercase.
1107 
1108 Arguments:
1109   Str        -  String to be converted
1110 
1111 Returns:
1112 
1113 --*/
1114 {
1115   CHAR16      *Ptr;
1116 
1117   for (Ptr = Str; *Ptr != L'\0'; Ptr++) {
1118     if (*Ptr >= L'A' && *Ptr <= L'Z') {
1119       *Ptr = (CHAR16) (*Ptr - L'A' + L'a');
1120     }
1121   }
1122 }
1123 
1124 EFI_STATUS
BufferToHexString(IN OUT CHAR16 * Str,IN UINT8 * Buffer,IN UINTN BufferSize)1125 BufferToHexString (
1126   IN OUT CHAR16    *Str,
1127   IN UINT8         *Buffer,
1128   IN UINTN         BufferSize
1129   )
1130 /*++
1131 
1132 Routine Description:
1133   Converts binary buffer to Unicode string in reversed byte order from BufToHexString().
1134 
1135 Arguments:
1136   Str        -  String for output
1137   Buffer     -  Binary buffer.
1138   BufferSize -  Size of the buffer in bytes.
1139 
1140 Returns:
1141   EFI_SUCCESS  -  The function completed successfully.
1142 
1143 --*/
1144 {
1145   EFI_STATUS  Status;
1146   UINT8       *NewBuffer;
1147   UINTN       StrBufferLen;
1148 
1149   NewBuffer = EfiLibAllocateCopyPool (BufferSize, Buffer);
1150   SwapBuffer (NewBuffer, BufferSize);
1151 
1152   StrBufferLen = BufferSize * 2 + 1;
1153   Status = BufToHexString (Str, &StrBufferLen, NewBuffer, BufferSize);
1154 
1155   gBS->FreePool (NewBuffer);
1156   //
1157   // Convert the uppercase to lowercase since <HexAf> is defined in lowercase format.
1158   //
1159   ToLower (Str);
1160 
1161   return Status;
1162 }
1163 
1164 EFI_STATUS
HexStringToBuffer(IN OUT UINT8 * Buffer,IN OUT UINTN * BufferSize,IN CHAR16 * Str)1165 HexStringToBuffer (
1166   IN OUT UINT8         *Buffer,
1167   IN OUT UINTN         *BufferSize,
1168   IN CHAR16            *Str
1169   )
1170 /*++
1171 
1172 Routine Description:
1173   Converts Hex String to binary buffer in reversed byte order from HexStringToBuf().
1174 
1175 Arguments:
1176     Buffer     - Pointer to buffer that receives the data.
1177     BufferSize - Length in bytes of the buffer to hold converted data.
1178                  If routine return with EFI_SUCCESS, containing length of converted data.
1179                  If routine return with EFI_BUFFER_TOO_SMALL, containg length of buffer desired.
1180     Str        - String to be converted from.
1181 
1182 Returns:
1183   EFI_SUCCESS    -  The function completed successfully.
1184 
1185 --*/
1186 {
1187   EFI_STATUS  Status;
1188   UINTN       ConvertedStrLen;
1189 
1190   ConvertedStrLen = 0;
1191   Status = HexStringToBuf (Buffer, BufferSize, Str, &ConvertedStrLen);
1192   if (!EFI_ERROR (Status)) {
1193     SwapBuffer (Buffer, (ConvertedStrLen + 1) / 2);
1194   }
1195 
1196   return Status;
1197 }
1198 
1199 EFI_STATUS
ConfigStringToUnicode(IN OUT CHAR16 * UnicodeString,IN OUT UINTN * StrBufferLen,IN CHAR16 * ConfigString)1200 ConfigStringToUnicode (
1201   IN OUT CHAR16                *UnicodeString,
1202   IN OUT UINTN                 *StrBufferLen,
1203   IN CHAR16                    *ConfigString
1204   )
1205 /*++
1206 
1207 Routine Description:
1208   Convert binary representation Config string (e.g. "0041004200430044") to the
1209   original string (e.g. "ABCD"). Config string appears in <ConfigHdr> (i.e.
1210   "&NAME=<string>"), or Name/Value pair in <ConfigBody> (i.e. "label=<string>").
1211 
1212 Arguments:
1213   UnicodeString - Original Unicode string.
1214   StrBufferLen  - On input: Length in bytes of buffer to hold the Unicode string.
1215                   Includes tailing '\0' character.
1216                   On output:
1217                     If return EFI_SUCCESS, containing length of Unicode string buffer.
1218                     If return EFI_BUFFER_TOO_SMALL, containg length of string buffer desired.
1219   ConfigString  - Binary representation of Unicode String, <string> := (<HexCh>4)+
1220 
1221 Returns:
1222   EFI_SUCCESS          - Routine success.
1223   EFI_BUFFER_TOO_SMALL - The string buffer is too small.
1224 
1225 --*/
1226 {
1227   UINTN       Index;
1228   UINTN       Len;
1229   UINTN       BufferSize;
1230   CHAR16      BackupChar;
1231 
1232   Len = EfiStrLen (ConfigString) / 4;
1233   BufferSize = (Len + 1) * sizeof (CHAR16);
1234 
1235   if (*StrBufferLen < BufferSize) {
1236     *StrBufferLen = BufferSize;
1237     return EFI_BUFFER_TOO_SMALL;
1238   }
1239 
1240   *StrBufferLen = BufferSize;
1241 
1242   for (Index = 0; Index < Len; Index++) {
1243     BackupChar = ConfigString[4];
1244     ConfigString[4] = L'\0';
1245 
1246     HexStringToBuf ((UINT8 *) UnicodeString, &BufferSize, ConfigString, NULL);
1247 
1248     ConfigString[4] = BackupChar;
1249 
1250     ConfigString += 4;
1251     UnicodeString += 1;
1252   }
1253 
1254   //
1255   // Add tailing '\0' character
1256   //
1257   *UnicodeString = L'\0';
1258 
1259   return EFI_SUCCESS;
1260 }
1261 
1262 EFI_STATUS
UnicodeToConfigString(IN OUT CHAR16 * ConfigString,IN OUT UINTN * StrBufferLen,IN CHAR16 * UnicodeString)1263 UnicodeToConfigString (
1264   IN OUT CHAR16                *ConfigString,
1265   IN OUT UINTN                 *StrBufferLen,
1266   IN CHAR16                    *UnicodeString
1267   )
1268 /*++
1269 
1270 Routine Description:
1271   Convert Unicode string to binary representation Config string, e.g.
1272   "ABCD" => "0041004200430044". Config string appears in <ConfigHdr> (i.e.
1273   "&NAME=<string>"), or Name/Value pair in <ConfigBody> (i.e. "label=<string>").
1274 
1275 Arguments:
1276   ConfigString  - Binary representation of Unicode String, <string> := (<HexCh>4)+
1277   StrBufferLen  - On input: Length in bytes of buffer to hold the Unicode string.
1278                   Includes tailing '\0' character.
1279                   On output:
1280                     If return EFI_SUCCESS, containing length of Unicode string buffer.
1281                     If return EFI_BUFFER_TOO_SMALL, containg length of string buffer desired.
1282   UnicodeString - Original Unicode string.
1283 
1284 Returns:
1285   EFI_SUCCESS          - Routine success.
1286   EFI_BUFFER_TOO_SMALL - The string buffer is too small.
1287 
1288 --*/
1289 {
1290   UINTN       Index;
1291   UINTN       Len;
1292   UINTN       BufferSize;
1293   CHAR16      *String;
1294 
1295   Len = EfiStrLen (UnicodeString);
1296   BufferSize = (Len * 4 + 1) * sizeof (CHAR16);
1297 
1298   if (*StrBufferLen < BufferSize) {
1299     *StrBufferLen = BufferSize;
1300     return EFI_BUFFER_TOO_SMALL;
1301   }
1302 
1303   *StrBufferLen = BufferSize;
1304   String        = ConfigString;
1305 
1306   for (Index = 0; Index < Len; Index++) {
1307     BufToHexString (ConfigString, &BufferSize, (UINT8 *) UnicodeString, 2);
1308 
1309     ConfigString += 4;
1310     UnicodeString += 1;
1311   }
1312 
1313   //
1314   // Add tailing '\0' character
1315   //
1316   *ConfigString = L'\0';
1317 
1318   //
1319   // Convert the uppercase to lowercase since <HexAf> is defined in lowercase format.
1320   //
1321   ToLower (String);
1322   return EFI_SUCCESS;
1323 }
1324 
1325 EFI_STATUS
ConstructConfigHdr(IN OUT CHAR16 * ConfigHdr,IN OUT UINTN * StrBufferLen,IN EFI_GUID * Guid,IN CHAR16 * Name,OPTIONAL IN EFI_HANDLE * DriverHandle)1326 ConstructConfigHdr (
1327   IN OUT CHAR16                *ConfigHdr,
1328   IN OUT UINTN                 *StrBufferLen,
1329   IN EFI_GUID                  *Guid,
1330   IN CHAR16                    *Name, OPTIONAL
1331   IN EFI_HANDLE                *DriverHandle
1332   )
1333 /*++
1334 
1335 Routine Description:
1336   Construct <ConfigHdr> using routing information GUID/NAME/PATH.
1337 
1338 Arguments:
1339   ConfigHdr    - Pointer to the ConfigHdr string.
1340   StrBufferLen - On input: Length in bytes of buffer to hold the ConfigHdr string.
1341                  Includes tailing '\0' character.
1342                  On output:
1343                     If return EFI_SUCCESS, containing length of ConfigHdr string buffer.
1344                     If return EFI_BUFFER_TOO_SMALL, containg length of string buffer desired.
1345   Guid         - Routing information: GUID.
1346   Name         - Routing information: NAME.
1347   DriverHandle - Driver handle which contains the routing information: PATH.
1348 
1349 Returns:
1350   EFI_SUCCESS          - Routine success.
1351   EFI_BUFFER_TOO_SMALL - The ConfigHdr string buffer is too small.
1352 
1353 --*/
1354 {
1355   EFI_STATUS                Status;
1356   UINTN                     NameStrLen;
1357   UINTN                     DevicePathSize;
1358   UINTN                     BufferSize;
1359   CHAR16                    *StrPtr;
1360   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
1361 
1362   if (Name == NULL) {
1363     //
1364     // There will be no "NAME" in <ConfigHdr> for  Name/Value storage
1365     //
1366     NameStrLen = 0;
1367   } else {
1368     //
1369     // For buffer storage
1370     //
1371     NameStrLen = EfiStrLen (Name);
1372   }
1373 
1374   //
1375   // Retrieve DevicePath Protocol associated with this HiiPackageList
1376   //
1377   Status = gBS->HandleProtocol (
1378                   DriverHandle,
1379                   &gEfiDevicePathProtocolGuid,
1380                   (VOID **) &DevicePath
1381                   );
1382   if (EFI_ERROR (Status)) {
1383     return Status;
1384   }
1385 
1386   DevicePathSize = EfiDevicePathSize (DevicePath);
1387 
1388   //
1389   // GUID=<HexCh>32&NAME=<Char>NameStrLen&PATH=<HexChar>DevicePathStrLen <NULL>
1390   // | 5  |   32   |  6  |  NameStrLen*4 |  6  |    DevicePathStrLen    | 1 |
1391   //
1392   BufferSize = (5 + 32 + 6 + NameStrLen * 4 + 6 + DevicePathSize * 2 + 1) * sizeof (CHAR16);
1393   if (*StrBufferLen < BufferSize) {
1394     *StrBufferLen = BufferSize;
1395     return EFI_BUFFER_TOO_SMALL;
1396   }
1397 
1398   if (ConfigHdr == NULL) {
1399     return EFI_INVALID_PARAMETER;
1400   }
1401 
1402   *StrBufferLen = BufferSize;
1403 
1404   StrPtr = ConfigHdr;
1405 
1406   EfiStrCpy (StrPtr, L"GUID=");
1407   StrPtr += 5;
1408   BufferToHexString (StrPtr, (UINT8 *) Guid, sizeof (EFI_GUID));
1409   StrPtr += 32;
1410 
1411   //
1412   // Convert name string, e.g. name "ABCD" => "&NAME=0041004200430044"
1413   //
1414   EfiStrCpy (StrPtr, L"&NAME=");
1415   StrPtr += 6;
1416   if (Name != NULL) {
1417     BufferSize = (NameStrLen * 4 + 1) * sizeof (CHAR16);
1418     UnicodeToConfigString (StrPtr, &BufferSize, Name);
1419     StrPtr += (NameStrLen * 4);
1420   }
1421 
1422   EfiStrCpy (StrPtr, L"&PATH=");
1423   StrPtr += 6;
1424   BufferToHexString (StrPtr, (UINT8 *) DevicePath, DevicePathSize);
1425 
1426   return EFI_SUCCESS;
1427 }
1428 
1429 BOOLEAN
IsConfigHdrMatch(IN EFI_STRING ConfigString,IN EFI_GUID * StorageGuid,OPTIONAL IN CHAR16 * StorageName OPTIONAL)1430 IsConfigHdrMatch (
1431   IN EFI_STRING                ConfigString,
1432   IN EFI_GUID                  *StorageGuid, OPTIONAL
1433   IN CHAR16                    *StorageName  OPTIONAL
1434   )
1435 /*++
1436 
1437 Routine Description:
1438   Determines if the Routing data (Guid and Name) is correct in <ConfigHdr>.
1439 
1440 Arguments:
1441   ConfigString - Either <ConfigRequest> or <ConfigResp>.
1442   StorageGuid  - GUID of the storage.
1443   StorageName  - Name of the stoarge.
1444 
1445 Returns:
1446   TRUE         - Routing information is correct in ConfigString.
1447   FALSE        - Routing information is incorrect in ConfigString.
1448 
1449 --*/
1450 {
1451   EFI_STATUS  Status;
1452   BOOLEAN     Match;
1453   EFI_GUID    Guid;
1454   CHAR16      *Name;
1455   CHAR16      *StrPtr;
1456   UINTN       BufferSize;
1457 
1458   //
1459   // <ConfigHdr> ::=
1460   // GUID=<HexCh>32&NAME=<Char>NameStrLen&PATH=<HexChar>DevicePathStrLen <NULL>
1461   // | 5  |   32   |  6  |  NameStrLen*4 |  6  |    DevicePathStrLen    | 1 |
1462   //
1463   if (EfiStrLen (ConfigString) <= (5 + 32 + 6)) {
1464     return FALSE;
1465   }
1466 
1467   //
1468   // Compare GUID
1469   //
1470   if (StorageGuid != NULL) {
1471 
1472     StrPtr = ConfigString + 5 + 32;
1473     if (*StrPtr != L'&') {
1474       return FALSE;
1475     }
1476     *StrPtr = L'\0';
1477 
1478     BufferSize = sizeof (EFI_GUID);
1479     Status = HexStringToBuffer (
1480                (UINT8 *) &Guid,
1481                &BufferSize,
1482                ConfigString + 5
1483                );
1484     *StrPtr = L'&';
1485 
1486     if (EFI_ERROR (Status)) {
1487       return FALSE;
1488     }
1489 
1490     if (!EfiCompareGuid (&Guid, StorageGuid)) {
1491       return FALSE;
1492     }
1493   }
1494 
1495   //
1496   // Compare Name
1497   //
1498   Match = TRUE;
1499   if (StorageName != NULL) {
1500     StrPtr = ConfigString + 5 + 32 + 6;
1501     while (*StrPtr != L'\0' && *StrPtr != L'&') {
1502       StrPtr++;
1503     }
1504     if (*StrPtr != L'&') {
1505       return FALSE;
1506     }
1507 
1508     *StrPtr = L'\0';
1509     BufferSize = (EfiStrLen (ConfigString + 5 + 32 + 6) + 1) * sizeof (CHAR16);
1510     Name = EfiLibAllocatePool (BufferSize);
1511     ASSERT (Name != NULL);
1512     Status = ConfigStringToUnicode (
1513                Name,
1514                &BufferSize,
1515                ConfigString + 5 + 32 + 6
1516                );
1517     *StrPtr = L'&';
1518 
1519     if (EFI_ERROR (Status) || (EfiStrCmp (Name, StorageName) != 0)) {
1520       Match = FALSE;
1521     }
1522     gBS->FreePool (Name);
1523   }
1524 
1525   return Match;
1526 }
1527 
1528 BOOLEAN
FindBlockName(IN OUT CHAR16 * String,UINTN Offset,UINTN Width)1529 FindBlockName (
1530   IN OUT CHAR16                *String,
1531   UINTN                        Offset,
1532   UINTN                        Width
1533   )
1534 /*++
1535 
1536 Routine Description:
1537   Search BlockName "&OFFSET=Offset&WIDTH=Width" in a string.
1538 
1539 Arguments:
1540   String       - The string to be searched in.
1541   Offset       - Offset in BlockName.
1542   Width        - Width in BlockName.
1543 
1544 Returns:
1545   TRUE         - Block name found.
1546   FALSE        - Block name not found.
1547 
1548 --*/
1549 {
1550   EFI_STATUS  Status;
1551   UINTN       Data;
1552   UINTN       BufferSize;
1553   UINTN       ConvertedStrLen;
1554 
1555   while ((String = EfiStrStr (String, L"&OFFSET=")) != NULL) {
1556     //
1557     // Skip '&OFFSET='
1558     //
1559     String = String + 8;
1560 
1561     Data = 0;
1562     BufferSize = sizeof (UINTN);
1563     Status = HexStringToBuf ((UINT8 *) &Data, &BufferSize, String, &ConvertedStrLen);
1564     if (EFI_ERROR (Status)) {
1565       return FALSE;
1566     }
1567     String = String + ConvertedStrLen;
1568 
1569     if (Data != Offset) {
1570       continue;
1571     }
1572 
1573     if (EfiStrnCmp (String, L"&WIDTH=", 7) != 0) {
1574       return FALSE;
1575     }
1576     String = String + 7;
1577 
1578     Data = 0;
1579     BufferSize = sizeof (UINTN);
1580     Status = HexStringToBuf ((UINT8 *) &Data, &BufferSize, String, &ConvertedStrLen);
1581     if (EFI_ERROR (Status)) {
1582       return FALSE;
1583     }
1584     if (Data == Width) {
1585       return TRUE;
1586     }
1587 
1588     String = String + ConvertedStrLen;
1589   }
1590 
1591   return FALSE;
1592 }
1593 
1594 EFI_STATUS
GetBrowserData(EFI_GUID * VariableGuid,OPTIONAL CHAR16 * VariableName,OPTIONAL UINTN * BufferSize,UINT8 * Buffer)1595 GetBrowserData (
1596   EFI_GUID                   *VariableGuid, OPTIONAL
1597   CHAR16                     *VariableName, OPTIONAL
1598   UINTN                      *BufferSize,
1599   UINT8                      *Buffer
1600   )
1601 /*++
1602 
1603 Routine Description:
1604   This routine is invoked by ConfigAccess.Callback() to retrived uncommitted data from Form Browser.
1605 
1606 Arguments:
1607   VariableGuid  - An optional field to indicate the target variable GUID name to use.
1608   VariableName  - An optional field to indicate the target human-readable variable name.
1609   BufferSize    - On input: Length in bytes of buffer to hold retrived data.
1610                   On output:
1611                     If return EFI_BUFFER_TOO_SMALL, containg length of buffer desired.
1612   Buffer        - Buffer to hold retrived data.
1613 
1614 Returns:
1615   EFI_SUCCESS          - Routine success.
1616   EFI_BUFFER_TOO_SMALL - The intput buffer is too small.
1617 
1618 --*/
1619 {
1620   EFI_STATUS                      Status;
1621   CHAR16                          *ConfigHdr;
1622   CHAR16                          *ConfigResp;
1623   CHAR16                          *StringPtr;
1624   UINTN                           HeaderLen;
1625   UINTN                           BufferLen;
1626   CHAR16                          *Progress;
1627   EFI_FORM_BROWSER2_PROTOCOL      *FormBrowser2;
1628   EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
1629 
1630   //
1631   // Locate protocols for use
1632   //
1633   Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &FormBrowser2);
1634   if (EFI_ERROR (Status)) {
1635     return Status;
1636   }
1637 
1638   Status = gBS->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid, NULL, (VOID **) &HiiConfigRouting);
1639   if (EFI_ERROR (Status)) {
1640     return Status;
1641   }
1642 
1643   //
1644   // Retrieve formset storage data from Form Browser
1645   //
1646   ConfigHdr = mFakeConfigHdr;
1647   HeaderLen = EfiStrLen (ConfigHdr);
1648 
1649   BufferLen = 0x4000;
1650   ConfigResp = EfiLibAllocateZeroPool (BufferLen + (HeaderLen + 1) * sizeof (CHAR16));
1651 
1652   StringPtr = ConfigResp + HeaderLen;
1653   *StringPtr = L'&';
1654   StringPtr++;
1655 
1656   Status = FormBrowser2->BrowserCallback (
1657                            FormBrowser2,
1658                            &BufferLen,
1659                            StringPtr,
1660                            TRUE,
1661                            VariableGuid,
1662                            VariableName
1663                            );
1664   if (Status == EFI_BUFFER_TOO_SMALL) {
1665     gBS->FreePool (ConfigResp);
1666     ConfigResp = EfiLibAllocateZeroPool (BufferLen + (HeaderLen + 1) * sizeof (CHAR16));
1667 
1668     StringPtr = ConfigResp + HeaderLen;
1669     *StringPtr = L'&';
1670     StringPtr++;
1671 
1672     Status = FormBrowser2->BrowserCallback (
1673                              FormBrowser2,
1674                              &BufferLen,
1675                              StringPtr,
1676                              TRUE,
1677                              VariableGuid,
1678                              VariableName
1679                              );
1680   }
1681   if (EFI_ERROR (Status)) {
1682     gBS->FreePool (ConfigResp);
1683     return Status;
1684   }
1685   EfiCopyMem (ConfigResp, ConfigHdr, HeaderLen * sizeof (UINT16));
1686 
1687   //
1688   // Convert <ConfigResp> to buffer data
1689   //
1690   Status = HiiConfigRouting->ConfigToBlock (
1691                                HiiConfigRouting,
1692                                ConfigResp,
1693                                Buffer,
1694                                BufferSize,
1695                                &Progress
1696                                );
1697   gBS->FreePool (ConfigResp);
1698 
1699   return Status;
1700 }
1701 
1702 EFI_STATUS
SetBrowserData(EFI_GUID * VariableGuid,OPTIONAL CHAR16 * VariableName,OPTIONAL UINTN BufferSize,UINT8 * Buffer,CHAR16 * RequestElement OPTIONAL)1703 SetBrowserData (
1704   EFI_GUID                   *VariableGuid, OPTIONAL
1705   CHAR16                     *VariableName, OPTIONAL
1706   UINTN                      BufferSize,
1707   UINT8                      *Buffer,
1708   CHAR16                     *RequestElement  OPTIONAL
1709   )
1710 /*++
1711 
1712 Routine Description:
1713   This routine is invoked by ConfigAccess.Callback() to update uncommitted data of Form Browser.
1714 
1715 Arguments:
1716   VariableGuid   - An optional field to indicate the target variable GUID name to use.
1717   VariableName   - An optional field to indicate the target human-readable variable name.
1718   BufferSize     - Length in bytes of buffer to hold retrived data.
1719   Buffer         - Buffer to hold retrived data.
1720   RequestElement - An optional field to specify which part of the buffer data
1721                    will be send back to Browser. If NULL, the whole buffer of
1722                    data will be committed to Browser.
1723                    <RequestElement> ::= &OFFSET=<Number>&WIDTH=<Number>*
1724 
1725 Returns:
1726   EFI_SUCCESS  - Routine success.
1727   Other        - Updating Browser uncommitted data failed.
1728 
1729 --*/
1730 {
1731   EFI_STATUS                      Status;
1732   CHAR16                          *ConfigHdr;
1733   CHAR16                          *ConfigResp;
1734   CHAR16                          *StringPtr;
1735   UINTN                           HeaderLen;
1736   UINTN                           BufferLen;
1737   CHAR16                          *Progress;
1738   EFI_FORM_BROWSER2_PROTOCOL      *FormBrowser2;
1739   EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
1740   CHAR16                          BlockName[33];
1741   CHAR16                          *ConfigRequest;
1742   CHAR16                          *Request;
1743 
1744   //
1745   // Locate protocols for use
1746   //
1747   Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &FormBrowser2);
1748   if (EFI_ERROR (Status)) {
1749     return Status;
1750   }
1751 
1752   Status = gBS->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid, NULL, (VOID **) &HiiConfigRouting);
1753   if (EFI_ERROR (Status)) {
1754     return Status;
1755   }
1756 
1757   //
1758   // Prepare <ConfigRequest>
1759   //
1760   ConfigHdr = mFakeConfigHdr;
1761   HeaderLen = EfiStrLen (ConfigHdr);
1762 
1763   if (RequestElement == NULL) {
1764     //
1765     // RequestElement not specified, use "&OFFSET=0&WIDTH=<BufferSize>" as <BlockName>
1766     //
1767     BlockName[0] = L'\0';
1768     EfiStrCpy (BlockName, L"&OFFSET=0&WIDTH=");
1769 
1770     //
1771     // String lenghth of L"&OFFSET=0&WIDTH=" is 16
1772     //
1773     StringPtr = BlockName + 16;
1774     BufferLen = sizeof (BlockName) - (16 * sizeof (CHAR16));
1775     BufToHexString (StringPtr, &BufferLen, (UINT8 *) &BufferSize, sizeof (UINTN));
1776 
1777     Request = BlockName;
1778   } else {
1779     Request = RequestElement;
1780   }
1781 
1782   BufferLen = HeaderLen * sizeof (CHAR16) + EfiStrSize (Request);
1783   ConfigRequest = EfiLibAllocateZeroPool (BufferLen);
1784 
1785   EfiCopyMem (ConfigRequest, ConfigHdr, HeaderLen * sizeof (CHAR16));
1786   StringPtr = ConfigRequest + HeaderLen;
1787   EfiStrCpy (StringPtr, Request);
1788 
1789   //
1790   // Convert buffer to <ConfigResp>
1791   //
1792   Status = HiiConfigRouting->BlockToConfig (
1793                                 HiiConfigRouting,
1794                                 ConfigRequest,
1795                                 Buffer,
1796                                 BufferSize,
1797                                 &ConfigResp,
1798                                 &Progress
1799                                 );
1800   if (EFI_ERROR (Status)) {
1801     gBS->FreePool (ConfigRequest);
1802     return Status;
1803   }
1804 
1805   //
1806   // Skip <ConfigHdr> and '&'
1807   //
1808   StringPtr = ConfigResp + HeaderLen + 1;
1809 
1810   //
1811   // Change uncommitted data in Browser
1812   //
1813   Status = FormBrowser2->BrowserCallback (
1814                            FormBrowser2,
1815                            &BufferSize,
1816                            StringPtr,
1817                            FALSE,
1818                            VariableGuid,
1819                            VariableName
1820                            );
1821   gBS->FreePool (ConfigResp);
1822   gBS->FreePool (ConfigRequest);
1823   return Status;
1824 }
1825