]>
Commit | Line | Data |
---|---|---|
26a76fbc | 1 | /** @file\r |
a9d85320 | 2 | This file implements functions related to Config Access Protocols installed by\r |
3 | by HII Thunk Modules. These Config access Protocols are used to thunk UEFI Config \r | |
4 | Access Callback to Framework HII Callback and EFI Variable Set/Get operations.\r | |
ebbd2793 | 5 | \r |
7412cb4d | 6 | Copyright (c) 2008 - 2012, Intel Corporation. All rights reserved.<BR>\r |
584d5652 | 7 | This program and the accompanying materials\r |
ebbd2793 | 8 | are licensed and made available under the terms and conditions of the BSD License\r |
9 | which accompanies this distribution. The full text of the license may be found at\r | |
10 | http://opensource.org/licenses/bsd-license.php\r | |
11 | \r | |
12 | THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r | |
13 | WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r | |
14 | \r | |
15 | **/\r | |
16 | \r | |
17 | #include "HiiDatabase.h"\r | |
a9d85320 | 18 | #include "UefiIfrParser.h"\r |
ebbd2793 | 19 | \r |
a9d85320 | 20 | BOOLEAN mHiiPackageListUpdated = FALSE;\r |
0368663f | 21 | \r |
f6f910dd | 22 | HII_VENDOR_DEVICE_PATH mUefiHiiVendorDevicePath = {\r |
23 | {\r | |
24 | {\r | |
f6f910dd | 25 | {\r |
6d931089 LG |
26 | HARDWARE_DEVICE_PATH,\r |
27 | HW_VENDOR_DP,\r | |
28 | {\r | |
29 | (UINT8) (sizeof (HII_VENDOR_DEVICE_PATH_NODE)),\r | |
30 | (UINT8) ((sizeof (HII_VENDOR_DEVICE_PATH_NODE)) >> 8)\r | |
31 | }\r | |
32 | },\r | |
33 | EFI_CALLER_ID_GUID\r | |
f6f910dd | 34 | },\r |
6d931089 LG |
35 | 0,\r |
36 | 0\r | |
f6f910dd | 37 | },\r |
38 | {\r | |
39 | END_DEVICE_PATH_TYPE,\r | |
40 | END_ENTIRE_DEVICE_PATH_SUBTYPE,\r | |
41 | { \r | |
6d931089 LG |
42 | (UINT8) (sizeof (EFI_DEVICE_PATH_PROTOCOL)),\r |
43 | (UINT8) ((sizeof (EFI_DEVICE_PATH_PROTOCOL)) >> 8)\r | |
f6f910dd | 44 | }\r |
45 | }\r | |
46 | };\r | |
47 | \r | |
0368663f | 48 | CONFIG_ACCESS_PRIVATE gConfigAccessPrivateTempate = {\r |
49 | CONFIG_ACCESS_PRIVATE_SIGNATURE,\r | |
ebbd2793 | 50 | {\r |
51 | ThunkExtractConfig,\r | |
52 | ThunkRouteConfig,\r | |
53 | ThunkCallback\r | |
54 | }, //ConfigAccessProtocol\r | |
0368663f | 55 | NULL, //FormCallbackProtocol\r |
0368663f | 56 | NULL \r |
ebbd2793 | 57 | };\r |
58 | \r | |
1a6cdbd9 | 59 | /**\r |
a9d85320 | 60 | Get the first EFI_IFR_VARSTORE from the FormSet. \r |
61 | \r | |
62 | @param FormSet The Form Set.\r | |
63 | \r | |
64 | @retval FORMSET_STORAGE * Return the first EFI_IFR_VARSTORE.\r | |
65 | @retval NULL If the Form Set does not have EFI_IFR_VARSTORE.\r | |
66 | **/\r | |
67 | FORMSET_STORAGE *\r | |
68 | GetFirstStorageOfFormSet (\r | |
69 | IN CONST FORM_BROWSER_FORMSET * FormSet\r | |
70 | ) \r | |
71 | {\r | |
72 | LIST_ENTRY *StorageList;\r | |
73 | FORMSET_STORAGE *Storage;\r | |
74 | \r | |
75 | StorageList = GetFirstNode (&FormSet->StorageListHead);\r | |
76 | \r | |
7412cb4d | 77 | while (!IsNull (&FormSet->StorageListHead, StorageList)) {\r |
a9d85320 | 78 | Storage = FORMSET_STORAGE_FROM_LINK (StorageList);\r |
7412cb4d ED |
79 | if (Storage->Type == EFI_HII_VARSTORE_BUFFER) {\r |
80 | return Storage;\r | |
81 | }\r | |
82 | StorageList = GetNextNode (&FormSet->StorageListHead, StorageList);\r | |
a9d85320 | 83 | }\r |
84 | \r | |
85 | return NULL;\r | |
86 | }\r | |
87 | \r | |
88 | /**\r | |
b6c72071 | 89 | Get the FORM_BROWSER_STATEMENT that matches the Question's value.\r |
1a6cdbd9 | 90 | \r |
a9d85320 | 91 | @param FormSet The Form Set.\r |
b6c72071 | 92 | @param QuestionId QuestionId\r |
1a6cdbd9 | 93 | \r |
b6c72071 LG |
94 | @retval FORM_BROWSER_STATEMENT* FORM_BROWSER_STATEMENT that match Question's value.\r |
95 | @retval NULL If the Form Set does not have EFI_IFR_VARSTORE.\r | |
1a6cdbd9 | 96 | **/\r |
b6c72071 | 97 | FORM_BROWSER_STATEMENT *\r |
a9d85320 | 98 | GetStorageFromQuestionId (\r |
99 | IN CONST FORM_BROWSER_FORMSET * FormSet,\r | |
100 | IN EFI_QUESTION_ID QuestionId\r | |
ebbd2793 | 101 | )\r |
102 | {\r | |
a9d85320 | 103 | LIST_ENTRY *FormList;\r |
104 | LIST_ENTRY *StatementList;\r | |
105 | FORM_BROWSER_FORM *Form;\r | |
106 | FORM_BROWSER_STATEMENT *Statement;\r | |
107 | \r | |
108 | FormList = GetFirstNode (&FormSet->FormListHead);\r | |
109 | \r | |
110 | while (!IsNull (&FormSet->FormListHead, FormList)) {\r | |
111 | Form = FORM_BROWSER_FORM_FROM_LINK (FormList);\r | |
112 | \r | |
113 | StatementList = GetFirstNode (&Form->StatementListHead);\r | |
114 | \r | |
115 | while (!IsNull (&Form->StatementListHead, StatementList)) {\r | |
116 | Statement = FORM_BROWSER_STATEMENT_FROM_LINK (StatementList);\r | |
117 | if ((QuestionId == Statement->QuestionId) && (Statement->Storage != NULL)) {\r | |
118 | //\r | |
119 | // UEFI Question ID is unique in a FormSet.\r | |
120 | //\r | |
121 | ASSERT (Statement->Storage->Type == EFI_HII_VARSTORE_BUFFER);\r | |
b6c72071 | 122 | return Statement;\r |
a9d85320 | 123 | }\r |
124 | StatementList = GetNextNode (&Form->StatementListHead, StatementList);\r | |
125 | }\r | |
ebbd2793 | 126 | \r |
a9d85320 | 127 | FormList = GetNextNode (&FormSet->FormListHead, FormList);\r |
128 | }\r | |
129 | \r | |
130 | return NULL;\r | |
131 | }\r | |
ebbd2793 | 132 | \r |
1a6cdbd9 | 133 | /**\r |
a9d85320 | 134 | Get the EFI_IFR_VARSTORE based the <ConfigHdr> string in a <ConfigRequest>\r |
135 | or a <ConfigResp> string.\r | |
136 | \r | |
137 | @param FormSet The Form Set.\r | |
138 | @param ConfigString The Configuration String which is defined by UEFI HII.\r | |
1a6cdbd9 | 139 | \r |
a9d85320 | 140 | @retval FORMSET_STORAGE * The EFI_IFR_VARSTORE where the Question's value is stored.\r |
141 | @retval NULL If the Form Set does not have EFI_IFR_VARSTORE with such ID.\r | |
1a6cdbd9 | 142 | **/\r |
a9d85320 | 143 | FORMSET_STORAGE *\r |
144 | GetStorageFromConfigString (\r | |
145 | IN CONST FORM_BROWSER_FORMSET *FormSet,\r | |
146 | IN CONST EFI_STRING ConfigString\r | |
ebbd2793 | 147 | )\r |
148 | {\r | |
a9d85320 | 149 | LIST_ENTRY *StorageList;\r |
150 | FORMSET_STORAGE *Storage;\r | |
dee207ee | 151 | CHAR16 *Name;\r |
ebbd2793 | 152 | \r |
59aefb7e LG |
153 | if (ConfigString == NULL) {\r |
154 | return NULL;\r | |
155 | }\r | |
156 | \r | |
a9d85320 | 157 | StorageList = GetFirstNode (&FormSet->StorageListHead);\r |
ebbd2793 | 158 | \r |
a9d85320 | 159 | while (!IsNull (&FormSet->StorageListHead, StorageList)) {\r |
160 | Storage = FORMSET_STORAGE_FROM_LINK (StorageList);\r | |
7412cb4d ED |
161 | StorageList = GetNextNode (&FormSet->StorageListHead, StorageList);\r |
162 | if (Storage->Type != EFI_HII_VARSTORE_BUFFER) {\r | |
163 | continue;\r | |
164 | }\r | |
ebbd2793 | 165 | \r |
dee207ee | 166 | if ((Storage->VarStoreId == FormSet->DefaultVarStoreId) && (FormSet->OriginalDefaultVarStoreName != NULL)) {\r |
167 | Name = FormSet->OriginalDefaultVarStoreName;\r | |
168 | } else {\r | |
169 | Name = Storage->Name;\r | |
170 | }\r | |
171 | \r | |
a5420536 | 172 | if (HiiIsConfigHdrMatch (ConfigString, &Storage->Guid, Name)) {\r |
a9d85320 | 173 | return Storage;\r |
ebbd2793 | 174 | }\r |
175 | }\r | |
1a6cdbd9 | 176 | \r |
59aefb7e | 177 | return NULL;\r |
ebbd2793 | 178 | }\r |
0368663f | 179 | \r |
1a6cdbd9 | 180 | /**\r |
181 | This function installs a EFI_CONFIG_ACCESS_PROTOCOL instance for a form package registered\r | |
182 | by a module using Framework HII Protocol Interfaces.\r | |
183 | \r | |
a9d85320 | 184 | UEFI HII require EFI_HII_CONFIG_ACCESS_PROTOCOL to be installed on a EFI_HANDLE, so\r |
185 | that Setup Utility can load the Buffer Storage using this protocol.\r | |
1a6cdbd9 | 186 | \r |
a9d85320 | 187 | @param Packages The Package List.\r |
188 | @param ThunkContext The Thunk Context.\r | |
1a6cdbd9 | 189 | \r |
a9d85320 | 190 | @retval EFI_SUCCESS The Config Access Protocol is installed successfully.\r |
191 | @retval EFI_OUT_RESOURCE There is not enough memory.\r | |
1a6cdbd9 | 192 | \r |
193 | **/\r | |
ebbd2793 | 194 | EFI_STATUS\r |
0368663f | 195 | InstallDefaultConfigAccessProtocol (\r |
196 | IN CONST EFI_HII_PACKAGES *Packages,\r | |
197 | IN OUT HII_THUNK_CONTEXT *ThunkContext\r | |
ebbd2793 | 198 | )\r |
199 | {\r | |
ebbd2793 | 200 | EFI_STATUS Status;\r |
0368663f | 201 | CONFIG_ACCESS_PRIVATE *ConfigAccessInstance;\r |
6d931089 | 202 | HII_VENDOR_DEVICE_PATH *HiiVendorPath;\r |
ebbd2793 | 203 | \r |
a9d85320 | 204 | ASSERT (ThunkContext->IfrPackageCount != 0);\r |
205 | \r | |
ebbd2793 | 206 | ConfigAccessInstance = AllocateCopyPool (\r |
0368663f | 207 | sizeof (CONFIG_ACCESS_PRIVATE), \r |
208 | &gConfigAccessPrivateTempate\r | |
ebbd2793 | 209 | );\r |
1a6cdbd9 | 210 | ASSERT (ConfigAccessInstance != NULL);\r |
6d931089 LG |
211 | \r |
212 | //\r | |
213 | // Use memory address as unique ID to distinguish from different device paths\r | |
214 | // This function may be called multi times by the framework HII driver.\r | |
215 | //\r | |
216 | HiiVendorPath = AllocateCopyPool (\r | |
217 | sizeof (HII_VENDOR_DEVICE_PATH), \r | |
218 | &mUefiHiiVendorDevicePath\r | |
219 | );\r | |
220 | ASSERT (HiiVendorPath != NULL);\r | |
221 | \r | |
222 | HiiVendorPath->Node.UniqueId = (UINT64) ((UINTN) HiiVendorPath);\r | |
223 | \r | |
ebbd2793 | 224 | Status = gBS->InstallMultipleProtocolInterfaces (\r |
0368663f | 225 | &ThunkContext->UefiHiiDriverHandle,\r |
f6f910dd | 226 | &gEfiDevicePathProtocolGuid, \r |
6d931089 | 227 | HiiVendorPath,\r |
ebbd2793 | 228 | &gEfiHiiConfigAccessProtocolGuid,\r |
229 | &ConfigAccessInstance->ConfigAccessProtocol,\r | |
230 | NULL\r | |
231 | );\r | |
232 | ASSERT_EFI_ERROR (Status);\r | |
0368663f | 233 | \r |
0368663f | 234 | ConfigAccessInstance->ThunkContext = ThunkContext;\r |
ebbd2793 | 235 | \r |
236 | return EFI_SUCCESS;\r | |
237 | }\r | |
238 | \r | |
a9d85320 | 239 | /**\r |
240 | This function un-installs the EFI_CONFIG_ACCESS_PROTOCOL instance for a form package registered\r | |
241 | by a module using Framework HII Protocol Interfaces.\r | |
0368663f | 242 | \r |
a9d85320 | 243 | ASSERT if no Config Access is found for such pakcage list or failed to uninstall the protocol.\r |
0368663f | 244 | \r |
a9d85320 | 245 | @param ThunkContext The Thunk Context.\r |
246 | \r | |
247 | **/\r | |
0368663f | 248 | VOID\r |
249 | UninstallDefaultConfigAccessProtocol (\r | |
250 | IN HII_THUNK_CONTEXT *ThunkContext\r | |
ebbd2793 | 251 | )\r |
252 | {\r | |
0368663f | 253 | EFI_STATUS Status;\r |
254 | EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;\r | |
647a768d | 255 | HII_VENDOR_DEVICE_PATH *HiiVendorPath;\r |
256 | \r | |
0368663f | 257 | Status = gBS->HandleProtocol (\r |
258 | ThunkContext->UefiHiiDriverHandle,\r | |
259 | &gEfiHiiConfigAccessProtocolGuid,\r | |
260 | (VOID **) &ConfigAccess\r | |
261 | );\r | |
0368663f | 262 | ASSERT_EFI_ERROR (Status);\r |
263 | \r | |
647a768d | 264 | Status = gBS->HandleProtocol (\r |
265 | ThunkContext->UefiHiiDriverHandle,\r | |
266 | &gEfiDevicePathProtocolGuid,\r | |
267 | (VOID **) &HiiVendorPath\r | |
268 | );\r | |
269 | ASSERT_EFI_ERROR (Status);\r | |
270 | \r | |
f6f910dd | 271 | Status = gBS->UninstallMultipleProtocolInterfaces (\r |
0368663f | 272 | ThunkContext->UefiHiiDriverHandle,\r |
f6f910dd | 273 | &gEfiDevicePathProtocolGuid,\r |
647a768d | 274 | HiiVendorPath,\r |
0368663f | 275 | &gEfiHiiConfigAccessProtocolGuid,\r |
f6f910dd | 276 | ConfigAccess,\r |
277 | NULL\r | |
0368663f | 278 | );\r |
279 | ASSERT_EFI_ERROR (Status);\r | |
280 | \r | |
ebbd2793 | 281 | }\r |
0368663f | 282 | \r |
ebbd2793 | 283 | \r |
1a6cdbd9 | 284 | /**\r |
285 | Wrap the EFI_HII_CONFIG_ACCESS_PROTOCOL.ExtractConfig to a call to EFI_FORM_CALLBACK_PROTOCOL.NvRead.\r | |
286 | \r | |
0368663f | 287 | @param BufferStorage The key with all attributes needed to call EFI_FORM_CALLBACK_PROTOCOL.NvRead.\r |
288 | @param FwFormCallBack The EFI_FORM_CALLBACK_PROTOCOL registered by Framework HII module.\r | |
289 | @param Data The data read.\r | |
290 | @param DataSize The size of data.\r | |
1a6cdbd9 | 291 | \r |
0368663f | 292 | @retval EFI_STATUS The status returned by the EFI_FORM_CALLBACK_PROTOCOL.NvWrite.\r |
1a6cdbd9 | 293 | @retval EFI_INVALID_PARAMETER If the EFI_FORM_CALLBACK_PROTOCOL.NvRead return the size information of the data\r |
0368663f | 294 | does not match what has been recorded early in he BUFFER_STORAGE_ENTRY.\r |
1a6cdbd9 | 295 | **/\r |
ebbd2793 | 296 | EFI_STATUS\r |
0368663f | 297 | CallFormCallBack (\r |
a9d85320 | 298 | IN FORMSET_STORAGE *BufferStorage,\r |
0368663f | 299 | IN EFI_FORM_CALLBACK_PROTOCOL *FwFormCallBack,\r |
ebbd2793 | 300 | OUT VOID **Data,\r |
301 | OUT UINTN *DataSize\r | |
302 | )\r | |
303 | {\r | |
304 | EFI_STATUS Status;\r | |
305 | \r | |
306 | *DataSize = 0;\r | |
307 | *Data = NULL;\r | |
308 | \r | |
0368663f | 309 | Status = FwFormCallBack->NvRead (\r |
310 | FwFormCallBack, \r | |
311 | BufferStorage->Name,\r | |
312 | &BufferStorage->Guid,\r | |
ebbd2793 | 313 | NULL,\r |
314 | DataSize,\r | |
315 | *Data\r | |
316 | );\r | |
317 | if (Status == EFI_BUFFER_TOO_SMALL) {\r | |
0368663f | 318 | if (BufferStorage->Size != *DataSize) {\r |
ebbd2793 | 319 | ASSERT (FALSE);\r |
320 | return EFI_INVALID_PARAMETER;\r | |
321 | }\r | |
322 | \r | |
323 | *Data = AllocateZeroPool (*DataSize);\r | |
e0e51f62 | 324 | if (*Data == NULL) {\r |
ebbd2793 | 325 | return EFI_OUT_OF_RESOURCES;\r |
326 | }\r | |
327 | \r | |
e0e51f62 | 328 | Status = FwFormCallBack->NvRead (\r |
0368663f | 329 | FwFormCallBack, \r |
330 | BufferStorage->Name,\r | |
331 | &BufferStorage->Guid,\r | |
ebbd2793 | 332 | NULL,\r |
333 | DataSize,\r | |
334 | *Data\r | |
335 | );\r | |
336 | }\r | |
337 | \r | |
338 | return Status;\r | |
339 | }\r | |
340 | \r | |
1a6cdbd9 | 341 | \r |
342 | /**\r | |
343 | Wrap the EFI_HII_CONFIG_ACCESS_PROTOCOL.ExtractConfig to a call to UEFI Variable Get Service.\r | |
344 | \r | |
0368663f | 345 | @param BufferStorage The key with all attributes needed to call a UEFI Variable Get Service.\r |
346 | @param Data The data read.\r | |
347 | @param DataSize The size of data.\r | |
1a6cdbd9 | 348 | \r |
349 | If the UEFI Variable Get Service return the size information of the data\r | |
0368663f | 350 | does not match what has been recorded early in he BUFFER_STORAGE_ENTRY.\r |
1a6cdbd9 | 351 | then ASSERT.\r |
352 | \r | |
0368663f | 353 | @retval EFI_STATUS The status returned by the UEFI Variable Get Service.\r |
1a6cdbd9 | 354 | @retval EFI_INVALID_PARAMETER If the UEFI Variable Get Service return the size information of the data\r |
0368663f | 355 | does not match what has been recorded early in he BUFFER_STORAGE_ENTRY.\r |
1a6cdbd9 | 356 | **/\r |
ebbd2793 | 357 | EFI_STATUS\r |
0368663f | 358 | GetUefiVariable (\r |
a9d85320 | 359 | IN FORMSET_STORAGE *BufferStorage,\r |
ebbd2793 | 360 | OUT VOID **Data,\r |
361 | OUT UINTN *DataSize\r | |
362 | )\r | |
363 | {\r | |
364 | EFI_STATUS Status;\r | |
365 | \r | |
366 | *DataSize = 0;\r | |
367 | *Data = NULL;\r | |
368 | Status = gRT->GetVariable (\r | |
0368663f | 369 | BufferStorage->Name,\r |
370 | &BufferStorage->Guid,\r | |
ebbd2793 | 371 | NULL,\r |
372 | DataSize,\r | |
373 | *Data\r | |
374 | );\r | |
375 | if (Status == EFI_BUFFER_TOO_SMALL) {\r | |
376 | \r | |
0368663f | 377 | if (BufferStorage->Size != *DataSize) {\r |
ebbd2793 | 378 | ASSERT (FALSE);\r |
379 | return EFI_INVALID_PARAMETER;\r | |
380 | }\r | |
381 | \r | |
382 | *Data = AllocateZeroPool (*DataSize);\r | |
e0e51f62 | 383 | if (*Data == NULL) {\r |
ebbd2793 | 384 | return EFI_OUT_OF_RESOURCES;\r |
385 | }\r | |
386 | \r | |
387 | Status = gRT->GetVariable (\r | |
0368663f | 388 | BufferStorage->Name,\r |
389 | &BufferStorage->Guid,\r | |
ebbd2793 | 390 | NULL,\r |
391 | DataSize,\r | |
392 | *Data\r | |
393 | );\r | |
394 | }\r | |
395 | \r | |
396 | return Status;\r | |
397 | }\r | |
398 | \r | |
1a6cdbd9 | 399 | /**\r |
400 | \r | |
401 | This function implement the EFI_HII_CONFIG_ACCESS_PROTOCOL.ExtractConfig\r | |
402 | so that data can be read from the data storage such as UEFI Variable or module's\r | |
403 | customized storage exposed by EFI_FRAMEWORK_CALLBACK.\r | |
404 | \r | |
0368663f | 405 | @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL\r |
1a6cdbd9 | 406 | @param Request A null-terminated Unicode string in <ConfigRequest> format. Note that this\r |
0368663f | 407 | includes the routing information as well as the configurable name / value pairs. It is\r |
408 | invalid for this string to be in <MultiConfigRequest> format.\r | |
1a6cdbd9 | 409 | \r |
0368663f | 410 | @param Progress On return, points to a character in the Request string. Points to the string's null\r |
411 | terminator if request was successful. Points to the most recent '&' before the first\r | |
412 | failing name / value pair (or the beginning of the string if the failure is in the first\r | |
413 | name / value pair) if the request was not successful\r | |
1a6cdbd9 | 414 | @param Results A null-terminated Unicode string in <ConfigAltResp> format which has all\r |
0368663f | 415 | values filled in for the names in the Request string. String to be allocated by the called\r |
416 | function.\r | |
1a6cdbd9 | 417 | \r |
418 | @retval EFI_INVALID_PARAMETER If there is no Buffer Storage for this Config Access instance.\r | |
0368663f | 419 | @retval EFI_SUCCESS The setting is retrived successfully.\r |
420 | @retval !EFI_SUCCESS The error returned by UEFI Get Variable or Framework Form Callback Nvread.\r | |
1a6cdbd9 | 421 | **/\r |
ebbd2793 | 422 | EFI_STATUS\r |
423 | EFIAPI\r | |
424 | ThunkExtractConfig (\r | |
425 | IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,\r | |
426 | IN CONST EFI_STRING Request,\r | |
427 | OUT EFI_STRING *Progress,\r | |
428 | OUT EFI_STRING *Results\r | |
429 | )\r | |
430 | {\r | |
59aefb7e LG |
431 | EFI_STATUS Status;\r |
432 | CONFIG_ACCESS_PRIVATE *ConfigAccess;\r | |
433 | FORMSET_STORAGE *BufferStorage;\r | |
434 | VOID *Data;\r | |
435 | UINTN DataSize;\r | |
436 | FORM_BROWSER_FORMSET *FormSetContext;\r | |
437 | CHAR16 *VarStoreName;\r | |
438 | EFI_STRING ConfigRequestHdr;\r | |
439 | EFI_STRING ConfigRequest;\r | |
440 | UINTN Size;\r | |
441 | BOOLEAN AllocatedRequest;\r | |
442 | LIST_ENTRY *StorageList;\r | |
443 | EFI_STRING SingleResult;\r | |
444 | EFI_STRING FinalResults;\r | |
445 | EFI_STRING StrPointer;\r | |
446 | \r | |
447 | if (Progress == NULL || Results == NULL) {\r | |
448 | return EFI_INVALID_PARAMETER;\r | |
449 | }\r | |
450 | *Progress = Request;\r | |
451 | \r | |
452 | Status = EFI_SUCCESS;\r | |
453 | Data = NULL;\r | |
454 | StrPointer = NULL;\r | |
455 | SingleResult = NULL;\r | |
456 | FinalResults = NULL;\r | |
457 | ConfigAccess = CONFIG_ACCESS_PRIVATE_FROM_PROTOCOL (This);\r | |
458 | FormSetContext = ConfigAccess->ThunkContext->FormSet;\r | |
459 | if (IsListEmpty (&FormSetContext->StorageListHead)) {\r | |
460 | //\r | |
461 | // No VarStorage does exist in this form.\r | |
462 | //\r | |
6a179dca | 463 | return EFI_NOT_FOUND;\r |
464 | }\r | |
59aefb7e | 465 | StorageList = GetFirstNode (&FormSetContext->StorageListHead);\r |
6a179dca | 466 | \r |
59aefb7e LG |
467 | do {\r |
468 | if (Request != NULL) {\r | |
469 | BufferStorage = GetStorageFromConfigString (ConfigAccess->ThunkContext->FormSet, Request);\r | |
470 | if (BufferStorage == NULL) {\r | |
471 | return EFI_NOT_FOUND;\r | |
472 | }\r | |
473 | } else {\r | |
474 | if (IsNull (&FormSetContext->StorageListHead, StorageList)) {\r | |
475 | //\r | |
476 | // No Storage to be extracted into the results.\r | |
477 | //\r | |
478 | break;\r | |
479 | }\r | |
480 | BufferStorage = FORMSET_STORAGE_FROM_LINK (StorageList);\r | |
481 | StorageList = GetNextNode (&FormSetContext->StorageListHead, StorageList);\r | |
7412cb4d ED |
482 | if (BufferStorage->Type != EFI_HII_VARSTORE_BUFFER) {\r |
483 | //\r | |
484 | // BufferStorage type should be EFI_HII_VARSTORE_BUFFER\r | |
485 | //\r | |
486 | continue;\r | |
487 | }\r | |
59aefb7e LG |
488 | }\r |
489 | \r | |
490 | VarStoreName = NULL;\r | |
491 | ConfigRequestHdr = NULL;\r | |
492 | ConfigRequest = NULL;\r | |
493 | Size = 0;\r | |
494 | AllocatedRequest = FALSE;\r | |
495 | \r | |
496 | if (ConfigAccess->ThunkContext->NvMapOverride == NULL) {\r | |
497 | //\r | |
498 | // NvMapOverride is not used. Get the Storage data from EFI Variable or Framework Form Callback.\r | |
499 | //\r | |
500 | if (ConfigAccess->FormCallbackProtocol == NULL ||\r | |
501 | ConfigAccess->FormCallbackProtocol->NvRead == NULL) {\r | |
502 | Status = GetUefiVariable (\r | |
503 | BufferStorage,\r | |
504 | &Data,\r | |
505 | &DataSize\r | |
506 | );\r | |
507 | } else {\r | |
508 | Status = CallFormCallBack (\r | |
509 | BufferStorage,\r | |
510 | ConfigAccess->FormCallbackProtocol,\r | |
511 | &Data,\r | |
512 | &DataSize\r | |
513 | );\r | |
514 | }\r | |
515 | } else {\r | |
516 | //\r | |
517 | // Use the NvMapOverride.\r | |
518 | //\r | |
519 | DataSize = BufferStorage->Size;\r | |
520 | Data = AllocateCopyPool (DataSize, ConfigAccess->ThunkContext->NvMapOverride);\r | |
521 | \r | |
522 | if (Data != NULL) {\r | |
523 | Status = EFI_SUCCESS;\r | |
524 | } else {\r | |
525 | Status = EFI_OUT_OF_RESOURCES;\r | |
526 | }\r | |
527 | }\r | |
528 | \r | |
529 | if (!EFI_ERROR (Status)) {\r | |
530 | ConfigRequest = Request;\r | |
531 | if (Request == NULL || (StrStr (Request, L"OFFSET") == NULL)) {\r | |
532 | //\r | |
533 | // Request is without any request element, construct full request string.\r | |
534 | //\r | |
ebbd2793 | 535 | \r |
59aefb7e LG |
536 | if ((BufferStorage->VarStoreId == FormSetContext->DefaultVarStoreId) && (FormSetContext->OriginalDefaultVarStoreName != NULL)) {\r |
537 | VarStoreName = FormSetContext->OriginalDefaultVarStoreName;\r | |
538 | } else {\r | |
539 | VarStoreName = BufferStorage->Name;\r | |
540 | }\r | |
ebbd2793 | 541 | \r |
59aefb7e LG |
542 | //\r |
543 | // First Set ConfigRequestHdr string.\r | |
544 | //\r | |
545 | ConfigRequestHdr = HiiConstructConfigHdr (&BufferStorage->Guid, VarStoreName, ConfigAccess->ThunkContext->UefiHiiDriverHandle);\r | |
546 | ASSERT (ConfigRequestHdr != NULL);\r | |
6a179dca | 547 | \r |
59aefb7e LG |
548 | //\r |
549 | // Allocate and fill a buffer large enough to hold the <ConfigHdr> template \r | |
550 | // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator\r | |
551 | //\r | |
552 | Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16);\r | |
553 | ConfigRequest = AllocateZeroPool (Size);\r | |
554 | ASSERT (ConfigRequest != NULL);\r | |
555 | AllocatedRequest = TRUE;\r | |
556 | UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr, (UINT64)DataSize);\r | |
557 | FreePool (ConfigRequestHdr);\r | |
558 | }\r | |
559 | Status = mHiiConfigRoutingProtocol->BlockToConfig (\r | |
560 | mHiiConfigRoutingProtocol,\r | |
561 | ConfigRequest,\r | |
562 | Data,\r | |
563 | DataSize,\r | |
564 | &SingleResult,\r | |
565 | Progress\r | |
566 | );\r | |
567 | //\r | |
568 | // Free the allocated config request string.\r | |
569 | //\r | |
570 | if (AllocatedRequest) {\r | |
571 | FreePool (ConfigRequest);\r | |
572 | ConfigRequest = NULL;\r | |
573 | }\r | |
574 | }\r | |
a9d85320 | 575 | //\r |
59aefb7e | 576 | // Free the allocated Data\r |
a9d85320 | 577 | //\r |
59aefb7e LG |
578 | if (Data != NULL) {\r |
579 | FreePool (Data);\r | |
133a9dfb | 580 | }\r |
a9d85320 | 581 | //\r |
59aefb7e | 582 | // Directly return when meet with error\r |
a9d85320 | 583 | //\r |
59aefb7e LG |
584 | if (EFI_ERROR (Status)) {\r |
585 | break;\r | |
586 | }\r | |
587 | //\r | |
588 | // Merge result into the final results.\r | |
589 | //\r | |
590 | if (FinalResults == NULL) {\r | |
591 | FinalResults = SingleResult;\r | |
592 | SingleResult = NULL;\r | |
133a9dfb | 593 | } else {\r |
59aefb7e LG |
594 | Size = StrLen (FinalResults);\r |
595 | Size = Size + 1;\r | |
596 | Size = Size + StrLen (SingleResult) + 1;\r | |
597 | StrPointer = AllocateZeroPool (Size * sizeof (CHAR16));\r | |
598 | ASSERT (StrPointer != NULL);\r | |
599 | StrCpy (StrPointer, FinalResults);\r | |
600 | FreePool (FinalResults);\r | |
601 | FinalResults = StrPointer;\r | |
602 | StrPointer = StrPointer + StrLen (StrPointer);\r | |
603 | *StrPointer = L'&';\r | |
604 | StrCpy (StrPointer + 1, SingleResult);\r | |
605 | FreePool (SingleResult);\r | |
133a9dfb | 606 | }\r |
59aefb7e LG |
607 | } while (Request == NULL);\r |
608 | \r | |
ebbd2793 | 609 | if (!EFI_ERROR (Status)) {\r |
59aefb7e LG |
610 | *Results = FinalResults;\r |
611 | } else {\r | |
612 | if (FinalResults != NULL) {\r | |
613 | FreePool (FinalResults);\r | |
614 | }\r | |
ebbd2793 | 615 | }\r |
59aefb7e LG |
616 | //\r |
617 | // Set Progress string to the original request string.\r | |
618 | //\r | |
619 | if (Request == NULL) {\r | |
620 | *Progress = NULL;\r | |
621 | } else if (StrStr (Request, L"OFFSET") == NULL) {\r | |
622 | *Progress = Request + StrLen (Request);\r | |
7001eaf8 | 623 | }\r |
59aefb7e | 624 | \r |
ebbd2793 | 625 | return Status;\r |
626 | }\r | |
627 | \r | |
1a6cdbd9 | 628 | /**\r |
1a6cdbd9 | 629 | This function implement the EFI_HII_CONFIG_ACCESS_PROTOCOL.RouteConfig\r |
630 | so that data can be written to the data storage such as UEFI Variable or module's\r | |
631 | customized storage exposed by EFI_FRAMEWORK_CALLBACK.\r | |
632 | \r | |
0368663f | 633 | @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL\r |
634 | @param Configuration A null-terminated Unicode string in <ConfigResp> format.\r | |
fd0d281b | 635 | @param Progress A pointer to a string filled in with the offset of the most recent '&' before the first\r |
0368663f | 636 | failing name / value pair (or the beginning of the string if the failure is in the first\r |
637 | name / value pair) or the terminating NULL if all was successful.\r | |
1a6cdbd9 | 638 | \r |
639 | @retval EFI_INVALID_PARAMETER If there is no Buffer Storage for this Config Access instance.\r | |
0368663f | 640 | @retval EFI_SUCCESS The setting is saved successfully.\r |
641 | @retval !EFI_SUCCESS The error returned by UEFI Set Variable or Framework Form Callback Nvwrite.\r | |
1a6cdbd9 | 642 | **/ \r |
ebbd2793 | 643 | EFI_STATUS\r |
644 | EFIAPI\r | |
645 | ThunkRouteConfig (\r | |
646 | IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,\r | |
647 | IN CONST EFI_STRING Configuration,\r | |
648 | OUT EFI_STRING *Progress\r | |
649 | )\r | |
650 | {\r | |
651 | EFI_STATUS Status;\r | |
0368663f | 652 | CONFIG_ACCESS_PRIVATE *ConfigAccess;\r |
a9d85320 | 653 | FORMSET_STORAGE *BufferStorage;\r |
98b16b9d | 654 | VOID *Data;\r |
ebbd2793 | 655 | UINTN DataSize;\r |
0368663f | 656 | UINTN DataSize2;\r |
0368663f | 657 | BOOLEAN ResetRequired;\r |
658 | BOOLEAN DataAllocated;\r | |
ebbd2793 | 659 | \r |
6a179dca | 660 | if (Configuration == NULL) {\r |
661 | return EFI_INVALID_PARAMETER;\r | |
662 | }\r | |
663 | \r | |
ebbd2793 | 664 | Data = NULL;\r |
0368663f | 665 | ConfigAccess = CONFIG_ACCESS_PRIVATE_FROM_PROTOCOL (This);\r |
ebbd2793 | 666 | \r |
a9d85320 | 667 | BufferStorage = GetStorageFromConfigString (ConfigAccess->ThunkContext->FormSet, Configuration);\r |
ebbd2793 | 668 | \r |
6a179dca | 669 | if (BufferStorage == NULL) {\r |
670 | *Progress = Configuration;\r | |
671 | return EFI_NOT_FOUND;\r | |
672 | }\r | |
673 | \r | |
0368663f | 674 | DataSize2 = BufferStorage->Size;\r |
675 | if (ConfigAccess->ThunkContext->NvMapOverride == NULL) {\r | |
133a9dfb | 676 | DataAllocated = TRUE;\r |
0368663f | 677 | if (ConfigAccess->FormCallbackProtocol == NULL ||\r |
678 | ConfigAccess->FormCallbackProtocol->NvRead == NULL) {\r | |
679 | Status = GetUefiVariable (\r | |
680 | BufferStorage,\r | |
681 | &Data,\r | |
682 | &DataSize\r | |
683 | );\r | |
0368663f | 684 | } else {\r |
685 | Status = CallFormCallBack (\r | |
686 | BufferStorage,\r | |
687 | ConfigAccess->FormCallbackProtocol,\r | |
688 | &Data,\r | |
689 | &DataSize\r | |
690 | );\r | |
0368663f | 691 | }\r |
692 | } else {\r | |
133a9dfb | 693 | //\r |
694 | // ConfigToBlock will convert the Config String and update the NvMapOverride accordingly.\r | |
695 | //\r | |
0368663f | 696 | Status = EFI_SUCCESS;\r |
697 | Data = ConfigAccess->ThunkContext->NvMapOverride;\r | |
698 | DataSize = DataSize2;\r | |
699 | DataAllocated = FALSE;\r | |
700 | } \r | |
133a9dfb | 701 | if (EFI_ERROR (Status) || (DataSize2 != DataSize)) {\r |
702 | if (Data == NULL) {\r | |
703 | Data = AllocateZeroPool (DataSize2);\r | |
704 | }\r | |
ebbd2793 | 705 | }\r |
0368663f | 706 | \r |
995c5940 | 707 | DataSize = DataSize2;\r |
59336178 | 708 | Status = mHiiConfigRoutingProtocol->ConfigToBlock (\r |
709 | mHiiConfigRoutingProtocol,\r | |
ebbd2793 | 710 | Configuration,\r |
711 | Data,\r | |
995c5940 | 712 | &DataSize,\r |
ebbd2793 | 713 | Progress\r |
714 | );\r | |
ebbd2793 | 715 | if (EFI_ERROR (Status)) {\r |
716 | goto Done;\r | |
717 | }\r | |
e0e51f62 | 718 | \r |
133a9dfb | 719 | if (ConfigAccess->ThunkContext->NvMapOverride == NULL) {\r |
720 | if (ConfigAccess->FormCallbackProtocol == NULL ||\r | |
721 | ConfigAccess->FormCallbackProtocol->NvWrite == NULL) {\r | |
722 | Status = gRT->SetVariable (\r | |
723 | BufferStorage->Name,\r | |
724 | &BufferStorage->Guid,\r | |
725 | EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r | |
726 | DataSize2,\r | |
727 | Data\r | |
728 | );\r | |
729 | } else {\r | |
730 | Status = ConfigAccess->FormCallbackProtocol->NvWrite (\r | |
731 | ConfigAccess->FormCallbackProtocol, \r | |
732 | BufferStorage->Name,\r | |
733 | &BufferStorage->Guid,\r | |
734 | EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r | |
735 | DataSize2,\r | |
736 | Data,\r | |
737 | &ResetRequired\r | |
738 | );\r | |
133a9dfb | 739 | }\r |
ebbd2793 | 740 | }\r |
741 | \r | |
0368663f | 742 | Done: \r |
743 | if (DataAllocated && (Data != NULL)) {\r | |
744 | FreePool (Data);\r | |
745 | }\r | |
746 | \r | |
ebbd2793 | 747 | return Status;\r |
748 | }\r | |
749 | \r | |
a9d85320 | 750 | /**\r |
aa2ebe0f LG |
751 | Build the EFI_IFR_DATA_ARRAY which will be used to pass to \r |
752 | EFI_FORM_CALLBACK_PROTOCOL.Callback. Check definition of EFI_IFR_DATA_ARRAY\r | |
a9d85320 | 753 | for details.\r |
754 | \r | |
755 | ASSERT if the Question Type is not EFI_IFR_TYPE_NUM_SIZE_* or EFI_IFR_TYPE_STRING.\r | |
756 | \r | |
26a76fbc | 757 | @param ConfigAccess Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL\r |
a9d85320 | 758 | @param QuestionId The Question ID.\r |
759 | @param Type The Question Type.\r | |
760 | @param Value The Question Value.\r | |
761 | @param NvMapAllocated On output indicates if a buffer is allocated for NvMap.\r | |
762 | \r | |
aa2ebe0f | 763 | @return A pointer to EFI_IFR_DATA_ARRAY. The caller must free this buffer allocated.\r |
a9d85320 | 764 | **/ \r |
aa2ebe0f | 765 | EFI_IFR_DATA_ARRAY *\r |
0368663f | 766 | CreateIfrDataArray (\r |
767 | IN CONFIG_ACCESS_PRIVATE *ConfigAccess,\r | |
768 | IN EFI_QUESTION_ID QuestionId,\r | |
769 | IN UINT8 Type,\r | |
770 | IN EFI_IFR_TYPE_VALUE *Value,\r | |
771 | OUT BOOLEAN *NvMapAllocated\r | |
772 | )\r | |
773 | {\r | |
aa2ebe0f LG |
774 | EFI_IFR_DATA_ARRAY *IfrDataArray;\r |
775 | EFI_IFR_DATA_ENTRY *IfrDataEntry;\r | |
0368663f | 776 | UINTN BrowserDataSize;\r |
a5420536 | 777 | FORMSET_STORAGE *BufferStorage;\r |
286f0de7 | 778 | UINTN Size;\r |
286f0de7 | 779 | EFI_STRING String;\r |
b6c72071 | 780 | FORM_BROWSER_STATEMENT *Statement;\r |
286f0de7 | 781 | \r |
a9d85320 | 782 | *NvMapAllocated = FALSE;\r |
0368663f | 783 | \r |
a9d85320 | 784 | String = NULL;\r |
286f0de7 | 785 | \r |
786 | switch (Type) {\r | |
787 | case EFI_IFR_TYPE_NUM_SIZE_8:\r | |
788 | case EFI_IFR_TYPE_NUM_SIZE_16:\r | |
789 | case EFI_IFR_TYPE_NUM_SIZE_32:\r | |
790 | case EFI_IFR_TYPE_NUM_SIZE_64:\r | |
791 | case EFI_IFR_TYPE_BOOLEAN:\r | |
792 | Size = sizeof (*Value);\r | |
793 | break;\r | |
794 | \r | |
795 | case EFI_IFR_TYPE_STRING:\r | |
887c077d | 796 | if (Value->string == 0) {\r |
797 | Size = 0;\r | |
798 | } else {\r | |
799 | String = HiiGetString (ConfigAccess->ThunkContext->UefiHiiHandle, Value->string, NULL);\r | |
800 | ASSERT (String != NULL);\r | |
286f0de7 | 801 | \r |
887c077d | 802 | Size = StrSize (String);\r |
803 | }\r | |
286f0de7 | 804 | break;\r |
d2f91345 | 805 | \r |
806 | case EFI_IFR_TYPE_ACTION:\r | |
eebe3bb8 | 807 | case EFI_IFR_TYPE_UNDEFINED:\r |
d2f91345 | 808 | Size = 0;\r |
809 | break;\r | |
286f0de7 | 810 | \r |
811 | default:\r | |
812 | ASSERT (FALSE);\r | |
813 | Size = 0;\r | |
814 | break;\r | |
815 | }\r | |
816 | \r | |
aa2ebe0f | 817 | IfrDataArray = AllocateZeroPool (sizeof (EFI_IFR_DATA_ARRAY) + sizeof (EFI_IFR_DATA_ENTRY) + Size);\r |
0368663f | 818 | ASSERT (IfrDataArray != NULL);\r |
b6c72071 LG |
819 | IfrDataArray->EntryCount = 1;\r |
820 | IfrDataEntry = (EFI_IFR_DATA_ENTRY *) (IfrDataArray + 1);\r | |
0368663f | 821 | \r |
b6c72071 | 822 | Statement = GetStorageFromQuestionId (ConfigAccess->ThunkContext->FormSet, QuestionId);\r |
0368663f | 823 | \r |
b6c72071 | 824 | if (Statement == NULL || Statement->Storage == NULL) {\r |
a9d85320 | 825 | //\r |
826 | // The QuestionId is not associated with a Buffer Storage.\r | |
827 | // Try to get the first Buffer Storage then.\r | |
828 | //\r | |
829 | BufferStorage = GetFirstStorageOfFormSet (ConfigAccess->ThunkContext->FormSet);\r | |
b6c72071 LG |
830 | } else {\r |
831 | BufferStorage = Statement->Storage;\r | |
832 | IfrDataEntry->OpCode = Statement->Operand;\r | |
0368663f | 833 | }\r |
133a9dfb | 834 | \r |
a9d85320 | 835 | if (BufferStorage != NULL) {\r |
b6c72071 LG |
836 | BrowserDataSize = BufferStorage->Size;\r |
837 | IfrDataEntry->Length = (UINT8) (sizeof (EFI_IFR_DATA_ENTRY) + Size);\r | |
0368663f | 838 | \r |
a9d85320 | 839 | if (ConfigAccess->ThunkContext->NvMapOverride == NULL) {\r |
840 | *NvMapAllocated = TRUE;\r | |
841 | IfrDataArray->NvRamMap = AllocateZeroPool (BrowserDataSize);\r | |
842 | } else {\r | |
843 | *NvMapAllocated = FALSE;\r | |
844 | IfrDataArray->NvRamMap = ConfigAccess->ThunkContext->NvMapOverride;\r | |
845 | }\r | |
846 | \r | |
27e87dab | 847 | ASSERT (HiiGetBrowserData (&BufferStorage->Guid, BufferStorage->Name, BrowserDataSize, (UINT8 *) IfrDataArray->NvRamMap));\r |
0368663f | 848 | \r |
a9d85320 | 849 | switch (Type) {\r |
850 | case EFI_IFR_TYPE_NUM_SIZE_8:\r | |
851 | case EFI_IFR_TYPE_NUM_SIZE_16:\r | |
852 | case EFI_IFR_TYPE_NUM_SIZE_32:\r | |
853 | case EFI_IFR_TYPE_NUM_SIZE_64:\r | |
854 | case EFI_IFR_TYPE_BOOLEAN:\r | |
855 | CopyMem (&IfrDataEntry->Data, &(Value->u8), sizeof (*Value));\r | |
856 | break;\r | |
857 | \r | |
858 | case EFI_IFR_TYPE_STRING:\r | |
887c077d | 859 | if (Size != 0) {\r |
860 | ASSERT (String != NULL);\r | |
861 | StrCpy ((CHAR16 *) &IfrDataEntry->Data, String);\r | |
862 | FreePool (String);\r | |
863 | }\r | |
a9d85320 | 864 | break;\r |
d2f91345 | 865 | \r |
866 | case EFI_IFR_TYPE_ACTION:\r | |
eebe3bb8 | 867 | case EFI_IFR_TYPE_UNDEFINED:\r |
d2f91345 | 868 | break;\r |
869 | \r | |
a9d85320 | 870 | default:\r |
871 | ASSERT (FALSE);\r | |
872 | break;\r | |
873 | }\r | |
874 | \r | |
875 | //\r | |
aa2ebe0f | 876 | // Need to fiil in the information for the rest of field for EFI_IFR_DATA_ENTRY.\r |
a9d85320 | 877 | // It seems that no implementation is found to use other fields. Leave them uninitialized for now.\r |
878 | //\r | |
879 | //UINT8 OpCode; // Likely a string, numeric, or one-of\r | |
aa2ebe0f | 880 | //UINT8 Length; // Length of the EFI_IFR_DATA_ENTRY packet\r |
a9d85320 | 881 | //UINT16 Flags; // Flags settings to determine what behavior is desired from the browser after the callback\r |
882 | //VOID *Data; // The data in the form based on the op-code type - this is not a pointer to the data, the data follows immediately\r | |
883 | // If the OpCode is a OneOf or Numeric type - Data is a UINT16 value\r | |
884 | // If the OpCode is a String type - Data is a CHAR16[x] type\r | |
885 | // If the OpCode is a Checkbox type - Data is a UINT8 value\r | |
886 | // If the OpCode is a NV Access type - Data is a FRAMEWORK_EFI_IFR_NV_DATA structure\r | |
0368663f | 887 | }\r |
888 | \r | |
889 | return IfrDataArray;\r | |
890 | }\r | |
891 | \r | |
a9d85320 | 892 | /**\r |
893 | If a NvMapOverride is passed in to EFI_FORM_BROWSER_PROTOCOL.SendForm, the Form Browser\r | |
894 | needs to be informed when data changed in NvMapOverride. This function will invoke\r | |
895 | SetBrowserData () to set internal data of Form Browser.\r | |
896 | \r | |
897 | @param ConfigAccess The Config Access Private Context.\r | |
898 | @param QuestionId The Question Id that invokes the callback.\r | |
899 | \r | |
900 | \r | |
901 | **/\r | |
133a9dfb | 902 | VOID\r |
903 | SyncBrowserDataForNvMapOverride (\r | |
a9d85320 | 904 | IN CONST CONFIG_ACCESS_PRIVATE *ConfigAccess,\r |
905 | IN EFI_QUESTION_ID QuestionId\r | |
133a9dfb | 906 | )\r |
907 | {\r | |
a5420536 LG |
908 | FORMSET_STORAGE *BufferStorage;\r |
909 | BOOLEAN CheckFlag;\r | |
910 | UINTN BrowserDataSize;\r | |
b6c72071 | 911 | FORM_BROWSER_STATEMENT *Statement;\r |
133a9dfb | 912 | \r |
913 | if (ConfigAccess->ThunkContext->NvMapOverride != NULL) {\r | |
a9d85320 | 914 | \r |
b6c72071 | 915 | Statement = GetStorageFromQuestionId (ConfigAccess->ThunkContext->FormSet, QuestionId);\r |
a9d85320 | 916 | \r |
b6c72071 | 917 | if (Statement == NULL || Statement->Storage == NULL) {\r |
a9d85320 | 918 | //\r |
919 | // QuestionId is a statement without Storage.\r | |
920 | // 1) It is a Goto. \r | |
921 | // \r | |
922 | //\r | |
923 | BufferStorage = GetFirstStorageOfFormSet (ConfigAccess->ThunkContext->FormSet);\r | |
b6c72071 LG |
924 | } else {\r |
925 | BufferStorage = Statement->Storage;\r | |
a9d85320 | 926 | }\r |
927 | \r | |
928 | //\r | |
929 | // If NvMapOverride is not NULL, this Form must have at least one Buffer Type Variable Storage.\r | |
930 | //\r | |
931 | ASSERT (BufferStorage != NULL);\r | |
133a9dfb | 932 | \r |
a9d85320 | 933 | BrowserDataSize = BufferStorage->Size;\r |
133a9dfb | 934 | \r |
a5420536 LG |
935 | CheckFlag = HiiSetBrowserData (&BufferStorage->Guid, BufferStorage->Name, BrowserDataSize, ConfigAccess->ThunkContext->NvMapOverride, NULL);\r |
936 | ASSERT (CheckFlag);\r | |
133a9dfb | 937 | }\r |
938 | \r | |
939 | }\r | |
940 | \r | |
a9d85320 | 941 | /**\r |
aa2ebe0f | 942 | Free up resource allocated for a EFI_IFR_DATA_ARRAY by CreateIfrDataArray ().\r |
a9d85320 | 943 | \r |
aa2ebe0f LG |
944 | @param Array The EFI_IFR_DATA_ARRAY allocated.\r |
945 | @param NvMapAllocated If the NvRamMap is allocated for EFI_IFR_DATA_ARRAY.\r | |
a9d85320 | 946 | \r |
947 | **/\r | |
0368663f | 948 | VOID\r |
949 | DestroyIfrDataArray (\r | |
aa2ebe0f | 950 | IN EFI_IFR_DATA_ARRAY *Array,\r |
0368663f | 951 | IN BOOLEAN NvMapAllocated\r |
952 | )\r | |
953 | {\r | |
d4775f2a | 954 | if (Array != NULL) {\r |
955 | if (NvMapAllocated) {\r | |
956 | FreePool (Array->NvRamMap);\r | |
957 | }\r | |
0368663f | 958 | \r |
d4775f2a | 959 | FreePool (Array);\r |
960 | }\r | |
0368663f | 961 | }\r |
962 | \r | |
a9d85320 | 963 | /**\r |
964 | Get the ONE_OF_OPTION_MAP_ENTRY for a QuestionId that invokes the \r | |
965 | EFI_FORM_CALLBACK_PROTOCOL.Callback. The information is needed as\r | |
966 | the callback mechanism for EFI_IFR_ONE_OF_OPTION is changed from \r | |
967 | EFI_IFR_ONE_OF_OPTION in Framework IFR. Check EFI_IFR_GUID_OPTIONKEY\r | |
968 | for detailed information.\r | |
969 | \r | |
970 | @param ThunkContext The Thunk Context.\r | |
971 | @param QuestionId The Question Id.\r | |
972 | @param Type The Question Type.\r | |
973 | @param Value The One Of Option's value.\r | |
974 | \r | |
975 | @return The ONE_OF_OPTION_MAP_ENTRY found.\r | |
976 | @retval NULL If no entry is found.\r | |
977 | **/\r | |
0368663f | 978 | ONE_OF_OPTION_MAP_ENTRY *\r |
979 | GetOneOfOptionMapEntry (\r | |
980 | IN HII_THUNK_CONTEXT *ThunkContext,\r | |
981 | IN EFI_QUESTION_ID QuestionId,\r | |
982 | IN UINT8 Type,\r | |
983 | IN EFI_IFR_TYPE_VALUE *Value\r | |
984 | )\r | |
985 | {\r | |
986 | LIST_ENTRY *Link;\r | |
987 | LIST_ENTRY *Link2;\r | |
988 | ONE_OF_OPTION_MAP_ENTRY *OneOfOptionMapEntry;\r | |
989 | ONE_OF_OPTION_MAP *OneOfOptionMap;\r | |
a9d85320 | 990 | FORM_BROWSER_FORMSET *FormSet;\r |
0368663f | 991 | \r |
a9d85320 | 992 | FormSet = ThunkContext->FormSet;\r |
0368663f | 993 | \r |
a9d85320 | 994 | Link = GetFirstNode (&FormSet->OneOfOptionMapListHead);\r |
995 | \r | |
996 | while (!IsNull (&FormSet->OneOfOptionMapListHead, Link)) {\r | |
0368663f | 997 | OneOfOptionMap = ONE_OF_OPTION_MAP_FROM_LINK(Link);\r |
998 | if (OneOfOptionMap->QuestionId == QuestionId) {\r | |
999 | ASSERT (OneOfOptionMap->ValueType == Type);\r | |
1000 | \r | |
1001 | Link2 = GetFirstNode (&OneOfOptionMap->OneOfOptionMapEntryListHead);\r | |
1002 | \r | |
1003 | while (!IsNull (&OneOfOptionMap->OneOfOptionMapEntryListHead, Link2)) {\r | |
1004 | OneOfOptionMapEntry = ONE_OF_OPTION_MAP_ENTRY_FROM_LINK (Link2);\r | |
1005 | \r | |
1006 | if (CompareMem (Value, &OneOfOptionMapEntry->Value, sizeof (EFI_IFR_TYPE_VALUE)) == 0) {\r | |
1007 | return OneOfOptionMapEntry;\r | |
1008 | }\r | |
1009 | \r | |
1010 | Link2 = GetNextNode (&OneOfOptionMap->OneOfOptionMapEntryListHead, Link2);\r | |
1011 | }\r | |
1012 | }\r | |
1013 | \r | |
a9d85320 | 1014 | Link = GetNextNode (&FormSet->OneOfOptionMapListHead, Link);\r |
0368663f | 1015 | }\r |
1016 | \r | |
1017 | \r | |
1018 | return NULL;\r | |
1019 | }\r | |
1020 | \r | |
1021 | /**\r | |
1022 | Functions which are registered to receive notification of\r | |
1023 | database events have this prototype. The actual event is encoded\r | |
1024 | in NotifyType. The following table describes how PackageType,\r | |
1025 | PackageGuid, Handle, and Package are used for each of the\r | |
1026 | notification types.\r | |
1027 | \r | |
a9d85320 | 1028 | If any Pakcage List in database is updated, mHiiPackageListUpdated\r |
1029 | will be set. If mHiiPackageListUpdated is set, Framework ThunkCallback()\r | |
1030 | will force the UEFI Setup Browser to save the uncommitted data. This\r | |
1031 | is needed as Framework's Callback function may dynamically update\r | |
1032 | opcode in a Package List. UEFI Setup Browser will quit itself and reparse\r | |
1033 | the Package List's IFR and display it. UEFI Config Access's implementation\r | |
1034 | is required to save the modified (SetBrowserData or directly save the data\r | |
1035 | to NV storage). But Framework HII Modules is not aware of this rule. Therefore,\r | |
1036 | we will enforce the rule in ThunkCallback (). The side effect of force saving\r | |
1037 | of NV data is the NV flag in browser may not flag a update as data has already\r | |
1038 | been saved to NV storage.\r | |
1039 | \r | |
0368663f | 1040 | @param PackageType Package type of the notification.\r |
1041 | \r | |
1042 | @param PackageGuid If PackageType is\r | |
1043 | EFI_HII_PACKAGE_TYPE_GUID, then this is\r | |
1044 | the pointer to the GUID from the Guid\r | |
1045 | field of EFI_HII_PACKAGE_GUID_HEADER.\r | |
1046 | Otherwise, it must be NULL.\r | |
1047 | \r | |
1048 | @param Package Points to the package referred to by the\r | |
1049 | notification Handle The handle of the package\r | |
1050 | list which contains the specified package.\r | |
1051 | \r | |
1052 | @param Handle The HII handle.\r | |
1053 | \r | |
1054 | @param NotifyType The type of change concerning the\r | |
1055 | database. See\r | |
1056 | EFI_HII_DATABASE_NOTIFY_TYPE.\r | |
1057 | \r | |
1058 | **/\r | |
1059 | EFI_STATUS\r | |
1060 | EFIAPI\r | |
1061 | FormUpdateNotify (\r | |
1062 | IN UINT8 PackageType,\r | |
1063 | IN CONST EFI_GUID *PackageGuid,\r | |
1064 | IN CONST EFI_HII_PACKAGE_HEADER *Package,\r | |
1065 | IN EFI_HII_HANDLE Handle,\r | |
1066 | IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType\r | |
1067 | )\r | |
1068 | {\r | |
1069 | mHiiPackageListUpdated = TRUE;\r | |
1070 | \r | |
1071 | return EFI_SUCCESS;\r | |
1072 | }\r | |
1073 | \r | |
1a6cdbd9 | 1074 | /**\r |
1075 | Wrap the EFI_HII_CONFIG_ACCESS_PROTOCOL.CallBack to EFI_FORM_CALLBACK_PROTOCOL.Callback. Therefor,\r | |
a9d85320 | 1076 | the framework HII module willl do no porting and work with a UEFI HII SetupBrowser.\r |
1a6cdbd9 | 1077 | \r |
0368663f | 1078 | @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r |
1079 | @param Action Specifies the type of action taken by the browser. See EFI_BROWSER_ACTION_x.\r | |
1a6cdbd9 | 1080 | @param QuestionId A unique value which is sent to the original exporting driver so that it can identify the\r |
0368663f | 1081 | type of data to expect. The format of the data tends to vary based on the opcode that\r |
1082 | generated the callback.\r | |
1083 | @param Type The type of value for the question. See EFI_IFR_TYPE_x in\r | |
1084 | EFI_IFR_ONE_OF_OPTION.\r | |
1085 | @param Value A pointer to the data being sent to the original exporting driver. The type is specified\r | |
1086 | by Type. Type EFI_IFR_TYPE_VALUE is defined in\r | |
1087 | EFI_IFR_ONE_OF_OPTION.\r | |
1a6cdbd9 | 1088 | @param ActionRequest On return, points to the action requested by the callback function. Type\r |
0368663f | 1089 | EFI_BROWSER_ACTION_REQUEST is specified in SendForm() in the Form\r |
1090 | Browser Protocol.\r | |
1a6cdbd9 | 1091 | \r |
0368663f | 1092 | @retval EFI_UNSUPPORTED If the Framework HII module does not register Callback although it specify the opcode under\r |
1093 | focuse to be INTERRACTIVE.\r | |
1a6cdbd9 | 1094 | @retval EFI_SUCCESS The callback complete successfully.\r |
1095 | @retval !EFI_SUCCESS The error code returned by EFI_FORM_CALLBACK_PROTOCOL.Callback.\r | |
1096 | \r | |
1097 | **/\r | |
ebbd2793 | 1098 | EFI_STATUS\r |
1099 | EFIAPI\r | |
1100 | ThunkCallback (\r | |
1101 | IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,\r | |
1102 | IN EFI_BROWSER_ACTION Action,\r | |
1103 | IN EFI_QUESTION_ID QuestionId,\r | |
1104 | IN UINT8 Type,\r | |
1105 | IN EFI_IFR_TYPE_VALUE *Value,\r | |
1106 | OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest\r | |
1107 | )\r | |
1108 | {\r | |
1109 | EFI_STATUS Status;\r | |
0368663f | 1110 | CONFIG_ACCESS_PRIVATE *ConfigAccess;\r |
1111 | EFI_FORM_CALLBACK_PROTOCOL *FormCallbackProtocol;\r | |
ebbd2793 | 1112 | EFI_HII_CALLBACK_PACKET *Packet;\r |
aa2ebe0f LG |
1113 | EFI_IFR_DATA_ARRAY *Data;\r |
1114 | EFI_IFR_DATA_ENTRY *DataEntry;\r | |
0368663f | 1115 | UINT16 KeyValue;\r |
1116 | ONE_OF_OPTION_MAP_ENTRY *OneOfOptionMapEntry;\r | |
1117 | EFI_HANDLE NotifyHandle;\r | |
1118 | EFI_INPUT_KEY Key; \r | |
1119 | BOOLEAN NvMapAllocated;\r | |
ebbd2793 | 1120 | \r |
d664f8a2 ED |
1121 | if (Action == EFI_BROWSER_ACTION_CHANGING) {\r |
1122 | ASSERT (This != NULL);\r | |
1123 | ASSERT (Value != NULL);\r | |
1124 | ASSERT (ActionRequest != NULL);\r | |
880ea0e2 | 1125 | \r |
d664f8a2 | 1126 | *ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;\r |
ebbd2793 | 1127 | \r |
d664f8a2 | 1128 | ConfigAccess = CONFIG_ACCESS_PRIVATE_FROM_PROTOCOL (This);\r |
ebbd2793 | 1129 | \r |
d664f8a2 ED |
1130 | FormCallbackProtocol = ConfigAccess->FormCallbackProtocol;\r |
1131 | if (FormCallbackProtocol == NULL) {\r | |
1132 | ASSERT (FALSE);\r | |
1133 | return EFI_UNSUPPORTED;\r | |
1134 | }\r | |
ebbd2793 | 1135 | \r |
d664f8a2 ED |
1136 | //\r |
1137 | // Check if the QuestionId match a OneOfOption.\r | |
1138 | //\r | |
1139 | OneOfOptionMapEntry = GetOneOfOptionMapEntry (ConfigAccess->ThunkContext, QuestionId, Type, Value);\r | |
ebbd2793 | 1140 | \r |
d664f8a2 ED |
1141 | if (OneOfOptionMapEntry == NULL) {\r |
1142 | //\r | |
1143 | // This is not a One-Of-Option opcode. QuestionId is the KeyValue\r | |
1144 | //\r | |
1145 | KeyValue = QuestionId;\r | |
1146 | } else {\r | |
1147 | //\r | |
1148 | // Otherwise, use the original Key specified in One Of Option in the Framework VFR syntax.\r | |
1149 | //\r | |
1150 | KeyValue = OneOfOptionMapEntry->FwKey;\r | |
1151 | }\r | |
0368663f | 1152 | \r |
0368663f | 1153 | //\r |
d664f8a2 | 1154 | // Build the EFI_IFR_DATA_ARRAY\r |
0368663f | 1155 | //\r |
d664f8a2 ED |
1156 | Data = CreateIfrDataArray (ConfigAccess, QuestionId, Type, Value, &NvMapAllocated);\r |
1157 | \r | |
1158 | Status = mHiiDatabase->RegisterPackageNotify (\r | |
1159 | mHiiDatabase,\r | |
1160 | EFI_HII_PACKAGE_FORMS,\r | |
1161 | NULL,\r | |
1162 | FormUpdateNotify,\r | |
1163 | EFI_HII_DATABASE_NOTIFY_REMOVE_PACK,\r | |
1164 | &NotifyHandle\r | |
1165 | );\r | |
a9d85320 | 1166 | //\r |
d664f8a2 | 1167 | //Call the Framework Callback function.\r |
a9d85320 | 1168 | //\r |
d664f8a2 ED |
1169 | Packet = NULL;\r |
1170 | Status = FormCallbackProtocol->Callback (\r | |
1171 | FormCallbackProtocol,\r | |
1172 | KeyValue,\r | |
1173 | Data,\r | |
1174 | &Packet\r | |
1175 | );\r | |
1176 | SyncBrowserDataForNvMapOverride (ConfigAccess, QuestionId);\r | |
ebbd2793 | 1177 | \r |
0368663f | 1178 | //\r |
d664f8a2 | 1179 | // Callback require browser to perform action\r |
0368663f | 1180 | //\r |
d664f8a2 ED |
1181 | if (EFI_ERROR (Status)) {\r |
1182 | if (Packet != NULL) {\r | |
1183 | do {\r | |
1184 | CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, Packet->String, NULL);\r | |
1185 | } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r | |
1186 | }\r | |
1187 | //\r | |
1188 | // Error Code in Status is discarded.\r | |
1189 | //\r | |
1190 | } else {\r | |
1191 | if (Packet != NULL) {\r | |
1192 | if (Packet->DataArray.EntryCount == 1 && Packet->DataArray.NvRamMap == NULL) {\r | |
1193 | DataEntry = (EFI_IFR_DATA_ENTRY *) ((UINT8 *) Packet + sizeof (EFI_IFR_DATA_ARRAY));\r | |
1194 | if ((DataEntry->Flags & EXIT_REQUIRED) == EXIT_REQUIRED) {\r | |
1195 | *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;\r | |
1196 | }\r | |
1197 | \r | |
1198 | if ((DataEntry->Flags & SAVE_REQUIRED) == SAVE_REQUIRED) {\r | |
1199 | Status = ConfigAccess->ConfigAccessProtocol.RouteConfig (\r | |
1200 | &ConfigAccess->ConfigAccessProtocol,\r | |
1201 | NULL,\r | |
1202 | NULL\r | |
1203 | );\r | |
1204 | }\r | |
0368663f | 1205 | }\r |
d664f8a2 ED |
1206 | FreePool (Packet);\r |
1207 | }\r | |
0368663f | 1208 | }\r |
0368663f | 1209 | \r |
d664f8a2 ED |
1210 | //\r |
1211 | // Unregister notify for Form package update\r | |
1212 | //\r | |
1213 | Status = mHiiDatabase->UnregisterPackageNotify (\r | |
1214 | mHiiDatabase,\r | |
1215 | NotifyHandle\r | |
1216 | );\r | |
1217 | //\r | |
1218 | // UEFI SetupBrowser behaves differently with Framework SetupBrowser when call back function \r | |
1219 | // update any forms in HII database. UEFI SetupBrowser will re-parse the displaying form package and load\r | |
1220 | // the values from variable storages. Framework SetupBrowser will only re-parse the displaying form packages.\r | |
1221 | // To make sure customer's previous changes is saved and the changing question behaves as expected, we\r | |
1222 | // issue a EFI_BROWSER_ACTION_REQUEST_SUBMIT to ask UEFI SetupBrowser to save the changes proceed to re-parse\r | |
1223 | // the form and load all the variable storages.\r | |
1224 | //\r | |
1225 | if (*ActionRequest == EFI_BROWSER_ACTION_REQUEST_NONE && mHiiPackageListUpdated) {\r | |
1226 | mHiiPackageListUpdated= FALSE;\r | |
1227 | *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT;\r | |
1228 | } else {\r | |
1229 | if (ConfigAccess->ThunkContext->FormSet->SubClass == EFI_FRONT_PAGE_SUBCLASS ||\r | |
1230 | ConfigAccess->ThunkContext->FormSet->SubClass == EFI_SINGLE_USE_SUBCLASS) {\r | |
1231 | *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;\r | |
1232 | }\r | |
fed39e58 | 1233 | }\r |
0368663f | 1234 | \r |
d664f8a2 ED |
1235 | //\r |
1236 | // Clean up.\r | |
1237 | //\r | |
1238 | DestroyIfrDataArray (Data, NvMapAllocated);\r | |
1239 | \r | |
1240 | return Status;\r | |
1241 | }\r | |
d4775f2a | 1242 | \r |
a9d85320 | 1243 | //\r |
d664f8a2 | 1244 | // All other action return unsupported.\r |
a9d85320 | 1245 | //\r |
d664f8a2 | 1246 | return EFI_UNSUPPORTED;\r |
ebbd2793 | 1247 | }\r |
1248 | \r |