]> git.proxmox.com Git - mirror_edk2.git/blob - MdePkg/Library/IfrSupportLib/UefiIfrForm.c
MdePkg/Include/IndustryStandard/Tpm12.h:
[mirror_edk2.git] / MdePkg / 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
77 /**
78 Draw a dialog and return the selected key.
79
80 @param NumberOfLines The number of lines for the dialog box
81 @param KeyValue The EFI_KEY value returned if HotKey is TRUE..
82 @param String Pointer to the first string in the list
83 @param ... A series of (quantity == NumberOfLines) text
84 strings which will be used to construct the dialog
85 box
86
87 @retval EFI_SUCCESS Displayed dialog and received user interaction
88 @retval EFI_INVALID_PARAMETER One of the parameters was invalid.
89
90 **/
91 EFI_STATUS
92 EFIAPI
93 IfrLibCreatePopUp (
94 IN UINTN NumberOfLines,
95 OUT EFI_INPUT_KEY *KeyValue,
96 IN CHAR16 *String,
97 ...
98 )
99 {
100 UINTN Index;
101 UINTN Count;
102 UINTN Start;
103 UINTN Top;
104 CHAR16 *StringPtr;
105 UINTN LeftColumn;
106 UINTN RightColumn;
107 UINTN TopRow;
108 UINTN BottomRow;
109 UINTN DimensionsWidth;
110 UINTN DimensionsHeight;
111 VA_LIST Marker;
112 EFI_INPUT_KEY Key;
113 UINTN LargestString;
114 CHAR16 *StackString;
115 EFI_STATUS Status;
116 UINTN StringLen;
117 CHAR16 *LineBuffer;
118 CHAR16 **StringArray;
119 EFI_EVENT TimerEvent;
120 EFI_EVENT WaitList[2];
121 UINTN CurrentAttribute;
122 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut;
123
124 if ((KeyValue == NULL) || (String == NULL)) {
125 return EFI_INVALID_PARAMETER;
126 }
127
128 TopRow = 0;
129 BottomRow = 0;
130 LeftColumn = 0;
131 RightColumn = 0;
132
133 ConOut = gST->ConOut;
134 ConOut->QueryMode (ConOut, ConOut->Mode->Mode, &RightColumn, &BottomRow);
135
136 DimensionsWidth = RightColumn - LeftColumn;
137 DimensionsHeight = BottomRow - TopRow;
138
139 CurrentAttribute = ConOut->Mode->Attribute;
140
141 LineBuffer = AllocateZeroPool (DimensionsWidth * sizeof (CHAR16));
142 ASSERT (LineBuffer != NULL);
143
144 //
145 // Determine the largest string in the dialog box
146 // Notice we are starting with 1 since String is the first string
147 //
148 StringArray = AllocateZeroPool (NumberOfLines * sizeof (CHAR16 *));
149 LargestString = StrLen (String);
150 StringArray[0] = String;
151
152 VA_START (Marker, String);
153 for (Index = 1; Index < NumberOfLines; Index++) {
154 StackString = VA_ARG (Marker, CHAR16 *);
155
156 if (StackString == NULL) {
157 return EFI_INVALID_PARAMETER;
158 }
159
160 StringArray[Index] = StackString;
161 StringLen = StrLen (StackString);
162 if (StringLen > LargestString) {
163 LargestString = StringLen;
164 }
165 }
166
167 if ((LargestString + 2) > DimensionsWidth) {
168 LargestString = DimensionsWidth - 2;
169 }
170
171 //
172 // Subtract the PopUp width from total Columns, allow for one space extra on
173 // each end plus a border.
174 //
175 Start = (DimensionsWidth - LargestString - 2) / 2 + LeftColumn + 1;
176
177 Top = ((DimensionsHeight - NumberOfLines - 2) / 2) + TopRow - 1;
178
179 //
180 // Disable cursor
181 //
182 ConOut->EnableCursor (ConOut, FALSE);
183 ConOut->SetAttribute (ConOut, EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE);
184
185 StringPtr = &LineBuffer[0];
186 *StringPtr++ = BOXDRAW_DOWN_RIGHT;
187 for (Index = 0; Index < LargestString; Index++) {
188 *StringPtr++ = BOXDRAW_HORIZONTAL;
189 }
190 *StringPtr++ = BOXDRAW_DOWN_LEFT;
191 *StringPtr = L'\0';
192
193 ConOut->SetCursorPosition (ConOut, Start, Top);
194 ConOut->OutputString (ConOut, LineBuffer);
195
196 for (Index = 0; Index < NumberOfLines; Index++) {
197 StringPtr = &LineBuffer[0];
198 *StringPtr++ = BOXDRAW_VERTICAL;
199
200 for (Count = 0; Count < LargestString; Count++) {
201 StringPtr[Count] = L' ';
202 }
203
204 StringLen = StrLen (StringArray[Index]);
205 if (StringLen > LargestString) {
206 StringLen = LargestString;
207 }
208 CopyMem (
209 StringPtr + ((LargestString - StringLen) / 2),
210 StringArray[Index],
211 StringLen * sizeof (CHAR16)
212 );
213 StringPtr += LargestString;
214
215 *StringPtr++ = BOXDRAW_VERTICAL;
216 *StringPtr = L'\0';
217
218 ConOut->SetCursorPosition (ConOut, Start, Top + 1 + Index);
219 ConOut->OutputString (ConOut, LineBuffer);
220 }
221
222 StringPtr = &LineBuffer[0];
223 *StringPtr++ = BOXDRAW_UP_RIGHT;
224 for (Index = 0; Index < LargestString; Index++) {
225 *StringPtr++ = BOXDRAW_HORIZONTAL;
226 }
227 *StringPtr++ = BOXDRAW_UP_LEFT;
228 *StringPtr = L'\0';
229
230 ConOut->SetCursorPosition (ConOut, Start, Top + NumberOfLines + 1);
231 ConOut->OutputString (ConOut, LineBuffer);
232
233 do {
234 Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent);
235
236 //
237 // Set a timer event of 1 second expiration
238 //
239 gBS->SetTimer (
240 TimerEvent,
241 TimerRelative,
242 10000000
243 );
244
245 //
246 // Wait for the keystroke event or the timer
247 //
248 WaitList[0] = gST->ConIn->WaitForKey;
249 WaitList[1] = TimerEvent;
250 Status = gBS->WaitForEvent (2, WaitList, &Index);
251
252 //
253 // Check for the timer expiration
254 //
255 if (!EFI_ERROR (Status) && Index == 1) {
256 Status = EFI_TIMEOUT;
257 }
258
259 gBS->CloseEvent (TimerEvent);
260 } while (Status == EFI_TIMEOUT);
261
262 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
263 CopyMem (KeyValue, &Key, sizeof (EFI_INPUT_KEY));
264
265 ConOut->SetAttribute (ConOut, CurrentAttribute);
266 ConOut->EnableCursor (ConOut, TRUE);
267
268 return Status;
269 }
270
271
272 /**
273 Swap bytes in the buffer.
274
275 @param Buffer Binary buffer.
276 @param BufferSize Size of the buffer in bytes.
277
278 @return None.
279
280 **/
281 STATIC
282 VOID
283 SwapBuffer (
284 IN OUT UINT8 *Buffer,
285 IN UINTN BufferSize
286 )
287 {
288 UINTN Index;
289 UINT8 Temp;
290 UINTN SwapCount;
291
292 SwapCount = (BufferSize - 1) / 2;
293 for (Index = 0; Index < SwapCount; Index++) {
294 Temp = Buffer[Index];
295 Buffer[Index] = Buffer[BufferSize - 1 - Index];
296 Buffer[BufferSize - 1 - Index] = Temp;
297 }
298 }
299
300
301 /**
302 Converts binary buffer to Unicode string in reversed byte order from R8_BufToHexString().
303
304 @param Str String for output
305 @param Buffer Binary buffer.
306 @param BufferSize Size of the buffer in bytes.
307
308 @retval EFI_SUCCESS The function completed successfully.
309
310 **/
311 EFI_STATUS
312 EFIAPI
313 BufferToHexString (
314 IN OUT CHAR16 *Str,
315 IN UINT8 *Buffer,
316 IN UINTN BufferSize
317 )
318 {
319 EFI_STATUS Status;
320 UINT8 *NewBuffer;
321 UINTN StrBufferLen;
322
323 NewBuffer = AllocateCopyPool (BufferSize, Buffer);
324 SwapBuffer (NewBuffer, BufferSize);
325
326 StrBufferLen = (BufferSize + 1) * sizeof (CHAR16);
327 Status = R8_BufToHexString (Str, &StrBufferLen, NewBuffer, BufferSize);
328
329 gBS->FreePool (NewBuffer);
330
331 return Status;
332 }
333
334
335 /**
336 Converts Hex String to binary buffer in reversed byte order from R8_HexStringToBuf().
337
338 @param Buffer Pointer to buffer that receives the data.
339 @param BufferSize Length in bytes of the buffer to hold converted
340 data. If routine return with EFI_SUCCESS,
341 containing length of converted data. If routine
342 return with EFI_BUFFER_TOO_SMALL, containg length
343 of buffer desired.
344 @param Str String to be converted from.
345
346 @retval EFI_SUCCESS The function completed successfully.
347
348 **/
349 EFI_STATUS
350 EFIAPI
351 HexStringToBuffer (
352 IN OUT UINT8 *Buffer,
353 IN OUT UINTN *BufferSize,
354 IN CHAR16 *Str
355 )
356 {
357 EFI_STATUS Status;
358 UINTN ConvertedStrLen;
359
360 ConvertedStrLen = 0;
361 Status = R8_HexStringToBuf (Buffer, BufferSize, Str, &ConvertedStrLen);
362 if (!EFI_ERROR (Status)) {
363 SwapBuffer (Buffer, ConvertedStrLen);
364 }
365
366 return Status;
367 }
368
369
370 /**
371 Construct <ConfigHdr> using routing information GUID/NAME/PATH.
372
373 @param ConfigHdr Pointer to the ConfigHdr string.
374 @param StrBufferLen On input: Length in bytes of buffer to hold the
375 ConfigHdr string. Includes tailing '\0' character.
376 On output: If return EFI_SUCCESS, containing
377 length of ConfigHdr string buffer. If return
378 EFI_BUFFER_TOO_SMALL, containg length of string
379 buffer desired.
380 @param Guid Routing information: GUID.
381 @param Name Routing information: NAME.
382 @param DriverHandle Driver handle which contains the routing
383 information: PATH.
384
385 @retval EFI_SUCCESS Routine success.
386 @retval EFI_BUFFER_TOO_SMALL The ConfigHdr string buffer is too small.
387
388 **/
389 EFI_STATUS
390 EFIAPI
391 ConstructConfigHdr (
392 IN OUT CHAR16 *ConfigHdr,
393 IN OUT UINTN *StrBufferLen,
394 IN EFI_GUID *Guid,
395 IN CHAR16 *Name, OPTIONAL
396 IN EFI_HANDLE *DriverHandle
397 )
398 {
399 EFI_STATUS Status;
400 UINTN NameStrLen;
401 UINTN DevicePathSize;
402 UINTN BufferSize;
403 CHAR16 *StrPtr;
404 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
405
406 if (Name == NULL) {
407 //
408 // There will be no "NAME" in <ConfigHdr> for Name/Value storage
409 //
410 NameStrLen = 0;
411 } else {
412 //
413 // For buffer storage
414 //
415 NameStrLen = StrLen (Name);
416 }
417
418 //
419 // Retrieve DevicePath Protocol associated with this HiiPackageList
420 //
421 Status = gBS->HandleProtocol (
422 DriverHandle,
423 &gEfiDevicePathProtocolGuid,
424 (VOID **) &DevicePath
425 );
426 if (EFI_ERROR (Status)) {
427 return Status;
428 }
429
430 DevicePathSize = GetDevicePathSize (DevicePath);
431
432 //
433 // GUID=<HexCh>32&NAME=<Alpha>NameStrLen&PATH=<HexChar>DevicePathStrLen <NULL>
434 // | 5 | 32 | 6 | NameStrLen | 6 | DevicePathStrLen |
435 //
436 BufferSize = (5 + 32 + 6 + NameStrLen + 6 + DevicePathSize * 2 + 1) * sizeof (CHAR16);
437 if (*StrBufferLen < BufferSize) {
438 *StrBufferLen = BufferSize;
439 return EFI_BUFFER_TOO_SMALL;
440 }
441
442 *StrBufferLen = BufferSize;
443
444 StrPtr = ConfigHdr;
445
446 StrCpy (StrPtr, L"GUID=");
447 StrPtr += 5;
448 BufferToHexString (StrPtr, (UINT8 *) Guid, sizeof (EFI_GUID));
449 StrPtr += 32;
450
451 StrCpy (StrPtr, L"&NAME=");
452 StrPtr += 6;
453 if (Name != NULL) {
454 StrCpy (StrPtr, Name);
455 StrPtr += NameStrLen;
456 }
457
458 StrCpy (StrPtr, L"&PATH=");
459 StrPtr += 6;
460 BufferToHexString (StrPtr, (UINT8 *) DevicePath, DevicePathSize);
461
462 return EFI_SUCCESS;
463 }
464
465
466 /**
467 Search BlockName "&OFFSET=Offset&WIDTH=Width" in a string.
468
469 @param String The string to be searched in.
470 @param Offset Offset in BlockName.
471 @param Width Width in BlockName.
472
473 @retval TRUE Block name found.
474 @retval FALSE Block name not found.
475
476 **/
477 BOOLEAN
478 FindBlockName (
479 IN OUT CHAR16 *String,
480 UINTN Offset,
481 UINTN Width
482 )
483 {
484 EFI_STATUS Status;
485 UINTN Data;
486 UINTN BufferSize;
487 UINTN ConvertedStrLen;
488
489 while ((String = StrStr (String, L"&OFFSET=")) != NULL) {
490 //
491 // Skip '&OFFSET='
492 //
493 String = String + 8;
494
495 Data = 0;
496 BufferSize = sizeof (UINTN);
497 Status = R8_HexStringToBuf ((UINT8 *) &Data, &BufferSize, String, &ConvertedStrLen);
498 if (EFI_ERROR (Status)) {
499 return FALSE;
500 }
501 String = String + ConvertedStrLen;
502
503 if (Data != Offset) {
504 continue;
505 }
506
507 if (StrnCmp (String, L"&WIDTH=", 7) != 0) {
508 return FALSE;
509 }
510 String = String + 7;
511
512 Data = 0;
513 BufferSize = sizeof (UINTN);
514 Status = R8_HexStringToBuf ((UINT8 *) &Data, &BufferSize, String, &ConvertedStrLen);
515 if (EFI_ERROR (Status)) {
516 return FALSE;
517 }
518 if (Data == Width) {
519 return TRUE;
520 }
521
522 String = String + ConvertedStrLen;
523 }
524
525 return FALSE;
526 }
527
528
529 /**
530 This routine is invoked by ConfigAccess.Callback() to retrived uncommitted data from Form Browser.
531
532 @param VariableGuid An optional field to indicate the target variable
533 GUID name to use.
534 @param VariableName An optional field to indicate the target
535 human-readable variable name.
536 @param BufferSize On input: Length in bytes of buffer to hold
537 retrived data. On output: If return
538 EFI_BUFFER_TOO_SMALL, containg length of buffer
539 desired.
540 @param Buffer Buffer to hold retrived data.
541
542 @retval EFI_SUCCESS Routine success.
543 @retval EFI_BUFFER_TOO_SMALL The intput buffer is too small.
544
545 **/
546 EFI_STATUS
547 EFIAPI
548 GetBrowserData (
549 EFI_GUID *VariableGuid, OPTIONAL
550 CHAR16 *VariableName, OPTIONAL
551 UINTN *BufferSize,
552 UINT8 *Buffer
553 )
554 {
555 EFI_STATUS Status;
556 CHAR16 *ConfigHdr;
557 CHAR16 *ConfigResp;
558 CHAR16 *StringPtr;
559 UINTN HeaderLen;
560 UINTN BufferLen;
561 CHAR16 *Progress;
562 EFI_FORM_BROWSER2_PROTOCOL *FormBrowser2;
563 EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
564
565 //
566 // Locate protocols for use
567 //
568 Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &FormBrowser2);
569 if (EFI_ERROR (Status)) {
570 return Status;
571 }
572
573 Status = gBS->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid, NULL, (VOID **) &HiiConfigRouting);
574 if (EFI_ERROR (Status)) {
575 return Status;
576 }
577
578 //
579 // Retrive formset storage data from Form Browser
580 //
581 ConfigHdr = mFakeConfigHdr;
582 HeaderLen = StrLen (ConfigHdr);
583
584 BufferLen = 0x4000;
585 ConfigResp = AllocateZeroPool (BufferLen + HeaderLen);
586
587 StringPtr = ConfigResp + HeaderLen;
588 *StringPtr = L'&';
589 StringPtr++;
590
591 Status = FormBrowser2->BrowserCallback (
592 FormBrowser2,
593 &BufferLen,
594 StringPtr,
595 TRUE,
596 VariableGuid,
597 VariableName
598 );
599 if (Status == EFI_BUFFER_TOO_SMALL) {
600 gBS->FreePool (ConfigResp);
601 ConfigResp = AllocateZeroPool (BufferLen + HeaderLen);
602
603 StringPtr = ConfigResp + HeaderLen;
604 *StringPtr = L'&';
605 StringPtr++;
606
607 Status = FormBrowser2->BrowserCallback (
608 FormBrowser2,
609 &BufferLen,
610 StringPtr,
611 TRUE,
612 VariableGuid,
613 VariableName
614 );
615 }
616 if (EFI_ERROR (Status)) {
617 gBS->FreePool (ConfigResp);
618 return Status;
619 }
620 CopyMem (ConfigResp, ConfigHdr, HeaderLen * sizeof (UINT16));
621
622 //
623 // Convert <ConfigResp> to buffer data
624 //
625 Status = HiiConfigRouting->ConfigToBlock (
626 HiiConfigRouting,
627 ConfigResp,
628 Buffer,
629 BufferSize,
630 &Progress
631 );
632 gBS->FreePool (ConfigResp);
633
634 return Status;
635 }
636
637
638 /**
639 This routine is invoked by ConfigAccess.Callback() to update uncommitted data of Form Browser.
640
641 @param VariableGuid An optional field to indicate the target variable
642 GUID name to use.
643 @param VariableName An optional field to indicate the target
644 human-readable variable name.
645 @param BufferSize Length in bytes of buffer to hold retrived data.
646 @param Buffer Buffer to hold retrived data.
647 @param RequestElement An optional field to specify which part of the
648 buffer data will be send back to Browser. If NULL,
649 the whole buffer of data will be committed to
650 Browser. <RequestElement> ::=
651 &OFFSET=<Number>&WIDTH=<Number>*
652
653 @retval EFI_SUCCESS Routine success.
654 @retval Other Updating Browser uncommitted data failed.
655
656 **/
657 EFI_STATUS
658 EFIAPI
659 SetBrowserData (
660 EFI_GUID *VariableGuid, OPTIONAL
661 CHAR16 *VariableName, OPTIONAL
662 UINTN BufferSize,
663 UINT8 *Buffer,
664 CHAR16 *RequestElement OPTIONAL
665 )
666 {
667 EFI_STATUS Status;
668 CHAR16 *ConfigHdr;
669 CHAR16 *ConfigResp;
670 CHAR16 *StringPtr;
671 UINTN HeaderLen;
672 UINTN BufferLen;
673 CHAR16 *Progress;
674 EFI_FORM_BROWSER2_PROTOCOL *FormBrowser2;
675 EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
676 CHAR16 BlockName[33];
677 CHAR16 *ConfigRequest;
678 CHAR16 *Request;
679
680 //
681 // Locate protocols for use
682 //
683 Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &FormBrowser2);
684 if (EFI_ERROR (Status)) {
685 return Status;
686 }
687
688 Status = gBS->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid, NULL, (VOID **) &HiiConfigRouting);
689 if (EFI_ERROR (Status)) {
690 return Status;
691 }
692
693 //
694 // Prepare <ConfigRequest>
695 //
696 ConfigHdr = mFakeConfigHdr;
697 HeaderLen = StrLen (ConfigHdr);
698
699 if (RequestElement == NULL) {
700 //
701 // RequestElement not specified, use "&OFFSET=0&WIDTH=<BufferSize>" as <BlockName>
702 //
703 BlockName[0] = L'\0';
704 StrCpy (BlockName, L"&OFFSET=0&WIDTH=");
705
706 //
707 // String lenghth of L"&OFFSET=0&WIDTH=" is 16
708 //
709 StringPtr = BlockName + 16;
710 BufferLen = sizeof (BlockName) - (16 * sizeof (CHAR16));
711 R8_BufToHexString (StringPtr, &BufferLen, (UINT8 *) &BufferSize, sizeof (UINTN));
712
713 Request = BlockName;
714 } else {
715 Request = RequestElement;
716 }
717
718 BufferLen = HeaderLen * sizeof (CHAR16) + StrSize (Request);
719 ConfigRequest = AllocateZeroPool (BufferLen);
720
721 CopyMem (ConfigRequest, ConfigHdr, HeaderLen * sizeof (CHAR16));
722 StringPtr = ConfigRequest + HeaderLen;
723 StrCpy (StringPtr, Request);
724
725 //
726 // Convert buffer to <ConfigResp>
727 //
728 Status = HiiConfigRouting->BlockToConfig (
729 HiiConfigRouting,
730 ConfigRequest,
731 Buffer,
732 BufferSize,
733 &ConfigResp,
734 &Progress
735 );
736 if (EFI_ERROR (Status)) {
737 gBS->FreePool (ConfigResp);
738 return Status;
739 }
740
741 //
742 // Skip <ConfigHdr> and '&'
743 //
744 StringPtr = ConfigResp + HeaderLen + 1;
745
746 //
747 // Change uncommitted data in Browser
748 //
749 Status = FormBrowser2->BrowserCallback (
750 FormBrowser2,
751 &BufferSize,
752 StringPtr,
753 FALSE,
754 NULL,
755 NULL
756 );
757 gBS->FreePool (ConfigResp);
758 return Status;
759 }