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