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                         End;
456   UINTN                         Top;
457   UINTN                         Bottom;
458   CHAR16                        *StringPtr;
459   UINTN                         LeftColumn;
460   UINTN                         RightColumn;
461   UINTN                         TopRow;
462   UINTN                         BottomRow;
463   UINTN                         DimensionsWidth;
464   UINTN                         DimensionsHeight;
465   VA_LIST                       Marker;
466   EFI_INPUT_KEY                 Key;
467   UINTN                         LargestString;
468   CHAR16                        *StackString;
469   EFI_STATUS                    Status;
470   UINTN                         StringLen;
471   CHAR16                        *LineBuffer;
472   CHAR16                        **StringArray;
473   EFI_EVENT                     TimerEvent;
474   EFI_EVENT                     WaitList[2];
475   UINTN                         CurrentAttribute;
476   EFI_SIMPLE_TEXT_OUT_PROTOCOL  *ConOut;
477 
478   if ((KeyValue == NULL) || (String == NULL)) {
479     return EFI_INVALID_PARAMETER;
480   }
481 
482   TopRow      = 0;
483   BottomRow   = 0;
484   LeftColumn  = 0;
485   RightColumn = 0;
486 
487   ConOut = gST->ConOut;
488   ConOut->QueryMode (ConOut, ConOut->Mode->Mode, &RightColumn, &BottomRow);
489 
490   DimensionsWidth  = RightColumn - LeftColumn;
491   DimensionsHeight = BottomRow - TopRow;
492 
493   CurrentAttribute = ConOut->Mode->Attribute;
494 
495   LineBuffer = EfiLibAllocateZeroPool (DimensionsWidth * sizeof (CHAR16));
496   ASSERT (LineBuffer != NULL);
497 
498   //
499   // Determine the largest string in the dialog box
500   // Notice we are starting with 1 since String is the first string
501   //
502   StringArray = EfiLibAllocateZeroPool (NumberOfLines * sizeof (CHAR16 *));
503   LargestString = EfiStrLen (String);
504   StringArray[0] = String;
505 
506   VA_START (Marker, String);
507   for (Index = 1; Index < NumberOfLines; Index++) {
508     StackString = VA_ARG (Marker, CHAR16 *);
509 
510     if (StackString == NULL) {
511       VA_END (Marker);
512       return EFI_INVALID_PARAMETER;
513     }
514 
515     StringArray[Index] = StackString;
516     StringLen = EfiStrLen (StackString);
517     if (StringLen > LargestString) {
518       LargestString = StringLen;
519     }
520   }
521   VA_END (Marker);
522 
523   if ((LargestString + 2) > DimensionsWidth) {
524     LargestString = DimensionsWidth - 2;
525   }
526 
527   //
528   // Subtract the PopUp width from total Columns, allow for one space extra on
529   // each end plus a border.
530   //
531   Start     = (DimensionsWidth - LargestString - 2) / 2 + LeftColumn + 1;
532   End       = Start + LargestString + 1;
533 
534   Top       = ((DimensionsHeight - NumberOfLines - 2) / 2) + TopRow - 1;
535   Bottom    = Top + NumberOfLines + 2;
536 
537   //
538   // Disable cursor
539   //
540   ConOut->EnableCursor (ConOut, FALSE);
541   ConOut->SetAttribute (ConOut, EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE);
542 
543   StringPtr = &LineBuffer[0];
544   *StringPtr++ = BOXDRAW_DOWN_RIGHT;
545   for (Index = 0; Index < LargestString; Index++) {
546     *StringPtr++ = BOXDRAW_HORIZONTAL;
547   }
548   *StringPtr++ = BOXDRAW_DOWN_LEFT;
549   *StringPtr = L'\0';
550 
551   ConOut->SetCursorPosition (ConOut, Start, Top);
552   ConOut->OutputString (ConOut, LineBuffer);
553 
554   for (Index = 0; Index < NumberOfLines; Index++) {
555     StringPtr = &LineBuffer[0];
556     *StringPtr++ = BOXDRAW_VERTICAL;
557 
558     for (Count = 0; Count < LargestString; Count++) {
559       StringPtr[Count] = L' ';
560     }
561 
562     StringLen = EfiStrLen (StringArray[Index]);
563     if (StringLen > LargestString) {
564       StringLen = LargestString;
565     }
566     EfiCopyMem (
567       StringPtr + ((LargestString - StringLen) / 2),
568       StringArray[Index],
569       StringLen * sizeof (CHAR16)
570       );
571     StringPtr += LargestString;
572 
573     *StringPtr++ = BOXDRAW_VERTICAL;
574     *StringPtr = L'\0';
575 
576     ConOut->SetCursorPosition (ConOut, Start, Top + 1 + Index);
577     ConOut->OutputString (ConOut, LineBuffer);
578   }
579 
580   StringPtr = &LineBuffer[0];
581   *StringPtr++ = BOXDRAW_UP_RIGHT;
582   for (Index = 0; Index < LargestString; Index++) {
583     *StringPtr++ = BOXDRAW_HORIZONTAL;
584   }
585   *StringPtr++ = BOXDRAW_UP_LEFT;
586   *StringPtr = L'\0';
587 
588   ConOut->SetCursorPosition (ConOut, Start, Top + NumberOfLines + 1);
589   ConOut->OutputString (ConOut, LineBuffer);
590 
591   do {
592     Status = gBS->CreateEvent (EFI_EVENT_TIMER, 0, NULL, NULL, &TimerEvent);
593 
594     //
595     // Set a timer event of 1 second expiration
596     //
597     gBS->SetTimer (
598           TimerEvent,
599           TimerRelative,
600           10000000
601           );
602 
603     //
604     // Wait for the keystroke event or the timer
605     //
606     WaitList[0] = gST->ConIn->WaitForKey;
607     WaitList[1] = TimerEvent;
608     Status      = gBS->WaitForEvent (2, WaitList, &Index);
609 
610     //
611     // Check for the timer expiration
612     //
613     if (!EFI_ERROR (Status) && Index == 1) {
614       Status = EFI_TIMEOUT;
615     }
616 
617     gBS->CloseEvent (TimerEvent);
618   } while (Status == EFI_TIMEOUT);
619 
620   Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
621   EfiCopyMem (KeyValue, &Key, sizeof (EFI_INPUT_KEY));
622 
623   ConOut->SetAttribute (ConOut, CurrentAttribute);
624   ConOut->EnableCursor (ConOut, TRUE);
625 
626   return Status;
627 }
628 
629 EFI_STATUS
ExtractDefault(IN VOID * Buffer,IN UINTN * BufferSize,UINTN Number,...)630 ExtractDefault(
631   IN VOID                         *Buffer,
632   IN UINTN                        *BufferSize,
633   UINTN                           Number,
634   ...
635   )
636 /*++
637 
638   Routine Description:
639 
640     Configure the buffer accrording to ConfigBody strings.
641 
642   Arguments:
643     DefaultId             - the ID of default.
644     Buffer                - the start address of buffer.
645     BufferSize            - the size of buffer.
646     Number                - the number of the strings.
647 
648   Returns:
649     EFI_BUFFER_TOO_SMALL  - the BufferSize is too small to operate.
650     EFI_INVALID_PARAMETER - Buffer is NULL or BufferSize is 0.
651     EFI_SUCCESS           - Operation successful.
652 
653 --*/
654 {
655   VA_LIST                         Args;
656   UINTN                           Index;
657   UINT32                          TotalLen;
658   UINT8                           *BufCfgArray;
659   UINT8                           *BufferPos;
660   UINT16                          Offset;
661   UINT16                          Width;
662   UINT8                           *Value;
663 
664   if ((Buffer == NULL) || (BufferSize == NULL)) {
665     return EFI_INVALID_PARAMETER;
666   }
667 
668   Offset = 0;
669   Width  = 0;
670   Value  = NULL;
671 
672   VA_START (Args, Number);
673   for (Index = 0; Index < Number; Index++) {
674     BufCfgArray = (UINT8 *) VA_ARG (Args, VOID *);
675     EfiCopyMem (&TotalLen, BufCfgArray, sizeof (UINT32));
676     BufferPos = BufCfgArray + sizeof (UINT32);
677 
678     while ((UINT32)(BufferPos - BufCfgArray) < TotalLen) {
679       EfiCopyMem (&Offset, BufferPos, sizeof (UINT16));
680       BufferPos += sizeof (UINT16);
681       EfiCopyMem (&Width, BufferPos, sizeof (UINT16));
682       BufferPos += sizeof (UINT16);
683       Value = BufferPos;
684       BufferPos += Width;
685 
686       if ((UINTN)(Offset + Width) > *BufferSize) {
687         VA_END (Args);
688         return EFI_BUFFER_TOO_SMALL;
689       }
690 
691       EfiCopyMem ((UINT8 *)Buffer + Offset, Value, Width);
692     }
693   }
694   VA_END (Args);
695 
696   *BufferSize = (UINTN)Offset;
697 
698   return EFI_SUCCESS;
699 }
700 
701 EFI_STATUS
ExtractBlockName(IN UINT8 * Buffer,OUT CHAR16 ** BlockName)702 ExtractBlockName (
703   IN UINT8                        *Buffer,
704   OUT CHAR16                      **BlockName
705   )
706 /*++
707 
708   Routine Description:
709 
710     Extract block name from the array generated by VFR compiler. The name of
711   this array is "Vfr + <StorageName> + BlockName", e.g. "VfrMyIfrNVDataBlockName".
712   Format of this array is:
713      Array length | 4-bytes
714        Offset     | 2-bytes
715        Width      | 2-bytes
716        Offset     | 2-bytes
717        Width      | 2-bytes
718        ... ...
719 
720   Arguments:
721     Buffer                - Array generated by VFR compiler.
722     BlockName             - The returned <BlockName>
723 
724   Returns:
725     EFI_OUT_OF_RESOURCES  - Run out of memory resource.
726     EFI_INVALID_PARAMETER - Buffer is NULL or BlockName is NULL.
727     EFI_SUCCESS           - Operation successful.
728 
729 --*/
730 {
731   UINTN       Index;
732   UINT32      Length;
733   UINT32      BlockNameNumber;
734   UINTN       HexStringBufferLen;
735   CHAR16      *StringPtr;
736 
737   if ((Buffer == NULL) || (BlockName == NULL)) {
738     return EFI_INVALID_PARAMETER;
739   }
740 
741   //
742   // Calculate number of Offset/Width pair
743   //
744   EfiCopyMem (&Length, Buffer, sizeof (UINT32));
745   BlockNameNumber = (Length - sizeof (UINT32)) / (sizeof (UINT16) * 2);
746 
747   //
748   // <BlockName> ::= &OFFSET=1234&WIDTH=1234
749   //                 |   8  | 4 |  7   | 4 |
750   //
751   StringPtr = EfiLibAllocateZeroPool ((BlockNameNumber * (8 + 4 + 7 + 4) + 1) * sizeof (CHAR16));
752   *BlockName = StringPtr;
753   if (StringPtr == NULL) {
754     return EFI_OUT_OF_RESOURCES;
755   }
756 
757   Buffer += sizeof (UINT32);
758   for (Index = 0; Index < BlockNameNumber; Index++) {
759     EfiStrCpy (StringPtr, L"&OFFSET=");
760     StringPtr += 8;
761 
762     HexStringBufferLen = 5;
763     BufToHexString (StringPtr, &HexStringBufferLen, Buffer, sizeof (UINT16));
764     Buffer += sizeof (UINT16);
765     StringPtr += 4;
766 
767     EfiStrCpy (StringPtr, L"&WIDTH=");
768     StringPtr += 7;
769 
770     HexStringBufferLen = 5;
771     BufToHexString (StringPtr, &HexStringBufferLen, Buffer, sizeof (UINT16));
772     Buffer += sizeof (UINT16);
773     StringPtr += 4;
774   }
775 
776   return EFI_SUCCESS;
777 }
778 
779 EFI_STATUS
ExtractBlockConfig(IN UINT8 * Buffer,OUT CHAR16 ** BlockConfig)780 ExtractBlockConfig (
781   IN UINT8                        *Buffer,
782   OUT CHAR16                      **BlockConfig
783   )
784 /*++
785 
786   Routine Description:
787 
788     Extract block config from the array generated by VFR compiler. The name of
789   this array is "Vfr + <StorageName> + Default<HexCh>4", e.g. "VfrMyIfrNVDataDefault0000".
790 
791   Arguments:
792     Buffer                - Array generated by VFR compiler.
793     BlockConfig           - The returned <BlockConfig>
794 
795   Returns:
796     EFI_OUT_OF_RESOURCES  - Run out of memory resource.
797     EFI_INVALID_PARAMETER - Buffer is NULL or BlockConfig is NULL.
798     EFI_SUCCESS           - Operation successful.
799 
800 --*/
801 {
802   UINT32      Length;
803   UINT16      Width;
804   UINTN       HexStringBufferLen;
805   CHAR16      *StringPtr;
806   UINT8       *BufferEnd;
807   CHAR16      *StringEnd;
808   EFI_STATUS  Status;
809 
810   if ((Buffer == NULL) || (BlockConfig == NULL)) {
811     return EFI_INVALID_PARAMETER;
812   }
813 
814   //
815   // Calculate length of AltResp string
816   // Format of Default value array is:
817   //  Array length | 4-bytes
818   //        Offset | 2-bytes
819   //        Width  | 2-bytes
820   //        Value  | Variable length
821   //        Offset | 2-bytes
822   //        Width  | 2-bytes
823   //        Value  | Variable length
824   //        ... ...
825   // When value is 1 byte in length, overhead of AltResp string will be maximum,
826   //  BlockConfig ::= <&OFFSET=1234&WIDTH=1234&VALUE=12>+
827   //                   |   8   | 4  |  7   | 4 |  7  |2|
828   // so the maximum length of BlockConfig could be calculated as:
829   // (ArrayLength / 5) * (8 + 4 + 7 + 4 + 7 + 2) = ArrayLength * 6.4 < ArrayLength * 7
830   //
831   EfiCopyMem (&Length, Buffer, sizeof (UINT32));
832   BufferEnd = Buffer + Length;
833   StringPtr = EfiLibAllocatePool (Length * 7 * sizeof (CHAR16));
834   *BlockConfig = StringPtr;
835   if (StringPtr == NULL) {
836       return EFI_OUT_OF_RESOURCES;
837   }
838   StringEnd = StringPtr + (Length * 7);
839 
840   Buffer += sizeof (UINT32);
841   while (Buffer < BufferEnd) {
842     EfiStrCpy (StringPtr, L"&OFFSET=");
843     StringPtr += 8;
844 
845     HexStringBufferLen = 5;
846     BufToHexString (StringPtr, &HexStringBufferLen, Buffer, sizeof (UINT16));
847     Buffer += sizeof (UINT16);
848     StringPtr += 4;
849 
850     EfiStrCpy (StringPtr, L"&WIDTH=");
851     StringPtr += 7;
852 
853     HexStringBufferLen = 5;
854     BufToHexString (StringPtr, &HexStringBufferLen, Buffer, sizeof (UINT16));
855     EfiCopyMem (&Width, Buffer, sizeof (UINT16));
856     Buffer += sizeof (UINT16);
857     StringPtr += 4;
858 
859     EfiStrCpy (StringPtr, L"&VALUE=");
860     StringPtr += 7;
861 
862     HexStringBufferLen = StringEnd - StringPtr;
863     Status = BufToHexString (StringPtr, &HexStringBufferLen, Buffer, Width);
864     if (EFI_ERROR (Status)) {
865       return Status;
866     }
867     Buffer += Width;
868     StringPtr += (Width * 2);
869   }
870 
871   return EFI_SUCCESS;
872 }
873 
874 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,...)875 ConstructConfigAltResp (
876   IN  EFI_STRING                  ConfigRequest,  OPTIONAL
877   OUT EFI_STRING                  *Progress,
878   OUT EFI_STRING                  *ConfigAltResp,
879   IN  EFI_GUID                    *Guid,
880   IN  CHAR16                      *Name,
881   IN  EFI_HANDLE                  *DriverHandle,
882   IN  VOID                        *BufferStorage,
883   IN  UINTN                       BufferStorageSize,
884   IN  VOID                        *BlockNameArray, OPTIONAL
885   IN  UINTN                       NumberAltCfg,
886   ...
887 //IN  UINT16                      AltCfgId,
888 //IN  VOID                        *DefaultValueArray,
889   )
890 /*++
891 
892   Routine Description:
893 
894   Construct <ConfigAltResp> for a buffer storage.
895 
896   Arguments:
897     ConfigRequest         - The Config request string. If set to NULL, all the
898                             configurable elements will be extracted from BlockNameArray.
899     ConfigAltResp         - The returned <ConfigAltResp>.
900     Progress              - On return, points to a character in the Request.
901     Guid                  - GUID of the buffer storage.
902     Name                  - Name of the buffer storage.
903     DriverHandle          - The DriverHandle which is used to invoke HiiDatabase
904                             protocol interface NewPackageList().
905     BufferStorage         - Content of the buffer storage.
906     BufferStorageSize     - Length in bytes of the buffer storage.
907     BlockNameArray        - Array generated by VFR compiler.
908     NumberAltCfg          - Number of Default value array generated by VFR compiler.
909                             The sequential input parameters will be number of
910                             AltCfgId and DefaultValueArray pairs. When set to 0,
911                             there will be no <AltResp>.
912 
913   Returns:
914     EFI_OUT_OF_RESOURCES  - Run out of memory resource.
915     EFI_INVALID_PARAMETER - ConfigAltResp is NULL.
916     EFI_SUCCESS           - Operation successful.
917 
918 --*/
919 {
920   EFI_STATUS                      Status;
921   CHAR16                          *ConfigHdr;
922   CHAR16                          *BlockName;
923   CHAR16                          *DescHdr;
924   CHAR16                          *StringPtr;
925   CHAR16                          **AltCfg;
926   UINT16                          AltCfgId;
927   VOID                            *DefaultValueArray;
928   UINTN                           StrBufferLen;
929   EFI_STRING                      ConfigResp;
930   EFI_STRING                      TempStr;
931   VA_LIST                         Args;
932   UINTN                           AltRespLen;
933   UINTN                           Index;
934   BOOLEAN                         NeedFreeConfigRequest;
935   EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
936 
937   if (ConfigAltResp == NULL) {
938     return EFI_INVALID_PARAMETER;
939   }
940 
941   //
942   // Construct <ConfigHdr> : "GUID=...&NAME=...&PATH=..."
943   //
944   ConfigHdr = NULL;
945   StrBufferLen = 0;
946   Status = ConstructConfigHdr (
947              ConfigHdr,
948              &StrBufferLen,
949              Guid,
950              Name,
951              DriverHandle
952              );
953   if (Status == EFI_BUFFER_TOO_SMALL) {
954     ConfigHdr = EfiLibAllocateZeroPool (StrBufferLen);
955     Status = ConstructConfigHdr (
956                ConfigHdr,
957                &StrBufferLen,
958                Guid,
959                Name,
960                DriverHandle
961                );
962   }
963 
964   if (EFI_ERROR (Status) || (ConfigHdr == NULL)) {
965     return Status;
966   }
967 
968   //
969   // Construct <ConfigResp>
970   //
971   NeedFreeConfigRequest = FALSE;
972   if (ConfigRequest == NULL) {
973     //
974     // If ConfigRequest is set to NULL, export all configurable elements in BlockNameArray
975     //
976     Status = ExtractBlockName (BlockNameArray, &BlockName);
977     if (EFI_ERROR (Status)) {
978       return Status;
979     }
980 
981     StrBufferLen = EfiStrSize (ConfigHdr);
982     StrBufferLen = StrBufferLen + EfiStrSize (BlockName) - sizeof (CHAR16);
983     ConfigRequest = EfiLibAllocateZeroPool (StrBufferLen);
984     EfiStrCpy (ConfigRequest, ConfigHdr);
985     EfiStrCat (ConfigRequest, BlockName);
986     NeedFreeConfigRequest = TRUE;
987   }
988 
989   Status = gBS->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid, NULL, (VOID **) &HiiConfigRouting);
990   if (EFI_ERROR (Status)) {
991     return Status;
992   }
993 
994   Status = HiiConfigRouting->BlockToConfig (
995                                HiiConfigRouting,
996                                ConfigRequest,
997                                BufferStorage,
998                                BufferStorageSize,
999                                &ConfigResp,
1000                                (Progress == NULL) ? &TempStr : Progress
1001                                );
1002   if (EFI_ERROR (Status)) {
1003     return Status;
1004   }
1005 
1006   //
1007   // Construct <AltResp>
1008   //
1009   DescHdr = EfiLibAllocateZeroPool (NumberAltCfg * 16 * sizeof (CHAR16));
1010   StringPtr = DescHdr;
1011   AltCfg = EfiLibAllocateZeroPool (NumberAltCfg * sizeof (CHAR16 *));
1012   AltRespLen = 0;
1013   VA_START (Args, NumberAltCfg);
1014   for (Index = 0; Index < NumberAltCfg; Index++) {
1015     AltCfgId = (UINT16) VA_ARG (Args, UINT16);
1016     DefaultValueArray = (UINT8 *) VA_ARG (Args, VOID *);
1017 
1018     //
1019     // '&' <ConfigHdr>
1020     //
1021     AltRespLen += (EfiStrLen (ConfigHdr) + 1);
1022 
1023     StringPtr = DescHdr + Index * 16;
1024     EfiStrCpy (StringPtr, L"&ALTCFG=");
1025     AltRespLen += (8 + sizeof (UINT16) * 2);
1026 
1027     StrBufferLen = 5;
1028     BufToHexString (StringPtr + 8, &StrBufferLen, (UINT8 *) &AltCfgId, sizeof (UINT16));
1029     Status = ExtractBlockConfig (DefaultValueArray, &AltCfg[Index]);
1030     if (EFI_ERROR (Status)) {
1031       VA_END (Args);
1032       return Status;
1033     }
1034     AltRespLen += EfiStrLen (AltCfg[Index]);
1035   }
1036   VA_END (Args);
1037 
1038   //
1039   // Generate the final <ConfigAltResp>
1040   //
1041   StrBufferLen = (EfiStrLen ((CHAR16 *) ConfigResp) + AltRespLen + 1) * sizeof (CHAR16);
1042   TempStr = EfiLibAllocateZeroPool (StrBufferLen);
1043   *ConfigAltResp = TempStr;
1044   if (TempStr == NULL) {
1045     return EFI_OUT_OF_RESOURCES;
1046   }
1047 
1048   //
1049   // <ConfigAltResp> ::= <ConfigResp> ['&' <AltResp>]*
1050   //
1051   EfiStrCpy (TempStr, ConfigResp);
1052   for (Index = 0; Index < NumberAltCfg; Index++) {
1053     EfiStrCat (TempStr, L"&");
1054     EfiStrCat (TempStr, ConfigHdr);
1055     EfiStrCat (TempStr, DescHdr + Index * 16);
1056     EfiStrCat (TempStr, AltCfg[Index]);
1057 
1058     gBS->FreePool (AltCfg[Index]);
1059   }
1060 
1061   if (NeedFreeConfigRequest) {
1062     gBS->FreePool (ConfigRequest);
1063   }
1064   gBS->FreePool (ConfigHdr);
1065   gBS->FreePool (ConfigResp);
1066   gBS->FreePool (DescHdr);
1067   gBS->FreePool (AltCfg);
1068 
1069   return EFI_SUCCESS;
1070 }
1071 
1072 VOID
SwapBuffer(IN OUT UINT8 * Buffer,IN UINTN BufferSize)1073 SwapBuffer (
1074   IN OUT UINT8     *Buffer,
1075   IN UINTN         BufferSize
1076   )
1077 /*++
1078 
1079 Routine Description:
1080   Swap bytes in the buffer.
1081 
1082 Arguments:
1083   Buffer     -  Binary buffer.
1084   BufferSize -  Size of the buffer in bytes.
1085 
1086 Returns:
1087   None.
1088 
1089 --*/
1090 {
1091   UINTN  Index;
1092   UINT8  Temp;
1093   UINTN  SwapCount;
1094 
1095   SwapCount = BufferSize / 2;
1096   for (Index = 0; Index < SwapCount; Index++) {
1097     Temp = Buffer[Index];
1098     Buffer[Index] = Buffer[BufferSize - 1 - Index];
1099     Buffer[BufferSize - 1 - Index] = Temp;
1100   }
1101 }
1102 
1103 VOID
ToLower(IN OUT CHAR16 * Str)1104 ToLower (
1105   IN OUT CHAR16    *Str
1106   )
1107 /*++
1108 
1109 Routine Description:
1110   Converts the unicode character of the string from uppercase to lowercase.
1111 
1112 Arguments:
1113   Str        -  String to be converted
1114 
1115 Returns:
1116 
1117 --*/
1118 {
1119   CHAR16      *Ptr;
1120 
1121   for (Ptr = Str; *Ptr != L'\0'; Ptr++) {
1122     if (*Ptr >= L'A' && *Ptr <= L'Z') {
1123       *Ptr = (CHAR16) (*Ptr - L'A' + L'a');
1124     }
1125   }
1126 }
1127 
1128 EFI_STATUS
BufferToHexString(IN OUT CHAR16 * Str,IN UINT8 * Buffer,IN UINTN BufferSize)1129 BufferToHexString (
1130   IN OUT CHAR16    *Str,
1131   IN UINT8         *Buffer,
1132   IN UINTN         BufferSize
1133   )
1134 /*++
1135 
1136 Routine Description:
1137   Converts binary buffer to Unicode string in reversed byte order from BufToHexString().
1138 
1139 Arguments:
1140   Str        -  String for output
1141   Buffer     -  Binary buffer.
1142   BufferSize -  Size of the buffer in bytes.
1143 
1144 Returns:
1145   EFI_SUCCESS  -  The function completed successfully.
1146 
1147 --*/
1148 {
1149   EFI_STATUS  Status;
1150   UINT8       *NewBuffer;
1151   UINTN       StrBufferLen;
1152 
1153   NewBuffer = EfiLibAllocateCopyPool (BufferSize, Buffer);
1154   SwapBuffer (NewBuffer, BufferSize);
1155 
1156   StrBufferLen = BufferSize * 2 + 1;
1157   Status = BufToHexString (Str, &StrBufferLen, NewBuffer, BufferSize);
1158 
1159   gBS->FreePool (NewBuffer);
1160   //
1161   // Convert the uppercase to lowercase since <HexAf> is defined in lowercase format.
1162   //
1163   ToLower (Str);
1164 
1165   return Status;
1166 }
1167 
1168 EFI_STATUS
HexStringToBuffer(IN OUT UINT8 * Buffer,IN OUT UINTN * BufferSize,IN CHAR16 * Str)1169 HexStringToBuffer (
1170   IN OUT UINT8         *Buffer,
1171   IN OUT UINTN         *BufferSize,
1172   IN CHAR16            *Str
1173   )
1174 /*++
1175 
1176 Routine Description:
1177   Converts Hex String to binary buffer in reversed byte order from HexStringToBuf().
1178 
1179 Arguments:
1180     Buffer     - Pointer to buffer that receives the data.
1181     BufferSize - Length in bytes of the buffer to hold converted data.
1182                  If routine return with EFI_SUCCESS, containing length of converted data.
1183                  If routine return with EFI_BUFFER_TOO_SMALL, containg length of buffer desired.
1184     Str        - String to be converted from.
1185 
1186 Returns:
1187   EFI_SUCCESS    -  The function completed successfully.
1188 
1189 --*/
1190 {
1191   EFI_STATUS  Status;
1192   UINTN       ConvertedStrLen;
1193 
1194   ConvertedStrLen = 0;
1195   Status = HexStringToBuf (Buffer, BufferSize, Str, &ConvertedStrLen);
1196   if (!EFI_ERROR (Status)) {
1197     SwapBuffer (Buffer, (ConvertedStrLen + 1) / 2);
1198   }
1199 
1200   return Status;
1201 }
1202 
1203 EFI_STATUS
ConfigStringToUnicode(IN OUT CHAR16 * UnicodeString,IN OUT UINTN * StrBufferLen,IN CHAR16 * ConfigString)1204 ConfigStringToUnicode (
1205   IN OUT CHAR16                *UnicodeString,
1206   IN OUT UINTN                 *StrBufferLen,
1207   IN CHAR16                    *ConfigString
1208   )
1209 /*++
1210 
1211 Routine Description:
1212   Convert binary representation Config string (e.g. "0041004200430044") to the
1213   original string (e.g. "ABCD"). Config string appears in <ConfigHdr> (i.e.
1214   "&NAME=<string>"), or Name/Value pair in <ConfigBody> (i.e. "label=<string>").
1215 
1216 Arguments:
1217   UnicodeString - Original Unicode string.
1218   StrBufferLen  - On input: Length in bytes of buffer to hold the Unicode string.
1219                   Includes tailing '\0' character.
1220                   On output:
1221                     If return EFI_SUCCESS, containing length of Unicode string buffer.
1222                     If return EFI_BUFFER_TOO_SMALL, containg length of string buffer desired.
1223   ConfigString  - Binary representation of Unicode String, <string> := (<HexCh>4)+
1224 
1225 Returns:
1226   EFI_SUCCESS          - Routine success.
1227   EFI_BUFFER_TOO_SMALL - The string buffer is too small.
1228 
1229 --*/
1230 {
1231   UINTN       Index;
1232   UINTN       Len;
1233   UINTN       BufferSize;
1234   CHAR16      BackupChar;
1235 
1236   Len = EfiStrLen (ConfigString) / 4;
1237   BufferSize = (Len + 1) * sizeof (CHAR16);
1238 
1239   if (*StrBufferLen < BufferSize) {
1240     *StrBufferLen = BufferSize;
1241     return EFI_BUFFER_TOO_SMALL;
1242   }
1243 
1244   *StrBufferLen = BufferSize;
1245 
1246   for (Index = 0; Index < Len; Index++) {
1247     BackupChar = ConfigString[4];
1248     ConfigString[4] = L'\0';
1249 
1250     HexStringToBuf ((UINT8 *) UnicodeString, &BufferSize, ConfigString, NULL);
1251 
1252     ConfigString[4] = BackupChar;
1253 
1254     ConfigString += 4;
1255     UnicodeString += 1;
1256   }
1257 
1258   //
1259   // Add tailing '\0' character
1260   //
1261   *UnicodeString = L'\0';
1262 
1263   return EFI_SUCCESS;
1264 }
1265 
1266 EFI_STATUS
UnicodeToConfigString(IN OUT CHAR16 * ConfigString,IN OUT UINTN * StrBufferLen,IN CHAR16 * UnicodeString)1267 UnicodeToConfigString (
1268   IN OUT CHAR16                *ConfigString,
1269   IN OUT UINTN                 *StrBufferLen,
1270   IN CHAR16                    *UnicodeString
1271   )
1272 /*++
1273 
1274 Routine Description:
1275   Convert Unicode string to binary representation Config string, e.g.
1276   "ABCD" => "0041004200430044". Config string appears in <ConfigHdr> (i.e.
1277   "&NAME=<string>"), or Name/Value pair in <ConfigBody> (i.e. "label=<string>").
1278 
1279 Arguments:
1280   ConfigString  - Binary representation of Unicode String, <string> := (<HexCh>4)+
1281   StrBufferLen  - On input: Length in bytes of buffer to hold the Unicode string.
1282                   Includes tailing '\0' character.
1283                   On output:
1284                     If return EFI_SUCCESS, containing length of Unicode string buffer.
1285                     If return EFI_BUFFER_TOO_SMALL, containg length of string buffer desired.
1286   UnicodeString - Original Unicode string.
1287 
1288 Returns:
1289   EFI_SUCCESS          - Routine success.
1290   EFI_BUFFER_TOO_SMALL - The string buffer is too small.
1291 
1292 --*/
1293 {
1294   UINTN       Index;
1295   UINTN       Len;
1296   UINTN       BufferSize;
1297   CHAR16      *String;
1298 
1299   Len = EfiStrLen (UnicodeString);
1300   BufferSize = (Len * 4 + 1) * sizeof (CHAR16);
1301 
1302   if (*StrBufferLen < BufferSize) {
1303     *StrBufferLen = BufferSize;
1304     return EFI_BUFFER_TOO_SMALL;
1305   }
1306 
1307   *StrBufferLen = BufferSize;
1308   String        = ConfigString;
1309 
1310   for (Index = 0; Index < Len; Index++) {
1311     BufToHexString (ConfigString, &BufferSize, (UINT8 *) UnicodeString, 2);
1312 
1313     ConfigString += 4;
1314     UnicodeString += 1;
1315   }
1316 
1317   //
1318   // Add tailing '\0' character
1319   //
1320   *ConfigString = L'\0';
1321 
1322   //
1323   // Convert the uppercase to lowercase since <HexAf> is defined in lowercase format.
1324   //
1325   ToLower (String);
1326   return EFI_SUCCESS;
1327 }
1328 
1329 EFI_STATUS
ConstructConfigHdr(IN OUT CHAR16 * ConfigHdr,IN OUT UINTN * StrBufferLen,IN EFI_GUID * Guid,IN CHAR16 * Name,OPTIONAL IN EFI_HANDLE * DriverHandle)1330 ConstructConfigHdr (
1331   IN OUT CHAR16                *ConfigHdr,
1332   IN OUT UINTN                 *StrBufferLen,
1333   IN EFI_GUID                  *Guid,
1334   IN CHAR16                    *Name, OPTIONAL
1335   IN EFI_HANDLE                *DriverHandle
1336   )
1337 /*++
1338 
1339 Routine Description:
1340   Construct <ConfigHdr> using routing information GUID/NAME/PATH.
1341 
1342 Arguments:
1343   ConfigHdr    - Pointer to the ConfigHdr string.
1344   StrBufferLen - On input: Length in bytes of buffer to hold the ConfigHdr string.
1345                  Includes tailing '\0' character.
1346                  On output:
1347                     If return EFI_SUCCESS, containing length of ConfigHdr string buffer.
1348                     If return EFI_BUFFER_TOO_SMALL, containg length of string buffer desired.
1349   Guid         - Routing information: GUID.
1350   Name         - Routing information: NAME.
1351   DriverHandle - Driver handle which contains the routing information: PATH.
1352 
1353 Returns:
1354   EFI_SUCCESS          - Routine success.
1355   EFI_BUFFER_TOO_SMALL - The ConfigHdr string buffer is too small.
1356 
1357 --*/
1358 {
1359   EFI_STATUS                Status;
1360   UINTN                     NameStrLen;
1361   UINTN                     DevicePathSize;
1362   UINTN                     BufferSize;
1363   CHAR16                    *StrPtr;
1364   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
1365 
1366   if (Name == NULL) {
1367     //
1368     // There will be no "NAME" in <ConfigHdr> for  Name/Value storage
1369     //
1370     NameStrLen = 0;
1371   } else {
1372     //
1373     // For buffer storage
1374     //
1375     NameStrLen = EfiStrLen (Name);
1376   }
1377 
1378   //
1379   // Retrieve DevicePath Protocol associated with this HiiPackageList
1380   //
1381   Status = gBS->HandleProtocol (
1382                   DriverHandle,
1383                   &gEfiDevicePathProtocolGuid,
1384                   (VOID **) &DevicePath
1385                   );
1386   if (EFI_ERROR (Status)) {
1387     return Status;
1388   }
1389 
1390   DevicePathSize = EfiDevicePathSize (DevicePath);
1391 
1392   //
1393   // GUID=<HexCh>32&NAME=<Char>NameStrLen&PATH=<HexChar>DevicePathStrLen <NULL>
1394   // | 5  |   32   |  6  |  NameStrLen*4 |  6  |    DevicePathStrLen    | 1 |
1395   //
1396   BufferSize = (5 + 32 + 6 + NameStrLen * 4 + 6 + DevicePathSize * 2 + 1) * sizeof (CHAR16);
1397   if (*StrBufferLen < BufferSize) {
1398     *StrBufferLen = BufferSize;
1399     return EFI_BUFFER_TOO_SMALL;
1400   }
1401 
1402   if (ConfigHdr == NULL) {
1403     return EFI_INVALID_PARAMETER;
1404   }
1405 
1406   *StrBufferLen = BufferSize;
1407 
1408   StrPtr = ConfigHdr;
1409 
1410   EfiStrCpy (StrPtr, L"GUID=");
1411   StrPtr += 5;
1412   BufferToHexString (StrPtr, (UINT8 *) Guid, sizeof (EFI_GUID));
1413   StrPtr += 32;
1414 
1415   //
1416   // Convert name string, e.g. name "ABCD" => "&NAME=0041004200430044"
1417   //
1418   EfiStrCpy (StrPtr, L"&NAME=");
1419   StrPtr += 6;
1420   if (Name != NULL) {
1421     BufferSize = (NameStrLen * 4 + 1) * sizeof (CHAR16);
1422     UnicodeToConfigString (StrPtr, &BufferSize, Name);
1423     StrPtr += (NameStrLen * 4);
1424   }
1425 
1426   EfiStrCpy (StrPtr, L"&PATH=");
1427   StrPtr += 6;
1428   BufferToHexString (StrPtr, (UINT8 *) DevicePath, DevicePathSize);
1429 
1430   return EFI_SUCCESS;
1431 }
1432 
1433 BOOLEAN
IsConfigHdrMatch(IN EFI_STRING ConfigString,IN EFI_GUID * StorageGuid,OPTIONAL IN CHAR16 * StorageName OPTIONAL)1434 IsConfigHdrMatch (
1435   IN EFI_STRING                ConfigString,
1436   IN EFI_GUID                  *StorageGuid, OPTIONAL
1437   IN CHAR16                    *StorageName  OPTIONAL
1438   )
1439 /*++
1440 
1441 Routine Description:
1442   Determines if the Routing data (Guid and Name) is correct in <ConfigHdr>.
1443 
1444 Arguments:
1445   ConfigString - Either <ConfigRequest> or <ConfigResp>.
1446   StorageGuid  - GUID of the storage.
1447   StorageName  - Name of the stoarge.
1448 
1449 Returns:
1450   TRUE         - Routing information is correct in ConfigString.
1451   FALSE        - Routing information is incorrect in ConfigString.
1452 
1453 --*/
1454 {
1455   EFI_STATUS  Status;
1456   BOOLEAN     Match;
1457   EFI_GUID    Guid;
1458   CHAR16      *Name;
1459   CHAR16      *StrPtr;
1460   UINTN       BufferSize;
1461 
1462   //
1463   // <ConfigHdr> ::=
1464   // GUID=<HexCh>32&NAME=<Char>NameStrLen&PATH=<HexChar>DevicePathStrLen <NULL>
1465   // | 5  |   32   |  6  |  NameStrLen*4 |  6  |    DevicePathStrLen    | 1 |
1466   //
1467   if (EfiStrLen (ConfigString) <= (5 + 32 + 6)) {
1468     return FALSE;
1469   }
1470 
1471   //
1472   // Compare GUID
1473   //
1474   if (StorageGuid != NULL) {
1475 
1476     StrPtr = ConfigString + 5 + 32;
1477     if (*StrPtr != L'&') {
1478       return FALSE;
1479     }
1480     *StrPtr = L'\0';
1481 
1482     BufferSize = sizeof (EFI_GUID);
1483     Status = HexStringToBuffer (
1484                (UINT8 *) &Guid,
1485                &BufferSize,
1486                ConfigString + 5
1487                );
1488     *StrPtr = L'&';
1489 
1490     if (EFI_ERROR (Status)) {
1491       return FALSE;
1492     }
1493 
1494     if (!EfiCompareGuid (&Guid, StorageGuid)) {
1495       return FALSE;
1496     }
1497   }
1498 
1499   //
1500   // Compare Name
1501   //
1502   Match = TRUE;
1503   if (StorageName != NULL) {
1504     StrPtr = ConfigString + 5 + 32 + 6;
1505     while (*StrPtr != L'\0' && *StrPtr != L'&') {
1506       StrPtr++;
1507     }
1508     if (*StrPtr != L'&') {
1509       return FALSE;
1510     }
1511 
1512     *StrPtr = L'\0';
1513     BufferSize = (EfiStrLen (ConfigString + 5 + 32 + 6) + 1) * sizeof (CHAR16);
1514     Name = EfiLibAllocatePool (BufferSize);
1515     ASSERT (Name != NULL);
1516     Status = ConfigStringToUnicode (
1517                Name,
1518                &BufferSize,
1519                ConfigString + 5 + 32 + 6
1520                );
1521     *StrPtr = L'&';
1522 
1523     if (EFI_ERROR (Status) || (EfiStrCmp (Name, StorageName) != 0)) {
1524       Match = FALSE;
1525     }
1526     gBS->FreePool (Name);
1527   }
1528 
1529   return Match;
1530 }
1531 
1532 BOOLEAN
FindBlockName(IN OUT CHAR16 * String,UINTN Offset,UINTN Width)1533 FindBlockName (
1534   IN OUT CHAR16                *String,
1535   UINTN                        Offset,
1536   UINTN                        Width
1537   )
1538 /*++
1539 
1540 Routine Description:
1541   Search BlockName "&OFFSET=Offset&WIDTH=Width" in a string.
1542 
1543 Arguments:
1544   String       - The string to be searched in.
1545   Offset       - Offset in BlockName.
1546   Width        - Width in BlockName.
1547 
1548 Returns:
1549   TRUE         - Block name found.
1550   FALSE        - Block name not found.
1551 
1552 --*/
1553 {
1554   EFI_STATUS  Status;
1555   UINTN       Data;
1556   UINTN       BufferSize;
1557   UINTN       ConvertedStrLen;
1558 
1559   while ((String = EfiStrStr (String, L"&OFFSET=")) != NULL) {
1560     //
1561     // Skip '&OFFSET='
1562     //
1563     String = String + 8;
1564 
1565     Data = 0;
1566     BufferSize = sizeof (UINTN);
1567     Status = HexStringToBuf ((UINT8 *) &Data, &BufferSize, String, &ConvertedStrLen);
1568     if (EFI_ERROR (Status)) {
1569       return FALSE;
1570     }
1571     String = String + ConvertedStrLen;
1572 
1573     if (Data != Offset) {
1574       continue;
1575     }
1576 
1577     if (EfiStrnCmp (String, L"&WIDTH=", 7) != 0) {
1578       return FALSE;
1579     }
1580     String = String + 7;
1581 
1582     Data = 0;
1583     BufferSize = sizeof (UINTN);
1584     Status = HexStringToBuf ((UINT8 *) &Data, &BufferSize, String, &ConvertedStrLen);
1585     if (EFI_ERROR (Status)) {
1586       return FALSE;
1587     }
1588     if (Data == Width) {
1589       return TRUE;
1590     }
1591 
1592     String = String + ConvertedStrLen;
1593   }
1594 
1595   return FALSE;
1596 }
1597 
1598 EFI_STATUS
GetBrowserData(EFI_GUID * VariableGuid,OPTIONAL CHAR16 * VariableName,OPTIONAL UINTN * BufferSize,UINT8 * Buffer)1599 GetBrowserData (
1600   EFI_GUID                   *VariableGuid, OPTIONAL
1601   CHAR16                     *VariableName, OPTIONAL
1602   UINTN                      *BufferSize,
1603   UINT8                      *Buffer
1604   )
1605 /*++
1606 
1607 Routine Description:
1608   This routine is invoked by ConfigAccess.Callback() to retrived uncommitted data from Form Browser.
1609 
1610 Arguments:
1611   VariableGuid  - An optional field to indicate the target variable GUID name to use.
1612   VariableName  - An optional field to indicate the target human-readable variable name.
1613   BufferSize    - On input: Length in bytes of buffer to hold retrived data.
1614                   On output:
1615                     If return EFI_BUFFER_TOO_SMALL, containg length of buffer desired.
1616   Buffer        - Buffer to hold retrived data.
1617 
1618 Returns:
1619   EFI_SUCCESS          - Routine success.
1620   EFI_BUFFER_TOO_SMALL - The intput buffer is too small.
1621 
1622 --*/
1623 {
1624   EFI_STATUS                      Status;
1625   CHAR16                          *ConfigHdr;
1626   CHAR16                          *ConfigResp;
1627   CHAR16                          *StringPtr;
1628   UINTN                           HeaderLen;
1629   UINTN                           BufferLen;
1630   CHAR16                          *Progress;
1631   EFI_FORM_BROWSER2_PROTOCOL      *FormBrowser2;
1632   EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
1633 
1634   //
1635   // Locate protocols for use
1636   //
1637   Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &FormBrowser2);
1638   if (EFI_ERROR (Status)) {
1639     return Status;
1640   }
1641 
1642   Status = gBS->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid, NULL, (VOID **) &HiiConfigRouting);
1643   if (EFI_ERROR (Status)) {
1644     return Status;
1645   }
1646 
1647   //
1648   // Retrive formset storage data from Form Browser
1649   //
1650   ConfigHdr = mFakeConfigHdr;
1651   HeaderLen = EfiStrLen (ConfigHdr);
1652 
1653   BufferLen = 0x4000;
1654   ConfigResp = EfiLibAllocateZeroPool (BufferLen + (HeaderLen + 1) * sizeof (CHAR16));
1655 
1656   StringPtr = ConfigResp + HeaderLen;
1657   *StringPtr = L'&';
1658   StringPtr++;
1659 
1660   Status = FormBrowser2->BrowserCallback (
1661                            FormBrowser2,
1662                            &BufferLen,
1663                            StringPtr,
1664                            TRUE,
1665                            VariableGuid,
1666                            VariableName
1667                            );
1668   if (Status == EFI_BUFFER_TOO_SMALL) {
1669     gBS->FreePool (ConfigResp);
1670     ConfigResp = EfiLibAllocateZeroPool (BufferLen + (HeaderLen + 1) * sizeof (CHAR16));
1671 
1672     StringPtr = ConfigResp + HeaderLen;
1673     *StringPtr = L'&';
1674     StringPtr++;
1675 
1676     Status = FormBrowser2->BrowserCallback (
1677                              FormBrowser2,
1678                              &BufferLen,
1679                              StringPtr,
1680                              TRUE,
1681                              VariableGuid,
1682                              VariableName
1683                              );
1684   }
1685   if (EFI_ERROR (Status)) {
1686     gBS->FreePool (ConfigResp);
1687     return Status;
1688   }
1689   EfiCopyMem (ConfigResp, ConfigHdr, HeaderLen * sizeof (UINT16));
1690 
1691   //
1692   // Convert <ConfigResp> to buffer data
1693   //
1694   Status = HiiConfigRouting->ConfigToBlock (
1695                                HiiConfigRouting,
1696                                ConfigResp,
1697                                Buffer,
1698                                BufferSize,
1699                                &Progress
1700                                );
1701   gBS->FreePool (ConfigResp);
1702 
1703   return Status;
1704 }
1705 
1706 EFI_STATUS
SetBrowserData(EFI_GUID * VariableGuid,OPTIONAL CHAR16 * VariableName,OPTIONAL UINTN BufferSize,UINT8 * Buffer,CHAR16 * RequestElement OPTIONAL)1707 SetBrowserData (
1708   EFI_GUID                   *VariableGuid, OPTIONAL
1709   CHAR16                     *VariableName, OPTIONAL
1710   UINTN                      BufferSize,
1711   UINT8                      *Buffer,
1712   CHAR16                     *RequestElement  OPTIONAL
1713   )
1714 /*++
1715 
1716 Routine Description:
1717   This routine is invoked by ConfigAccess.Callback() to update uncommitted data of Form Browser.
1718 
1719 Arguments:
1720   VariableGuid   - An optional field to indicate the target variable GUID name to use.
1721   VariableName   - An optional field to indicate the target human-readable variable name.
1722   BufferSize     - Length in bytes of buffer to hold retrived data.
1723   Buffer         - Buffer to hold retrived data.
1724   RequestElement - An optional field to specify which part of the buffer data
1725                    will be send back to Browser. If NULL, the whole buffer of
1726                    data will be committed to Browser.
1727                    <RequestElement> ::= &OFFSET=<Number>&WIDTH=<Number>*
1728 
1729 Returns:
1730   EFI_SUCCESS  - Routine success.
1731   Other        - Updating Browser uncommitted data failed.
1732 
1733 --*/
1734 {
1735   EFI_STATUS                      Status;
1736   CHAR16                          *ConfigHdr;
1737   CHAR16                          *ConfigResp;
1738   CHAR16                          *StringPtr;
1739   UINTN                           HeaderLen;
1740   UINTN                           BufferLen;
1741   CHAR16                          *Progress;
1742   EFI_FORM_BROWSER2_PROTOCOL      *FormBrowser2;
1743   EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
1744   CHAR16                          BlockName[33];
1745   CHAR16                          *ConfigRequest;
1746   CHAR16                          *Request;
1747 
1748   //
1749   // Locate protocols for use
1750   //
1751   Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &FormBrowser2);
1752   if (EFI_ERROR (Status)) {
1753     return Status;
1754   }
1755 
1756   Status = gBS->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid, NULL, (VOID **) &HiiConfigRouting);
1757   if (EFI_ERROR (Status)) {
1758     return Status;
1759   }
1760 
1761   //
1762   // Prepare <ConfigRequest>
1763   //
1764   ConfigHdr = mFakeConfigHdr;
1765   HeaderLen = EfiStrLen (ConfigHdr);
1766 
1767   if (RequestElement == NULL) {
1768     //
1769     // RequestElement not specified, use "&OFFSET=0&WIDTH=<BufferSize>" as <BlockName>
1770     //
1771     BlockName[0] = L'\0';
1772     EfiStrCpy (BlockName, L"&OFFSET=0&WIDTH=");
1773 
1774     //
1775     // String lenghth of L"&OFFSET=0&WIDTH=" is 16
1776     //
1777     StringPtr = BlockName + 16;
1778     BufferLen = sizeof (BlockName) - (16 * sizeof (CHAR16));
1779     BufToHexString (StringPtr, &BufferLen, (UINT8 *) &BufferSize, sizeof (UINTN));
1780 
1781     Request = BlockName;
1782   } else {
1783     Request = RequestElement;
1784   }
1785 
1786   BufferLen = HeaderLen * sizeof (CHAR16) + EfiStrSize (Request);
1787   ConfigRequest = EfiLibAllocateZeroPool (BufferLen);
1788 
1789   EfiCopyMem (ConfigRequest, ConfigHdr, HeaderLen * sizeof (CHAR16));
1790   StringPtr = ConfigRequest + HeaderLen;
1791   EfiStrCpy (StringPtr, Request);
1792 
1793   //
1794   // Convert buffer to <ConfigResp>
1795   //
1796   Status = HiiConfigRouting->BlockToConfig (
1797                                 HiiConfigRouting,
1798                                 ConfigRequest,
1799                                 Buffer,
1800                                 BufferSize,
1801                                 &ConfigResp,
1802                                 &Progress
1803                                 );
1804   if (EFI_ERROR (Status)) {
1805     gBS->FreePool (ConfigRequest);
1806     return Status;
1807   }
1808 
1809   //
1810   // Skip <ConfigHdr> and '&'
1811   //
1812   StringPtr = ConfigResp + HeaderLen + 1;
1813 
1814   //
1815   // Change uncommitted data in Browser
1816   //
1817   Status = FormBrowser2->BrowserCallback (
1818                            FormBrowser2,
1819                            &BufferSize,
1820                            StringPtr,
1821                            FALSE,
1822                            VariableGuid,
1823                            VariableName
1824                            );
1825   gBS->FreePool (ConfigResp);
1826   gBS->FreePool (ConfigRequest);
1827   return Status;
1828 }
1829