]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/HiiDatabaseDxe/ConfigRouting.c
Apply GetBestLanguage() for the implementation of HiiStringIdToImage() API.
[mirror_edk2.git] / MdeModulePkg / Universal / HiiDatabaseDxe / ConfigRouting.c
1 /** @file
2 Implementation of interfaces function for EFI_HII_CONFIG_ROUTING_PROTOCOL.
3
4 Copyright (c) 2007 - 2008, Intel Corporation
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15
16 #include "HiiDatabase.h"
17
18 /**
19 Calculate the number of Unicode characters of the incoming Configuration string,
20 not including NULL terminator.
21
22 This is a internal function.
23
24 @param String String in <MultiConfigRequest> or
25 <MultiConfigResp> format.
26
27 @return The number of Unicode characters.
28
29 **/
30 UINTN
31 CalculateConfigStringLen (
32 IN EFI_STRING String
33 )
34 {
35 UINTN Length;
36
37 //
38 // "GUID=" should be the first element of incoming string.
39 //
40 ASSERT (String != NULL);
41 ASSERT (StrnCmp (String, L"GUID=", StrLen (L"GUID=")) == 0);
42
43 Length = StrLen (L"GUID=");
44 String += Length;
45
46 //
47 // The beginning of next <ConfigRequest>/<ConfigResp> should be "&GUID=".
48 // Will meet '\0' if there is only one <ConfigRequest>/<ConfigResp>.
49 //
50 while (*String != 0 && StrnCmp (String, L"&GUID=", StrLen (L"&GUID=")) != 0) {
51 Length++;
52 String++;
53 }
54
55 return Length;
56 }
57
58
59 /**
60 Convert the hex UNICODE %02x encoding of a UEFI device path to binary
61 from <PathHdr> of <ConfigHdr>.
62
63 This is a internal function.
64
65 @param String UEFI configuration string
66 @param DevicePath binary of a UEFI device path.
67
68 @retval EFI_INVALID_PARAMETER Any incoming parameter is invalid.
69 @retval EFI_OUT_OF_RESOURCES Lake of resources to store neccesary structures.
70 @retval EFI_SUCCESS The device path is retrieved and translated to
71 binary format.
72
73 **/
74 EFI_STATUS
75 GetDevicePath (
76 IN EFI_STRING String,
77 OUT UINT8 **DevicePath
78 )
79 {
80 UINTN Length;
81 EFI_STRING PathHdr;
82 EFI_STRING DevicePathString;
83
84 if (String == NULL || DevicePath == NULL) {
85 return EFI_INVALID_PARAMETER;
86 }
87
88 //
89 // Find the 'PATH=' of <PathHdr> and skip it.
90 //
91 for (; (*String != 0 && StrnCmp (String, L"PATH=", StrLen (L"PATH=")) != 0); String++);
92 if (*String == 0) {
93 return EFI_INVALID_PARAMETER;
94 }
95
96 String += StrLen (L"PATH=");
97 PathHdr = String;
98
99 //
100 // The content between 'PATH=' of <ConfigHdr> and '&' of next element
101 // or '\0' (end of configuration string) is the UNICODE %02x bytes encoding
102 // of UEFI device path.
103 //
104 for (Length = 0; *String != 0 && *String != L'&'; String++, Length++);
105 DevicePathString = (EFI_STRING) AllocateZeroPool ((Length + 1) * sizeof (CHAR16));
106 if (DevicePathString == NULL) {
107 return EFI_OUT_OF_RESOURCES;
108 }
109 StrnCpy (DevicePathString, PathHdr, Length);
110 *(DevicePathString + Length) = 0;
111
112 //
113 // The data in <PathHdr> is encoded as hex UNICODE %02x bytes in the same order
114 // as the device path resides in RAM memory.
115 // Translate the data into binary.
116 //
117 Length /= 2;
118 *DevicePath = (UINT8 *) AllocateZeroPool (Length);
119 if (*DevicePath == NULL) {
120 FreePool (DevicePathString);
121 return EFI_OUT_OF_RESOURCES;
122 }
123
124 HexStringToBufInReverseOrder (*DevicePath, &Length, DevicePathString);
125
126 FreePool (DevicePathString);
127
128 return EFI_SUCCESS;
129
130 }
131
132
133 /**
134 Generate a sub string then output it.
135
136 This is a internal function.
137
138 @param String A constant string which is the prefix of the to be
139 generated string, e.g. GUID=
140 @param BufferLen The length of the Buffer in bytes.
141 @param Buffer Points to a buffer which will be converted to be the
142 content of the generated string.
143 @param Flag If 1, the buffer contains data for the value of GUID or PATH stored in
144 UINT8 *; if 2, the buffer contains unicode string for the value of NAME;
145 if 3, the buffer contains other data.
146 @param SubStr Points to the output string. It's caller's
147 responsibility to free this buffer.
148
149
150 **/
151 VOID
152 GenerateSubStr (
153 IN CONST EFI_STRING String,
154 IN UINTN BufferLen,
155 IN VOID *Buffer,
156 IN UINT8 Flag,
157 OUT EFI_STRING *SubStr
158 )
159 {
160 UINTN Length;
161 EFI_STRING Str;
162 EFI_STATUS Status;
163 EFI_STRING StringHeader;
164
165 ASSERT (String != NULL && SubStr != NULL);
166
167 if (Buffer == NULL) {
168 *SubStr = AllocateCopyPool (StrSize (String), String);
169 ASSERT (*SubStr != NULL);
170 return ;
171 }
172
173 Length = StrLen (String) + BufferLen * 2 + 1 + 1;
174 Str = AllocateZeroPool (Length * sizeof (CHAR16));
175 ASSERT (Str != NULL);
176
177 StrCpy (Str, String);
178 Length = (BufferLen * 2 + 1) * sizeof (CHAR16);
179
180 Status = EFI_SUCCESS;
181 StringHeader = Str + StrLen (String);
182
183 switch (Flag) {
184 case 1:
185 Status = BufInReverseOrderToHexString (StringHeader, (UINT8 *) Buffer, BufferLen);
186 break;
187 case 2:
188 Status = UnicodeToConfigString (StringHeader, &Length, (CHAR16 *) Buffer);
189 break;
190 case 3:
191 Status = BufToHexString (StringHeader, &Length, (UINT8 *) Buffer, BufferLen);
192 //
193 // Convert the uppercase to lowercase since <HexAf> is defined in lowercase format.
194 //
195 ToLower (StringHeader);
196 break;
197 default:
198 break;
199 }
200
201 ASSERT_EFI_ERROR (Status);
202 StrCat (Str, L"&");
203
204 *SubStr = Str;
205 }
206
207
208 /**
209 Retrieve the <ConfigBody> from String then output it.
210
211 This is a internal function.
212
213 @param String A sub string of a configuration string in
214 <MultiConfigAltResp> format.
215 @param ConfigBody Points to the output string. It's caller's
216 responsibility to free this buffer.
217
218 @retval EFI_INVALID_PARAMETER There is no form package in current hii database.
219 @retval EFI_OUT_OF_RESOURCES Not enough memory to finish this operation.
220 @retval EFI_SUCCESS All existing storage is exported.
221
222 **/
223 EFI_STATUS
224 OutputConfigBody (
225 IN EFI_STRING String,
226 OUT EFI_STRING *ConfigBody
227 )
228 {
229 EFI_STRING TmpPtr;
230 EFI_STRING Result;
231 UINTN Length;
232
233 if (String == NULL || ConfigBody == NULL) {
234 return EFI_INVALID_PARAMETER;
235 }
236
237 TmpPtr = StrStr (String, L"GUID=");
238 if (TmpPtr == NULL) {
239 //
240 // It is the last <ConfigResp> of the incoming configuration string.
241 //
242 Result = AllocateCopyPool (StrSize (String), String);
243 if (Result == NULL) {
244 return EFI_OUT_OF_RESOURCES;
245 } else {
246 *ConfigBody = Result;
247 return EFI_SUCCESS;
248 }
249 }
250
251 Length = TmpPtr - String;
252 Result = AllocateCopyPool (Length * sizeof (CHAR16), String);
253 if (Result == NULL) {
254 return EFI_OUT_OF_RESOURCES;
255 }
256
257 *(Result + Length - 1) = 0;
258 *ConfigBody = Result;
259 return EFI_SUCCESS;
260
261 }
262
263 /**
264 Append a string to a multi-string format.
265
266 This is a internal function.
267
268 @param MultiString String in <MultiConfigRequest>,
269 <MultiConfigAltResp>, or <MultiConfigResp>. On
270 input, the buffer length of this string is
271 MAX_STRING_LENGTH. On output, the buffer length
272 might be updated.
273 @param AppendString NULL-terminated Unicode string.
274
275 @retval EFI_INVALID_PARAMETER Any incoming parameter is invalid.
276 @retval EFI_SUCCESS AppendString is append to the end of MultiString
277
278 **/
279 EFI_STATUS
280 AppendToMultiString (
281 IN OUT EFI_STRING *MultiString,
282 IN EFI_STRING AppendString
283 )
284 {
285 UINTN AppendStringSize;
286 UINTN MultiStringSize;
287
288 if (MultiString == NULL || *MultiString == NULL || AppendString == NULL) {
289 return EFI_INVALID_PARAMETER;
290 }
291
292 AppendStringSize = StrSize (AppendString);
293 MultiStringSize = StrSize (*MultiString);
294
295 //
296 // Enlarge the buffer each time when length exceeds MAX_STRING_LENGTH.
297 //
298 if (MultiStringSize + AppendStringSize > MAX_STRING_LENGTH ||
299 MultiStringSize > MAX_STRING_LENGTH) {
300 *MultiString = (EFI_STRING) ReallocatePool (
301 MultiStringSize,
302 MultiStringSize + AppendStringSize,
303 (VOID *) (*MultiString)
304 );
305 ASSERT (*MultiString != NULL);
306 }
307 //
308 // Append the incoming string
309 //
310 StrCat (*MultiString, AppendString);
311
312 return EFI_SUCCESS;
313 }
314
315
316 /**
317 Get the value of <Number> in <BlockConfig> format, i.e. the value of OFFSET
318 or WIDTH or VALUE.
319 <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE'=<Number>
320
321 This is a internal function.
322
323 @param StringPtr String in <BlockConfig> format and points to the
324 first character of <Number>.
325 @param Number The output value. Caller takes the responsibility
326 to free memory.
327 @param Len Length of the <Number>, in characters.
328
329 @retval EFI_OUT_OF_RESOURCES Insufficient resources to store neccessary
330 structures.
331 @retval EFI_SUCCESS Value of <Number> is outputted in Number
332 successfully.
333
334 **/
335 EFI_STATUS
336 GetValueOfNumber (
337 IN EFI_STRING StringPtr,
338 OUT UINT8 **Number,
339 OUT UINTN *Len
340 )
341 {
342 EFI_STRING TmpPtr;
343 UINTN Length;
344 EFI_STRING Str;
345 UINT8 *Buf;
346 EFI_STATUS Status;
347
348 ASSERT (StringPtr != NULL && Number != NULL && Len != NULL);
349 ASSERT (*StringPtr != 0);
350
351 Buf = NULL;
352
353 TmpPtr = StringPtr;
354 while (*StringPtr != 0 && *StringPtr != L'&') {
355 StringPtr++;
356 }
357 *Len = StringPtr - TmpPtr;
358 Length = *Len + 1;
359
360 Str = (EFI_STRING) AllocateZeroPool (Length * sizeof (EFI_STRING));
361 if (Str == NULL) {
362 Status = EFI_OUT_OF_RESOURCES;
363 goto Exit;
364 }
365 CopyMem (Str, TmpPtr, *Len * sizeof (CHAR16));
366 *(Str + *Len) = 0;
367
368 Length = (Length + 1) / 2;
369 Buf = (UINT8 *) AllocateZeroPool (Length);
370 if (Buf == NULL) {
371 Status = EFI_OUT_OF_RESOURCES;
372 goto Exit;
373 }
374
375 Status = HexStringToBuf (Buf, &Length, Str, NULL);
376 if (EFI_ERROR (Status)) {
377 goto Exit;
378 }
379
380 *Number = Buf;
381 Status = EFI_SUCCESS;
382
383 Exit:
384 if (Str != NULL) {
385 FreePool (Str);
386 }
387 return Status;
388 }
389
390
391 /**
392 This function allows a caller to extract the current configuration
393 for one or more named elements from one or more drivers.
394
395 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
396 instance.
397 @param Request A null-terminated Unicode string in
398 <MultiConfigRequest> format.
399 @param Progress On return, points to a character in the Request
400 string. Points to the string's null terminator if
401 request was successful. Points to the most recent
402 & before the first failing name / value pair (or
403 the beginning of the string if the failure is in
404 the first name / value pair) if the request was
405 not successful.
406 @param Results Null-terminated Unicode string in
407 <MultiConfigAltResp> format which has all values
408 filled in for the names in the Request string.
409 String to be allocated by the called function.
410
411 @retval EFI_SUCCESS The Results string is filled with the values
412 corresponding to all requested names.
413 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
414 results that must be stored awaiting possible
415 future protocols.
416 @retval EFI_NOT_FOUND Routing data doesn't match any known driver.
417 Progress set to the "G" in "GUID" of the routing
418 header that doesn't match. Note: There is no
419 requirement that all routing data be validated
420 before any configuration extraction.
421 @retval EFI_INVALID_PARAMETER For example, passing in a NULL for the Request
422 parameter would result in this type of error. The
423 Progress parameter is set to NULL.
424 @retval EFI_INVALID_PARAMETER Illegal syntax. Progress set to most recent &
425 before the error or the beginning of the string.
426 @retval EFI_INVALID_PARAMETER Unknown name. Progress points to the & before the
427 name in question.
428
429 **/
430 EFI_STATUS
431 EFIAPI
432 HiiConfigRoutingExtractConfig (
433 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
434 IN CONST EFI_STRING Request,
435 OUT EFI_STRING *Progress,
436 OUT EFI_STRING *Results
437 )
438 {
439 HII_DATABASE_PRIVATE_DATA *Private;
440 EFI_STRING StringPtr;
441 EFI_STRING ConfigRequest;
442 UINTN Length;
443 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
444 EFI_STATUS Status;
445 LIST_ENTRY *Link;
446 HII_DATABASE_RECORD *Database;
447 UINT8 *DevicePathPkg;
448 UINT8 *CurrentDevicePath;
449 EFI_HANDLE DriverHandle;
450 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
451 EFI_STRING AccessProgress;
452 EFI_STRING AccessResults;
453 BOOLEAN FirstElement;
454
455 if (This == NULL || Progress == NULL || Results == NULL) {
456 return EFI_INVALID_PARAMETER;
457 }
458
459 if (Request == NULL) {
460 *Progress = NULL;
461 return EFI_INVALID_PARAMETER;
462 }
463
464 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
465 StringPtr = Request;
466 *Progress = StringPtr;
467
468 //
469 // The first element of <MultiConfigRequest> should be
470 // <GuidHdr>, which is in 'GUID='<Guid> syntax.
471 //
472 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
473 return EFI_INVALID_PARAMETER;
474 }
475
476 FirstElement = TRUE;
477
478 //
479 // Allocate a fix length of memory to store Results. Reallocate memory for
480 // Results if this fix length is insufficient.
481 //
482 *Results = (EFI_STRING) AllocateZeroPool (MAX_STRING_LENGTH);
483 if (*Results == NULL) {
484 return EFI_OUT_OF_RESOURCES;
485 }
486
487 while (*StringPtr != 0 && StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) == 0) {
488 //
489 // If parsing error, set Progress to the beginning of the <MultiConfigRequest>
490 // or most recent & before the error.
491 //
492 if (StringPtr == Request) {
493 *Progress = StringPtr;
494 } else {
495 *Progress = StringPtr - 1;
496 }
497
498 //
499 // Process each <ConfigRequest> of <MultiConfigRequest>
500 //
501 Length = CalculateConfigStringLen (StringPtr);
502 ConfigRequest = AllocateCopyPool ((Length + 1) * sizeof (CHAR16), StringPtr);
503 if (ConfigRequest == NULL) {
504 return EFI_OUT_OF_RESOURCES;
505 }
506 *(ConfigRequest + Length) = 0;
507
508 //
509 // Get the UEFI device path
510 //
511 Status = GetDevicePath (ConfigRequest, (UINT8 **) &DevicePath);
512 if (EFI_ERROR (Status)) {
513 FreePool (ConfigRequest);
514 return Status;
515 }
516
517 //
518 // Find driver which matches the routing data.
519 //
520 DriverHandle = NULL;
521 for (Link = Private->DatabaseList.ForwardLink;
522 Link != &Private->DatabaseList;
523 Link = Link->ForwardLink
524 ) {
525 Database = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
526
527 if ((DevicePathPkg = Database->PackageList->DevicePathPkg) != NULL) {
528 CurrentDevicePath = DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER);
529 if (CompareMem (
530 DevicePath,
531 CurrentDevicePath,
532 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) CurrentDevicePath)
533 ) == 0) {
534 DriverHandle = Database->DriverHandle;
535 break;
536 }
537 }
538 }
539
540 FreePool (DevicePath);
541
542 if (DriverHandle == NULL) {
543 //
544 // Routing data does not match any known driver.
545 // Set Progress to the 'G' in "GUID" of the routing header.
546 //
547 *Progress = StringPtr;
548 FreePool (ConfigRequest);
549 return EFI_NOT_FOUND;
550 }
551
552 //
553 // Call corresponding ConfigAccess protocol to extract settings
554 //
555 Status = gBS->HandleProtocol (
556 DriverHandle,
557 &gEfiHiiConfigAccessProtocolGuid,
558 (VOID **) &ConfigAccess
559 );
560 ASSERT_EFI_ERROR (Status);
561
562 Status = ConfigAccess->ExtractConfig (
563 ConfigAccess,
564 ConfigRequest,
565 &AccessProgress,
566 &AccessResults
567 );
568 if (EFI_ERROR (Status)) {
569 //
570 // AccessProgress indicates the parsing progress on <ConfigRequest>.
571 // Map it to the progress on <MultiConfigRequest> then return it.
572 //
573 *Progress = StrStr (StringPtr, AccessProgress);
574 FreePool (ConfigRequest);
575 return Status;
576 }
577
578 //
579 // Attach this <ConfigAltResp> to a <MultiConfigAltResp>. There is a '&'
580 // which seperates the first <ConfigAltResp> and the following ones.
581 //
582 ASSERT (*AccessProgress == 0);
583
584 if (!FirstElement) {
585 Status = AppendToMultiString (Results, L"&");
586 ASSERT_EFI_ERROR (Status);
587 }
588
589 Status = AppendToMultiString (Results, AccessResults);
590 ASSERT_EFI_ERROR (Status);
591
592 FirstElement = FALSE;
593
594 FreePool (AccessResults);
595 AccessResults = NULL;
596 FreePool (ConfigRequest);
597 ConfigRequest = NULL;
598
599 //
600 // Go to next <ConfigRequest> (skip '&').
601 //
602 StringPtr += Length;
603 if (*StringPtr == 0) {
604 *Progress = StringPtr;
605 break;
606 }
607
608 StringPtr++;
609
610 }
611
612 return EFI_SUCCESS;
613
614 }
615
616
617 /**
618 This function allows the caller to request the current configuration for the
619 entirety of the current HII database and returns the data in a
620 null-terminated Unicode string.
621
622 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
623 instance.
624 @param Results Null-terminated Unicode string in
625 <MultiConfigAltResp> format which has all values
626 filled in for the names in the Request string.
627 String to be allocated by the called function.
628 De-allocation is up to the caller.
629
630 @retval EFI_SUCCESS The Results string is filled with the values
631 corresponding to all requested names.
632 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
633 results that must be stored awaiting possible
634 future protocols.
635 @retval EFI_INVALID_PARAMETER For example, passing in a NULL for the Results
636 parameter would result in this type of error.
637
638 **/
639 EFI_STATUS
640 EFIAPI
641 HiiConfigRoutingExportConfig (
642 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
643 OUT EFI_STRING *Results
644 )
645 {
646 EFI_STATUS Status;
647 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
648 EFI_STRING AccessResults;
649 UINTN Index;
650 EFI_HANDLE *ConfigAccessHandles;
651 UINTN NumberConfigAccessHandles;
652 BOOLEAN FirstElement;
653
654 if (This == NULL || Results == NULL) {
655 return EFI_INVALID_PARAMETER;
656 }
657
658 //
659 // Allocate a fix length of memory to store Results. Reallocate memory for
660 // Results if this fix length is insufficient.
661 //
662 *Results = (EFI_STRING) AllocateZeroPool (MAX_STRING_LENGTH);
663 if (*Results == NULL) {
664 return EFI_OUT_OF_RESOURCES;
665 }
666
667 NumberConfigAccessHandles = 0;
668 Status = gBS->LocateHandleBuffer (
669 ByProtocol,
670 &gEfiHiiConfigAccessProtocolGuid,
671 NULL,
672 &NumberConfigAccessHandles,
673 &ConfigAccessHandles
674 );
675 if (EFI_ERROR (Status)) {
676 return Status;
677 }
678
679 FirstElement = TRUE;
680
681 for (Index = 0; Index < NumberConfigAccessHandles; Index++) {
682 Status = gBS->HandleProtocol (
683 ConfigAccessHandles[Index],
684 &gEfiHiiConfigAccessProtocolGuid,
685 (VOID **) &ConfigAccess
686 );
687 if (EFI_ERROR (Status)) {
688 continue;
689 }
690
691 Status = ConfigAccess->ExtractConfig (
692 ConfigAccess,
693 NULL,
694 NULL,
695 &AccessResults
696 );
697 if (!EFI_ERROR (Status)) {
698 //
699 // Attach this <ConfigAltResp> to a <MultiConfigAltResp>. There is a '&'
700 // which seperates the first <ConfigAltResp> and the following ones.
701 //
702 if (!FirstElement) {
703 Status = AppendToMultiString (Results, L"&");
704 ASSERT_EFI_ERROR (Status);
705 }
706
707 Status = AppendToMultiString (Results, AccessResults);
708 ASSERT_EFI_ERROR (Status);
709
710 FirstElement = FALSE;
711
712 FreePool (AccessResults);
713 AccessResults = NULL;
714 }
715 }
716 FreePool (ConfigAccessHandles);
717
718 return EFI_SUCCESS;
719 }
720
721
722 /**
723 This function processes the results of processing forms and routes it to the
724 appropriate handlers or storage.
725
726 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
727 instance.
728 @param Configuration A null-terminated Unicode string in
729 <MulltiConfigResp> format.
730 @param Progress A pointer to a string filled in with the offset of
731 the most recent & before the first failing name /
732 value pair (or the beginning of the string if the
733 failure is in the first name / value pair) or the
734 terminating NULL if all was successful.
735
736 @retval EFI_SUCCESS The results have been distributed or are awaiting
737 distribution.
738 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
739 results that must be stored awaiting possible
740 future protocols.
741 @retval EFI_INVALID_PARAMETER Passing in a NULL for the Configuration parameter
742 would result in this type of error.
743 @retval EFI_NOT_FOUND Target for the specified routing data was not
744 found.
745
746 **/
747 EFI_STATUS
748 EFIAPI
749 HiiConfigRoutingRouteConfig (
750 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
751 IN CONST EFI_STRING Configuration,
752 OUT EFI_STRING *Progress
753 )
754 {
755 HII_DATABASE_PRIVATE_DATA *Private;
756 EFI_STRING StringPtr;
757 EFI_STRING ConfigResp;
758 UINTN Length;
759 EFI_STATUS Status;
760 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
761 LIST_ENTRY *Link;
762 HII_DATABASE_RECORD *Database;
763 UINT8 *DevicePathPkg;
764 UINT8 *CurrentDevicePath;
765 EFI_HANDLE DriverHandle;
766 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
767 EFI_STRING AccessProgress;
768
769 if (This == NULL || Progress == NULL) {
770 return EFI_INVALID_PARAMETER;
771 }
772
773 if (Configuration == NULL) {
774 *Progress = NULL;
775 return EFI_INVALID_PARAMETER;
776 }
777
778 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
779 StringPtr = Configuration;
780 *Progress = StringPtr;
781
782 //
783 // The first element of <MultiConfigResp> should be
784 // <GuidHdr>, which is in 'GUID='<Guid> syntax.
785 //
786 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
787 return EFI_INVALID_PARAMETER;
788 }
789
790 while (*StringPtr != 0 && StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) == 0) {
791 //
792 // If parsing error, set Progress to the beginning of the <MultiConfigResp>
793 // or most recent & before the error.
794 //
795 if (StringPtr == Configuration) {
796 *Progress = StringPtr;
797 } else {
798 *Progress = StringPtr - 1;
799 }
800
801 //
802 // Process each <ConfigResp> of <MultiConfigResp>
803 //
804 Length = CalculateConfigStringLen (StringPtr);
805 ConfigResp = AllocateCopyPool ((Length + 1) * sizeof (CHAR16), StringPtr);
806 if (ConfigResp == NULL) {
807 return EFI_OUT_OF_RESOURCES;
808 }
809 //
810 // Append '\0' to the end of ConfigRequest
811 //
812 *(ConfigResp + Length) = 0;
813
814 //
815 // Get the UEFI device path
816 //
817 Status = GetDevicePath (ConfigResp, (UINT8 **) &DevicePath);
818 if (EFI_ERROR (Status)) {
819 FreePool (ConfigResp);
820 return Status;
821 }
822
823 //
824 // Find driver which matches the routing data.
825 //
826 DriverHandle = NULL;
827 for (Link = Private->DatabaseList.ForwardLink;
828 Link != &Private->DatabaseList;
829 Link = Link->ForwardLink
830 ) {
831 Database = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
832
833 if ((DevicePathPkg = Database->PackageList->DevicePathPkg) != NULL) {
834 CurrentDevicePath = DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER);
835 if (CompareMem (
836 DevicePath,
837 CurrentDevicePath,
838 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) CurrentDevicePath)
839 ) == 0) {
840 DriverHandle = Database->DriverHandle;
841 break;
842 }
843 }
844 }
845
846 FreePool (DevicePath);
847
848 if (DriverHandle == NULL) {
849 //
850 // Routing data does not match any known driver.
851 // Set Progress to the 'G' in "GUID" of the routing header.
852 //
853 *Progress = StringPtr;
854 FreePool (ConfigResp);
855 return EFI_NOT_FOUND;
856 }
857
858 //
859 // Call corresponding ConfigAccess protocol to route settings
860 //
861 Status = gBS->HandleProtocol (
862 DriverHandle,
863 &gEfiHiiConfigAccessProtocolGuid,
864 (VOID **) &ConfigAccess
865 );
866 ASSERT_EFI_ERROR (Status);
867
868 Status = ConfigAccess->RouteConfig (
869 ConfigAccess,
870 ConfigResp,
871 &AccessProgress
872 );
873
874 if (EFI_ERROR (Status)) {
875 //
876 // AccessProgress indicates the parsing progress on <ConfigResp>.
877 // Map it to the progress on <MultiConfigResp> then return it.
878 //
879 *Progress = StrStr (StringPtr, AccessProgress);
880
881 FreePool (ConfigResp);
882 return Status;
883 }
884
885 FreePool (ConfigResp);
886 ConfigResp = NULL;
887
888 //
889 // Go to next <ConfigResp> (skip '&').
890 //
891 StringPtr += Length;
892 if (*StringPtr == 0) {
893 *Progress = StringPtr;
894 break;
895 }
896
897 StringPtr++;
898
899 }
900
901 return EFI_SUCCESS;
902 }
903
904
905 /**
906 This helper function is to be called by drivers to map configuration data
907 stored in byte array ("block") formats such as UEFI Variables into current
908 configuration strings.
909
910 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
911 instance.
912 @param ConfigRequest A null-terminated Unicode string in
913 <ConfigRequest> format.
914 @param Block Array of bytes defining the block's configuration.
915 @param BlockSize Length in bytes of Block.
916 @param Config Filled-in configuration string. String allocated
917 by the function. Returned only if call is
918 successful.
919 @param Progress A pointer to a string filled in with the offset of
920 the most recent & before the first failing
921 name/value pair (or the beginning of the string if
922 the failure is in the first name / value pair) or
923 the terminating NULL if all was successful.
924
925 @retval EFI_SUCCESS The request succeeded. Progress points to the null
926 terminator at the end of the ConfigRequest
927 string.
928 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate Config. Progress
929 points to the first character of ConfigRequest.
930 @retval EFI_INVALID_PARAMETER Passing in a NULL for the ConfigRequest or
931 Block parameter would result in this type of
932 error. Progress points to the first character of
933 ConfigRequest.
934 @retval EFI_DEVICE_ERROR Block not large enough. Progress undefined.
935 @retval EFI_INVALID_PARAMETER Encountered non <BlockName> formatted string.
936 Block is left updated and Progress points at
937 the "&" preceding the first non-<BlockName>.
938
939 **/
940 EFI_STATUS
941 EFIAPI
942 HiiBlockToConfig (
943 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
944 IN CONST EFI_STRING ConfigRequest,
945 IN CONST UINT8 *Block,
946 IN CONST UINTN BlockSize,
947 OUT EFI_STRING *Config,
948 OUT EFI_STRING *Progress
949 )
950 {
951 HII_DATABASE_PRIVATE_DATA *Private;
952 EFI_STRING StringPtr;
953 UINTN Length;
954 EFI_STATUS Status;
955 EFI_STRING TmpPtr;
956 UINT8 *TmpBuffer;
957 UINTN Offset;
958 UINTN Width;
959 UINT8 *Value;
960 EFI_STRING ValueStr;
961 EFI_STRING ConfigElement;
962
963 if (This == NULL || Progress == NULL || Config == NULL) {
964 return EFI_INVALID_PARAMETER;
965 }
966
967 if (Block == NULL || ConfigRequest == NULL) {
968 *Progress = ConfigRequest;
969 return EFI_INVALID_PARAMETER;
970 }
971
972
973 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
974 ASSERT (Private != NULL);
975
976 StringPtr = ConfigRequest;
977 ValueStr = NULL;
978 Value = NULL;
979 ConfigElement = NULL;
980
981 //
982 // Allocate a fix length of memory to store Results. Reallocate memory for
983 // Results if this fix length is insufficient.
984 //
985 *Config = (EFI_STRING) AllocateZeroPool (MAX_STRING_LENGTH);
986 if (*Config == NULL) {
987 return EFI_OUT_OF_RESOURCES;
988 }
989
990 //
991 // Jump <ConfigHdr>
992 //
993 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
994 *Progress = StringPtr;
995 Status = EFI_INVALID_PARAMETER;
996 goto Exit;
997 }
998 while (*StringPtr != 0 && StrnCmp (StringPtr, L"PATH=", StrLen (L"PATH=")) != 0) {
999 StringPtr++;
1000 }
1001 if (*StringPtr == 0) {
1002 *Progress = StringPtr;
1003 Status = EFI_INVALID_PARAMETER;
1004 goto Exit;
1005 }
1006
1007 while (*StringPtr != L'&' && *StringPtr != 0) {
1008 StringPtr++;
1009 }
1010 if (*StringPtr == 0) {
1011 *Progress = StringPtr;
1012 Status = EFI_INVALID_PARAMETER;
1013 goto Exit;
1014 }
1015 //
1016 // Skip '&'
1017 //
1018 StringPtr++;
1019
1020 //
1021 // Copy <ConfigHdr> and an additional '&' to <ConfigResp>
1022 //
1023 Length = StringPtr - ConfigRequest;
1024 CopyMem (*Config, ConfigRequest, Length * sizeof (CHAR16));
1025
1026 //
1027 // Parse each <RequestElement> if exists
1028 // Only <BlockName> format is supported by this help function.
1029 // <BlockName> ::= 'OFFSET='<Number>&'WIDTH='<Number>
1030 //
1031 while (*StringPtr != 0 && StrnCmp (StringPtr, L"OFFSET=", StrLen (L"OFFSET=")) == 0) {
1032 //
1033 // Back up the header of one <BlockName>
1034 //
1035 TmpPtr = StringPtr;
1036
1037 StringPtr += StrLen (L"OFFSET=");
1038 //
1039 // Get Offset
1040 //
1041 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
1042 if (Status == EFI_OUT_OF_RESOURCES) {
1043 *Progress = ConfigRequest;
1044 goto Exit;
1045 }
1046 Offset = 0;
1047 CopyMem (
1048 &Offset,
1049 TmpBuffer,
1050 (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
1051 );
1052 FreePool (TmpBuffer);
1053
1054 StringPtr += Length;
1055 if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {
1056 *Progress = StringPtr - Length - StrLen (L"OFFSET=") - 1;
1057 Status = EFI_INVALID_PARAMETER;
1058 goto Exit;
1059 }
1060 StringPtr += StrLen (L"&WIDTH=");
1061
1062 //
1063 // Get Width
1064 //
1065 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
1066 if (Status == EFI_OUT_OF_RESOURCES) {
1067 *Progress = ConfigRequest;
1068 goto Exit;
1069 }
1070 Width = 0;
1071 CopyMem (
1072 &Width,
1073 TmpBuffer,
1074 (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
1075 );
1076 FreePool (TmpBuffer);
1077
1078 StringPtr += Length;
1079 if (*StringPtr != 0 && *StringPtr != L'&') {
1080 *Progress = StringPtr - Length - StrLen (L"&WIDTH=");
1081 Status = EFI_INVALID_PARAMETER;
1082 goto Exit;
1083 }
1084
1085 //
1086 // Calculate Value and convert it to hex string.
1087 //
1088 if (Offset + Width > BlockSize) {
1089 *Progress = StringPtr;
1090 Status = EFI_DEVICE_ERROR;
1091 goto Exit;
1092 }
1093
1094 Value = (UINT8 *) AllocateZeroPool (Width);
1095 if (Value == NULL) {
1096 *Progress = ConfigRequest;
1097 Status = EFI_OUT_OF_RESOURCES;
1098 goto Exit;
1099 }
1100
1101 CopyMem (Value, (UINT8 *) Block + Offset, Width);
1102
1103 Length = Width * 2 + 1;
1104 ValueStr = (EFI_STRING) AllocateZeroPool (Length * sizeof (CHAR16));
1105 if (ValueStr == NULL) {
1106 *Progress = ConfigRequest;
1107 Status = EFI_OUT_OF_RESOURCES;
1108 goto Exit;
1109 }
1110
1111 Status = BufToHexString (ValueStr, &Length, Value, Width);
1112 ASSERT_EFI_ERROR (Status);
1113 ToLower (ValueStr);
1114
1115 FreePool (Value);
1116 Value = NULL;
1117
1118 //
1119 // Build a ConfigElement
1120 //
1121 Length += StringPtr - TmpPtr + 1 + StrLen (L"VALUE=");
1122 ConfigElement = (EFI_STRING) AllocateZeroPool (Length * sizeof (CHAR16));
1123 if (ConfigElement == NULL) {
1124 Status = EFI_OUT_OF_RESOURCES;
1125 goto Exit;
1126 }
1127 CopyMem (ConfigElement, TmpPtr, (StringPtr - TmpPtr + 1) * sizeof (CHAR16));
1128 if (*StringPtr == 0) {
1129 *(ConfigElement + (StringPtr - TmpPtr)) = L'&';
1130 }
1131 *(ConfigElement + (StringPtr - TmpPtr) + 1) = 0;
1132 StrCat (ConfigElement, L"VALUE=");
1133 StrCat (ConfigElement, ValueStr);
1134
1135 AppendToMultiString (Config, ConfigElement);
1136
1137 FreePool (ConfigElement);
1138 FreePool (ValueStr);
1139 ConfigElement = NULL;
1140 ValueStr = NULL;
1141
1142 //
1143 // If '\0', parsing is finished. Otherwise skip '&' to continue
1144 //
1145 if (*StringPtr == 0) {
1146 break;
1147 }
1148 AppendToMultiString (Config, L"&");
1149 StringPtr++;
1150
1151 }
1152
1153 if (*StringPtr != 0) {
1154 *Progress = StringPtr - 1;
1155 Status = EFI_INVALID_PARAMETER;
1156 goto Exit;
1157 }
1158
1159 *Progress = StringPtr;
1160 return EFI_SUCCESS;
1161
1162 Exit:
1163 FreePool (*Config);
1164 if (ValueStr != NULL) {
1165 FreePool (ValueStr);
1166 }
1167 if (Value != NULL) {
1168 FreePool (Value);
1169 }
1170 if (ConfigElement != NULL) {
1171 FreePool (ConfigElement);
1172 }
1173
1174 return Status;
1175
1176 }
1177
1178
1179 /**
1180 This helper function is to be called by drivers to map configuration strings
1181 to configurations stored in byte array ("block") formats such as UEFI Variables.
1182
1183 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
1184 instance.
1185 @param ConfigResp A null-terminated Unicode string in <ConfigResp>
1186 format.
1187 @param Block A possibly null array of bytes representing the
1188 current block. Only bytes referenced in the
1189 ConfigResp string in the block are modified. If
1190 this parameter is null or if the *BlockSize
1191 parameter is (on input) shorter than required by
1192 the Configuration string, only the BlockSize
1193 parameter is updated and an appropriate status
1194 (see below) is returned.
1195 @param BlockSize The length of the Block in units of UINT8. On
1196 input, this is the size of the Block. On output,
1197 if successful, contains the index of the last
1198 modified byte in the Block.
1199 @param Progress On return, points to an element of the ConfigResp
1200 string filled in with the offset of the most
1201 recent '&' before the first failing name / value
1202 pair (or the beginning of the string if the
1203 failure is in the first name / value pair) or the
1204 terminating NULL if all was successful.
1205
1206 @retval EFI_SUCCESS The request succeeded. Progress points to the null
1207 terminator at the end of the ConfigResp string.
1208 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate Config. Progress
1209 points to the first character of ConfigResp.
1210 @retval EFI_INVALID_PARAMETER Passing in a NULL for the ConfigResp or
1211 Block parameter would result in this type of
1212 error. Progress points to the first character of
1213 ConfigResp.
1214 @retval EFI_INVALID_PARAMETER Encountered non <BlockName> formatted name /
1215 value pair. Block is left updated and
1216 Progress points at the '&' preceding the first
1217 non-<BlockName>.
1218
1219 **/
1220 EFI_STATUS
1221 EFIAPI
1222 HiiConfigToBlock (
1223 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
1224 IN CONST EFI_STRING ConfigResp,
1225 IN OUT UINT8 *Block,
1226 IN OUT UINTN *BlockSize,
1227 OUT EFI_STRING *Progress
1228 )
1229 {
1230 HII_DATABASE_PRIVATE_DATA *Private;
1231 EFI_STRING StringPtr;
1232 UINTN Length;
1233 EFI_STATUS Status;
1234 UINT8 *TmpBuffer;
1235 UINTN Offset;
1236 UINTN Width;
1237 UINT8 *Value;
1238 UINTN BufferSize;
1239
1240 if (This == NULL || BlockSize == NULL || Progress == NULL) {
1241 return EFI_INVALID_PARAMETER;
1242 }
1243
1244 if (ConfigResp == NULL || Block == NULL) {
1245 *Progress = ConfigResp;
1246 return EFI_INVALID_PARAMETER;
1247 }
1248
1249 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
1250 ASSERT (Private != NULL);
1251
1252 StringPtr = ConfigResp;
1253 BufferSize = *BlockSize;
1254 Value = NULL;
1255
1256 //
1257 // Jump <ConfigHdr>
1258 //
1259 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
1260 *Progress = StringPtr;
1261 Status = EFI_INVALID_PARAMETER;
1262 goto Exit;
1263 }
1264 while (*StringPtr != 0 && StrnCmp (StringPtr, L"PATH=", StrLen (L"PATH=")) != 0) {
1265 StringPtr++;
1266 }
1267 if (*StringPtr == 0) {
1268 *Progress = StringPtr;
1269 Status = EFI_INVALID_PARAMETER;
1270 goto Exit;
1271 }
1272
1273 while (*StringPtr != L'&' && *StringPtr != 0) {
1274 StringPtr++;
1275 }
1276 if (*StringPtr == 0) {
1277 *Progress = StringPtr;
1278 Status = EFI_INVALID_PARAMETER;
1279 goto Exit;
1280 }
1281 //
1282 // Skip '&'
1283 //
1284 StringPtr++;
1285
1286 //
1287 // Parse each <ConfigElement> if exists
1288 // Only <BlockConfig> format is supported by this help function.
1289 // <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE='<Number>
1290 //
1291 while (*StringPtr != 0 && StrnCmp (StringPtr, L"OFFSET=", StrLen (L"OFFSET=")) == 0) {
1292 StringPtr += StrLen (L"OFFSET=");
1293 //
1294 // Get Offset
1295 //
1296 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
1297 if (EFI_ERROR (Status)) {
1298 *Progress = ConfigResp;
1299 goto Exit;
1300 }
1301 Offset = 0;
1302 CopyMem (
1303 &Offset,
1304 TmpBuffer,
1305 (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
1306 );
1307 FreePool (TmpBuffer);
1308
1309 StringPtr += Length;
1310 if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {
1311 *Progress = StringPtr - Length - StrLen (L"OFFSET=") - 1;
1312 Status = EFI_INVALID_PARAMETER;
1313 goto Exit;
1314 }
1315 StringPtr += StrLen (L"&WIDTH=");
1316
1317 //
1318 // Get Width
1319 //
1320 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
1321 if (Status == EFI_OUT_OF_RESOURCES) {
1322 *Progress = ConfigResp;
1323 goto Exit;
1324 }
1325 Width = 0;
1326 CopyMem (
1327 &Width,
1328 TmpBuffer,
1329 (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
1330 );
1331 FreePool (TmpBuffer);
1332
1333 StringPtr += Length;
1334 if (StrnCmp (StringPtr, L"&VALUE=", StrLen (L"&VALUE=")) != 0) {
1335 *Progress = StringPtr - Length - StrLen (L"&WIDTH=");
1336 Status = EFI_INVALID_PARAMETER;
1337 goto Exit;
1338 }
1339 StringPtr += StrLen (L"&VALUE=");
1340
1341 //
1342 // Get Value
1343 //
1344 Status = GetValueOfNumber (StringPtr, &Value, &Length);
1345 if (EFI_ERROR (Status)) {
1346 *Progress = ConfigResp;
1347 goto Exit;
1348 }
1349
1350 StringPtr += Length;
1351 if (*StringPtr != 0 && *StringPtr != L'&') {
1352 *Progress = StringPtr - Length - 7;
1353 Status = EFI_INVALID_PARAMETER;
1354 goto Exit;
1355 }
1356
1357 //
1358 // Update the Block with configuration info
1359 //
1360
1361 if (Offset + Width > BufferSize) {
1362 return EFI_DEVICE_ERROR;
1363 }
1364
1365 CopyMem (Block + Offset, Value, Width);
1366 *BlockSize = Offset + Width - 1;
1367
1368 FreePool (Value);
1369 Value = NULL;
1370
1371 //
1372 // If '\0', parsing is finished. Otherwise skip '&' to continue
1373 //
1374 if (*StringPtr == 0) {
1375 break;
1376 }
1377
1378 StringPtr++;
1379 }
1380
1381 if (*StringPtr != 0) {
1382 *Progress = StringPtr - 1;
1383 Status = EFI_INVALID_PARAMETER;
1384 goto Exit;
1385 }
1386
1387 *Progress = StringPtr;
1388 return EFI_SUCCESS;
1389
1390 Exit:
1391
1392 if (Value != NULL) {
1393 FreePool (Value);
1394 }
1395 return Status;
1396 }
1397
1398
1399 /**
1400 This helper function is to be called by drivers to extract portions of
1401 a larger configuration string.
1402
1403 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
1404 instance.
1405 @param Configuration A null-terminated Unicode string in
1406 <MultiConfigAltResp> format.
1407 @param Guid A pointer to the GUID value to search for in the
1408 routing portion of the ConfigResp string when
1409 retrieving the requested data. If Guid is NULL,
1410 then all GUID values will be searched for.
1411 @param Name A pointer to the NAME value to search for in the
1412 routing portion of the ConfigResp string when
1413 retrieving the requested data. If Name is NULL,
1414 then all Name values will be searched for.
1415 @param DevicePath A pointer to the PATH value to search for in the
1416 routing portion of the ConfigResp string when
1417 retrieving the requested data. If DevicePath is
1418 NULL, then all DevicePath values will be searched
1419 for.
1420 @param AltCfgId A pointer to the ALTCFG value to search for in the
1421 routing portion of the ConfigResp string when
1422 retrieving the requested data. If this parameter
1423 is NULL, then the current setting will be
1424 retrieved.
1425 @param AltCfgResp A pointer to a buffer which will be allocated by
1426 the function which contains the retrieved string
1427 as requested. This buffer is only allocated if
1428 the call was successful.
1429
1430 @retval EFI_SUCCESS The request succeeded. The requested data was
1431 extracted and placed in the newly allocated
1432 AltCfgResp buffer.
1433 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate AltCfgResp.
1434 @retval EFI_INVALID_PARAMETER Any parameter is invalid.
1435 @retval EFI_NOT_FOUND Target for the specified routing data was not
1436 found.
1437
1438 **/
1439 EFI_STATUS
1440 EFIAPI
1441 HiiGetAltCfg (
1442 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
1443 IN CONST EFI_STRING Configuration,
1444 IN CONST EFI_GUID *Guid,
1445 IN CONST EFI_STRING Name,
1446 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,
1447 IN CONST UINT16 *AltCfgId,
1448 OUT EFI_STRING *AltCfgResp
1449 )
1450 {
1451 EFI_STATUS Status;
1452 EFI_STRING StringPtr;
1453 EFI_STRING HdrStart;
1454 EFI_STRING HdrEnd;
1455 EFI_STRING TmpPtr;
1456 UINTN Length;
1457 EFI_STRING GuidStr;
1458 EFI_STRING NameStr;
1459 EFI_STRING PathStr;
1460 EFI_STRING AltIdStr;
1461 EFI_STRING Result;
1462 BOOLEAN GuidFlag;
1463 BOOLEAN NameFlag;
1464 BOOLEAN PathFlag;
1465
1466 HdrStart = NULL;
1467 HdrEnd = NULL;
1468 GuidStr = NULL;
1469 NameStr = NULL;
1470 PathStr = NULL;
1471 AltIdStr = NULL;
1472 Result = NULL;
1473 GuidFlag = FALSE;
1474 NameFlag = FALSE;
1475 PathFlag = FALSE;
1476
1477 if (This == NULL || Configuration == NULL || AltCfgResp == NULL) {
1478 return EFI_INVALID_PARAMETER;
1479 }
1480
1481 StringPtr = Configuration;
1482 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
1483 return EFI_INVALID_PARAMETER;
1484 }
1485
1486 //
1487 // Generate the sub string for later matching.
1488 //
1489 GenerateSubStr (L"GUID=", sizeof (EFI_GUID), (VOID *) Guid, 1, &GuidStr);
1490 GenerateSubStr (
1491 L"PATH=",
1492 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) DevicePath),
1493 (VOID *) DevicePath,
1494 1,
1495 &PathStr
1496 );
1497 if (AltCfgId != NULL) {
1498 GenerateSubStr (L"ALTCFG=", sizeof (UINT16), (VOID *) AltCfgId, 3, &AltIdStr);
1499 }
1500 if (Name != NULL) {
1501 GenerateSubStr (L"NAME=", StrLen (Name) * sizeof (CHAR16), (VOID *) Name, 2, &NameStr);
1502 } else {
1503 GenerateSubStr (L"NAME=", 0, NULL, 2, &NameStr);
1504 }
1505
1506 while (*StringPtr != 0) {
1507 //
1508 // Try to match the GUID
1509 //
1510 if (!GuidFlag) {
1511 TmpPtr = StrStr (StringPtr, GuidStr);
1512 if (TmpPtr == NULL) {
1513 Status = EFI_NOT_FOUND;
1514 goto Exit;
1515 }
1516 HdrStart = TmpPtr;
1517
1518 //
1519 // Jump to <NameHdr>
1520 //
1521 if (Guid != NULL) {
1522 StringPtr = TmpPtr + StrLen (GuidStr);
1523 } else {
1524 StringPtr = StrStr (TmpPtr, L"NAME=");
1525 if (StringPtr == NULL) {
1526 Status = EFI_NOT_FOUND;
1527 goto Exit;
1528 }
1529 }
1530 GuidFlag = TRUE;
1531 }
1532
1533 //
1534 // Try to match the NAME
1535 //
1536 if (GuidFlag && !NameFlag) {
1537 if (StrnCmp (StringPtr, NameStr, StrLen (NameStr)) != 0) {
1538 GuidFlag = FALSE;
1539 } else {
1540 //
1541 // Jump to <PathHdr>
1542 //
1543 if (Name != NULL) {
1544 StringPtr += StrLen (NameStr);
1545 } else {
1546 StringPtr = StrStr (StringPtr, L"PATH=");
1547 if (StringPtr == NULL) {
1548 Status = EFI_NOT_FOUND;
1549 goto Exit;
1550 }
1551 }
1552 NameFlag = TRUE;
1553 }
1554 }
1555
1556 //
1557 // Try to match the DevicePath
1558 //
1559 if (GuidFlag && NameFlag && !PathFlag) {
1560 if (StrnCmp (StringPtr, PathStr, StrLen (PathStr)) != 0) {
1561 GuidFlag = FALSE;
1562 NameFlag = FALSE;
1563 } else {
1564 //
1565 // Jump to '&' before <DescHdr> or <ConfigBody>
1566 //
1567 if (DevicePath != NULL) {
1568 StringPtr += StrLen (PathStr);
1569 } else {
1570 StringPtr = StrStr (StringPtr, L"&");
1571 if (StringPtr == NULL) {
1572 Status = EFI_NOT_FOUND;
1573 goto Exit;
1574 }
1575 }
1576 PathFlag = TRUE;
1577 HdrEnd = ++StringPtr;
1578 }
1579 }
1580
1581 //
1582 // Try to match the AltCfgId
1583 //
1584 if (GuidFlag && NameFlag && PathFlag) {
1585 if (AltCfgId == NULL) {
1586 //
1587 // Return Current Setting when AltCfgId is NULL.
1588 //
1589 Status = OutputConfigBody (StringPtr, &Result);
1590 goto Exit;
1591 }
1592 //
1593 // Search the <ConfigAltResp> to get the <AltResp> with AltCfgId.
1594 //
1595 if (StrnCmp (StringPtr, AltIdStr, StrLen (AltIdStr)) != 0) {
1596 GuidFlag = FALSE;
1597 NameFlag = FALSE;
1598 PathFlag = FALSE;
1599 } else {
1600 Status = OutputConfigBody (StringPtr, &Result);
1601 goto Exit;
1602 }
1603 }
1604 }
1605
1606 Status = EFI_NOT_FOUND;
1607
1608 Exit:
1609
1610 if (!EFI_ERROR (Status) && (Result != NULL)) {
1611 //
1612 // Copy the <ConfigHdr> and <ConfigBody>
1613 //
1614 Length = HdrEnd - HdrStart + StrLen (Result);
1615 *AltCfgResp = AllocateZeroPool (Length * sizeof (CHAR16));
1616 if (*AltCfgResp == NULL) {
1617 Status = EFI_OUT_OF_RESOURCES;
1618 } else {
1619 StrnCpy (*AltCfgResp, HdrStart, HdrEnd - HdrStart);
1620 StrCat (*AltCfgResp, Result);
1621 Status = EFI_SUCCESS;
1622 }
1623 }
1624
1625 if (GuidStr != NULL) {
1626 FreePool (GuidStr);
1627 }
1628 if (NameStr != NULL) {
1629 FreePool (NameStr);
1630 }
1631 if (PathStr != NULL) {
1632 FreePool (PathStr);
1633 }
1634 if (AltIdStr != NULL) {
1635 FreePool (AltIdStr);
1636 }
1637 if (Result != NULL) {
1638 FreePool (Result);
1639 }
1640
1641 return Status;
1642
1643 }
1644
1645