]> git.proxmox.com Git - mirror_edk2.git/blame - EdkCompatibilityPkg/Compatibility/FrameworkHiiToUefiHiiThunk/ConfigAccess.c
Bug fixes for FrameworkHiiToUefiHiiThunk;
[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
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
0368663f 454 if (ConfigAccess->FormCallbackProtocol == NULL ||\r
455 ConfigAccess->FormCallbackProtocol->NvRead == NULL) {\r
456 Status = GetUefiVariable (\r
457 BufferStorage,\r
ebbd2793 458 &Data,\r
459 &DataSize\r
460 );\r
461 } else {\r
0368663f 462 Status = CallFormCallBack (\r
463 BufferStorage,\r
464 ConfigAccess->FormCallbackProtocol,\r
ebbd2793 465 &Data,\r
466 &DataSize\r
467 );\r
468 }\r
469 \r
470 if (!EFI_ERROR (Status)) {\r
59336178 471 Status = mHiiConfigRoutingProtocol->BlockToConfig (\r
472 mHiiConfigRoutingProtocol,\r
ebbd2793 473 Request,\r
474 Data,\r
475 DataSize,\r
476 Results,\r
477 Progress\r
478 );\r
479 }\r
480\r
481 SafeFreePool (Data);\r
482 return Status;\r
483}\r
484\r
1a6cdbd9 485/**\r
486\r
487 This function implement the EFI_HII_CONFIG_ACCESS_PROTOCOL.RouteConfig\r
488 so that data can be written to the data storage such as UEFI Variable or module's\r
489 customized storage exposed by EFI_FRAMEWORK_CALLBACK.\r
490 \r
0368663f 491 @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL\r
492 @param Configuration A null-terminated Unicode string in <ConfigResp> format.\r
fd0d281b 493 @param Progress A pointer to a string filled in with the offset of the most recent '&' before the first\r
0368663f 494 failing name / value pair (or the beginning of the string if the failure is in the first\r
495 name / value pair) or the terminating NULL if all was successful.\r
1a6cdbd9 496 \r
497 @retval EFI_INVALID_PARAMETER If there is no Buffer Storage for this Config Access instance.\r
0368663f 498 @retval EFI_SUCCESS The setting is saved successfully.\r
499 @retval !EFI_SUCCESS The error returned by UEFI Set Variable or Framework Form Callback Nvwrite.\r
1a6cdbd9 500**/ \r
ebbd2793 501EFI_STATUS\r
502EFIAPI\r
503ThunkRouteConfig (\r
504 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,\r
505 IN CONST EFI_STRING Configuration,\r
506 OUT EFI_STRING *Progress\r
507 )\r
508{\r
509 EFI_STATUS Status;\r
0368663f 510 CONFIG_ACCESS_PRIVATE *ConfigAccess;\r
511 LIST_ENTRY *Link;\r
512 BUFFER_STORAGE_ENTRY *BufferStorage;\r
513 UINT8 *Data;\r
ebbd2793 514 UINTN DataSize;\r
0368663f 515 UINTN DataSize2;\r
ebbd2793 516 UINTN LastModifiedByteIndex;\r
0368663f 517 BOOLEAN ResetRequired;\r
518 BOOLEAN DataAllocated;\r
ebbd2793 519\r
520 Data = NULL;\r
0368663f 521 DataAllocated = TRUE;\r
522 ConfigAccess = CONFIG_ACCESS_PRIVATE_FROM_PROTOCOL (This);\r
ebbd2793 523\r
1a6cdbd9 524 //\r
525 // For now, only one var varstore is supported so that we don't need to parse the Configuration string.\r
526 //\r
0368663f 527 Link = GetFirstNode (&ConfigAccess->BufferStorageListHead);\r
528 if (Link == NULL) {\r
ebbd2793 529 ASSERT (FALSE);\r
530 return EFI_INVALID_PARAMETER;\r
531 }\r
532\r
0368663f 533 BufferStorage = BUFFER_STORAGE_ENTRY_FROM_LINK (Link);\r
534 DataSize2 = BufferStorage->Size;\r
535 if (ConfigAccess->ThunkContext->NvMapOverride == NULL) {\r
536 if (ConfigAccess->FormCallbackProtocol == NULL ||\r
537 ConfigAccess->FormCallbackProtocol->NvRead == NULL) {\r
538 Status = GetUefiVariable (\r
539 BufferStorage,\r
540 &Data,\r
541 &DataSize\r
542 );\r
543 ASSERT (DataSize == DataSize2);\r
544 \r
545 } else {\r
546 Status = CallFormCallBack (\r
547 BufferStorage,\r
548 ConfigAccess->FormCallbackProtocol,\r
549 &Data,\r
550 &DataSize\r
551 );\r
552 ASSERT (DataSize == DataSize2);\r
553 \r
554 }\r
555 } else {\r
556 Status = EFI_SUCCESS;\r
557 Data = ConfigAccess->ThunkContext->NvMapOverride;\r
558 DataSize = DataSize2;\r
559 DataAllocated = FALSE;\r
560 } \r
561 if (EFI_ERROR (Status)) {\r
562 goto Done;\r
ebbd2793 563 }\r
0368663f 564\r
59336178 565 Status = mHiiConfigRoutingProtocol->ConfigToBlock (\r
566 mHiiConfigRoutingProtocol,\r
ebbd2793 567 Configuration,\r
568 Data,\r
569 &LastModifiedByteIndex,\r
570 Progress\r
571 );\r
ebbd2793 572 if (EFI_ERROR (Status)) {\r
573 goto Done;\r
574 }\r
575\r
0368663f 576 if (ConfigAccess->FormCallbackProtocol == NULL ||\r
577 ConfigAccess->FormCallbackProtocol->NvWrite == NULL) {\r
578 Status = gRT->SetVariable (\r
579 BufferStorage->Name,\r
580 &BufferStorage->Guid,\r
581 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
582 DataSize,\r
583 Data\r
584 );\r
ebbd2793 585 } else {\r
0368663f 586 Status = ConfigAccess->FormCallbackProtocol->NvWrite (\r
587 ConfigAccess->FormCallbackProtocol, \r
588 BufferStorage->Name,\r
589 &BufferStorage->Guid,\r
590 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
591 DataSize,\r
592 Data,\r
593 &ResetRequired\r
594 );\r
595 \r
ebbd2793 596 }\r
597\r
0368663f 598Done: \r
599 if (DataAllocated && (Data != NULL)) {\r
600 FreePool (Data);\r
601 }\r
602 \r
ebbd2793 603 return Status;\r
604}\r
605\r
0368663f 606FRAMEWORK_EFI_IFR_DATA_ARRAY *\r
607CreateIfrDataArray (\r
608 IN CONFIG_ACCESS_PRIVATE *ConfigAccess,\r
609 IN EFI_QUESTION_ID QuestionId,\r
610 IN UINT8 Type,\r
611 IN EFI_IFR_TYPE_VALUE *Value,\r
612 OUT BOOLEAN *NvMapAllocated\r
613 )\r
614{\r
615 FRAMEWORK_EFI_IFR_DATA_ARRAY *IfrDataArray;\r
616 FRAMEWORK_EFI_IFR_DATA_ENTRY *IfrDataEntry;\r
617 UINTN BrowserDataSize;\r
618 BUFFER_STORAGE_ENTRY *BufferStorageEntry;\r
619 LIST_ENTRY *Link;\r
620\r
621 IfrDataArray = AllocateZeroPool (0x100);\r
622 ASSERT (IfrDataArray != NULL);\r
623\r
624 if (ConfigAccess->ThunkContext->NvMapOverride == NULL) {\r
625 Link = GetFirstNode (&ConfigAccess->BufferStorageListHead);\r
626\r
627 ASSERT (!IsNull (&ConfigAccess->BufferStorageListHead, Link));\r
628\r
629 BufferStorageEntry = BUFFER_STORAGE_ENTRY_FROM_LINK(Link);\r
630\r
631 BrowserDataSize = BufferStorageEntry->Size;\r
632 *NvMapAllocated = TRUE;\r
633 IfrDataArray->NvRamMap = AllocateZeroPool (BrowserDataSize);\r
634 GetBrowserData (NULL, NULL, &BrowserDataSize, IfrDataArray->NvRamMap);\r
635 } else {\r
636 *NvMapAllocated = FALSE;\r
637 IfrDataArray->NvRamMap = ConfigAccess->ThunkContext->NvMapOverride;\r
638 }\r
639\r
640 IfrDataEntry = (FRAMEWORK_EFI_IFR_DATA_ENTRY *) (IfrDataArray + 1);\r
641\r
642 switch (Type) {\r
643 case EFI_IFR_TYPE_NUM_SIZE_8:\r
644 case EFI_IFR_TYPE_NUM_SIZE_16:\r
645 case EFI_IFR_TYPE_NUM_SIZE_32:\r
646 case EFI_IFR_TYPE_NUM_SIZE_64:\r
647 case EFI_IFR_TYPE_BOOLEAN:\r
648 CopyMem (&IfrDataEntry->Data, &(Value->u8), sizeof (*Value));\r
649 break;\r
650\r
651 default:\r
652 ASSERT (FALSE);\r
653 break;\r
654 }\r
655\r
656 return IfrDataArray;\r
657}\r
658\r
659VOID\r
660DestroyIfrDataArray (\r
661 IN FRAMEWORK_EFI_IFR_DATA_ARRAY *Array,\r
662 IN BOOLEAN NvMapAllocated\r
663 )\r
664{\r
665 if (NvMapAllocated) {\r
666 FreePool (Array->NvRamMap);\r
667 }\r
668\r
669 FreePool (Array);\r
670}\r
671\r
672\r
673ONE_OF_OPTION_MAP_ENTRY *\r
674GetOneOfOptionMapEntry (\r
675 IN HII_THUNK_CONTEXT *ThunkContext,\r
676 IN EFI_QUESTION_ID QuestionId,\r
677 IN UINT8 Type,\r
678 IN EFI_IFR_TYPE_VALUE *Value\r
679 )\r
680{\r
681 LIST_ENTRY *Link;\r
682 LIST_ENTRY *Link2;\r
683 ONE_OF_OPTION_MAP_ENTRY *OneOfOptionMapEntry;\r
684 ONE_OF_OPTION_MAP *OneOfOptionMap;\r
685\r
686 Link = GetFirstNode (&ThunkContext->OneOfOptionMapListHead);\r
687\r
688 while (!IsNull (&ThunkContext->OneOfOptionMapListHead, Link)) {\r
689 OneOfOptionMap = ONE_OF_OPTION_MAP_FROM_LINK(Link);\r
690 if (OneOfOptionMap->QuestionId == QuestionId) {\r
691 ASSERT (OneOfOptionMap->ValueType == Type);\r
692\r
693 Link2 = GetFirstNode (&OneOfOptionMap->OneOfOptionMapEntryListHead);\r
694\r
695 while (!IsNull (&OneOfOptionMap->OneOfOptionMapEntryListHead, Link2)) {\r
696 OneOfOptionMapEntry = ONE_OF_OPTION_MAP_ENTRY_FROM_LINK (Link2);\r
697\r
698 if (CompareMem (Value, &OneOfOptionMapEntry->Value, sizeof (EFI_IFR_TYPE_VALUE)) == 0) {\r
699 return OneOfOptionMapEntry;\r
700 }\r
701\r
702 Link2 = GetNextNode (&OneOfOptionMap->OneOfOptionMapEntryListHead, Link2);\r
703 }\r
704 }\r
705\r
706 Link = GetNextNode (&ThunkContext->OneOfOptionMapListHead, Link);\r
707 }\r
708\r
709\r
710 return NULL;\r
711}\r
712\r
713/**\r
714 Functions which are registered to receive notification of\r
715 database events have this prototype. The actual event is encoded\r
716 in NotifyType. The following table describes how PackageType,\r
717 PackageGuid, Handle, and Package are used for each of the\r
718 notification types.\r
719\r
720 @param PackageType Package type of the notification.\r
721\r
722 @param PackageGuid If PackageType is\r
723 EFI_HII_PACKAGE_TYPE_GUID, then this is\r
724 the pointer to the GUID from the Guid\r
725 field of EFI_HII_PACKAGE_GUID_HEADER.\r
726 Otherwise, it must be NULL.\r
727\r
728 @param Package Points to the package referred to by the\r
729 notification Handle The handle of the package\r
730 list which contains the specified package.\r
731\r
732 @param Handle The HII handle.\r
733\r
734 @param NotifyType The type of change concerning the\r
735 database. See\r
736 EFI_HII_DATABASE_NOTIFY_TYPE.\r
737\r
738**/\r
739EFI_STATUS\r
740EFIAPI\r
741FormUpdateNotify (\r
742 IN UINT8 PackageType,\r
743 IN CONST EFI_GUID *PackageGuid,\r
744 IN CONST EFI_HII_PACKAGE_HEADER *Package,\r
745 IN EFI_HII_HANDLE Handle,\r
746 IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType\r
747 )\r
748{\r
749 mHiiPackageListUpdated = TRUE;\r
750\r
751 return EFI_SUCCESS;\r
752}\r
753\r
1a6cdbd9 754/**\r
755 Wrap the EFI_HII_CONFIG_ACCESS_PROTOCOL.CallBack to EFI_FORM_CALLBACK_PROTOCOL.Callback. Therefor,\r
756 the framework HII module willl do no porting (except some porting works needed for callback for EFI_ONE_OF_OPTION opcode)\r
757 and still work with a UEFI HII SetupBrowser.\r
758 \r
0368663f 759 @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
760 @param Action Specifies the type of action taken by the browser. See EFI_BROWSER_ACTION_x.\r
1a6cdbd9 761 @param QuestionId A unique value which is sent to the original exporting driver so that it can identify the\r
0368663f 762 type of data to expect. The format of the data tends to vary based on the opcode that\r
763 generated the callback.\r
764 @param Type The type of value for the question. See EFI_IFR_TYPE_x in\r
765 EFI_IFR_ONE_OF_OPTION.\r
766 @param Value A pointer to the data being sent to the original exporting driver. The type is specified\r
767 by Type. Type EFI_IFR_TYPE_VALUE is defined in\r
768 EFI_IFR_ONE_OF_OPTION.\r
1a6cdbd9 769 @param ActionRequest On return, points to the action requested by the callback function. Type\r
0368663f 770 EFI_BROWSER_ACTION_REQUEST is specified in SendForm() in the Form\r
771 Browser Protocol.\r
1a6cdbd9 772 \r
0368663f 773 @retval EFI_UNSUPPORTED If the Framework HII module does not register Callback although it specify the opcode under\r
774 focuse to be INTERRACTIVE.\r
1a6cdbd9 775 @retval EFI_SUCCESS The callback complete successfully.\r
776 @retval !EFI_SUCCESS The error code returned by EFI_FORM_CALLBACK_PROTOCOL.Callback.\r
777 \r
778 **/\r
ebbd2793 779EFI_STATUS\r
780EFIAPI\r
781ThunkCallback (\r
782 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,\r
783 IN EFI_BROWSER_ACTION Action,\r
784 IN EFI_QUESTION_ID QuestionId,\r
785 IN UINT8 Type,\r
786 IN EFI_IFR_TYPE_VALUE *Value,\r
787 OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest\r
788 )\r
789{\r
790 EFI_STATUS Status;\r
0368663f 791 CONFIG_ACCESS_PRIVATE *ConfigAccess;\r
792 EFI_FORM_CALLBACK_PROTOCOL *FormCallbackProtocol;\r
ebbd2793 793 EFI_HII_CALLBACK_PACKET *Packet;\r
0368663f 794 FRAMEWORK_EFI_IFR_DATA_ARRAY *Data;\r
ebbd2793 795 FRAMEWORK_EFI_IFR_DATA_ENTRY *DataEntry;\r
0368663f 796 UINT16 KeyValue;\r
797 ONE_OF_OPTION_MAP_ENTRY *OneOfOptionMapEntry;\r
798 EFI_HANDLE NotifyHandle;\r
799 EFI_INPUT_KEY Key; \r
800 BOOLEAN NvMapAllocated;\r
ebbd2793 801\r
802 ASSERT (This != NULL);\r
803 ASSERT (Value != NULL);\r
804 ASSERT (ActionRequest != NULL);\r
805\r
806 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;\r
807\r
0368663f 808 ConfigAccess = CONFIG_ACCESS_PRIVATE_FROM_PROTOCOL (This);\r
ebbd2793 809\r
0368663f 810 FormCallbackProtocol = ConfigAccess->FormCallbackProtocol;\r
811 if (FormCallbackProtocol == NULL) {\r
812 ASSERT (FALSE);\r
ebbd2793 813 return EFI_UNSUPPORTED;\r
814 }\r
ebbd2793 815\r
0368663f 816 //\r
817 // Check if the QuestionId match a OneOfOption.\r
818 //\r
819 OneOfOptionMapEntry = GetOneOfOptionMapEntry (ConfigAccess->ThunkContext, QuestionId, Type, Value);\r
820\r
821 if (OneOfOptionMapEntry == NULL) {\r
822 //\r
823 // This is not a One-Of-Option opcode. QuestionId is the KeyValue\r
824 //\r
825 KeyValue = QuestionId;\r
826 } else {\r
827 KeyValue = OneOfOptionMapEntry->FwKey;\r
828 }\r
829\r
830 //\r
831 // Build the FRAMEWORK_EFI_IFR_DATA_ARRAY\r
832 //\r
833 Data = CreateIfrDataArray (ConfigAccess, QuestionId, Type, Value, &NvMapAllocated);\r
834\r
835 Status = mHiiDatabase->RegisterPackageNotify (\r
836 mHiiDatabase,\r
837 EFI_HII_PACKAGE_FORM,\r
838 NULL,\r
839 FormUpdateNotify,\r
840 EFI_HII_DATABASE_NOTIFY_REMOVE_PACK,\r
841 &NotifyHandle\r
842 );\r
843 //\r
844 //\r
845 //\r
846 Packet = NULL;\r
847 Status = FormCallbackProtocol->Callback (\r
848 FormCallbackProtocol,\r
849 KeyValue,\r
850 Data,\r
ebbd2793 851 &Packet\r
852 );\r
853\r
854 //\r
855 // Callback require browser to perform action\r
856 //\r
0368663f 857 if (EFI_ERROR (Status)) {\r
858 if (Packet != NULL) {\r
859 //\r
860 // BUGBUG: need to restore the changing question to default value\r
861 //\r
862\r
863 do {\r
864 IfrLibCreatePopUp (1, &Key, Packet->String);\r
865\r
866 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
867 \r
ebbd2793 868 }\r
0368663f 869\r
870 //\r
871 // Error Code in Status is discarded.\r
872 //\r
873 } else {\r
874 if (Packet != NULL) {\r
875 if (Packet->DataArray.EntryCount == 1 && Packet->DataArray.NvRamMap == NULL) {\r
876 DataEntry = (FRAMEWORK_EFI_IFR_DATA_ENTRY *) ((UINT8 *) Packet + sizeof (FRAMEWORK_EFI_IFR_DATA_ARRAY));\r
877 if ((DataEntry->Flags & EXIT_REQUIRED) == EXIT_REQUIRED) {\r
878 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;\r
879 }\r
880\r
881 if ((DataEntry->Flags & SAVE_REQUIRED) == SAVE_REQUIRED) {\r
882 Status = ConfigAccess->ConfigAccessProtocol.RouteConfig (\r
883 &ConfigAccess->ConfigAccessProtocol,\r
884 NULL,\r
885 NULL\r
886 );\r
887 }\r
888 }\r
889 FreePool (Packet);\r
890 }\r
891 }\r
892\r
893 //\r
894 // Unregister notify for Form package update\r
895 //\r
896 Status = mHiiDatabase->UnregisterPackageNotify (\r
897 mHiiDatabase,\r
898 NotifyHandle\r
899 );\r
900 //\r
901 // UEFI SetupBrowser handles scenario differently with Framework SetupBrowser when call back function \r
902 // update any forms in HII database. UEFI SetupBrowser will re-parse the displaying form package and load\r
903 // the values from variable storages. Framework SetupBrowser will only re-parse the displaying form packages.\r
904 // To make sure customer's previous changes is saved and the changing question behaves as expected, we\r
905 // issue a EFI_BROWSER_ACTION_REQUEST_SUBMIT to ask UEFI SetupBrowser to save the changes proceed to re-parse\r
906 // the form and load all the variable storages.\r
907 //\r
908 if (*ActionRequest == EFI_BROWSER_ACTION_REQUEST_NONE && mHiiPackageListUpdated) {\r
909 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT;\r
ebbd2793 910 }\r
0368663f 911\r
912 DestroyIfrDataArray (Data, NvMapAllocated);\r
ebbd2793 913 \r
914 return Status;\r
915}\r
916\r