]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Library/IfrSupportLib/UefiIfrForm.c
UEFI HII: Merge UEFI HII support changes from branch.
[mirror_edk2.git] / MdeModulePkg / Library / IfrSupportLib / UefiIfrForm.c
1 /** @file
2
3 Copyright (c) 2007, Intel Corporation
4 All rights reserved. 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
23 #include "UefiIfrLibraryInternal.h"
24
25 //
26 // Fake <ConfigHdr>
27 //
28 UINT16 mFakeConfigHdr[] = L"GUID=00000000000000000000000000000000&NAME=0000&PATH=0";
29
30 STATIC
31 EFI_STATUS
32 GetPackageDataFromPackageList (
33 IN EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList,
34 IN UINT32 PackageIndex,
35 OUT UINT32 *BufferLen,
36 OUT EFI_HII_PACKAGE_HEADER **Buffer
37 )
38 {
39 UINT32 Index;
40 EFI_HII_PACKAGE_HEADER *Package;
41 UINT32 Offset;
42 UINT32 PackageListLength;
43 EFI_HII_PACKAGE_HEADER PackageHeader = {0, 0};
44
45 ASSERT(HiiPackageList != NULL);
46
47 if ((BufferLen == NULL) || (Buffer == NULL)) {
48 return EFI_INVALID_PARAMETER;
49 }
50
51 Package = NULL;
52 Index = 0;
53 Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
54 CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32));
55 while (Offset < PackageListLength) {
56 Package = (EFI_HII_PACKAGE_HEADER *) (((UINT8 *) HiiPackageList) + Offset);
57 CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
58 if (Index == PackageIndex) {
59 break;
60 }
61 Offset += PackageHeader.Length;
62 Index++;
63 }
64 if (Offset >= PackageListLength) {
65 //
66 // no package found in this Package List
67 //
68 return EFI_NOT_FOUND;
69 }
70
71 *BufferLen = PackageHeader.Length;
72 *Buffer = Package;
73 return EFI_SUCCESS;
74 }
75
76 STATIC
77 EFI_STATUS
78 UpdateFormPackageData (
79 IN EFI_GUID *FormSetGuid,
80 IN EFI_FORM_ID FormId,
81 IN EFI_HII_PACKAGE_HEADER *Package,
82 IN UINT32 PackageLength,
83 IN UINT16 Label,
84 IN BOOLEAN Insert,
85 IN EFI_HII_UPDATE_DATA *Data,
86 OUT UINT8 **TempBuffer,
87 OUT UINT32 *TempBufferSize
88 )
89 {
90 UINTN AddSize;
91 UINT8 *BufferPos;
92 EFI_HII_PACKAGE_HEADER PackageHeader;
93 UINTN Offset;
94 EFI_IFR_OP_HEADER *IfrOpHdr;
95 BOOLEAN GetFormSet;
96 BOOLEAN GetForm;
97 UINT8 ExtendOpCode;
98 UINT16 LabelNumber;
99 BOOLEAN Updated;
100 EFI_IFR_OP_HEADER *AddOpCode;
101
102 if ((TempBuffer == NULL) || (TempBufferSize == NULL)) {
103 return EFI_INVALID_PARAMETER;
104 }
105
106 *TempBufferSize = PackageLength;
107 if (Data != NULL) {
108 *TempBufferSize += Data->Offset;
109 }
110 *TempBuffer = AllocateZeroPool (*TempBufferSize);
111 if (*TempBuffer == NULL) {
112 return EFI_OUT_OF_RESOURCES;
113 }
114
115 CopyMem (*TempBuffer, Package, sizeof (EFI_HII_PACKAGE_HEADER));
116 *TempBufferSize = sizeof (EFI_HII_PACKAGE_HEADER);
117 BufferPos = *TempBuffer + sizeof (EFI_HII_PACKAGE_HEADER);
118
119 CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
120 IfrOpHdr = (EFI_IFR_OP_HEADER *)((UINT8 *) Package + sizeof (EFI_HII_PACKAGE_HEADER));
121 Offset = sizeof (EFI_HII_PACKAGE_HEADER);
122 GetFormSet = (BOOLEAN) ((FormSetGuid == NULL) ? TRUE : FALSE);
123 GetForm = FALSE;
124 Updated = FALSE;
125
126 while (Offset < PackageHeader.Length) {
127 CopyMem (BufferPos, IfrOpHdr, IfrOpHdr->Length);
128 BufferPos += IfrOpHdr->Length;
129 *TempBufferSize += IfrOpHdr->Length;
130
131 switch (IfrOpHdr->OpCode) {
132 case EFI_IFR_FORM_SET_OP :
133 if (FormSetGuid != NULL) {
134 if (CompareMem (&((EFI_IFR_FORM_SET *) IfrOpHdr)->Guid, FormSetGuid, sizeof (EFI_GUID)) == 0) {
135 GetFormSet = TRUE;
136 }
137 }
138 break;
139
140 case EFI_IFR_FORM_OP:
141 if (CompareMem (&((EFI_IFR_FORM *) IfrOpHdr)->FormId, &FormId, sizeof (EFI_FORM_ID)) == 0) {
142 GetForm = TRUE;
143 }
144 break;
145
146 case EFI_IFR_GUID_OP :
147 if (!GetFormSet || !GetForm || Updated) {
148 //
149 // Go to the next Op-Code
150 //
151 Offset += IfrOpHdr->Length;
152 IfrOpHdr = (EFI_IFR_OP_HEADER *) ((CHAR8 *) (IfrOpHdr) + IfrOpHdr->Length);
153 continue;
154 }
155
156 ExtendOpCode = ((EFI_IFR_GUID_LABEL *) IfrOpHdr)->ExtendOpCode;
157 CopyMem (&LabelNumber, &((EFI_IFR_GUID_LABEL *)IfrOpHdr)->Number, sizeof (UINT16));
158 if ((ExtendOpCode != EFI_IFR_EXTEND_OP_LABEL) || (LabelNumber != Label)) {
159 //
160 // Go to the next Op-Code
161 //
162 Offset += IfrOpHdr->Length;
163 IfrOpHdr = (EFI_IFR_OP_HEADER *) ((CHAR8 *) (IfrOpHdr) + IfrOpHdr->Length);
164 continue;
165 }
166
167 if (Insert && (Data != NULL)) {
168 //
169 // insert the DataCount amount of opcodes to TempBuffer if Data is NULL remove
170 // DataCount amount of opcodes unless runing into a label.
171 //
172 AddOpCode = (EFI_IFR_OP_HEADER *)Data->Data;
173 AddSize = 0;
174 while (AddSize < Data->Offset) {
175 CopyMem (BufferPos, AddOpCode, AddOpCode->Length);
176 BufferPos += AddOpCode->Length;
177 *TempBufferSize += AddOpCode->Length;
178
179 AddSize += AddOpCode->Length;
180 AddOpCode = (EFI_IFR_OP_HEADER *) ((CHAR8 *) (AddOpCode) + AddOpCode->Length);
181 }
182 } else {
183 //
184 // Search the next Label.
185 //
186 while (TRUE) {
187 Offset += IfrOpHdr->Length;
188 //
189 // Search the next label and Fail if not label found.
190 //
191 if (Offset >= PackageHeader.Length) {
192 goto Fail;
193 }
194 IfrOpHdr = (EFI_IFR_OP_HEADER *) ((CHAR8 *) (IfrOpHdr) + IfrOpHdr->Length);
195 if (IfrOpHdr->OpCode == EFI_IFR_GUID_OP) {
196 ExtendOpCode = ((EFI_IFR_GUID_LABEL *) IfrOpHdr)->ExtendOpCode;
197 if (ExtendOpCode == EFI_IFR_EXTEND_OP_LABEL) {
198 break;
199 }
200 }
201 }
202
203 if (Data != NULL) {
204 AddOpCode = (EFI_IFR_OP_HEADER *)Data->Data;
205 AddSize = 0;
206 while (AddSize < Data->Offset) {
207 CopyMem (BufferPos, AddOpCode, AddOpCode->Length);
208 BufferPos += AddOpCode->Length;
209 *TempBufferSize += AddOpCode->Length;
210
211 AddSize += AddOpCode->Length;
212 AddOpCode = (EFI_IFR_OP_HEADER *) ((CHAR8 *) (AddOpCode) + AddOpCode->Length);
213 }
214 }
215
216 //
217 // copy the next label
218 //
219 CopyMem (BufferPos, IfrOpHdr, IfrOpHdr->Length);
220 BufferPos += IfrOpHdr->Length;
221 *TempBufferSize += IfrOpHdr->Length;
222 }
223
224 Updated = TRUE;
225 break;
226 default :
227 break;
228 }
229
230 //
231 // Go to the next Op-Code
232 //
233 Offset += IfrOpHdr->Length;
234 IfrOpHdr = (EFI_IFR_OP_HEADER *) ((CHAR8 *) (IfrOpHdr) + IfrOpHdr->Length);
235 }
236
237 //
238 // Update the package length.
239 //
240 PackageHeader.Length = *TempBufferSize;
241 CopyMem (*TempBuffer, &PackageHeader, sizeof (EFI_HII_PACKAGE_HEADER));
242
243 Fail:
244 if (!Updated) {
245 gBS->FreePool (*TempBuffer);
246 *TempBufferSize = 0;
247 return EFI_NOT_FOUND;
248 }
249
250 return EFI_SUCCESS;
251 }
252
253
254 /**
255 This function allows the caller to update a form that has
256 previously been registered with the EFI HII database.
257
258 @param Handle Hii Handle
259 @param FormSetGuid The formset should be updated.
260 @param FormId The form should be updated.
261 @param Label Update information starting immediately after this
262 label in the IFR
263 @param Insert If TRUE and Data is not NULL, insert data after
264 Label. If FALSE, replace opcodes between two
265 labels with Data
266 @param Data The adding data; If NULL, remove opcodes between
267 two Label.
268
269 @retval EFI_SUCCESS Update success.
270 @retval Other Update fail.
271
272 **/
273 EFI_STATUS
274 IfrLibUpdateForm (
275 IN EFI_HII_HANDLE Handle,
276 IN EFI_GUID *FormSetGuid, OPTIONAL
277 IN EFI_FORM_ID FormId,
278 IN UINT16 Label,
279 IN BOOLEAN Insert,
280 IN EFI_HII_UPDATE_DATA *Data
281 )
282 {
283 EFI_STATUS Status;
284 EFI_HII_DATABASE_PROTOCOL *HiiDatabase;
285 EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList;
286 UINT32 Index;
287 EFI_HII_PACKAGE_LIST_HEADER *UpdateBuffer;
288 UINTN BufferSize;
289 UINT8 *UpdateBufferPos;
290 EFI_HII_PACKAGE_HEADER PackageHeader;
291 EFI_HII_PACKAGE_HEADER *Package;
292 UINT32 PackageLength;
293 EFI_HII_PACKAGE_HEADER *TempBuffer;
294 UINT32 TempBufferSize;
295 BOOLEAN Updated;
296
297 if (Data == NULL) {
298 return EFI_INVALID_PARAMETER;
299 }
300
301 LocateHiiProtocols ();
302 HiiDatabase = gIfrLibHiiDatabase;
303
304 //
305 // Get the orginal package list
306 //
307 BufferSize = 0;
308 HiiPackageList = NULL;
309 Status = HiiDatabase->ExportPackageLists (HiiDatabase, Handle, &BufferSize, HiiPackageList);
310 if (Status == EFI_BUFFER_TOO_SMALL) {
311 HiiPackageList = AllocatePool (BufferSize);
312 ASSERT (HiiPackageList != NULL);
313
314 Status = HiiDatabase->ExportPackageLists (HiiDatabase, Handle, &BufferSize, HiiPackageList);
315 if (EFI_ERROR (Status)) {
316 gBS->FreePool (HiiPackageList);
317 return Status;
318 }
319 }
320
321 //
322 // Calculate and allocate space for retrieval of IFR data
323 //
324 BufferSize += Data->Offset;
325 UpdateBuffer = AllocateZeroPool (BufferSize);
326 if (UpdateBuffer == NULL) {
327 return EFI_OUT_OF_RESOURCES;
328 }
329
330 UpdateBufferPos = (UINT8 *) UpdateBuffer;
331
332 //
333 // copy the package list header
334 //
335 CopyMem (UpdateBufferPos, HiiPackageList, sizeof (EFI_HII_PACKAGE_LIST_HEADER));
336 UpdateBufferPos += sizeof (EFI_HII_PACKAGE_LIST_HEADER);
337
338 Updated = FALSE;
339 for (Index = 0; ; Index++) {
340 Status = GetPackageDataFromPackageList (HiiPackageList, Index, &PackageLength, &Package);
341 if (Status == EFI_SUCCESS) {
342 CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
343 if ((PackageHeader.Type == EFI_HII_PACKAGE_FORM) && !Updated) {
344 Status = UpdateFormPackageData (FormSetGuid, FormId, Package, PackageLength, Label, Insert, Data, (UINT8 **)&TempBuffer, &TempBufferSize);
345 if (!EFI_ERROR(Status)) {
346 if (FormSetGuid == NULL) {
347 Updated = TRUE;
348 }
349 CopyMem (UpdateBufferPos, TempBuffer, TempBufferSize);
350 UpdateBufferPos += TempBufferSize;
351 gBS->FreePool (TempBuffer);
352 continue;
353 }
354 }
355
356 CopyMem (UpdateBufferPos, Package, PackageLength);
357 UpdateBufferPos += PackageLength;
358 } else if (Status == EFI_NOT_FOUND) {
359 break;
360 } else {
361 gBS->FreePool (HiiPackageList);
362 return Status;
363 }
364 }
365
366 //
367 // Update package list length
368 //
369 BufferSize = UpdateBufferPos - (UINT8 *) UpdateBuffer;
370 CopyMem (&UpdateBuffer->PackageLength, &BufferSize, sizeof (UINT32));
371
372 gBS->FreePool (HiiPackageList);
373
374 return HiiDatabase->UpdatePackageList (HiiDatabase, Handle, UpdateBuffer);
375 }
376
377
378 /**
379 Draw a dialog and return the selected key.
380
381 @param NumberOfLines The number of lines for the dialog box
382 @param KeyValue The EFI_KEY value returned if HotKey is TRUE..
383 @param String Pointer to the first string in the list
384 @param ... A series of (quantity == NumberOfLines) text
385 strings which will be used to construct the dialog
386 box
387
388 @retval EFI_SUCCESS Displayed dialog and received user interaction
389 @retval EFI_INVALID_PARAMETER One of the parameters was invalid.
390
391 **/
392 EFI_STATUS
393 IfrLibCreatePopUp (
394 IN UINTN NumberOfLines,
395 OUT EFI_INPUT_KEY *KeyValue,
396 IN CHAR16 *String,
397 ...
398 )
399 {
400 UINTN Index;
401 UINTN Count;
402 UINTN Start;
403 UINTN Top;
404 CHAR16 *StringPtr;
405 UINTN LeftColumn;
406 UINTN RightColumn;
407 UINTN TopRow;
408 UINTN BottomRow;
409 UINTN DimensionsWidth;
410 UINTN DimensionsHeight;
411 VA_LIST Marker;
412 EFI_INPUT_KEY Key;
413 UINTN LargestString;
414 CHAR16 *StackString;
415 EFI_STATUS Status;
416 UINTN StringLen;
417 CHAR16 *LineBuffer;
418 CHAR16 **StringArray;
419 EFI_EVENT TimerEvent;
420 EFI_EVENT WaitList[2];
421 UINTN CurrentAttribute;
422 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut;
423
424 if ((KeyValue == NULL) || (String == NULL)) {
425 return EFI_INVALID_PARAMETER;
426 }
427
428 TopRow = 0;
429 BottomRow = 0;
430 LeftColumn = 0;
431 RightColumn = 0;
432
433 ConOut = gST->ConOut;
434 ConOut->QueryMode (ConOut, ConOut->Mode->Mode, &RightColumn, &BottomRow);
435
436 DimensionsWidth = RightColumn - LeftColumn;
437 DimensionsHeight = BottomRow - TopRow;
438
439 CurrentAttribute = ConOut->Mode->Attribute;
440
441 LineBuffer = AllocateZeroPool (DimensionsWidth * sizeof (CHAR16));
442 ASSERT (LineBuffer != NULL);
443
444 //
445 // Determine the largest string in the dialog box
446 // Notice we are starting with 1 since String is the first string
447 //
448 StringArray = AllocateZeroPool (NumberOfLines * sizeof (CHAR16 *));
449 LargestString = StrLen (String);
450 StringArray[0] = String;
451
452 VA_START (Marker, String);
453 for (Index = 1; Index < NumberOfLines; Index++) {
454 StackString = VA_ARG (Marker, CHAR16 *);
455
456 if (StackString == NULL) {
457 return EFI_INVALID_PARAMETER;
458 }
459
460 StringArray[Index] = StackString;
461 StringLen = StrLen (StackString);
462 if (StringLen > LargestString) {
463 LargestString = StringLen;
464 }
465 }
466
467 if ((LargestString + 2) > DimensionsWidth) {
468 LargestString = DimensionsWidth - 2;
469 }
470
471 //
472 // Subtract the PopUp width from total Columns, allow for one space extra on
473 // each end plus a border.
474 //
475 Start = (DimensionsWidth - LargestString - 2) / 2 + LeftColumn + 1;
476
477 Top = ((DimensionsHeight - NumberOfLines - 2) / 2) + TopRow - 1;
478
479 //
480 // Disable cursor
481 //
482 ConOut->EnableCursor (ConOut, FALSE);
483 ConOut->SetAttribute (ConOut, EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE);
484
485 StringPtr = &LineBuffer[0];
486 *StringPtr++ = BOXDRAW_DOWN_RIGHT;
487 for (Index = 0; Index < LargestString; Index++) {
488 *StringPtr++ = BOXDRAW_HORIZONTAL;
489 }
490 *StringPtr++ = BOXDRAW_DOWN_LEFT;
491 *StringPtr = L'\0';
492
493 ConOut->SetCursorPosition (ConOut, Start, Top);
494 ConOut->OutputString (ConOut, LineBuffer);
495
496 for (Index = 0; Index < NumberOfLines; Index++) {
497 StringPtr = &LineBuffer[0];
498 *StringPtr++ = BOXDRAW_VERTICAL;
499
500 for (Count = 0; Count < LargestString; Count++) {
501 StringPtr[Count] = L' ';
502 }
503
504 StringLen = StrLen (StringArray[Index]);
505 if (StringLen > LargestString) {
506 StringLen = LargestString;
507 }
508 CopyMem (
509 StringPtr + ((LargestString - StringLen) / 2),
510 StringArray[Index],
511 StringLen * sizeof (CHAR16)
512 );
513 StringPtr += LargestString;
514
515 *StringPtr++ = BOXDRAW_VERTICAL;
516 *StringPtr = L'\0';
517
518 ConOut->SetCursorPosition (ConOut, Start, Top + 1 + Index);
519 ConOut->OutputString (ConOut, LineBuffer);
520 }
521
522 StringPtr = &LineBuffer[0];
523 *StringPtr++ = BOXDRAW_UP_RIGHT;
524 for (Index = 0; Index < LargestString; Index++) {
525 *StringPtr++ = BOXDRAW_HORIZONTAL;
526 }
527 *StringPtr++ = BOXDRAW_UP_LEFT;
528 *StringPtr = L'\0';
529
530 ConOut->SetCursorPosition (ConOut, Start, Top + NumberOfLines + 1);
531 ConOut->OutputString (ConOut, LineBuffer);
532
533 do {
534 Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent);
535
536 //
537 // Set a timer event of 1 second expiration
538 //
539 gBS->SetTimer (
540 TimerEvent,
541 TimerRelative,
542 10000000
543 );
544
545 //
546 // Wait for the keystroke event or the timer
547 //
548 WaitList[0] = gST->ConIn->WaitForKey;
549 WaitList[1] = TimerEvent;
550 Status = gBS->WaitForEvent (2, WaitList, &Index);
551
552 //
553 // Check for the timer expiration
554 //
555 if (!EFI_ERROR (Status) && Index == 1) {
556 Status = EFI_TIMEOUT;
557 }
558
559 gBS->CloseEvent (TimerEvent);
560 } while (Status == EFI_TIMEOUT);
561
562 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
563 CopyMem (KeyValue, &Key, sizeof (EFI_INPUT_KEY));
564
565 ConOut->SetAttribute (ConOut, CurrentAttribute);
566 ConOut->EnableCursor (ConOut, TRUE);
567
568 return Status;
569 }
570
571
572 /**
573 Configure the buffer accrording to ConfigBody strings.
574
575 @param DefaultId the ID of default.
576 @param Buffer the start address of buffer.
577 @param BufferSize the size of buffer.
578 @param Number the number of the strings.
579
580 @retval EFI_BUFFER_TOO_SMALL the BufferSize is too small to operate.
581 @retval EFI_INVALID_PARAMETER Buffer is NULL or BufferSize is 0.
582 @retval EFI_SUCCESS Operation successful.
583
584 **/
585 EFI_STATUS
586 ExtractDefault(
587 IN VOID *Buffer,
588 IN UINTN *BufferSize,
589 UINTN Number,
590 ...
591 )
592 {
593 VA_LIST Args;
594 UINTN Index;
595 UINT32 TotalLen;
596 UINT8 *BufCfgArray;
597 UINT8 *BufferPos;
598 UINT16 Offset;
599 UINT16 Width;
600 UINT8 *Value;
601
602 if ((Buffer == NULL) || (BufferSize == NULL)) {
603 return EFI_INVALID_PARAMETER;
604 }
605
606 Offset = 0;
607 Width = 0;
608 Value = NULL;
609
610 VA_START (Args, Number);
611 for (Index = 0; Index < Number; Index++) {
612 BufCfgArray = (UINT8 *) VA_ARG (Args, VOID *);
613 CopyMem (&TotalLen, BufCfgArray, sizeof (UINT32));
614 BufferPos = BufCfgArray + sizeof (UINT32);
615
616 while ((UINT32)(BufferPos - BufCfgArray) < TotalLen) {
617 CopyMem (&Offset, BufferPos, sizeof (UINT16));
618 BufferPos += sizeof (UINT16);
619 CopyMem (&Width, BufferPos, sizeof (UINT16));
620 BufferPos += sizeof (UINT16);
621 Value = BufferPos;
622 BufferPos += Width;
623
624 if ((UINTN)(Offset + Width) > *BufferSize) {
625 return EFI_BUFFER_TOO_SMALL;
626 }
627
628 CopyMem ((UINT8 *)Buffer + Offset, Value, Width);
629 }
630 }
631 VA_END (Args);
632
633 *BufferSize = (UINTN)Offset;
634
635 return EFI_SUCCESS;
636 }
637
638
639 /**
640 Swap bytes in the buffer.
641
642 @param Buffer Binary buffer.
643 @param BufferSize Size of the buffer in bytes.
644
645 @return None.
646
647 **/
648 STATIC
649 VOID
650 SwapBuffer (
651 IN OUT UINT8 *Buffer,
652 IN UINTN BufferSize
653 )
654 {
655 UINTN Index;
656 UINT8 Temp;
657 UINTN SwapCount;
658
659 SwapCount = (BufferSize - 1) / 2;
660 for (Index = 0; Index < SwapCount; Index++) {
661 Temp = Buffer[Index];
662 Buffer[Index] = Buffer[BufferSize - 1 - Index];
663 Buffer[BufferSize - 1 - Index] = Temp;
664 }
665 }
666
667
668 /**
669 Converts binary buffer to Unicode string in reversed byte order from R8_BufToHexString().
670
671 @param Str String for output
672 @param Buffer Binary buffer.
673 @param BufferSize Size of the buffer in bytes.
674
675 @retval EFI_SUCCESS The function completed successfully.
676
677 **/
678 EFI_STATUS
679 BufferToHexString (
680 IN OUT CHAR16 *Str,
681 IN UINT8 *Buffer,
682 IN UINTN BufferSize
683 )
684 {
685 EFI_STATUS Status;
686 UINT8 *NewBuffer;
687 UINTN StrBufferLen;
688
689 NewBuffer = AllocateCopyPool (BufferSize, Buffer);
690 SwapBuffer (NewBuffer, BufferSize);
691
692 StrBufferLen = (BufferSize + 1) * sizeof (CHAR16);
693 Status = R8_BufToHexString (Str, &StrBufferLen, NewBuffer, BufferSize);
694
695 gBS->FreePool (NewBuffer);
696
697 return Status;
698 }
699
700
701 /**
702 Converts Hex String to binary buffer in reversed byte order from R8_HexStringToBuf().
703
704 @param Buffer Pointer to buffer that receives the data.
705 @param BufferSize Length in bytes of the buffer to hold converted
706 data. If routine return with EFI_SUCCESS,
707 containing length of converted data. If routine
708 return with EFI_BUFFER_TOO_SMALL, containg length
709 of buffer desired.
710 @param Str String to be converted from.
711
712 @retval EFI_SUCCESS The function completed successfully.
713
714 **/
715 EFI_STATUS
716 HexStringToBuffer (
717 IN OUT UINT8 *Buffer,
718 IN OUT UINTN *BufferSize,
719 IN CHAR16 *Str
720 )
721 {
722 EFI_STATUS Status;
723 UINTN ConvertedStrLen;
724
725 ConvertedStrLen = 0;
726 Status = R8_HexStringToBuf (Buffer, BufferSize, Str, &ConvertedStrLen);
727 if (!EFI_ERROR (Status)) {
728 SwapBuffer (Buffer, ConvertedStrLen);
729 }
730
731 return Status;
732 }
733
734
735 /**
736 Construct <ConfigHdr> using routing information GUID/NAME/PATH.
737
738 @param ConfigHdr Pointer to the ConfigHdr string.
739 @param StrBufferLen On input: Length in bytes of buffer to hold the
740 ConfigHdr string. Includes tailing '\0' character.
741 On output: If return EFI_SUCCESS, containing
742 length of ConfigHdr string buffer. If return
743 EFI_BUFFER_TOO_SMALL, containg length of string
744 buffer desired.
745 @param Guid Routing information: GUID.
746 @param Name Routing information: NAME.
747 @param DriverHandle Driver handle which contains the routing
748 information: PATH.
749
750 @retval EFI_SUCCESS Routine success.
751 @retval EFI_BUFFER_TOO_SMALL The ConfigHdr string buffer is too small.
752
753 **/
754 EFI_STATUS
755 ConstructConfigHdr (
756 IN OUT CHAR16 *ConfigHdr,
757 IN OUT UINTN *StrBufferLen,
758 IN EFI_GUID *Guid,
759 IN CHAR16 *Name, OPTIONAL
760 IN EFI_HANDLE *DriverHandle
761 )
762 {
763 EFI_STATUS Status;
764 UINTN NameStrLen;
765 UINTN DevicePathSize;
766 UINTN BufferSize;
767 CHAR16 *StrPtr;
768 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
769
770 if (Name == NULL) {
771 //
772 // There will be no "NAME" in <ConfigHdr> for Name/Value storage
773 //
774 NameStrLen = 0;
775 } else {
776 //
777 // For buffer storage
778 //
779 NameStrLen = StrLen (Name);
780 }
781
782 //
783 // Retrieve DevicePath Protocol associated with this HiiPackageList
784 //
785 Status = gBS->HandleProtocol (
786 DriverHandle,
787 &gEfiDevicePathProtocolGuid,
788 (VOID **) &DevicePath
789 );
790 if (EFI_ERROR (Status)) {
791 return Status;
792 }
793
794 DevicePathSize = GetDevicePathSize (DevicePath);
795
796 //
797 // GUID=<HexCh>32&NAME=<Alpha>NameStrLen&PATH=<HexChar>DevicePathStrLen <NULL>
798 // | 5 | 32 | 6 | NameStrLen | 6 | DevicePathStrLen |
799 //
800 BufferSize = (5 + 32 + 6 + NameStrLen + 6 + DevicePathSize * 2 + 1) * sizeof (CHAR16);
801 if (*StrBufferLen < BufferSize) {
802 *StrBufferLen = BufferSize;
803 return EFI_BUFFER_TOO_SMALL;
804 }
805
806 *StrBufferLen = BufferSize;
807
808 StrPtr = ConfigHdr;
809
810 StrCpy (StrPtr, L"GUID=");
811 StrPtr += 5;
812 BufferToHexString (StrPtr, (UINT8 *) Guid, sizeof (EFI_GUID));
813 StrPtr += 32;
814
815 StrCpy (StrPtr, L"&NAME=");
816 StrPtr += 6;
817 if (Name != NULL) {
818 StrCpy (StrPtr, Name);
819 StrPtr += NameStrLen;
820 }
821
822 StrCpy (StrPtr, L"&PATH=");
823 StrPtr += 6;
824 BufferToHexString (StrPtr, (UINT8 *) DevicePath, DevicePathSize);
825
826 return EFI_SUCCESS;
827 }
828
829
830 /**
831 Search BlockName "&OFFSET=Offset&WIDTH=Width" in a string.
832
833 @param String The string to be searched in.
834 @param Offset Offset in BlockName.
835 @param Width Width in BlockName.
836
837 @retval TRUE Block name found.
838 @retval FALSE Block name not found.
839
840 **/
841 BOOLEAN
842 FindBlockName (
843 IN OUT CHAR16 *String,
844 UINTN Offset,
845 UINTN Width
846 )
847 {
848 EFI_STATUS Status;
849 UINTN Data;
850 UINTN BufferSize;
851 UINTN ConvertedStrLen;
852
853 while ((String = StrStr (String, L"&OFFSET=")) != NULL) {
854 //
855 // Skip '&OFFSET='
856 //
857 String = String + 8;
858
859 Data = 0;
860 BufferSize = sizeof (UINTN);
861 Status = R8_HexStringToBuf ((UINT8 *) &Data, &BufferSize, String, &ConvertedStrLen);
862 if (EFI_ERROR (Status)) {
863 return FALSE;
864 }
865 String = String + ConvertedStrLen;
866
867 if (Data != Offset) {
868 continue;
869 }
870
871 if (StrnCmp (String, L"&WIDTH=", 7) != 0) {
872 return FALSE;
873 }
874 String = String + 7;
875
876 Data = 0;
877 BufferSize = sizeof (UINTN);
878 Status = R8_HexStringToBuf ((UINT8 *) &Data, &BufferSize, String, &ConvertedStrLen);
879 if (EFI_ERROR (Status)) {
880 return FALSE;
881 }
882 if (Data == Width) {
883 return TRUE;
884 }
885
886 String = String + ConvertedStrLen;
887 }
888
889 return FALSE;
890 }
891
892
893 /**
894 This routine is invoked by ConfigAccess.Callback() to retrived uncommitted data from Form Browser.
895
896 @param VariableGuid An optional field to indicate the target variable
897 GUID name to use.
898 @param VariableName An optional field to indicate the target
899 human-readable variable name.
900 @param BufferSize On input: Length in bytes of buffer to hold
901 retrived data. On output: If return
902 EFI_BUFFER_TOO_SMALL, containg length of buffer
903 desired.
904 @param Buffer Buffer to hold retrived data.
905
906 @retval EFI_SUCCESS Routine success.
907 @retval EFI_BUFFER_TOO_SMALL The intput buffer is too small.
908
909 **/
910 EFI_STATUS
911 GetBrowserData (
912 EFI_GUID *VariableGuid, OPTIONAL
913 CHAR16 *VariableName, OPTIONAL
914 UINTN *BufferSize,
915 UINT8 *Buffer
916 )
917 {
918 EFI_STATUS Status;
919 CHAR16 *ConfigHdr;
920 CHAR16 *ConfigResp;
921 CHAR16 *StringPtr;
922 UINTN HeaderLen;
923 UINTN BufferLen;
924 CHAR16 *Progress;
925 EFI_FORM_BROWSER2_PROTOCOL *FormBrowser2;
926 EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
927
928 //
929 // Locate protocols for use
930 //
931 Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &FormBrowser2);
932 if (EFI_ERROR (Status)) {
933 return Status;
934 }
935
936 Status = gBS->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid, NULL, (VOID **) &HiiConfigRouting);
937 if (EFI_ERROR (Status)) {
938 return Status;
939 }
940
941 //
942 // Retrive formset storage data from Form Browser
943 //
944 ConfigHdr = mFakeConfigHdr;
945 HeaderLen = StrLen (ConfigHdr);
946
947 BufferLen = 0x4000;
948 ConfigResp = AllocateZeroPool (BufferLen + HeaderLen);
949
950 StringPtr = ConfigResp + HeaderLen;
951 *StringPtr = L'&';
952 StringPtr++;
953
954 Status = FormBrowser2->BrowserCallback (
955 FormBrowser2,
956 &BufferLen,
957 StringPtr,
958 TRUE,
959 VariableGuid,
960 VariableName
961 );
962 if (Status == EFI_BUFFER_TOO_SMALL) {
963 gBS->FreePool (ConfigResp);
964 ConfigResp = AllocateZeroPool (BufferLen + HeaderLen);
965
966 StringPtr = ConfigResp + HeaderLen;
967 *StringPtr = L'&';
968 StringPtr++;
969
970 Status = FormBrowser2->BrowserCallback (
971 FormBrowser2,
972 &BufferLen,
973 StringPtr,
974 TRUE,
975 VariableGuid,
976 VariableName
977 );
978 }
979 if (EFI_ERROR (Status)) {
980 gBS->FreePool (ConfigResp);
981 return Status;
982 }
983 CopyMem (ConfigResp, ConfigHdr, HeaderLen * sizeof (UINT16));
984
985 //
986 // Convert <ConfigResp> to buffer data
987 //
988 Status = HiiConfigRouting->ConfigToBlock (
989 HiiConfigRouting,
990 ConfigResp,
991 Buffer,
992 BufferSize,
993 &Progress
994 );
995 gBS->FreePool (ConfigResp);
996
997 return Status;
998 }
999
1000
1001 /**
1002 This routine is invoked by ConfigAccess.Callback() to update uncommitted data of Form Browser.
1003
1004 @param VariableGuid An optional field to indicate the target variable
1005 GUID name to use.
1006 @param VariableName An optional field to indicate the target
1007 human-readable variable name.
1008 @param BufferSize Length in bytes of buffer to hold retrived data.
1009 @param Buffer Buffer to hold retrived data.
1010 @param RequestElement An optional field to specify which part of the
1011 buffer data will be send back to Browser. If NULL,
1012 the whole buffer of data will be committed to
1013 Browser. <RequestElement> ::=
1014 &OFFSET=<Number>&WIDTH=<Number>*
1015
1016 @retval EFI_SUCCESS Routine success.
1017 @retval Other Updating Browser uncommitted data failed.
1018
1019 **/
1020 EFI_STATUS
1021 SetBrowserData (
1022 EFI_GUID *VariableGuid, OPTIONAL
1023 CHAR16 *VariableName, OPTIONAL
1024 UINTN BufferSize,
1025 UINT8 *Buffer,
1026 CHAR16 *RequestElement OPTIONAL
1027 )
1028 {
1029 EFI_STATUS Status;
1030 CHAR16 *ConfigHdr;
1031 CHAR16 *ConfigResp;
1032 CHAR16 *StringPtr;
1033 UINTN HeaderLen;
1034 UINTN BufferLen;
1035 CHAR16 *Progress;
1036 EFI_FORM_BROWSER2_PROTOCOL *FormBrowser2;
1037 EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
1038 CHAR16 BlockName[33];
1039 CHAR16 *ConfigRequest;
1040 CHAR16 *Request;
1041
1042 //
1043 // Locate protocols for use
1044 //
1045 Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &FormBrowser2);
1046 if (EFI_ERROR (Status)) {
1047 return Status;
1048 }
1049
1050 Status = gBS->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid, NULL, (VOID **) &HiiConfigRouting);
1051 if (EFI_ERROR (Status)) {
1052 return Status;
1053 }
1054
1055 //
1056 // Prepare <ConfigRequest>
1057 //
1058 ConfigHdr = mFakeConfigHdr;
1059 HeaderLen = StrLen (ConfigHdr);
1060
1061 if (RequestElement == NULL) {
1062 //
1063 // RequestElement not specified, use "&OFFSET=0&WIDTH=<BufferSize>" as <BlockName>
1064 //
1065 BlockName[0] = L'\0';
1066 StrCpy (BlockName, L"&OFFSET=0&WIDTH=");
1067
1068 //
1069 // String lenghth of L"&OFFSET=0&WIDTH=" is 16
1070 //
1071 StringPtr = BlockName + 16;
1072 BufferLen = sizeof (BlockName) - (16 * sizeof (CHAR16));
1073 R8_BufToHexString (StringPtr, &BufferLen, (UINT8 *) &BufferSize, sizeof (UINTN));
1074
1075 Request = BlockName;
1076 } else {
1077 Request = RequestElement;
1078 }
1079
1080 BufferLen = HeaderLen * sizeof (CHAR16) + StrSize (Request);
1081 ConfigRequest = AllocateZeroPool (BufferLen);
1082
1083 CopyMem (ConfigRequest, ConfigHdr, HeaderLen * sizeof (CHAR16));
1084 StringPtr = ConfigRequest + HeaderLen;
1085 StrCpy (StringPtr, Request);
1086
1087 //
1088 // Convert buffer to <ConfigResp>
1089 //
1090 Status = HiiConfigRouting->BlockToConfig (
1091 HiiConfigRouting,
1092 ConfigRequest,
1093 Buffer,
1094 BufferSize,
1095 &ConfigResp,
1096 &Progress
1097 );
1098 if (EFI_ERROR (Status)) {
1099 gBS->FreePool (ConfigResp);
1100 return Status;
1101 }
1102
1103 //
1104 // Skip <ConfigHdr> and '&'
1105 //
1106 StringPtr = ConfigResp + HeaderLen + 1;
1107
1108 //
1109 // Change uncommitted data in Browser
1110 //
1111 Status = FormBrowser2->BrowserCallback (
1112 FormBrowser2,
1113 &BufferSize,
1114 StringPtr,
1115 FALSE,
1116 NULL,
1117 NULL
1118 );
1119 gBS->FreePool (ConfigResp);
1120 return Status;
1121 }