]> git.proxmox.com Git - mirror_edk2.git/blame - EdkCompatibilityPkg/Compatibility/FrameworkHiiToUefiHiiThunk/ConfigAccess.c
Update some module INF files in IntelFrameworkModulePkg to UEFI_DRIVER
[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
636 IfrDataArray = AllocateZeroPool (0x100);\r
637 ASSERT (IfrDataArray != NULL);\r
638\r
133a9dfb 639 Link = GetFirstNode (&ConfigAccess->BufferStorageListHead);\r
640 ASSERT (!IsNull (&ConfigAccess->BufferStorageListHead, Link));\r
641 \r
642 BufferStorageEntry = BUFFER_STORAGE_ENTRY_FROM_LINK(Link);\r
643 BrowserDataSize = BufferStorageEntry->Size;\r
0368663f 644\r
133a9dfb 645 if (ConfigAccess->ThunkContext->NvMapOverride == NULL) {\r
0368663f 646 *NvMapAllocated = TRUE;\r
647 IfrDataArray->NvRamMap = AllocateZeroPool (BrowserDataSize);\r
0368663f 648 } else {\r
649 *NvMapAllocated = FALSE;\r
650 IfrDataArray->NvRamMap = ConfigAccess->ThunkContext->NvMapOverride;\r
651 }\r
133a9dfb 652 \r
653 Status = GetBrowserData (NULL, NULL, &BrowserDataSize, IfrDataArray->NvRamMap);\r
654 ASSERT_EFI_ERROR (Status);\r
0368663f 655\r
656 IfrDataEntry = (FRAMEWORK_EFI_IFR_DATA_ENTRY *) (IfrDataArray + 1);\r
657\r
658 switch (Type) {\r
659 case EFI_IFR_TYPE_NUM_SIZE_8:\r
660 case EFI_IFR_TYPE_NUM_SIZE_16:\r
661 case EFI_IFR_TYPE_NUM_SIZE_32:\r
662 case EFI_IFR_TYPE_NUM_SIZE_64:\r
663 case EFI_IFR_TYPE_BOOLEAN:\r
664 CopyMem (&IfrDataEntry->Data, &(Value->u8), sizeof (*Value));\r
665 break;\r
666\r
667 default:\r
668 ASSERT (FALSE);\r
669 break;\r
670 }\r
671\r
672 return IfrDataArray;\r
673}\r
674\r
133a9dfb 675VOID\r
676SyncBrowserDataForNvMapOverride (\r
677 IN CONFIG_ACCESS_PRIVATE *ConfigAccess\r
678 )\r
679{\r
680 BUFFER_STORAGE_ENTRY *BufferStorageEntry;\r
681 LIST_ENTRY *Link;\r
682 EFI_STATUS Status;\r
683 UINTN BrowserDataSize;\r
684\r
685 if (ConfigAccess->ThunkContext->NvMapOverride != NULL) {\r
686 \r
687 Link = GetFirstNode (&ConfigAccess->BufferStorageListHead);\r
688 ASSERT (!IsNull (&ConfigAccess->BufferStorageListHead, Link));\r
689 \r
690 BufferStorageEntry = BUFFER_STORAGE_ENTRY_FROM_LINK(Link);\r
691 BrowserDataSize = BufferStorageEntry->Size;\r
692\r
693 Status = SetBrowserData (NULL, NULL, BrowserDataSize, ConfigAccess->ThunkContext->NvMapOverride, NULL);\r
694 ASSERT_EFI_ERROR (Status);\r
695 }\r
696\r
697}\r
698\r
0368663f 699VOID\r
700DestroyIfrDataArray (\r
701 IN FRAMEWORK_EFI_IFR_DATA_ARRAY *Array,\r
702 IN BOOLEAN NvMapAllocated\r
703 )\r
704{\r
705 if (NvMapAllocated) {\r
706 FreePool (Array->NvRamMap);\r
707 }\r
708\r
709 FreePool (Array);\r
710}\r
711\r
712\r
713ONE_OF_OPTION_MAP_ENTRY *\r
714GetOneOfOptionMapEntry (\r
715 IN HII_THUNK_CONTEXT *ThunkContext,\r
716 IN EFI_QUESTION_ID QuestionId,\r
717 IN UINT8 Type,\r
718 IN EFI_IFR_TYPE_VALUE *Value\r
719 )\r
720{\r
721 LIST_ENTRY *Link;\r
722 LIST_ENTRY *Link2;\r
723 ONE_OF_OPTION_MAP_ENTRY *OneOfOptionMapEntry;\r
724 ONE_OF_OPTION_MAP *OneOfOptionMap;\r
725\r
726 Link = GetFirstNode (&ThunkContext->OneOfOptionMapListHead);\r
727\r
728 while (!IsNull (&ThunkContext->OneOfOptionMapListHead, Link)) {\r
729 OneOfOptionMap = ONE_OF_OPTION_MAP_FROM_LINK(Link);\r
730 if (OneOfOptionMap->QuestionId == QuestionId) {\r
731 ASSERT (OneOfOptionMap->ValueType == Type);\r
732\r
733 Link2 = GetFirstNode (&OneOfOptionMap->OneOfOptionMapEntryListHead);\r
734\r
735 while (!IsNull (&OneOfOptionMap->OneOfOptionMapEntryListHead, Link2)) {\r
736 OneOfOptionMapEntry = ONE_OF_OPTION_MAP_ENTRY_FROM_LINK (Link2);\r
737\r
738 if (CompareMem (Value, &OneOfOptionMapEntry->Value, sizeof (EFI_IFR_TYPE_VALUE)) == 0) {\r
739 return OneOfOptionMapEntry;\r
740 }\r
741\r
742 Link2 = GetNextNode (&OneOfOptionMap->OneOfOptionMapEntryListHead, Link2);\r
743 }\r
744 }\r
745\r
746 Link = GetNextNode (&ThunkContext->OneOfOptionMapListHead, Link);\r
747 }\r
748\r
749\r
750 return NULL;\r
751}\r
752\r
753/**\r
754 Functions which are registered to receive notification of\r
755 database events have this prototype. The actual event is encoded\r
756 in NotifyType. The following table describes how PackageType,\r
757 PackageGuid, Handle, and Package are used for each of the\r
758 notification types.\r
759\r
760 @param PackageType Package type of the notification.\r
761\r
762 @param PackageGuid If PackageType is\r
763 EFI_HII_PACKAGE_TYPE_GUID, then this is\r
764 the pointer to the GUID from the Guid\r
765 field of EFI_HII_PACKAGE_GUID_HEADER.\r
766 Otherwise, it must be NULL.\r
767\r
768 @param Package Points to the package referred to by the\r
769 notification Handle The handle of the package\r
770 list which contains the specified package.\r
771\r
772 @param Handle The HII handle.\r
773\r
774 @param NotifyType The type of change concerning the\r
775 database. See\r
776 EFI_HII_DATABASE_NOTIFY_TYPE.\r
777\r
778**/\r
779EFI_STATUS\r
780EFIAPI\r
781FormUpdateNotify (\r
782 IN UINT8 PackageType,\r
783 IN CONST EFI_GUID *PackageGuid,\r
784 IN CONST EFI_HII_PACKAGE_HEADER *Package,\r
785 IN EFI_HII_HANDLE Handle,\r
786 IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType\r
787 )\r
788{\r
789 mHiiPackageListUpdated = TRUE;\r
790\r
791 return EFI_SUCCESS;\r
792}\r
793\r
1a6cdbd9 794/**\r
795 Wrap the EFI_HII_CONFIG_ACCESS_PROTOCOL.CallBack to EFI_FORM_CALLBACK_PROTOCOL.Callback. Therefor,\r
796 the framework HII module willl do no porting (except some porting works needed for callback for EFI_ONE_OF_OPTION opcode)\r
797 and still work with a UEFI HII SetupBrowser.\r
798 \r
0368663f 799 @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
800 @param Action Specifies the type of action taken by the browser. See EFI_BROWSER_ACTION_x.\r
1a6cdbd9 801 @param QuestionId A unique value which is sent to the original exporting driver so that it can identify the\r
0368663f 802 type of data to expect. The format of the data tends to vary based on the opcode that\r
803 generated the callback.\r
804 @param Type The type of value for the question. See EFI_IFR_TYPE_x in\r
805 EFI_IFR_ONE_OF_OPTION.\r
806 @param Value A pointer to the data being sent to the original exporting driver. The type is specified\r
807 by Type. Type EFI_IFR_TYPE_VALUE is defined in\r
808 EFI_IFR_ONE_OF_OPTION.\r
1a6cdbd9 809 @param ActionRequest On return, points to the action requested by the callback function. Type\r
0368663f 810 EFI_BROWSER_ACTION_REQUEST is specified in SendForm() in the Form\r
811 Browser Protocol.\r
1a6cdbd9 812 \r
0368663f 813 @retval EFI_UNSUPPORTED If the Framework HII module does not register Callback although it specify the opcode under\r
814 focuse to be INTERRACTIVE.\r
1a6cdbd9 815 @retval EFI_SUCCESS The callback complete successfully.\r
816 @retval !EFI_SUCCESS The error code returned by EFI_FORM_CALLBACK_PROTOCOL.Callback.\r
817 \r
818 **/\r
ebbd2793 819EFI_STATUS\r
820EFIAPI\r
821ThunkCallback (\r
822 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,\r
823 IN EFI_BROWSER_ACTION Action,\r
824 IN EFI_QUESTION_ID QuestionId,\r
825 IN UINT8 Type,\r
826 IN EFI_IFR_TYPE_VALUE *Value,\r
827 OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest\r
828 )\r
829{\r
830 EFI_STATUS Status;\r
0368663f 831 CONFIG_ACCESS_PRIVATE *ConfigAccess;\r
832 EFI_FORM_CALLBACK_PROTOCOL *FormCallbackProtocol;\r
ebbd2793 833 EFI_HII_CALLBACK_PACKET *Packet;\r
0368663f 834 FRAMEWORK_EFI_IFR_DATA_ARRAY *Data;\r
ebbd2793 835 FRAMEWORK_EFI_IFR_DATA_ENTRY *DataEntry;\r
0368663f 836 UINT16 KeyValue;\r
837 ONE_OF_OPTION_MAP_ENTRY *OneOfOptionMapEntry;\r
838 EFI_HANDLE NotifyHandle;\r
839 EFI_INPUT_KEY Key; \r
840 BOOLEAN NvMapAllocated;\r
ebbd2793 841\r
842 ASSERT (This != NULL);\r
843 ASSERT (Value != NULL);\r
844 ASSERT (ActionRequest != NULL);\r
845\r
846 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;\r
847\r
0368663f 848 ConfigAccess = CONFIG_ACCESS_PRIVATE_FROM_PROTOCOL (This);\r
ebbd2793 849\r
0368663f 850 FormCallbackProtocol = ConfigAccess->FormCallbackProtocol;\r
851 if (FormCallbackProtocol == NULL) {\r
852 ASSERT (FALSE);\r
ebbd2793 853 return EFI_UNSUPPORTED;\r
854 }\r
ebbd2793 855\r
0368663f 856 //\r
857 // Check if the QuestionId match a OneOfOption.\r
858 //\r
859 OneOfOptionMapEntry = GetOneOfOptionMapEntry (ConfigAccess->ThunkContext, QuestionId, Type, Value);\r
860\r
861 if (OneOfOptionMapEntry == NULL) {\r
862 //\r
863 // This is not a One-Of-Option opcode. QuestionId is the KeyValue\r
864 //\r
865 KeyValue = QuestionId;\r
866 } else {\r
867 KeyValue = OneOfOptionMapEntry->FwKey;\r
868 }\r
869\r
870 //\r
871 // Build the FRAMEWORK_EFI_IFR_DATA_ARRAY\r
872 //\r
873 Data = CreateIfrDataArray (ConfigAccess, QuestionId, Type, Value, &NvMapAllocated);\r
874\r
875 Status = mHiiDatabase->RegisterPackageNotify (\r
876 mHiiDatabase,\r
877 EFI_HII_PACKAGE_FORM,\r
878 NULL,\r
879 FormUpdateNotify,\r
880 EFI_HII_DATABASE_NOTIFY_REMOVE_PACK,\r
881 &NotifyHandle\r
882 );\r
883 //\r
884 //\r
885 //\r
886 Packet = NULL;\r
887 Status = FormCallbackProtocol->Callback (\r
888 FormCallbackProtocol,\r
889 KeyValue,\r
890 Data,\r
ebbd2793 891 &Packet\r
892 );\r
133a9dfb 893 SyncBrowserDataForNvMapOverride (ConfigAccess);\r
ebbd2793 894\r
895 //\r
896 // Callback require browser to perform action\r
897 //\r
0368663f 898 if (EFI_ERROR (Status)) {\r
899 if (Packet != NULL) {\r
900 //\r
901 // BUGBUG: need to restore the changing question to default value\r
902 //\r
903\r
904 do {\r
905 IfrLibCreatePopUp (1, &Key, Packet->String);\r
906\r
907 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
908 \r
ebbd2793 909 }\r
0368663f 910\r
911 //\r
912 // Error Code in Status is discarded.\r
913 //\r
914 } else {\r
915 if (Packet != NULL) {\r
916 if (Packet->DataArray.EntryCount == 1 && Packet->DataArray.NvRamMap == NULL) {\r
917 DataEntry = (FRAMEWORK_EFI_IFR_DATA_ENTRY *) ((UINT8 *) Packet + sizeof (FRAMEWORK_EFI_IFR_DATA_ARRAY));\r
918 if ((DataEntry->Flags & EXIT_REQUIRED) == EXIT_REQUIRED) {\r
919 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;\r
920 }\r
921\r
922 if ((DataEntry->Flags & SAVE_REQUIRED) == SAVE_REQUIRED) {\r
923 Status = ConfigAccess->ConfigAccessProtocol.RouteConfig (\r
924 &ConfigAccess->ConfigAccessProtocol,\r
925 NULL,\r
926 NULL\r
927 );\r
928 }\r
929 }\r
930 FreePool (Packet);\r
931 }\r
932 }\r
933\r
934 //\r
935 // Unregister notify for Form package update\r
936 //\r
937 Status = mHiiDatabase->UnregisterPackageNotify (\r
938 mHiiDatabase,\r
939 NotifyHandle\r
940 );\r
941 //\r
942 // UEFI SetupBrowser handles scenario differently with Framework SetupBrowser when call back function \r
943 // update any forms in HII database. UEFI SetupBrowser will re-parse the displaying form package and load\r
944 // the values from variable storages. Framework SetupBrowser will only re-parse the displaying form packages.\r
945 // To make sure customer's previous changes is saved and the changing question behaves as expected, we\r
946 // issue a EFI_BROWSER_ACTION_REQUEST_SUBMIT to ask UEFI SetupBrowser to save the changes proceed to re-parse\r
947 // the form and load all the variable storages.\r
948 //\r
949 if (*ActionRequest == EFI_BROWSER_ACTION_REQUEST_NONE && mHiiPackageListUpdated) {\r
950 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT;\r
ebbd2793 951 }\r
0368663f 952\r
953 DestroyIfrDataArray (Data, NvMapAllocated);\r
ebbd2793 954 \r
955 return Status;\r
956}\r
957\r