]> git.proxmox.com Git - mirror_edk2.git/blame - EdkCompatibilityPkg/Compatibility/FrameworkHiiToUefiHiiThunk/ConfigAccess.c
Add compatibility logic to handle framework fvhob and install FvInfo ppi. And remove...
[mirror_edk2.git] / EdkCompatibilityPkg / Compatibility / FrameworkHiiToUefiHiiThunk / ConfigAccess.c
CommitLineData
ebbd2793 1/**@file\r
2 This file contains functions related to Config Access Protocols installed by\r
3 by HII Thunk Modules which is used to thunk UEFI Config Access Callback to \r
4 Framework HII Callback.\r
5 \r
6Copyright (c) 2008, Intel Corporation\r
7All rights reserved. This program and the accompanying materials\r
8are licensed and made available under the terms and conditions of the BSD License\r
9which accompanies this distribution. The full text of the license may be found at\r
10http://opensource.org/licenses/bsd-license.php\r
11\r
12THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
13WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
14\r
15**/\r
16\r
17#include "HiiDatabase.h"\r
18\r
0368663f 19BOOLEAN mHiiPackageListUpdated;\r
20\r
21CONFIG_ACCESS_PRIVATE gConfigAccessPrivateTempate = {\r
22 CONFIG_ACCESS_PRIVATE_SIGNATURE,\r
ebbd2793 23 {\r
24 ThunkExtractConfig,\r
25 ThunkRouteConfig,\r
26 ThunkCallback\r
27 }, //ConfigAccessProtocol\r
0368663f 28 NULL, //FormCallbackProtocol\r
29 {NULL, NULL}, //ConfigAccessStorageListHead\r
30 NULL \r
ebbd2793 31};\r
32\r
1a6cdbd9 33/**\r
34 Find and return the pointer to Package Header of the Form package\r
35 in the Framework Package List. The Framework Package List is created\r
36 by a module calling the Framework HII interface.\r
37 The Framwork Package List contains package data \r
38 generated by Intel's UEFI VFR Compiler and String gather tool. The data format\r
39 of the package data is defined by TIANO_AUTOGEN_PACKAGES_HEADER.\r
40\r
41 If the package list contains other type of packages such as KEYBOARD_LAYOUT,\r
42 FONTS and IMAGES, the ASSERT. This is to make sure the caller is a \r
43 Framework Module which does not include packages introduced by UEFI Specification\r
44 or packages that is not supported by Thunk layer.\r
45 \r
0368663f 46 @param Packages The Framework Package List\r
1a6cdbd9 47 \r
0368663f 48 @retval EFI_HII_PACKAGE_HEADER* Return the Package Header of Form Package.\r
49 @retval NULL If no Form Package is found.\r
1a6cdbd9 50**/\r
ebbd2793 51EFI_HII_PACKAGE_HEADER *\r
52GetIfrFormSet (\r
53 IN CONST EFI_HII_PACKAGES *Packages\r
54 )\r
55{\r
56 TIANO_AUTOGEN_PACKAGES_HEADER **TianoAutogenPackageHdrArray;\r
57 EFI_HII_PACKAGE_HEADER *IfrPackage;\r
58 UINTN Index;\r
59\r
60 ASSERT (Packages != NULL);\r
61\r
62 IfrPackage = NULL;\r
63\r
64 TianoAutogenPackageHdrArray = (TIANO_AUTOGEN_PACKAGES_HEADER **) (((UINT8 *) &Packages->GuidId) + sizeof (Packages->GuidId));\r
65 for (Index = 0; Index < Packages->NumberOfPackages; Index++) {\r
66 //\r
67 // BugBug: The current UEFI HII build tool generate a binary in the format defined in: \r
68 // TIANO_AUTOGEN_PACKAGES_HEADER. We assume that all packages generated in\r
69 // this binary is with same package type. So the returned IfrPackNum and StringPackNum\r
70 // may not be the exact number of valid package number in the binary generated \r
71 // by HII Build tool.\r
72 //\r
73 switch (TianoAutogenPackageHdrArray[Index]->PackageHeader.Type) {\r
74 case EFI_HII_PACKAGE_FORM:\r
75 return &TianoAutogenPackageHdrArray[Index]->PackageHeader;\r
76 break;\r
77\r
78 case EFI_HII_PACKAGE_STRINGS:\r
79 case EFI_HII_PACKAGE_SIMPLE_FONTS:\r
80 break;\r
81\r
82 //\r
83 // The following fonts are invalid for a module that using Framework to UEFI thunk layer.\r
84 //\r
85 case EFI_HII_PACKAGE_KEYBOARD_LAYOUT:\r
86 case EFI_HII_PACKAGE_FONTS:\r
87 case EFI_HII_PACKAGE_IMAGES:\r
88 default:\r
89 ASSERT (FALSE);\r
90 break;\r
91 }\r
92 }\r
93\r
94 return (EFI_HII_PACKAGE_HEADER *) NULL;\r
95}\r
96\r
1a6cdbd9 97/**\r
98 This function scan EFI_IFR_VARSTORE_OP in the Form Package.\r
99 It create entries for these VARSTORE found and append the entry\r
100 to a Link List.\r
101\r
102 If FormSetPackage is not EFI_HII_PACKAGE_FORM, then ASSERT.\r
103 If there is no linear buffer storage in this formset, then ASSERT.\r
104\r
0368663f 105 @param FormSetPackage The Form Package header.\r
1a6cdbd9 106 @param BufferStorageListHead The link list for the VARSTORE found in the form package.\r
107 \r
0368663f 108 @retval EFI_SUCCESS The function scan the form set and find one or more VARSTOREs.\r
1a6cdbd9 109 @retval EFI_OUT_OF_RESOURCES There is not enough memory to complete the function.\r
110**/\r
ebbd2793 111EFI_STATUS\r
112GetBufferStorage (\r
113 IN CONST EFI_HII_PACKAGE_HEADER *FormSetPackage,\r
114 OUT LIST_ENTRY *BufferStorageListHead\r
115 )\r
116{\r
117 UINTN OpCodeOffset;\r
118 UINTN OpCodeLength;\r
119 UINT8 *OpCodeData;\r
120 UINT8 Operand;\r
121 EFI_IFR_VARSTORE *VarStoreOpCode;\r
0368663f 122 BUFFER_STORAGE_ENTRY *BufferStorage;\r
ebbd2793 123\r
1a6cdbd9 124 ASSERT (FormSetPackage->Type == EFI_HII_PACKAGE_FORM);\r
125\r
ebbd2793 126 OpCodeOffset = sizeof (EFI_HII_PACKAGE_HEADER);\r
0368663f 127 //\r
128 // Scan all opcode for the FormSet Package for \r
129 // EFI_IFR_VARSTORE_OP opcode.\r
130 //\r
ebbd2793 131 while (OpCodeOffset < FormSetPackage->Length) {\r
132 OpCodeData = (UINT8 *) FormSetPackage + OpCodeOffset;\r
133\r
134 OpCodeLength = ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;\r
135 OpCodeOffset += OpCodeLength;\r
136 Operand = ((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode;\r
137\r
138 if (Operand == EFI_IFR_VARSTORE_OP) {\r
139 VarStoreOpCode = (EFI_IFR_VARSTORE *)OpCodeData;\r
0368663f 140 BufferStorage = AllocateZeroPool (sizeof (*BufferStorage));\r
141 if (BufferStorage == NULL) {\r
ebbd2793 142 return EFI_OUT_OF_RESOURCES;\r
143 }\r
0368663f 144 //\r
145 // Record the attributes: GUID, Name, VarStoreId and Size.\r
146 //\r
147 CopyMem (&BufferStorage->Guid, &VarStoreOpCode->Guid, sizeof (EFI_GUID));\r
0915f6dc 148 \r
0368663f 149 BufferStorage->Name = AllocateZeroPool (AsciiStrSize (VarStoreOpCode->Name) * 2);\r
150 AsciiStrToUnicodeStr (VarStoreOpCode->Name, BufferStorage->Name);\r
ebbd2793 151\r
0368663f 152 BufferStorage->VarStoreId = VarStoreOpCode->VarStoreId;\r
ebbd2793 153\r
0368663f 154 BufferStorage->Size = VarStoreOpCode->Size;\r
155 BufferStorage->Signature = BUFFER_STORAGE_ENTRY_SIGNATURE;\r
ebbd2793 156\r
0368663f 157 InsertTailList (BufferStorageListHead, &BufferStorage->Link);\r
ebbd2793 158 }\r
159 }\r
1a6cdbd9 160\r
ebbd2793 161 return EFI_SUCCESS;\r
162}\r
0368663f 163\r
164\r
1a6cdbd9 165/**\r
166 This function installs a EFI_CONFIG_ACCESS_PROTOCOL instance for a form package registered\r
167 by a module using Framework HII Protocol Interfaces.\r
168\r
169 UEFI HII require EFI_HII_CONFIG_ACCESS_PROTOCOL to be installed on a EFI_HANDLE, so\r
170 that Setup Utility can load the Buffer Storage using this protocol.\r
171 \r
0368663f 172 @param Packages The framework package list.\r
173 @param ThunkContext The Thunk Layer Handle Mapping Database Entry.\r
1a6cdbd9 174 \r
0368663f 175 @retval EFI_SUCCESS The Config Access Protocol is installed successfully.\r
176 @retval EFI_OUT_RESOURCE There is not enough memory.\r
1a6cdbd9 177 \r
178**/\r
ebbd2793 179EFI_STATUS\r
0368663f 180InstallDefaultConfigAccessProtocol (\r
181 IN CONST EFI_HII_PACKAGES *Packages,\r
182 IN OUT HII_THUNK_CONTEXT *ThunkContext\r
ebbd2793 183 )\r
184{\r
185 EFI_HII_PACKAGE_HEADER *FormSetPackage;\r
186 EFI_STATUS Status;\r
0368663f 187 CONFIG_ACCESS_PRIVATE *ConfigAccessInstance;\r
ebbd2793 188\r
0368663f 189 Status = HiiLibCreateHiiDriverHandle (&ThunkContext->UefiHiiDriverHandle);\r
ebbd2793 190 ConfigAccessInstance = AllocateCopyPool (\r
0368663f 191 sizeof (CONFIG_ACCESS_PRIVATE), \r
192 &gConfigAccessPrivateTempate\r
ebbd2793 193 );\r
1a6cdbd9 194 ASSERT (ConfigAccessInstance != NULL);\r
0368663f 195 \r
196 InitializeListHead (&ConfigAccessInstance->BufferStorageListHead);\r
ebbd2793 197\r
198 //\r
199 // We assume there is only one formset package in each Forms Package\r
200 //\r
201 FormSetPackage = GetIfrFormSet (Packages);\r
1a6cdbd9 202 ASSERT (FormSetPackage != NULL);\r
203 \r
0368663f 204 Status = GetBufferStorage (FormSetPackage, &ConfigAccessInstance->BufferStorageListHead);\r
ebbd2793 205 if (EFI_ERROR (Status)) {\r
206 FreePool (ConfigAccessInstance);\r
207 ASSERT (FALSE);\r
208 return Status;\r
209 }\r
210\r
211 Status = gBS->InstallMultipleProtocolInterfaces (\r
0368663f 212 &ThunkContext->UefiHiiDriverHandle,\r
ebbd2793 213 &gEfiHiiConfigAccessProtocolGuid,\r
214 &ConfigAccessInstance->ConfigAccessProtocol,\r
215 NULL\r
216 );\r
0368663f 217 //\r
218 //BUGBUG: Remove when done.\r
219 //\r
ebbd2793 220 ASSERT_EFI_ERROR (Status);\r
0368663f 221 \r
ebbd2793 222 if (EFI_ERROR (Status)) {\r
223 FreePool (ConfigAccessInstance);\r
224 return Status;\r
225 }\r
0368663f 226\r
227 ConfigAccessInstance->ThunkContext = ThunkContext;\r
ebbd2793 228 \r
229 return EFI_SUCCESS;\r
230}\r
231\r
0368663f 232VOID\r
233DestroyBufferStorageList (\r
234 IN LIST_ENTRY *ListHead\r
235 )\r
236{\r
237 LIST_ENTRY *Link;\r
238 BUFFER_STORAGE_ENTRY *Entry;\r
1a6cdbd9 239\r
0368663f 240 while (!IsListEmpty (ListHead)) {\r
241 Link = GetFirstNode (ListHead);\r
242 \r
243 Entry = BUFFER_STORAGE_ENTRY_FROM_LINK(Link);\r
244\r
245 FreePool (Entry->Name);\r
246 Link = RemoveEntryList (Link);\r
247\r
248 FreePool (Entry);\r
249 }\r
250}\r
251\r
252VOID\r
253UninstallDefaultConfigAccessProtocol (\r
254 IN HII_THUNK_CONTEXT *ThunkContext\r
ebbd2793 255 )\r
256{\r
0368663f 257 EFI_STATUS Status;\r
258 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;\r
259 CONFIG_ACCESS_PRIVATE *ConfigAccessInstance;\r
260 \r
261 HiiLibDestroyHiiDriverHandle (ThunkContext->UefiHiiDriverHandle);\r
262\r
263 Status = gBS->HandleProtocol (\r
264 ThunkContext->UefiHiiDriverHandle,\r
265 &gEfiHiiConfigAccessProtocolGuid,\r
266 (VOID **) &ConfigAccess\r
267 );\r
268\r
269 ASSERT_EFI_ERROR (Status);\r
270\r
271 Status = gBS->UninstallProtocolInterface (\r
272 ThunkContext->UefiHiiDriverHandle,\r
273 &gEfiHiiConfigAccessProtocolGuid,\r
274 ConfigAccess\r
275 );\r
276 ASSERT_EFI_ERROR (Status);\r
277\r
278 ConfigAccessInstance = CONFIG_ACCESS_PRIVATE_FROM_PROTOCOL (ConfigAccess);\r
279\r
280 DestroyBufferStorageList (&ConfigAccessInstance->BufferStorageListHead);\r
ebbd2793 281\r
ebbd2793 282}\r
0368663f 283 \r
ebbd2793 284\r
1a6cdbd9 285/**\r
286 Wrap the EFI_HII_CONFIG_ACCESS_PROTOCOL.ExtractConfig to a call to EFI_FORM_CALLBACK_PROTOCOL.NvRead.\r
287 \r
0368663f 288 @param BufferStorage The key with all attributes needed to call EFI_FORM_CALLBACK_PROTOCOL.NvRead.\r
289 @param FwFormCallBack The EFI_FORM_CALLBACK_PROTOCOL registered by Framework HII module.\r
290 @param Data The data read.\r
291 @param DataSize The size of data.\r
1a6cdbd9 292 \r
0368663f 293 @retval EFI_STATUS The status returned by the EFI_FORM_CALLBACK_PROTOCOL.NvWrite.\r
1a6cdbd9 294 @retval EFI_INVALID_PARAMETER If the EFI_FORM_CALLBACK_PROTOCOL.NvRead return the size information of the data\r
0368663f 295 does not match what has been recorded early in he BUFFER_STORAGE_ENTRY.\r
1a6cdbd9 296 **/\r
ebbd2793 297EFI_STATUS\r
0368663f 298CallFormCallBack (\r
299 IN BUFFER_STORAGE_ENTRY *BufferStorage,\r
300 IN EFI_FORM_CALLBACK_PROTOCOL *FwFormCallBack,\r
ebbd2793 301 OUT VOID **Data,\r
302 OUT UINTN *DataSize\r
303 )\r
304{\r
305 EFI_STATUS Status;\r
306\r
307 *DataSize = 0;\r
308 *Data = NULL;\r
309 \r
0368663f 310 Status = FwFormCallBack->NvRead (\r
311 FwFormCallBack, \r
312 BufferStorage->Name,\r
313 &BufferStorage->Guid,\r
ebbd2793 314 NULL,\r
315 DataSize,\r
316 *Data\r
317 );\r
318 if (Status == EFI_BUFFER_TOO_SMALL) {\r
0368663f 319 if (BufferStorage->Size != *DataSize) {\r
ebbd2793 320 ASSERT (FALSE);\r
321 return EFI_INVALID_PARAMETER;\r
322 }\r
323\r
324 *Data = AllocateZeroPool (*DataSize);\r
325 if (Data == NULL) {\r
326 return EFI_OUT_OF_RESOURCES;\r
327 }\r
328\r
0368663f 329 FwFormCallBack->NvRead (\r
330 FwFormCallBack, \r
331 BufferStorage->Name,\r
332 &BufferStorage->Guid,\r
ebbd2793 333 NULL,\r
334 DataSize,\r
335 *Data\r
336 );\r
337 }\r
338\r
339 return Status;\r
340}\r
341\r
1a6cdbd9 342\r
343/**\r
344 Wrap the EFI_HII_CONFIG_ACCESS_PROTOCOL.ExtractConfig to a call to UEFI Variable Get Service.\r
345 \r
0368663f 346 @param BufferStorage The key with all attributes needed to call a UEFI Variable Get Service.\r
347 @param Data The data read.\r
348 @param DataSize The size of data.\r
1a6cdbd9 349\r
350 If the UEFI Variable Get Service return the size information of the data\r
0368663f 351 does not match what has been recorded early in he BUFFER_STORAGE_ENTRY.\r
1a6cdbd9 352 then ASSERT.\r
353 \r
0368663f 354 @retval EFI_STATUS The status returned by the UEFI Variable Get Service.\r
1a6cdbd9 355 @retval EFI_INVALID_PARAMETER If the UEFI Variable Get Service return the size information of the data\r
0368663f 356 does not match what has been recorded early in he BUFFER_STORAGE_ENTRY.\r
1a6cdbd9 357 **/\r
358\r
ebbd2793 359EFI_STATUS\r
0368663f 360GetUefiVariable (\r
361 IN BUFFER_STORAGE_ENTRY *BufferStorage,\r
ebbd2793 362 OUT VOID **Data,\r
363 OUT UINTN *DataSize\r
364 )\r
365{\r
366 EFI_STATUS Status;\r
367\r
368 *DataSize = 0;\r
369 *Data = NULL;\r
370 Status = gRT->GetVariable (\r
0368663f 371 BufferStorage->Name,\r
372 &BufferStorage->Guid,\r
ebbd2793 373 NULL,\r
374 DataSize,\r
375 *Data\r
376 );\r
377 if (Status == EFI_BUFFER_TOO_SMALL) {\r
378\r
0368663f 379 if (BufferStorage->Size != *DataSize) {\r
ebbd2793 380 ASSERT (FALSE);\r
381 return EFI_INVALID_PARAMETER;\r
382 }\r
383\r
384 *Data = AllocateZeroPool (*DataSize);\r
385 if (Data == NULL) {\r
386 return EFI_OUT_OF_RESOURCES;\r
387 }\r
388\r
389 Status = gRT->GetVariable (\r
0368663f 390 BufferStorage->Name,\r
391 &BufferStorage->Guid,\r
ebbd2793 392 NULL,\r
393 DataSize,\r
394 *Data\r
395 );\r
396 }\r
397\r
398 return Status;\r
399}\r
400\r
1a6cdbd9 401/**\r
402\r
403 This function implement the EFI_HII_CONFIG_ACCESS_PROTOCOL.ExtractConfig\r
404 so that data can be read from the data storage such as UEFI Variable or module's\r
405 customized storage exposed by EFI_FRAMEWORK_CALLBACK.\r
406\r
0368663f 407 @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL\r
1a6cdbd9 408 @param Request A null-terminated Unicode string in <ConfigRequest> format. Note that this\r
0368663f 409 includes the routing information as well as the configurable name / value pairs. It is\r
410 invalid for this string to be in <MultiConfigRequest> format.\r
1a6cdbd9 411\r
0368663f 412 @param Progress On return, points to a character in the Request string. Points to the string's null\r
413 terminator if request was successful. Points to the most recent '&' before the first\r
414 failing name / value pair (or the beginning of the string if the failure is in the first\r
415 name / value pair) if the request was not successful\r
1a6cdbd9 416 @param Results A null-terminated Unicode string in <ConfigAltResp> format which has all\r
0368663f 417 values filled in for the names in the Request string. String to be allocated by the called\r
418 function.\r
1a6cdbd9 419 \r
420 @retval EFI_INVALID_PARAMETER If there is no Buffer Storage for this Config Access instance.\r
0368663f 421 @retval EFI_SUCCESS The setting is retrived successfully.\r
422 @retval !EFI_SUCCESS The error returned by UEFI Get Variable or Framework Form Callback Nvread.\r
1a6cdbd9 423 **/\r
ebbd2793 424EFI_STATUS\r
425EFIAPI\r
426ThunkExtractConfig (\r
427 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,\r
428 IN CONST EFI_STRING Request,\r
429 OUT EFI_STRING *Progress,\r
430 OUT EFI_STRING *Results\r
431 )\r
432{\r
433 EFI_STATUS Status;\r
0368663f 434 CONFIG_ACCESS_PRIVATE *ConfigAccess;\r
435 LIST_ENTRY *Link;\r
133a9dfb 436 BUFFER_STORAGE_ENTRY *BufferStorage;\r
ebbd2793 437 VOID *Data;\r
438 UINTN DataSize;\r
439\r
440 Data = NULL;\r
0368663f 441 ConfigAccess = CONFIG_ACCESS_PRIVATE_FROM_PROTOCOL (This);\r
ebbd2793 442\r
1a6cdbd9 443 //\r
444 // For now, only one var varstore is supported so that we don't need to parse the Configuration string.\r
445 //\r
0368663f 446 Link = GetFirstNode (&ConfigAccess->BufferStorageListHead);\r
447 if (Link == NULL) {\r
ebbd2793 448 ASSERT (FALSE);\r
449 return EFI_INVALID_PARAMETER;\r
450 }\r
451 \r
0368663f 452 BufferStorage = BUFFER_STORAGE_ENTRY_FROM_LINK (Link);\r
ebbd2793 453\r
133a9dfb 454 if (ConfigAccess->ThunkContext->NvMapOverride == NULL) {\r
455 if (ConfigAccess->FormCallbackProtocol == NULL ||\r
456 ConfigAccess->FormCallbackProtocol->NvRead == NULL) {\r
457 Status = GetUefiVariable (\r
458 BufferStorage,\r
459 &Data,\r
460 &DataSize\r
461 );\r
462 } else {\r
463 Status = CallFormCallBack (\r
464 BufferStorage,\r
465 ConfigAccess->FormCallbackProtocol,\r
466 &Data,\r
467 &DataSize\r
468 );\r
469 }\r
ebbd2793 470 } else {\r
133a9dfb 471 DataSize = BufferStorage->Size;\r
472 Data = AllocateCopyPool (DataSize, ConfigAccess->ThunkContext->NvMapOverride);\r
473 \r
474 if (Data != NULL) {\r
475 Status = EFI_SUCCESS;\r
476 } else {\r
477 Status = EFI_OUT_OF_RESOURCES;\r
478 }\r
ebbd2793 479 }\r
480 \r
481 if (!EFI_ERROR (Status)) {\r
59336178 482 Status = mHiiConfigRoutingProtocol->BlockToConfig (\r
483 mHiiConfigRoutingProtocol,\r
ebbd2793 484 Request,\r
485 Data,\r
486 DataSize,\r
487 Results,\r
488 Progress\r
489 );\r
490 }\r
491\r
492 SafeFreePool (Data);\r
493 return Status;\r
494}\r
495\r
1a6cdbd9 496/**\r
497\r
498 This function implement the EFI_HII_CONFIG_ACCESS_PROTOCOL.RouteConfig\r
499 so that data can be written to the data storage such as UEFI Variable or module's\r
500 customized storage exposed by EFI_FRAMEWORK_CALLBACK.\r
501 \r
0368663f 502 @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL\r
503 @param Configuration A null-terminated Unicode string in <ConfigResp> format.\r
fd0d281b 504 @param Progress A pointer to a string filled in with the offset of the most recent '&' before the first\r
0368663f 505 failing name / value pair (or the beginning of the string if the failure is in the first\r
506 name / value pair) or the terminating NULL if all was successful.\r
1a6cdbd9 507 \r
508 @retval EFI_INVALID_PARAMETER If there is no Buffer Storage for this Config Access instance.\r
0368663f 509 @retval EFI_SUCCESS The setting is saved successfully.\r
510 @retval !EFI_SUCCESS The error returned by UEFI Set Variable or Framework Form Callback Nvwrite.\r
1a6cdbd9 511**/ \r
ebbd2793 512EFI_STATUS\r
513EFIAPI\r
514ThunkRouteConfig (\r
515 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,\r
516 IN CONST EFI_STRING Configuration,\r
517 OUT EFI_STRING *Progress\r
518 )\r
519{\r
520 EFI_STATUS Status;\r
0368663f 521 CONFIG_ACCESS_PRIVATE *ConfigAccess;\r
522 LIST_ENTRY *Link;\r
523 BUFFER_STORAGE_ENTRY *BufferStorage;\r
524 UINT8 *Data;\r
ebbd2793 525 UINTN DataSize;\r
0368663f 526 UINTN DataSize2;\r
ebbd2793 527 UINTN LastModifiedByteIndex;\r
0368663f 528 BOOLEAN ResetRequired;\r
529 BOOLEAN DataAllocated;\r
ebbd2793 530\r
531 Data = NULL;\r
0368663f 532 ConfigAccess = CONFIG_ACCESS_PRIVATE_FROM_PROTOCOL (This);\r
ebbd2793 533\r
1a6cdbd9 534 //\r
535 // For now, only one var varstore is supported so that we don't need to parse the Configuration string.\r
536 //\r
0368663f 537 Link = GetFirstNode (&ConfigAccess->BufferStorageListHead);\r
538 if (Link == NULL) {\r
ebbd2793 539 ASSERT (FALSE);\r
540 return EFI_INVALID_PARAMETER;\r
541 }\r
542\r
0368663f 543 BufferStorage = BUFFER_STORAGE_ENTRY_FROM_LINK (Link);\r
544 DataSize2 = BufferStorage->Size;\r
545 if (ConfigAccess->ThunkContext->NvMapOverride == NULL) {\r
133a9dfb 546 DataAllocated = TRUE;\r
0368663f 547 if (ConfigAccess->FormCallbackProtocol == NULL ||\r
548 ConfigAccess->FormCallbackProtocol->NvRead == NULL) {\r
549 Status = GetUefiVariable (\r
550 BufferStorage,\r
551 &Data,\r
552 &DataSize\r
553 );\r
0368663f 554 } else {\r
555 Status = CallFormCallBack (\r
556 BufferStorage,\r
557 ConfigAccess->FormCallbackProtocol,\r
558 &Data,\r
559 &DataSize\r
560 );\r
0368663f 561 }\r
562 } else {\r
133a9dfb 563 //\r
564 // ConfigToBlock will convert the Config String and update the NvMapOverride accordingly.\r
565 //\r
0368663f 566 Status = EFI_SUCCESS;\r
567 Data = ConfigAccess->ThunkContext->NvMapOverride;\r
568 DataSize = DataSize2;\r
569 DataAllocated = FALSE;\r
570 } \r
133a9dfb 571 if (EFI_ERROR (Status) || (DataSize2 != DataSize)) {\r
572 if (Data == NULL) {\r
573 Data = AllocateZeroPool (DataSize2);\r
574 }\r
ebbd2793 575 }\r
0368663f 576\r
59336178 577 Status = mHiiConfigRoutingProtocol->ConfigToBlock (\r
578 mHiiConfigRoutingProtocol,\r
ebbd2793 579 Configuration,\r
580 Data,\r
581 &LastModifiedByteIndex,\r
582 Progress\r
583 );\r
ebbd2793 584 if (EFI_ERROR (Status)) {\r
585 goto Done;\r
586 }\r
587\r
133a9dfb 588 if (ConfigAccess->ThunkContext->NvMapOverride == NULL) {\r
589 if (ConfigAccess->FormCallbackProtocol == NULL ||\r
590 ConfigAccess->FormCallbackProtocol->NvWrite == NULL) {\r
591 Status = gRT->SetVariable (\r
592 BufferStorage->Name,\r
593 &BufferStorage->Guid,\r
594 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
595 DataSize2,\r
596 Data\r
597 );\r
598 } else {\r
599 Status = ConfigAccess->FormCallbackProtocol->NvWrite (\r
600 ConfigAccess->FormCallbackProtocol, \r
601 BufferStorage->Name,\r
602 &BufferStorage->Guid,\r
603 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
604 DataSize2,\r
605 Data,\r
606 &ResetRequired\r
607 );\r
608 \r
609 }\r
ebbd2793 610 }\r
611\r
0368663f 612Done: \r
613 if (DataAllocated && (Data != NULL)) {\r
614 FreePool (Data);\r
615 }\r
616 \r
ebbd2793 617 return Status;\r
618}\r
619\r
0368663f 620FRAMEWORK_EFI_IFR_DATA_ARRAY *\r
621CreateIfrDataArray (\r
622 IN CONFIG_ACCESS_PRIVATE *ConfigAccess,\r
623 IN EFI_QUESTION_ID QuestionId,\r
624 IN UINT8 Type,\r
625 IN EFI_IFR_TYPE_VALUE *Value,\r
626 OUT BOOLEAN *NvMapAllocated\r
627 )\r
628{\r
629 FRAMEWORK_EFI_IFR_DATA_ARRAY *IfrDataArray;\r
630 FRAMEWORK_EFI_IFR_DATA_ENTRY *IfrDataEntry;\r
631 UINTN BrowserDataSize;\r
632 BUFFER_STORAGE_ENTRY *BufferStorageEntry;\r
633 LIST_ENTRY *Link;\r
133a9dfb 634 EFI_STATUS Status;\r
0368663f 635\r
d4775f2a 636 Link = GetFirstNode (&ConfigAccess->BufferStorageListHead);\r
637 if (IsNull (&ConfigAccess->BufferStorageListHead, Link)) {\r
638 return NULL;\r
639 }\r
640 \r
0368663f 641 IfrDataArray = AllocateZeroPool (0x100);\r
642 ASSERT (IfrDataArray != NULL);\r
643\r
133a9dfb 644 BufferStorageEntry = BUFFER_STORAGE_ENTRY_FROM_LINK(Link);\r
645 BrowserDataSize = BufferStorageEntry->Size;\r
0368663f 646\r
133a9dfb 647 if (ConfigAccess->ThunkContext->NvMapOverride == NULL) {\r
0368663f 648 *NvMapAllocated = TRUE;\r
649 IfrDataArray->NvRamMap = AllocateZeroPool (BrowserDataSize);\r
0368663f 650 } else {\r
651 *NvMapAllocated = FALSE;\r
652 IfrDataArray->NvRamMap = ConfigAccess->ThunkContext->NvMapOverride;\r
653 }\r
133a9dfb 654 \r
655 Status = GetBrowserData (NULL, NULL, &BrowserDataSize, IfrDataArray->NvRamMap);\r
656 ASSERT_EFI_ERROR (Status);\r
0368663f 657\r
658 IfrDataEntry = (FRAMEWORK_EFI_IFR_DATA_ENTRY *) (IfrDataArray + 1);\r
659\r
660 switch (Type) {\r
661 case EFI_IFR_TYPE_NUM_SIZE_8:\r
662 case EFI_IFR_TYPE_NUM_SIZE_16:\r
663 case EFI_IFR_TYPE_NUM_SIZE_32:\r
664 case EFI_IFR_TYPE_NUM_SIZE_64:\r
665 case EFI_IFR_TYPE_BOOLEAN:\r
666 CopyMem (&IfrDataEntry->Data, &(Value->u8), sizeof (*Value));\r
667 break;\r
668\r
669 default:\r
670 ASSERT (FALSE);\r
671 break;\r
672 }\r
673\r
674 return IfrDataArray;\r
675}\r
676\r
133a9dfb 677VOID\r
678SyncBrowserDataForNvMapOverride (\r
679 IN CONFIG_ACCESS_PRIVATE *ConfigAccess\r
680 )\r
681{\r
682 BUFFER_STORAGE_ENTRY *BufferStorageEntry;\r
683 LIST_ENTRY *Link;\r
684 EFI_STATUS Status;\r
685 UINTN BrowserDataSize;\r
686\r
687 if (ConfigAccess->ThunkContext->NvMapOverride != NULL) {\r
688 \r
689 Link = GetFirstNode (&ConfigAccess->BufferStorageListHead);\r
690 ASSERT (!IsNull (&ConfigAccess->BufferStorageListHead, Link));\r
691 \r
692 BufferStorageEntry = BUFFER_STORAGE_ENTRY_FROM_LINK(Link);\r
693 BrowserDataSize = BufferStorageEntry->Size;\r
694\r
695 Status = SetBrowserData (NULL, NULL, BrowserDataSize, ConfigAccess->ThunkContext->NvMapOverride, NULL);\r
696 ASSERT_EFI_ERROR (Status);\r
697 }\r
698\r
699}\r
700\r
0368663f 701VOID\r
702DestroyIfrDataArray (\r
703 IN FRAMEWORK_EFI_IFR_DATA_ARRAY *Array,\r
704 IN BOOLEAN NvMapAllocated\r
705 )\r
706{\r
d4775f2a 707 if (Array != NULL) {\r
708 if (NvMapAllocated) {\r
709 FreePool (Array->NvRamMap);\r
710 }\r
0368663f 711\r
d4775f2a 712 FreePool (Array);\r
713 }\r
0368663f 714}\r
715\r
716\r
717ONE_OF_OPTION_MAP_ENTRY *\r
718GetOneOfOptionMapEntry (\r
719 IN HII_THUNK_CONTEXT *ThunkContext,\r
720 IN EFI_QUESTION_ID QuestionId,\r
721 IN UINT8 Type,\r
722 IN EFI_IFR_TYPE_VALUE *Value\r
723 )\r
724{\r
725 LIST_ENTRY *Link;\r
726 LIST_ENTRY *Link2;\r
727 ONE_OF_OPTION_MAP_ENTRY *OneOfOptionMapEntry;\r
728 ONE_OF_OPTION_MAP *OneOfOptionMap;\r
729\r
730 Link = GetFirstNode (&ThunkContext->OneOfOptionMapListHead);\r
731\r
732 while (!IsNull (&ThunkContext->OneOfOptionMapListHead, Link)) {\r
733 OneOfOptionMap = ONE_OF_OPTION_MAP_FROM_LINK(Link);\r
734 if (OneOfOptionMap->QuestionId == QuestionId) {\r
735 ASSERT (OneOfOptionMap->ValueType == Type);\r
736\r
737 Link2 = GetFirstNode (&OneOfOptionMap->OneOfOptionMapEntryListHead);\r
738\r
739 while (!IsNull (&OneOfOptionMap->OneOfOptionMapEntryListHead, Link2)) {\r
740 OneOfOptionMapEntry = ONE_OF_OPTION_MAP_ENTRY_FROM_LINK (Link2);\r
741\r
742 if (CompareMem (Value, &OneOfOptionMapEntry->Value, sizeof (EFI_IFR_TYPE_VALUE)) == 0) {\r
743 return OneOfOptionMapEntry;\r
744 }\r
745\r
746 Link2 = GetNextNode (&OneOfOptionMap->OneOfOptionMapEntryListHead, Link2);\r
747 }\r
748 }\r
749\r
750 Link = GetNextNode (&ThunkContext->OneOfOptionMapListHead, Link);\r
751 }\r
752\r
753\r
754 return NULL;\r
755}\r
756\r
757/**\r
758 Functions which are registered to receive notification of\r
759 database events have this prototype. The actual event is encoded\r
760 in NotifyType. The following table describes how PackageType,\r
761 PackageGuid, Handle, and Package are used for each of the\r
762 notification types.\r
763\r
764 @param PackageType Package type of the notification.\r
765\r
766 @param PackageGuid If PackageType is\r
767 EFI_HII_PACKAGE_TYPE_GUID, then this is\r
768 the pointer to the GUID from the Guid\r
769 field of EFI_HII_PACKAGE_GUID_HEADER.\r
770 Otherwise, it must be NULL.\r
771\r
772 @param Package Points to the package referred to by the\r
773 notification Handle The handle of the package\r
774 list which contains the specified package.\r
775\r
776 @param Handle The HII handle.\r
777\r
778 @param NotifyType The type of change concerning the\r
779 database. See\r
780 EFI_HII_DATABASE_NOTIFY_TYPE.\r
781\r
782**/\r
783EFI_STATUS\r
784EFIAPI\r
785FormUpdateNotify (\r
786 IN UINT8 PackageType,\r
787 IN CONST EFI_GUID *PackageGuid,\r
788 IN CONST EFI_HII_PACKAGE_HEADER *Package,\r
789 IN EFI_HII_HANDLE Handle,\r
790 IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType\r
791 )\r
792{\r
793 mHiiPackageListUpdated = TRUE;\r
794\r
795 return EFI_SUCCESS;\r
796}\r
797\r
1a6cdbd9 798/**\r
799 Wrap the EFI_HII_CONFIG_ACCESS_PROTOCOL.CallBack to EFI_FORM_CALLBACK_PROTOCOL.Callback. Therefor,\r
800 the framework HII module willl do no porting (except some porting works needed for callback for EFI_ONE_OF_OPTION opcode)\r
801 and still work with a UEFI HII SetupBrowser.\r
802 \r
0368663f 803 @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
804 @param Action Specifies the type of action taken by the browser. See EFI_BROWSER_ACTION_x.\r
1a6cdbd9 805 @param QuestionId A unique value which is sent to the original exporting driver so that it can identify the\r
0368663f 806 type of data to expect. The format of the data tends to vary based on the opcode that\r
807 generated the callback.\r
808 @param Type The type of value for the question. See EFI_IFR_TYPE_x in\r
809 EFI_IFR_ONE_OF_OPTION.\r
810 @param Value A pointer to the data being sent to the original exporting driver. The type is specified\r
811 by Type. Type EFI_IFR_TYPE_VALUE is defined in\r
812 EFI_IFR_ONE_OF_OPTION.\r
1a6cdbd9 813 @param ActionRequest On return, points to the action requested by the callback function. Type\r
0368663f 814 EFI_BROWSER_ACTION_REQUEST is specified in SendForm() in the Form\r
815 Browser Protocol.\r
1a6cdbd9 816 \r
0368663f 817 @retval EFI_UNSUPPORTED If the Framework HII module does not register Callback although it specify the opcode under\r
818 focuse to be INTERRACTIVE.\r
1a6cdbd9 819 @retval EFI_SUCCESS The callback complete successfully.\r
820 @retval !EFI_SUCCESS The error code returned by EFI_FORM_CALLBACK_PROTOCOL.Callback.\r
821 \r
822 **/\r
ebbd2793 823EFI_STATUS\r
824EFIAPI\r
825ThunkCallback (\r
826 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,\r
827 IN EFI_BROWSER_ACTION Action,\r
828 IN EFI_QUESTION_ID QuestionId,\r
829 IN UINT8 Type,\r
830 IN EFI_IFR_TYPE_VALUE *Value,\r
831 OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest\r
832 )\r
833{\r
834 EFI_STATUS Status;\r
0368663f 835 CONFIG_ACCESS_PRIVATE *ConfigAccess;\r
836 EFI_FORM_CALLBACK_PROTOCOL *FormCallbackProtocol;\r
ebbd2793 837 EFI_HII_CALLBACK_PACKET *Packet;\r
0368663f 838 FRAMEWORK_EFI_IFR_DATA_ARRAY *Data;\r
ebbd2793 839 FRAMEWORK_EFI_IFR_DATA_ENTRY *DataEntry;\r
0368663f 840 UINT16 KeyValue;\r
841 ONE_OF_OPTION_MAP_ENTRY *OneOfOptionMapEntry;\r
842 EFI_HANDLE NotifyHandle;\r
843 EFI_INPUT_KEY Key; \r
844 BOOLEAN NvMapAllocated;\r
ebbd2793 845\r
846 ASSERT (This != NULL);\r
847 ASSERT (Value != NULL);\r
848 ASSERT (ActionRequest != NULL);\r
849\r
850 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;\r
851\r
0368663f 852 ConfigAccess = CONFIG_ACCESS_PRIVATE_FROM_PROTOCOL (This);\r
ebbd2793 853\r
0368663f 854 FormCallbackProtocol = ConfigAccess->FormCallbackProtocol;\r
855 if (FormCallbackProtocol == NULL) {\r
856 ASSERT (FALSE);\r
ebbd2793 857 return EFI_UNSUPPORTED;\r
858 }\r
ebbd2793 859\r
0368663f 860 //\r
861 // Check if the QuestionId match a OneOfOption.\r
862 //\r
863 OneOfOptionMapEntry = GetOneOfOptionMapEntry (ConfigAccess->ThunkContext, QuestionId, Type, Value);\r
864\r
865 if (OneOfOptionMapEntry == NULL) {\r
866 //\r
867 // This is not a One-Of-Option opcode. QuestionId is the KeyValue\r
868 //\r
869 KeyValue = QuestionId;\r
870 } else {\r
871 KeyValue = OneOfOptionMapEntry->FwKey;\r
872 }\r
873\r
874 //\r
875 // Build the FRAMEWORK_EFI_IFR_DATA_ARRAY\r
876 //\r
877 Data = CreateIfrDataArray (ConfigAccess, QuestionId, Type, Value, &NvMapAllocated);\r
878\r
879 Status = mHiiDatabase->RegisterPackageNotify (\r
880 mHiiDatabase,\r
881 EFI_HII_PACKAGE_FORM,\r
882 NULL,\r
883 FormUpdateNotify,\r
884 EFI_HII_DATABASE_NOTIFY_REMOVE_PACK,\r
885 &NotifyHandle\r
886 );\r
887 //\r
888 //\r
889 //\r
890 Packet = NULL;\r
891 Status = FormCallbackProtocol->Callback (\r
892 FormCallbackProtocol,\r
893 KeyValue,\r
894 Data,\r
ebbd2793 895 &Packet\r
896 );\r
133a9dfb 897 SyncBrowserDataForNvMapOverride (ConfigAccess);\r
ebbd2793 898\r
899 //\r
900 // Callback require browser to perform action\r
901 //\r
0368663f 902 if (EFI_ERROR (Status)) {\r
903 if (Packet != NULL) {\r
904 //\r
905 // BUGBUG: need to restore the changing question to default value\r
906 //\r
907\r
908 do {\r
909 IfrLibCreatePopUp (1, &Key, Packet->String);\r
910\r
911 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
912 \r
ebbd2793 913 }\r
0368663f 914\r
915 //\r
916 // Error Code in Status is discarded.\r
917 //\r
918 } else {\r
919 if (Packet != NULL) {\r
920 if (Packet->DataArray.EntryCount == 1 && Packet->DataArray.NvRamMap == NULL) {\r
921 DataEntry = (FRAMEWORK_EFI_IFR_DATA_ENTRY *) ((UINT8 *) Packet + sizeof (FRAMEWORK_EFI_IFR_DATA_ARRAY));\r
922 if ((DataEntry->Flags & EXIT_REQUIRED) == EXIT_REQUIRED) {\r
923 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;\r
924 }\r
925\r
926 if ((DataEntry->Flags & SAVE_REQUIRED) == SAVE_REQUIRED) {\r
927 Status = ConfigAccess->ConfigAccessProtocol.RouteConfig (\r
928 &ConfigAccess->ConfigAccessProtocol,\r
929 NULL,\r
930 NULL\r
931 );\r
932 }\r
933 }\r
934 FreePool (Packet);\r
935 }\r
936 }\r
937\r
938 //\r
939 // Unregister notify for Form package update\r
940 //\r
941 Status = mHiiDatabase->UnregisterPackageNotify (\r
942 mHiiDatabase,\r
943 NotifyHandle\r
944 );\r
945 //\r
946 // UEFI SetupBrowser handles scenario differently with Framework SetupBrowser when call back function \r
947 // update any forms in HII database. UEFI SetupBrowser will re-parse the displaying form package and load\r
948 // the values from variable storages. Framework SetupBrowser will only re-parse the displaying form packages.\r
949 // To make sure customer's previous changes is saved and the changing question behaves as expected, we\r
950 // issue a EFI_BROWSER_ACTION_REQUEST_SUBMIT to ask UEFI SetupBrowser to save the changes proceed to re-parse\r
951 // the form and load all the variable storages.\r
952 //\r
953 if (*ActionRequest == EFI_BROWSER_ACTION_REQUEST_NONE && mHiiPackageListUpdated) {\r
954 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT;\r
ebbd2793 955 }\r
0368663f 956\r
d4775f2a 957\r
0368663f 958 DestroyIfrDataArray (Data, NvMapAllocated);\r
ebbd2793 959 \r
960 return Status;\r
961}\r
962\r