]> git.proxmox.com Git - mirror_edk2.git/blob - EdkCompatibilityPkg/Foundation/Library/Dxe/UefiEfiIfrSupportLib/UefiIfrForm.c
Add Missing invocations to VA_END() for VA_START().
[mirror_edk2.git] / EdkCompatibilityPkg / Foundation / Library / Dxe / UefiEfiIfrSupportLib / UefiIfrForm.c
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 }