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