]> git.proxmox.com Git - mirror_edk2.git/blob - EdkCompatibilityPkg/Foundation/Library/Dxe/UefiEfiIfrSupportLib/UefiIfrForm.c
864a850d4a7991889e8b3d9ce6bc5cfcac4b6cf2
[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 Top;
456 CHAR16 *StringPtr;
457 UINTN LeftColumn;
458 UINTN RightColumn;
459 UINTN TopRow;
460 UINTN BottomRow;
461 UINTN DimensionsWidth;
462 UINTN DimensionsHeight;
463 VA_LIST Marker;
464 EFI_INPUT_KEY Key;
465 UINTN LargestString;
466 CHAR16 *StackString;
467 EFI_STATUS Status;
468 UINTN StringLen;
469 CHAR16 *LineBuffer;
470 CHAR16 **StringArray;
471 EFI_EVENT TimerEvent;
472 EFI_EVENT WaitList[2];
473 UINTN CurrentAttribute;
474 EFI_SIMPLE_TEXT_OUT_PROTOCOL *ConOut;
475
476 if ((KeyValue == NULL) || (String == NULL)) {
477 return EFI_INVALID_PARAMETER;
478 }
479
480 TopRow = 0;
481 BottomRow = 0;
482 LeftColumn = 0;
483 RightColumn = 0;
484
485 ConOut = gST->ConOut;
486 ConOut->QueryMode (ConOut, ConOut->Mode->Mode, &RightColumn, &BottomRow);
487
488 DimensionsWidth = RightColumn - LeftColumn;
489 DimensionsHeight = BottomRow - TopRow;
490
491 CurrentAttribute = ConOut->Mode->Attribute;
492
493 LineBuffer = EfiLibAllocateZeroPool (DimensionsWidth * sizeof (CHAR16));
494 ASSERT (LineBuffer != NULL);
495
496 //
497 // Determine the largest string in the dialog box
498 // Notice we are starting with 1 since String is the first string
499 //
500 StringArray = EfiLibAllocateZeroPool (NumberOfLines * sizeof (CHAR16 *));
501 LargestString = EfiStrLen (String);
502 StringArray[0] = String;
503
504 VA_START (Marker, String);
505 for (Index = 1; Index < NumberOfLines; Index++) {
506 StackString = VA_ARG (Marker, CHAR16 *);
507
508 if (StackString == NULL) {
509 VA_END (Marker);
510 return EFI_INVALID_PARAMETER;
511 }
512
513 StringArray[Index] = StackString;
514 StringLen = EfiStrLen (StackString);
515 if (StringLen > LargestString) {
516 LargestString = StringLen;
517 }
518 }
519 VA_END (Marker);
520
521 if ((LargestString + 2) > DimensionsWidth) {
522 LargestString = DimensionsWidth - 2;
523 }
524
525 //
526 // Subtract the PopUp width from total Columns, allow for one space extra on
527 // each end plus a border.
528 //
529 Start = (DimensionsWidth - LargestString - 2) / 2 + LeftColumn + 1;
530
531 Top = ((DimensionsHeight - NumberOfLines - 2) / 2) + TopRow - 1;
532
533 //
534 // Disable cursor
535 //
536 ConOut->EnableCursor (ConOut, FALSE);
537 ConOut->SetAttribute (ConOut, EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE);
538
539 StringPtr = &LineBuffer[0];
540 *StringPtr++ = BOXDRAW_DOWN_RIGHT;
541 for (Index = 0; Index < LargestString; Index++) {
542 *StringPtr++ = BOXDRAW_HORIZONTAL;
543 }
544 *StringPtr++ = BOXDRAW_DOWN_LEFT;
545 *StringPtr = L'\0';
546
547 ConOut->SetCursorPosition (ConOut, Start, Top);
548 ConOut->OutputString (ConOut, LineBuffer);
549
550 for (Index = 0; Index < NumberOfLines; Index++) {
551 StringPtr = &LineBuffer[0];
552 *StringPtr++ = BOXDRAW_VERTICAL;
553
554 for (Count = 0; Count < LargestString; Count++) {
555 StringPtr[Count] = L' ';
556 }
557
558 StringLen = EfiStrLen (StringArray[Index]);
559 if (StringLen > LargestString) {
560 StringLen = LargestString;
561 }
562 EfiCopyMem (
563 StringPtr + ((LargestString - StringLen) / 2),
564 StringArray[Index],
565 StringLen * sizeof (CHAR16)
566 );
567 StringPtr += LargestString;
568
569 *StringPtr++ = BOXDRAW_VERTICAL;
570 *StringPtr = L'\0';
571
572 ConOut->SetCursorPosition (ConOut, Start, Top + 1 + Index);
573 ConOut->OutputString (ConOut, LineBuffer);
574 }
575
576 StringPtr = &LineBuffer[0];
577 *StringPtr++ = BOXDRAW_UP_RIGHT;
578 for (Index = 0; Index < LargestString; Index++) {
579 *StringPtr++ = BOXDRAW_HORIZONTAL;
580 }
581 *StringPtr++ = BOXDRAW_UP_LEFT;
582 *StringPtr = L'\0';
583
584 ConOut->SetCursorPosition (ConOut, Start, Top + NumberOfLines + 1);
585 ConOut->OutputString (ConOut, LineBuffer);
586
587 do {
588 Status = gBS->CreateEvent (EFI_EVENT_TIMER, 0, NULL, NULL, &TimerEvent);
589
590 //
591 // Set a timer event of 1 second expiration
592 //
593 gBS->SetTimer (
594 TimerEvent,
595 TimerRelative,
596 10000000
597 );
598
599 //
600 // Wait for the keystroke event or the timer
601 //
602 WaitList[0] = gST->ConIn->WaitForKey;
603 WaitList[1] = TimerEvent;
604 Status = gBS->WaitForEvent (2, WaitList, &Index);
605
606 //
607 // Check for the timer expiration
608 //
609 if (!EFI_ERROR (Status) && Index == 1) {
610 Status = EFI_TIMEOUT;
611 }
612
613 gBS->CloseEvent (TimerEvent);
614 } while (Status == EFI_TIMEOUT);
615
616 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
617 EfiCopyMem (KeyValue, &Key, sizeof (EFI_INPUT_KEY));
618
619 ConOut->SetAttribute (ConOut, CurrentAttribute);
620 ConOut->EnableCursor (ConOut, TRUE);
621
622 return Status;
623 }
624
625 EFI_STATUS
626 ExtractDefault(
627 IN VOID *Buffer,
628 IN UINTN *BufferSize,
629 UINTN Number,
630 ...
631 )
632 /*++
633
634 Routine Description:
635
636 Configure the buffer accrording to ConfigBody strings.
637
638 Arguments:
639 DefaultId - the ID of default.
640 Buffer - the start address of buffer.
641 BufferSize - the size of buffer.
642 Number - the number of the strings.
643
644 Returns:
645 EFI_BUFFER_TOO_SMALL - the BufferSize is too small to operate.
646 EFI_INVALID_PARAMETER - Buffer is NULL or BufferSize is 0.
647 EFI_SUCCESS - Operation successful.
648
649 --*/
650 {
651 VA_LIST Args;
652 UINTN Index;
653 UINT32 TotalLen;
654 UINT8 *BufCfgArray;
655 UINT8 *BufferPos;
656 UINT16 Offset;
657 UINT16 Width;
658 UINT8 *Value;
659
660 if ((Buffer == NULL) || (BufferSize == NULL)) {
661 return EFI_INVALID_PARAMETER;
662 }
663
664 Offset = 0;
665 Width = 0;
666 Value = NULL;
667
668 VA_START (Args, Number);
669 for (Index = 0; Index < Number; Index++) {
670 BufCfgArray = (UINT8 *) VA_ARG (Args, VOID *);
671 EfiCopyMem (&TotalLen, BufCfgArray, sizeof (UINT32));
672 BufferPos = BufCfgArray + sizeof (UINT32);
673
674 while ((UINT32)(BufferPos - BufCfgArray) < TotalLen) {
675 EfiCopyMem (&Offset, BufferPos, sizeof (UINT16));
676 BufferPos += sizeof (UINT16);
677 EfiCopyMem (&Width, BufferPos, sizeof (UINT16));
678 BufferPos += sizeof (UINT16);
679 Value = BufferPos;
680 BufferPos += Width;
681
682 if ((UINTN)(Offset + Width) > *BufferSize) {
683 VA_END (Args);
684 return EFI_BUFFER_TOO_SMALL;
685 }
686
687 EfiCopyMem ((UINT8 *)Buffer + Offset, Value, Width);
688 }
689 }
690 VA_END (Args);
691
692 *BufferSize = (UINTN)Offset;
693
694 return EFI_SUCCESS;
695 }
696
697 EFI_STATUS
698 ExtractBlockName (
699 IN UINT8 *Buffer,
700 OUT CHAR16 **BlockName
701 )
702 /*++
703
704 Routine Description:
705
706 Extract block name from the array generated by VFR compiler. The name of
707 this array is "Vfr + <StorageName> + BlockName", e.g. "VfrMyIfrNVDataBlockName".
708 Format of this array is:
709 Array length | 4-bytes
710 Offset | 2-bytes
711 Width | 2-bytes
712 Offset | 2-bytes
713 Width | 2-bytes
714 ... ...
715
716 Arguments:
717 Buffer - Array generated by VFR compiler.
718 BlockName - The returned <BlockName>
719
720 Returns:
721 EFI_OUT_OF_RESOURCES - Run out of memory resource.
722 EFI_INVALID_PARAMETER - Buffer is NULL or BlockName is NULL.
723 EFI_SUCCESS - Operation successful.
724
725 --*/
726 {
727 UINTN Index;
728 UINT32 Length;
729 UINT32 BlockNameNumber;
730 UINTN HexStringBufferLen;
731 CHAR16 *StringPtr;
732
733 if ((Buffer == NULL) || (BlockName == NULL)) {
734 return EFI_INVALID_PARAMETER;
735 }
736
737 //
738 // Calculate number of Offset/Width pair
739 //
740 EfiCopyMem (&Length, Buffer, sizeof (UINT32));
741 BlockNameNumber = (Length - sizeof (UINT32)) / (sizeof (UINT16) * 2);
742
743 //
744 // <BlockName> ::= &OFFSET=1234&WIDTH=1234
745 // | 8 | 4 | 7 | 4 |
746 //
747 StringPtr = EfiLibAllocateZeroPool ((BlockNameNumber * (8 + 4 + 7 + 4) + 1) * sizeof (CHAR16));
748 *BlockName = StringPtr;
749 if (StringPtr == NULL) {
750 return EFI_OUT_OF_RESOURCES;
751 }
752
753 Buffer += sizeof (UINT32);
754 for (Index = 0; Index < BlockNameNumber; Index++) {
755 EfiStrCpy (StringPtr, L"&OFFSET=");
756 StringPtr += 8;
757
758 HexStringBufferLen = 5;
759 BufToHexString (StringPtr, &HexStringBufferLen, Buffer, sizeof (UINT16));
760 Buffer += sizeof (UINT16);
761 StringPtr += 4;
762
763 EfiStrCpy (StringPtr, L"&WIDTH=");
764 StringPtr += 7;
765
766 HexStringBufferLen = 5;
767 BufToHexString (StringPtr, &HexStringBufferLen, Buffer, sizeof (UINT16));
768 Buffer += sizeof (UINT16);
769 StringPtr += 4;
770 }
771
772 return EFI_SUCCESS;
773 }
774
775 EFI_STATUS
776 ExtractBlockConfig (
777 IN UINT8 *Buffer,
778 OUT CHAR16 **BlockConfig
779 )
780 /*++
781
782 Routine Description:
783
784 Extract block config from the array generated by VFR compiler. The name of
785 this array is "Vfr + <StorageName> + Default<HexCh>4", e.g. "VfrMyIfrNVDataDefault0000".
786
787 Arguments:
788 Buffer - Array generated by VFR compiler.
789 BlockConfig - The returned <BlockConfig>
790
791 Returns:
792 EFI_OUT_OF_RESOURCES - Run out of memory resource.
793 EFI_INVALID_PARAMETER - Buffer is NULL or BlockConfig is NULL.
794 EFI_SUCCESS - Operation successful.
795
796 --*/
797 {
798 UINT32 Length;
799 UINT16 Width;
800 UINTN HexStringBufferLen;
801 CHAR16 *StringPtr;
802 UINT8 *BufferEnd;
803 CHAR16 *StringEnd;
804 EFI_STATUS Status;
805
806 if ((Buffer == NULL) || (BlockConfig == NULL)) {
807 return EFI_INVALID_PARAMETER;
808 }
809
810 //
811 // Calculate length of AltResp string
812 // Format of Default value array is:
813 // Array length | 4-bytes
814 // Offset | 2-bytes
815 // Width | 2-bytes
816 // Value | Variable length
817 // Offset | 2-bytes
818 // Width | 2-bytes
819 // Value | Variable length
820 // ... ...
821 // When value is 1 byte in length, overhead of AltResp string will be maximum,
822 // BlockConfig ::= <&OFFSET=1234&WIDTH=1234&VALUE=12>+
823 // | 8 | 4 | 7 | 4 | 7 |2|
824 // so the maximum length of BlockConfig could be calculated as:
825 // (ArrayLength / 5) * (8 + 4 + 7 + 4 + 7 + 2) = ArrayLength * 6.4 < ArrayLength * 7
826 //
827 EfiCopyMem (&Length, Buffer, sizeof (UINT32));
828 BufferEnd = Buffer + Length;
829 StringPtr = EfiLibAllocatePool (Length * 7 * sizeof (CHAR16));
830 *BlockConfig = StringPtr;
831 if (StringPtr == NULL) {
832 return EFI_OUT_OF_RESOURCES;
833 }
834 StringEnd = StringPtr + (Length * 7);
835
836 Buffer += sizeof (UINT32);
837 while (Buffer < BufferEnd) {
838 EfiStrCpy (StringPtr, L"&OFFSET=");
839 StringPtr += 8;
840
841 HexStringBufferLen = 5;
842 BufToHexString (StringPtr, &HexStringBufferLen, Buffer, sizeof (UINT16));
843 Buffer += sizeof (UINT16);
844 StringPtr += 4;
845
846 EfiStrCpy (StringPtr, L"&WIDTH=");
847 StringPtr += 7;
848
849 HexStringBufferLen = 5;
850 BufToHexString (StringPtr, &HexStringBufferLen, Buffer, sizeof (UINT16));
851 EfiCopyMem (&Width, Buffer, sizeof (UINT16));
852 Buffer += sizeof (UINT16);
853 StringPtr += 4;
854
855 EfiStrCpy (StringPtr, L"&VALUE=");
856 StringPtr += 7;
857
858 HexStringBufferLen = StringEnd - StringPtr;
859 Status = BufToHexString (StringPtr, &HexStringBufferLen, Buffer, Width);
860 if (EFI_ERROR (Status)) {
861 return Status;
862 }
863 Buffer += Width;
864 StringPtr += (Width * 2);
865 }
866
867 return EFI_SUCCESS;
868 }
869
870 EFI_STATUS
871 ConstructConfigAltResp (
872 IN EFI_STRING ConfigRequest, OPTIONAL
873 OUT EFI_STRING *Progress,
874 OUT EFI_STRING *ConfigAltResp,
875 IN EFI_GUID *Guid,
876 IN CHAR16 *Name,
877 IN EFI_HANDLE *DriverHandle,
878 IN VOID *BufferStorage,
879 IN UINTN BufferStorageSize,
880 IN VOID *BlockNameArray, OPTIONAL
881 IN UINTN NumberAltCfg,
882 ...
883 //IN UINT16 AltCfgId,
884 //IN VOID *DefaultValueArray,
885 )
886 /*++
887
888 Routine Description:
889
890 Construct <ConfigAltResp> for a buffer storage.
891
892 Arguments:
893 ConfigRequest - The Config request string. If set to NULL, all the
894 configurable elements will be extracted from BlockNameArray.
895 ConfigAltResp - The returned <ConfigAltResp>.
896 Progress - On return, points to a character in the Request.
897 Guid - GUID of the buffer storage.
898 Name - Name of the buffer storage.
899 DriverHandle - The DriverHandle which is used to invoke HiiDatabase
900 protocol interface NewPackageList().
901 BufferStorage - Content of the buffer storage.
902 BufferStorageSize - Length in bytes of the buffer storage.
903 BlockNameArray - Array generated by VFR compiler.
904 NumberAltCfg - Number of Default value array generated by VFR compiler.
905 The sequential input parameters will be number of
906 AltCfgId and DefaultValueArray pairs. When set to 0,
907 there will be no <AltResp>.
908
909 Returns:
910 EFI_OUT_OF_RESOURCES - Run out of memory resource.
911 EFI_INVALID_PARAMETER - ConfigAltResp is NULL.
912 EFI_SUCCESS - Operation successful.
913
914 --*/
915 {
916 EFI_STATUS Status;
917 CHAR16 *ConfigHdr;
918 CHAR16 *BlockName;
919 CHAR16 *DescHdr;
920 CHAR16 *StringPtr;
921 CHAR16 **AltCfg;
922 UINT16 AltCfgId;
923 VOID *DefaultValueArray;
924 UINTN StrBufferLen;
925 EFI_STRING ConfigResp;
926 EFI_STRING TempStr;
927 VA_LIST Args;
928 UINTN AltRespLen;
929 UINTN Index;
930 BOOLEAN NeedFreeConfigRequest;
931 EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
932
933 if (ConfigAltResp == NULL) {
934 return EFI_INVALID_PARAMETER;
935 }
936
937 //
938 // Construct <ConfigHdr> : "GUID=...&NAME=...&PATH=..."
939 //
940 ConfigHdr = NULL;
941 StrBufferLen = 0;
942 Status = ConstructConfigHdr (
943 ConfigHdr,
944 &StrBufferLen,
945 Guid,
946 Name,
947 DriverHandle
948 );
949 if (Status == EFI_BUFFER_TOO_SMALL) {
950 ConfigHdr = EfiLibAllocateZeroPool (StrBufferLen);
951 Status = ConstructConfigHdr (
952 ConfigHdr,
953 &StrBufferLen,
954 Guid,
955 Name,
956 DriverHandle
957 );
958 }
959
960 if (EFI_ERROR (Status) || (ConfigHdr == NULL)) {
961 return Status;
962 }
963
964 //
965 // Construct <ConfigResp>
966 //
967 NeedFreeConfigRequest = FALSE;
968 if (ConfigRequest == NULL) {
969 //
970 // If ConfigRequest is set to NULL, export all configurable elements in BlockNameArray
971 //
972 Status = ExtractBlockName (BlockNameArray, &BlockName);
973 if (EFI_ERROR (Status)) {
974 return Status;
975 }
976
977 StrBufferLen = EfiStrSize (ConfigHdr);
978 StrBufferLen = StrBufferLen + EfiStrSize (BlockName) - sizeof (CHAR16);
979 ConfigRequest = EfiLibAllocateZeroPool (StrBufferLen);
980 EfiStrCpy (ConfigRequest, ConfigHdr);
981 EfiStrCat (ConfigRequest, BlockName);
982 NeedFreeConfigRequest = TRUE;
983 }
984
985 Status = gBS->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid, NULL, (VOID **) &HiiConfigRouting);
986 if (EFI_ERROR (Status)) {
987 return Status;
988 }
989
990 Status = HiiConfigRouting->BlockToConfig (
991 HiiConfigRouting,
992 ConfigRequest,
993 BufferStorage,
994 BufferStorageSize,
995 &ConfigResp,
996 (Progress == NULL) ? &TempStr : Progress
997 );
998 if (EFI_ERROR (Status)) {
999 return Status;
1000 }
1001
1002 //
1003 // Construct <AltResp>
1004 //
1005 DescHdr = EfiLibAllocateZeroPool (NumberAltCfg * 16 * sizeof (CHAR16));
1006 StringPtr = DescHdr;
1007 AltCfg = EfiLibAllocateZeroPool (NumberAltCfg * sizeof (CHAR16 *));
1008 AltRespLen = 0;
1009 VA_START (Args, NumberAltCfg);
1010 for (Index = 0; Index < NumberAltCfg; Index++) {
1011 AltCfgId = (UINT16) VA_ARG (Args, UINT16);
1012 DefaultValueArray = (UINT8 *) VA_ARG (Args, VOID *);
1013
1014 //
1015 // '&' <ConfigHdr>
1016 //
1017 AltRespLen += (EfiStrLen (ConfigHdr) + 1);
1018
1019 StringPtr = DescHdr + Index * 16;
1020 EfiStrCpy (StringPtr, L"&ALTCFG=");
1021 AltRespLen += (8 + sizeof (UINT16) * 2);
1022
1023 StrBufferLen = 5;
1024 BufToHexString (StringPtr + 8, &StrBufferLen, (UINT8 *) &AltCfgId, sizeof (UINT16));
1025 Status = ExtractBlockConfig (DefaultValueArray, &AltCfg[Index]);
1026 if (EFI_ERROR (Status)) {
1027 VA_END (Args);
1028 return Status;
1029 }
1030 AltRespLen += EfiStrLen (AltCfg[Index]);
1031 }
1032 VA_END (Args);
1033
1034 //
1035 // Generate the final <ConfigAltResp>
1036 //
1037 StrBufferLen = (EfiStrLen ((CHAR16 *) ConfigResp) + AltRespLen + 1) * sizeof (CHAR16);
1038 TempStr = EfiLibAllocateZeroPool (StrBufferLen);
1039 *ConfigAltResp = TempStr;
1040 if (TempStr == NULL) {
1041 return EFI_OUT_OF_RESOURCES;
1042 }
1043
1044 //
1045 // <ConfigAltResp> ::= <ConfigResp> ['&' <AltResp>]*
1046 //
1047 EfiStrCpy (TempStr, ConfigResp);
1048 for (Index = 0; Index < NumberAltCfg; Index++) {
1049 EfiStrCat (TempStr, L"&");
1050 EfiStrCat (TempStr, ConfigHdr);
1051 EfiStrCat (TempStr, DescHdr + Index * 16);
1052 EfiStrCat (TempStr, AltCfg[Index]);
1053
1054 gBS->FreePool (AltCfg[Index]);
1055 }
1056
1057 if (NeedFreeConfigRequest) {
1058 gBS->FreePool (ConfigRequest);
1059 }
1060 gBS->FreePool (ConfigHdr);
1061 gBS->FreePool (ConfigResp);
1062 gBS->FreePool (DescHdr);
1063 gBS->FreePool (AltCfg);
1064
1065 return EFI_SUCCESS;
1066 }
1067
1068 VOID
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 if (ConfigHdr == NULL) {
1399 return EFI_INVALID_PARAMETER;
1400 }
1401
1402 *StrBufferLen = BufferSize;
1403
1404 StrPtr = ConfigHdr;
1405
1406 EfiStrCpy (StrPtr, L"GUID=");
1407 StrPtr += 5;
1408 BufferToHexString (StrPtr, (UINT8 *) Guid, sizeof (EFI_GUID));
1409 StrPtr += 32;
1410
1411 //
1412 // Convert name string, e.g. name "ABCD" => "&NAME=0041004200430044"
1413 //
1414 EfiStrCpy (StrPtr, L"&NAME=");
1415 StrPtr += 6;
1416 if (Name != NULL) {
1417 BufferSize = (NameStrLen * 4 + 1) * sizeof (CHAR16);
1418 UnicodeToConfigString (StrPtr, &BufferSize, Name);
1419 StrPtr += (NameStrLen * 4);
1420 }
1421
1422 EfiStrCpy (StrPtr, L"&PATH=");
1423 StrPtr += 6;
1424 BufferToHexString (StrPtr, (UINT8 *) DevicePath, DevicePathSize);
1425
1426 return EFI_SUCCESS;
1427 }
1428
1429 BOOLEAN
1430 IsConfigHdrMatch (
1431 IN EFI_STRING ConfigString,
1432 IN EFI_GUID *StorageGuid, OPTIONAL
1433 IN CHAR16 *StorageName OPTIONAL
1434 )
1435 /*++
1436
1437 Routine Description:
1438 Determines if the Routing data (Guid and Name) is correct in <ConfigHdr>.
1439
1440 Arguments:
1441 ConfigString - Either <ConfigRequest> or <ConfigResp>.
1442 StorageGuid - GUID of the storage.
1443 StorageName - Name of the stoarge.
1444
1445 Returns:
1446 TRUE - Routing information is correct in ConfigString.
1447 FALSE - Routing information is incorrect in ConfigString.
1448
1449 --*/
1450 {
1451 EFI_STATUS Status;
1452 BOOLEAN Match;
1453 EFI_GUID Guid;
1454 CHAR16 *Name;
1455 CHAR16 *StrPtr;
1456 UINTN BufferSize;
1457
1458 //
1459 // <ConfigHdr> ::=
1460 // GUID=<HexCh>32&NAME=<Char>NameStrLen&PATH=<HexChar>DevicePathStrLen <NULL>
1461 // | 5 | 32 | 6 | NameStrLen*4 | 6 | DevicePathStrLen | 1 |
1462 //
1463 if (EfiStrLen (ConfigString) <= (5 + 32 + 6)) {
1464 return FALSE;
1465 }
1466
1467 //
1468 // Compare GUID
1469 //
1470 if (StorageGuid != NULL) {
1471
1472 StrPtr = ConfigString + 5 + 32;
1473 if (*StrPtr != L'&') {
1474 return FALSE;
1475 }
1476 *StrPtr = L'\0';
1477
1478 BufferSize = sizeof (EFI_GUID);
1479 Status = HexStringToBuffer (
1480 (UINT8 *) &Guid,
1481 &BufferSize,
1482 ConfigString + 5
1483 );
1484 *StrPtr = L'&';
1485
1486 if (EFI_ERROR (Status)) {
1487 return FALSE;
1488 }
1489
1490 if (!EfiCompareGuid (&Guid, StorageGuid)) {
1491 return FALSE;
1492 }
1493 }
1494
1495 //
1496 // Compare Name
1497 //
1498 Match = TRUE;
1499 if (StorageName != NULL) {
1500 StrPtr = ConfigString + 5 + 32 + 6;
1501 while (*StrPtr != L'\0' && *StrPtr != L'&') {
1502 StrPtr++;
1503 }
1504 if (*StrPtr != L'&') {
1505 return FALSE;
1506 }
1507
1508 *StrPtr = L'\0';
1509 BufferSize = (EfiStrLen (ConfigString + 5 + 32 + 6) + 1) * sizeof (CHAR16);
1510 Name = EfiLibAllocatePool (BufferSize);
1511 ASSERT (Name != NULL);
1512 Status = ConfigStringToUnicode (
1513 Name,
1514 &BufferSize,
1515 ConfigString + 5 + 32 + 6
1516 );
1517 *StrPtr = L'&';
1518
1519 if (EFI_ERROR (Status) || (EfiStrCmp (Name, StorageName) != 0)) {
1520 Match = FALSE;
1521 }
1522 gBS->FreePool (Name);
1523 }
1524
1525 return Match;
1526 }
1527
1528 BOOLEAN
1529 FindBlockName (
1530 IN OUT CHAR16 *String,
1531 UINTN Offset,
1532 UINTN Width
1533 )
1534 /*++
1535
1536 Routine Description:
1537 Search BlockName "&OFFSET=Offset&WIDTH=Width" in a string.
1538
1539 Arguments:
1540 String - The string to be searched in.
1541 Offset - Offset in BlockName.
1542 Width - Width in BlockName.
1543
1544 Returns:
1545 TRUE - Block name found.
1546 FALSE - Block name not found.
1547
1548 --*/
1549 {
1550 EFI_STATUS Status;
1551 UINTN Data;
1552 UINTN BufferSize;
1553 UINTN ConvertedStrLen;
1554
1555 while ((String = EfiStrStr (String, L"&OFFSET=")) != NULL) {
1556 //
1557 // Skip '&OFFSET='
1558 //
1559 String = String + 8;
1560
1561 Data = 0;
1562 BufferSize = sizeof (UINTN);
1563 Status = HexStringToBuf ((UINT8 *) &Data, &BufferSize, String, &ConvertedStrLen);
1564 if (EFI_ERROR (Status)) {
1565 return FALSE;
1566 }
1567 String = String + ConvertedStrLen;
1568
1569 if (Data != Offset) {
1570 continue;
1571 }
1572
1573 if (EfiStrnCmp (String, L"&WIDTH=", 7) != 0) {
1574 return FALSE;
1575 }
1576 String = String + 7;
1577
1578 Data = 0;
1579 BufferSize = sizeof (UINTN);
1580 Status = HexStringToBuf ((UINT8 *) &Data, &BufferSize, String, &ConvertedStrLen);
1581 if (EFI_ERROR (Status)) {
1582 return FALSE;
1583 }
1584 if (Data == Width) {
1585 return TRUE;
1586 }
1587
1588 String = String + ConvertedStrLen;
1589 }
1590
1591 return FALSE;
1592 }
1593
1594 EFI_STATUS
1595 GetBrowserData (
1596 EFI_GUID *VariableGuid, OPTIONAL
1597 CHAR16 *VariableName, OPTIONAL
1598 UINTN *BufferSize,
1599 UINT8 *Buffer
1600 )
1601 /*++
1602
1603 Routine Description:
1604 This routine is invoked by ConfigAccess.Callback() to retrived uncommitted data from Form Browser.
1605
1606 Arguments:
1607 VariableGuid - An optional field to indicate the target variable GUID name to use.
1608 VariableName - An optional field to indicate the target human-readable variable name.
1609 BufferSize - On input: Length in bytes of buffer to hold retrived data.
1610 On output:
1611 If return EFI_BUFFER_TOO_SMALL, containg length of buffer desired.
1612 Buffer - Buffer to hold retrived data.
1613
1614 Returns:
1615 EFI_SUCCESS - Routine success.
1616 EFI_BUFFER_TOO_SMALL - The intput buffer is too small.
1617
1618 --*/
1619 {
1620 EFI_STATUS Status;
1621 CHAR16 *ConfigHdr;
1622 CHAR16 *ConfigResp;
1623 CHAR16 *StringPtr;
1624 UINTN HeaderLen;
1625 UINTN BufferLen;
1626 CHAR16 *Progress;
1627 EFI_FORM_BROWSER2_PROTOCOL *FormBrowser2;
1628 EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
1629
1630 //
1631 // Locate protocols for use
1632 //
1633 Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &FormBrowser2);
1634 if (EFI_ERROR (Status)) {
1635 return Status;
1636 }
1637
1638 Status = gBS->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid, NULL, (VOID **) &HiiConfigRouting);
1639 if (EFI_ERROR (Status)) {
1640 return Status;
1641 }
1642
1643 //
1644 // Retrive formset storage data from Form Browser
1645 //
1646 ConfigHdr = mFakeConfigHdr;
1647 HeaderLen = EfiStrLen (ConfigHdr);
1648
1649 BufferLen = 0x4000;
1650 ConfigResp = EfiLibAllocateZeroPool (BufferLen + (HeaderLen + 1) * sizeof (CHAR16));
1651
1652 StringPtr = ConfigResp + HeaderLen;
1653 *StringPtr = L'&';
1654 StringPtr++;
1655
1656 Status = FormBrowser2->BrowserCallback (
1657 FormBrowser2,
1658 &BufferLen,
1659 StringPtr,
1660 TRUE,
1661 VariableGuid,
1662 VariableName
1663 );
1664 if (Status == EFI_BUFFER_TOO_SMALL) {
1665 gBS->FreePool (ConfigResp);
1666 ConfigResp = EfiLibAllocateZeroPool (BufferLen + (HeaderLen + 1) * sizeof (CHAR16));
1667
1668 StringPtr = ConfigResp + HeaderLen;
1669 *StringPtr = L'&';
1670 StringPtr++;
1671
1672 Status = FormBrowser2->BrowserCallback (
1673 FormBrowser2,
1674 &BufferLen,
1675 StringPtr,
1676 TRUE,
1677 VariableGuid,
1678 VariableName
1679 );
1680 }
1681 if (EFI_ERROR (Status)) {
1682 gBS->FreePool (ConfigResp);
1683 return Status;
1684 }
1685 EfiCopyMem (ConfigResp, ConfigHdr, HeaderLen * sizeof (UINT16));
1686
1687 //
1688 // Convert <ConfigResp> to buffer data
1689 //
1690 Status = HiiConfigRouting->ConfigToBlock (
1691 HiiConfigRouting,
1692 ConfigResp,
1693 Buffer,
1694 BufferSize,
1695 &Progress
1696 );
1697 gBS->FreePool (ConfigResp);
1698
1699 return Status;
1700 }
1701
1702 EFI_STATUS
1703 SetBrowserData (
1704 EFI_GUID *VariableGuid, OPTIONAL
1705 CHAR16 *VariableName, OPTIONAL
1706 UINTN BufferSize,
1707 UINT8 *Buffer,
1708 CHAR16 *RequestElement OPTIONAL
1709 )
1710 /*++
1711
1712 Routine Description:
1713 This routine is invoked by ConfigAccess.Callback() to update uncommitted data of Form Browser.
1714
1715 Arguments:
1716 VariableGuid - An optional field to indicate the target variable GUID name to use.
1717 VariableName - An optional field to indicate the target human-readable variable name.
1718 BufferSize - Length in bytes of buffer to hold retrived data.
1719 Buffer - Buffer to hold retrived data.
1720 RequestElement - An optional field to specify which part of the buffer data
1721 will be send back to Browser. If NULL, the whole buffer of
1722 data will be committed to Browser.
1723 <RequestElement> ::= &OFFSET=<Number>&WIDTH=<Number>*
1724
1725 Returns:
1726 EFI_SUCCESS - Routine success.
1727 Other - Updating Browser uncommitted data failed.
1728
1729 --*/
1730 {
1731 EFI_STATUS Status;
1732 CHAR16 *ConfigHdr;
1733 CHAR16 *ConfigResp;
1734 CHAR16 *StringPtr;
1735 UINTN HeaderLen;
1736 UINTN BufferLen;
1737 CHAR16 *Progress;
1738 EFI_FORM_BROWSER2_PROTOCOL *FormBrowser2;
1739 EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
1740 CHAR16 BlockName[33];
1741 CHAR16 *ConfigRequest;
1742 CHAR16 *Request;
1743
1744 //
1745 // Locate protocols for use
1746 //
1747 Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &FormBrowser2);
1748 if (EFI_ERROR (Status)) {
1749 return Status;
1750 }
1751
1752 Status = gBS->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid, NULL, (VOID **) &HiiConfigRouting);
1753 if (EFI_ERROR (Status)) {
1754 return Status;
1755 }
1756
1757 //
1758 // Prepare <ConfigRequest>
1759 //
1760 ConfigHdr = mFakeConfigHdr;
1761 HeaderLen = EfiStrLen (ConfigHdr);
1762
1763 if (RequestElement == NULL) {
1764 //
1765 // RequestElement not specified, use "&OFFSET=0&WIDTH=<BufferSize>" as <BlockName>
1766 //
1767 BlockName[0] = L'\0';
1768 EfiStrCpy (BlockName, L"&OFFSET=0&WIDTH=");
1769
1770 //
1771 // String lenghth of L"&OFFSET=0&WIDTH=" is 16
1772 //
1773 StringPtr = BlockName + 16;
1774 BufferLen = sizeof (BlockName) - (16 * sizeof (CHAR16));
1775 BufToHexString (StringPtr, &BufferLen, (UINT8 *) &BufferSize, sizeof (UINTN));
1776
1777 Request = BlockName;
1778 } else {
1779 Request = RequestElement;
1780 }
1781
1782 BufferLen = HeaderLen * sizeof (CHAR16) + EfiStrSize (Request);
1783 ConfigRequest = EfiLibAllocateZeroPool (BufferLen);
1784
1785 EfiCopyMem (ConfigRequest, ConfigHdr, HeaderLen * sizeof (CHAR16));
1786 StringPtr = ConfigRequest + HeaderLen;
1787 EfiStrCpy (StringPtr, Request);
1788
1789 //
1790 // Convert buffer to <ConfigResp>
1791 //
1792 Status = HiiConfigRouting->BlockToConfig (
1793 HiiConfigRouting,
1794 ConfigRequest,
1795 Buffer,
1796 BufferSize,
1797 &ConfigResp,
1798 &Progress
1799 );
1800 if (EFI_ERROR (Status)) {
1801 gBS->FreePool (ConfigRequest);
1802 return Status;
1803 }
1804
1805 //
1806 // Skip <ConfigHdr> and '&'
1807 //
1808 StringPtr = ConfigResp + HeaderLen + 1;
1809
1810 //
1811 // Change uncommitted data in Browser
1812 //
1813 Status = FormBrowser2->BrowserCallback (
1814 FormBrowser2,
1815 &BufferSize,
1816 StringPtr,
1817 FALSE,
1818 VariableGuid,
1819 VariableName
1820 );
1821 gBS->FreePool (ConfigResp);
1822 gBS->FreePool (ConfigRequest);
1823 return Status;
1824 }