1 /** @file 2 Function and Macro defintions for to extract default values from UEFI Form package. 3 4 Copyright (c) 2008 - 2010, Intel Corporation. All rights reserved.<BR> 5 This program and the accompanying materials 6 are licensed and made available under the terms and conditions of the BSD License 7 which accompanies this distribution. The full text of the license may be found at 8 http://opensource.org/licenses/bsd-license.php 9 10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 12 13 **/ 14 15 #include "HiiDatabase.h" 16 #include "UefiIfrParser.h" 17 #include "UefiIfrDefault.h" 18 19 // 20 // Extern Variables 21 // 22 extern CONST EFI_HII_DATABASE_PROTOCOL *mHiiDatabase; 23 extern CONST EFI_HII_IMAGE_PROTOCOL *mHiiImageProtocol; 24 extern CONST EFI_HII_STRING_PROTOCOL *mHiiStringProtocol; 25 extern CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *mHiiConfigRoutingProtocol; 26 27 /** 28 Set the data position at Offset with Width in Node->Buffer based 29 the value passed in. 30 31 @param Node The Buffer Storage Node. 32 @param Value The input value. 33 @param Offset The offset in Node->Buffer for the update. 34 @param Width The length of the Value. 35 36 **/ 37 VOID 38 SetNodeBuffer ( 39 OUT UEFI_IFR_BUFFER_STORAGE_NODE *Node, 40 IN CONST EFI_HII_VALUE *Value, 41 IN UINTN Offset, 42 IN UINTN Width 43 ) 44 { 45 ASSERT (Node->Signature == UEFI_IFR_BUFFER_STORAGE_NODE_SIGNATURE); 46 ASSERT (Offset + Width <= Node->Size); 47 48 CopyMem (Node->Buffer + Offset, &Value->Value.u8, Width); 49 } 50 51 52 /** 53 Get question default value, and set it into the match var storage. 54 55 Note Framework 0.92's HII Implementation does not support for default value for these opcodes: 56 EFI_IFR_ORDERED_LIST_OP: 57 EFI_IFR_PASSWORD_OP: 58 EFI_IFR_STRING_OP: 59 60 @param Question Question to be set to its default value. 61 @param DefaultId The Class of the default. 62 @param VarStoreId Id of var storage. 63 @param Node Var storage buffer to store the got default value. 64 65 @retval EFI_SUCCESS Question is reset to default value. 66 67 **/ 68 EFI_STATUS 69 GetQuestionDefault ( 70 IN FORM_BROWSER_STATEMENT *Question, 71 IN UINT16 DefaultId, 72 IN UINT16 VarStoreId, 73 OUT UEFI_IFR_BUFFER_STORAGE_NODE *Node 74 ) 75 { 76 EFI_STATUS Status; 77 LIST_ENTRY *Link; 78 QUESTION_DEFAULT *Default; 79 QUESTION_OPTION *Option; 80 EFI_HII_VALUE *HiiValue; 81 82 Status = EFI_SUCCESS; 83 84 // 85 // Statement don't have storage, skip them 86 // 87 if (Question->QuestionId == 0) { 88 return Status; 89 } 90 91 if (Question->VarStoreId != VarStoreId) { 92 return Status; 93 } 94 95 ASSERT (Question->Storage->Type == EFI_HII_VARSTORE_BUFFER); 96 97 // 98 // There are three ways to specify default value for a Question: 99 // 1, use nested EFI_IFR_DEFAULT (highest priority) 100 // 2, set flags of EFI_ONE_OF_OPTION (provide Standard and Manufacturing default) 101 // 3, set flags of EFI_IFR_CHECKBOX (provide Standard and Manufacturing default) (lowest priority) 102 // 103 HiiValue = &Question->HiiValue; 104 105 // 106 // EFI_IFR_DEFAULT has highest priority 107 // 108 if (!IsListEmpty (&Question->DefaultListHead)) { 109 Link = GetFirstNode (&Question->DefaultListHead); 110 while (!IsNull (&Question->DefaultListHead, Link)) { 111 Default = QUESTION_DEFAULT_FROM_LINK (Link); 112 113 if (Default->DefaultId == DefaultId) { 114 // 115 // Default value is embedded in EFI_IFR_DEFAULT 116 // 117 CopyMem (HiiValue, &Default->Value, sizeof (EFI_HII_VALUE)); 118 119 SetNodeBuffer (Node, HiiValue, Question->VarStoreInfo.VarOffset, Question->StorageWidth); 120 return EFI_SUCCESS; 121 } 122 123 Link = GetNextNode (&Question->DefaultListHead, Link); 124 } 125 } 126 127 // 128 // EFI_ONE_OF_OPTION 129 // 130 if ((Question->Operand == EFI_IFR_ONE_OF_OP) && !IsListEmpty (&Question->OptionListHead)) { 131 if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING) { 132 // 133 // OneOfOption could only provide Standard and Manufacturing default 134 // 135 Link = GetFirstNode (&Question->OptionListHead); 136 while (!IsNull (&Question->OptionListHead, Link)) { 137 Option = QUESTION_OPTION_FROM_LINK (Link); 138 139 if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT) == EFI_IFR_OPTION_DEFAULT)) || 140 ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT_MFG) == EFI_IFR_OPTION_DEFAULT_MFG)) 141 ) { 142 CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE)); 143 144 SetNodeBuffer (Node, HiiValue, Question->VarStoreInfo.VarOffset, Question->StorageWidth); 145 return EFI_SUCCESS; 146 } 147 148 Link = GetNextNode (&Question->OptionListHead, Link); 149 } 150 } 151 } 152 153 // 154 // EFI_IFR_CHECKBOX - lowest priority 155 // 156 if (Question->Operand == EFI_IFR_CHECKBOX_OP) { 157 if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING) { 158 // 159 // Checkbox could only provide Standard and Manufacturing default 160 // 161 if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT) == EFI_IFR_CHECKBOX_DEFAULT)) || 162 ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT_MFG) == EFI_IFR_CHECKBOX_DEFAULT_MFG)) 163 ) { 164 HiiValue->Value.b = TRUE; 165 } else { 166 HiiValue->Value.b = FALSE; 167 } 168 169 SetNodeBuffer (Node, HiiValue, Question->VarStoreInfo.VarOffset, Question->StorageWidth); 170 return EFI_SUCCESS; 171 } 172 } 173 174 return Status; 175 } 176 177 178 /** 179 Extract the default values from all questions in the input Form, 180 and set default value into the matched var storage. 181 182 @param Form The Form which to be reset. 183 @param DefaultId The Class of the default. 184 @param VarStoreId Id of var storage. 185 @param Node Var storage buffer to store the got default value. 186 187 @retval EFI_SUCCESS The function completed successfully. 188 189 **/ 190 EFI_STATUS 191 ExtractFormDefault ( 192 IN FORM_BROWSER_FORM *Form, 193 IN UINT16 DefaultId, 194 IN UINT16 VarStoreId, 195 OUT UEFI_IFR_BUFFER_STORAGE_NODE *Node 196 ) 197 { 198 EFI_STATUS Status; 199 LIST_ENTRY *Link; 200 FORM_BROWSER_STATEMENT *Question; 201 202 Link = GetFirstNode (&Form->StatementListHead); 203 while (!IsNull (&Form->StatementListHead, Link)) { 204 Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link); 205 // 206 // Reset Question to its default value 207 // 208 Status = GetQuestionDefault (Question, DefaultId, VarStoreId, Node); 209 if (EFI_ERROR (Status)) { 210 continue; 211 } 212 213 Link = GetNextNode (&Form->StatementListHead, Link); 214 } 215 return EFI_SUCCESS; 216 } 217 218 219 /** 220 Destroy all the buffer allocated for the fileds of 221 UEFI_IFR_BUFFER_STORAGE_NODE. The Node itself 222 will be freed too. 223 224 @param Node Var storage buffer. 225 226 **/ 227 VOID 228 DestroyDefaultNode ( 229 IN UEFI_IFR_BUFFER_STORAGE_NODE *Node 230 ) 231 { 232 FreePool (Node->Buffer); 233 FreePool (Node->Name); 234 FreePool (Node); 235 } 236 237 238 /** 239 Get the default value for Buffer Type storage named by 240 a Default Store and a Storage Store from a FormSet. 241 The result is in the a instance of UEFI_IFR_BUFFER_STORAGE_NODE 242 allocated by this function. It is inserted to the link list. 243 244 @param DefaultStore The Default Store. 245 @param Storage The Storage. 246 @param FormSet The Form Set. 247 @param UefiDefaultsListHead The head of link list for the output. 248 249 @retval EFI_SUCCESS Successful. 250 251 **/ 252 EFI_STATUS 253 GetBufferTypeDefaultIdAndStorageId ( 254 IN FORMSET_DEFAULTSTORE *DefaultStore, 255 IN FORMSET_STORAGE *Storage, 256 IN FORM_BROWSER_FORMSET *FormSet, 257 OUT LIST_ENTRY *UefiDefaultsListHead 258 ) 259 { 260 UEFI_IFR_BUFFER_STORAGE_NODE *Node; 261 LIST_ENTRY *Link; 262 FORM_BROWSER_FORM *Form; 263 EFI_STATUS Status; 264 265 Node = AllocateZeroPool (sizeof (UEFI_IFR_BUFFER_STORAGE_NODE)); 266 ASSERT (Node != NULL); 267 268 Node->Signature = UEFI_IFR_BUFFER_STORAGE_NODE_SIGNATURE; 269 Node->Name = AllocateCopyPool (StrSize (Storage->Name), Storage->Name); 270 Node->DefaultId = DefaultStore->DefaultId; 271 Node->StoreId = Storage->VarStoreId; 272 CopyGuid (&Node->Guid, &Storage->Guid); 273 Node->Size = Storage->Size; 274 Node->Buffer = AllocateZeroPool (Node->Size); 275 // 276 // Extract default from IFR binary 277 // 278 Link = GetFirstNode (&FormSet->FormListHead); 279 while (!IsNull (&FormSet->FormListHead, Link)) { 280 Form = FORM_BROWSER_FORM_FROM_LINK (Link); 281 282 Status = ExtractFormDefault (Form, DefaultStore->DefaultId, Storage->VarStoreId, Node); 283 ASSERT_EFI_ERROR (Status); 284 285 Link = GetNextNode (&FormSet->FormListHead, Link); 286 } 287 288 InsertTailList (UefiDefaultsListHead, &Node->List); 289 290 return EFI_SUCCESS; 291 } 292 293 294 /** 295 Get the default value for Buffer Type storage named by 296 a Default Store from a FormSet. 297 The result is in the a instance of UEFI_IFR_BUFFER_STORAGE_NODE 298 allocated by this function. The output can be multiple instances 299 of UEFI_IFR_BUFFER_STORAGE_NODE. It is inserted to the link list. 300 301 @param DefaultStore The Default Store. 302 @param FormSet The Form Set. 303 @param UefiDefaultsListHead The head of link list for the output. 304 305 @retval EFI_SUCCESS Successful. 306 307 **/ 308 EFI_STATUS 309 GetBufferTypeDefaultId ( 310 IN FORMSET_DEFAULTSTORE *DefaultStore, 311 IN FORM_BROWSER_FORMSET *FormSet, 312 OUT LIST_ENTRY *UefiDefaultsListHead 313 ) 314 { 315 LIST_ENTRY *StorageLink; 316 FORMSET_STORAGE *Storage; 317 EFI_STATUS Status; 318 319 StorageLink = GetFirstNode (&FormSet->StorageListHead); 320 321 while (!IsNull (&FormSet->StorageListHead, StorageLink)) { 322 Storage = FORMSET_STORAGE_FROM_LINK(StorageLink); 323 324 if (Storage->Type == EFI_HII_VARSTORE_BUFFER) { 325 Status = GetBufferTypeDefaultIdAndStorageId (DefaultStore, Storage, FormSet, UefiDefaultsListHead); 326 ASSERT_EFI_ERROR (Status); 327 } 328 329 StorageLink = GetNextNode (&FormSet->StorageListHead, StorageLink); 330 } 331 332 return EFI_SUCCESS; 333 } 334 335 336 /** 337 Get the default value for Buffer Type storage from the FormSet in ThunkContext. 338 339 The results can be multiple instances of UEFI_IFR_BUFFER_STORAGE_NODE. 340 They are inserted to the link list. 341 342 @param ThunkContext Hii thunk context. 343 @param UefiDefaults The head of link list for the output. 344 345 @retval EFI_SUCCESS Successful. 346 347 **/ 348 EFI_STATUS 349 UefiIfrGetBufferTypeDefaults ( 350 IN HII_THUNK_CONTEXT *ThunkContext, 351 OUT LIST_ENTRY **UefiDefaults 352 ) 353 { 354 LIST_ENTRY *DefaultLink; 355 FORMSET_DEFAULTSTORE *DefaultStore; 356 EFI_STATUS Status; 357 358 ASSERT (UefiDefaults != NULL); 359 360 *UefiDefaults = AllocateZeroPool (sizeof (LIST_ENTRY)); 361 ASSERT (*UefiDefaults != NULL); 362 InitializeListHead (*UefiDefaults); 363 364 DefaultLink = GetFirstNode (&ThunkContext->FormSet->DefaultStoreListHead); 365 while (!IsNull (&ThunkContext->FormSet->DefaultStoreListHead, DefaultLink)) { 366 DefaultStore = FORMSET_DEFAULTSTORE_FROM_LINK(DefaultLink); 367 368 Status = GetBufferTypeDefaultId (DefaultStore, ThunkContext->FormSet, *UefiDefaults); 369 ASSERT_EFI_ERROR (Status); 370 371 DefaultLink = GetNextNode (&ThunkContext->FormSet->DefaultStoreListHead, DefaultLink); 372 } 373 374 return EFI_SUCCESS; 375 } 376 377 378 /** 379 Convert the UEFI Buffer Type default values to a Framework HII default 380 values specified by a EFI_HII_VARIABLE_PACK_LIST structure. 381 382 @param ListHead The link list of UEFI_IFR_BUFFER_STORAGE_NODE 383 which contains the default values retrived from a UEFI form set. 384 @param DefaultMask The default mask. 385 The valid values are EFI_IFR_FLAG_DEFAULT and EFI_IFR_FLAG_MANUFACTURING. 386 UEFI spec only map EFI_IFR_FLAG_DEFAULT and EFI_IFR_FLAG_MANUFACTURING 387 from specification to valid default class. 388 @param UefiFormSetDefaultVarStoreId 389 ID of the default varstore in FormSet. 390 @param VariablePackList The output default value in a format defined in Framework. 391 392 @retval EFI_SUCCESS Successful. 393 @retval EFI_INVALID_PARAMETER The default mask is not EFI_IFR_FLAG_DEFAULT or 394 EFI_IFR_FLAG_MANUFACTURING. 395 **/ 396 EFI_STATUS 397 UefiDefaultsToFwDefaults ( 398 IN LIST_ENTRY *ListHead, 399 IN UINTN DefaultMask, 400 IN EFI_VARSTORE_ID UefiFormSetDefaultVarStoreId, 401 OUT EFI_HII_VARIABLE_PACK_LIST **VariablePackList 402 ) 403 { 404 LIST_ENTRY *List; 405 UEFI_IFR_BUFFER_STORAGE_NODE *Node; 406 UINTN Size; 407 UINTN Count; 408 UINT16 DefaultId; 409 EFI_HII_VARIABLE_PACK *Pack; 410 EFI_HII_VARIABLE_PACK_LIST *PackList; 411 UINTN Index; 412 413 if (DefaultMask == EFI_IFR_FLAG_DEFAULT) { 414 DefaultId = EFI_HII_DEFAULT_CLASS_STANDARD; 415 } else if (DefaultMask == EFI_IFR_FLAG_MANUFACTURING) { 416 DefaultId = EFI_HII_DEFAULT_CLASS_MANUFACTURING; 417 } else { 418 // 419 // UEFI spec only map EFI_IFR_FLAG_DEFAULT and EFI_IFR_FLAG_MANUFACTURING 420 // from specification to valid default class. 421 // 422 ASSERT (FALSE); 423 return EFI_INVALID_PARAMETER; 424 } 425 426 // 427 // Calculate the size of the output EFI_HII_VARIABLE_PACK_LIST structure 428 // 429 Size = 0; 430 Count = 0; 431 List = GetFirstNode (ListHead); 432 while (!IsNull (ListHead, List)) { 433 Node = UEFI_IFR_BUFFER_STORAGE_NODE_FROM_LIST(List); 434 435 if (Node->DefaultId == DefaultId) { 436 Size += Node->Size; 437 Size += StrSize (Node->Name); 438 439 Count++; 440 } 441 442 List = GetNextNode (ListHead, List); 443 } 444 445 if (Count == 0) { 446 *VariablePackList = NULL; 447 return EFI_NOT_FOUND; 448 } 449 450 Size = Size + Count * (sizeof (EFI_HII_VARIABLE_PACK_LIST) + sizeof (EFI_HII_VARIABLE_PACK)); 451 452 *VariablePackList = AllocateZeroPool (Size); 453 ASSERT (*VariablePackList != NULL); 454 455 List = GetFirstNode (ListHead); 456 457 PackList = (EFI_HII_VARIABLE_PACK_LIST *) *VariablePackList; 458 Pack = (EFI_HII_VARIABLE_PACK *) (PackList + 1); 459 Index = 0; 460 while (!IsNull (ListHead, List)) { 461 Node = UEFI_IFR_BUFFER_STORAGE_NODE_FROM_LIST(List); 462 463 Size = 0; 464 if (Node->DefaultId == DefaultId) { 465 Size += Node->Size; 466 Size += sizeof (EFI_HII_VARIABLE_PACK); 467 468 Pack->VariableNameLength = (UINT32) StrSize (Node->Name); 469 470 if (Node->StoreId == UefiFormSetDefaultVarStoreId) { 471 // 472 // The default VARSTORE in VFR from a Framework module has Varstore ID of 0. 473 // 474 Pack->VariableId = 0; 475 } else { 476 Pack->VariableId = Node->StoreId; 477 } 478 479 CopyMem ((UINT8 *) Pack + sizeof (EFI_HII_VARIABLE_PACK), Node->Name, StrSize (Node->Name)); 480 Size += Pack->VariableNameLength; 481 482 // 483 // Initialize EFI_HII_VARIABLE_PACK 484 // 485 Pack->Header.Type = 0; 486 Pack->Header.Length = (UINT32) Size; 487 CopyMem (&Pack->VariableGuid, &Node->Guid, sizeof (EFI_GUID)); 488 489 CopyMem ((UINT8 *) Pack + sizeof (EFI_HII_VARIABLE_PACK) + Pack->VariableNameLength, Node->Buffer, Node->Size); 490 491 Size += sizeof (EFI_HII_VARIABLE_PACK_LIST); 492 493 // 494 // Initialize EFI_HII_VARIABLE_PACK_LIST 495 // 496 PackList->VariablePack = Pack; 497 Index++; 498 if (Index < Count) { 499 PackList->NextVariablePack = (EFI_HII_VARIABLE_PACK_LIST *)((UINT8 *) PackList + Size); 500 501 PackList = PackList->NextVariablePack; 502 Pack = (EFI_HII_VARIABLE_PACK *) (PackList + 1); 503 } 504 505 } 506 507 List = GetNextNode (ListHead, List); 508 } 509 510 511 return EFI_SUCCESS; 512 } 513 514 515 /** 516 Free up all buffer allocated for the link list of UEFI_IFR_BUFFER_STORAGE_NODE. 517 518 @param ListHead The link list of UEFI_IFR_BUFFER_STORAGE_NODE 519 which contains the default values retrived from 520 a UEFI form set. 521 522 **/ 523 VOID 524 FreeDefaultList ( 525 IN LIST_ENTRY *ListHead 526 ) 527 { 528 LIST_ENTRY *Link; 529 UEFI_IFR_BUFFER_STORAGE_NODE *Default; 530 531 while (!IsListEmpty (ListHead)) { 532 Link = GetFirstNode (ListHead); 533 534 Default = UEFI_IFR_BUFFER_STORAGE_NODE_FROM_LIST(Link); 535 536 RemoveEntryList (Link); 537 538 DestroyDefaultNode (Default); 539 } 540 541 FreePool (ListHead); 542 } 543 544