1 /** @file 2 This file contains the form processing code to the HII database. 3 4 Copyright (c) 2006 - 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 16 #include "HiiDatabase.h" 17 #include "UefiIfrDefault.h" 18 19 // 20 // This structure is only intended to be used in this file. 21 // 22 #pragma pack(1) 23 typedef struct { 24 EFI_HII_PACK_HEADER PackageHeader; 25 FRAMEWORK_EFI_IFR_FORM_SET FormSet; 26 EFI_IFR_END_FORM_SET EndFormSet; 27 } FW_HII_FORMSET_TEMPLATE; 28 #pragma pack() 29 30 FW_HII_FORMSET_TEMPLATE FormSetTemplate = { 31 { 32 sizeof (FW_HII_FORMSET_TEMPLATE), 33 EFI_HII_IFR 34 }, 35 { 36 { 37 FRAMEWORK_EFI_IFR_FORM_SET_OP, 38 sizeof (FRAMEWORK_EFI_IFR_FORM_SET) 39 }, 40 {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}}, //Guid 41 0, 42 0, 43 0, 44 0, 45 0, 46 0 47 }, 48 { 49 { 50 EFI_IFR_END_FORM_SET_OP, 51 sizeof (EFI_IFR_END_FORM_SET) 52 } 53 } 54 }; 55 56 57 EFI_GUID mTianoHiiIfrGuid = EFI_IFR_TIANO_GUID; 58 59 /** 60 61 This thunk module only handles UEFI HII packages. The caller of this function 62 won't be able to parse the content. Therefore, it is not supported. 63 64 This function will ASSERT and return EFI_UNSUPPORTED. 65 66 @param This N.A. 67 @param Handle N.A. 68 @param BufferSize N.A. 69 @param Buffer N.A. 70 71 @retval EFI_UNSUPPORTED 72 73 **/ 74 EFI_STATUS 75 EFIAPI 76 HiiExportDatabase ( 77 IN EFI_HII_PROTOCOL *This, 78 IN FRAMEWORK_EFI_HII_HANDLE Handle, 79 IN OUT UINTN *BufferSize, 80 OUT VOID *Buffer 81 ) 82 { 83 ASSERT (FALSE); 84 return EFI_UNSUPPORTED; 85 } 86 87 88 /** 89 This function allows a program to extract a form or form package that has 90 previously been registered with the EFI HII database. 91 92 In this thunk module, this function will create a IFR Package with only 93 one Formset. Effectively, only the GUID of the Formset is updated and return 94 in this IFR package to caller. This is enable the Framework modules which call 95 a API named GetStringFromToken. GetStringFromToken retieves a String based on 96 a String Token from a Package List known only by the Formset GUID. 97 98 99 100 @param This A pointer to the EFI_HII_PROTOCOL instance. 101 @param Handle Handle on which the form resides. Type FRAMEWORK_EFI_HII_HANDLE is defined in 102 EFI_HII_PROTOCOL.NewPack() in the Packages section. 103 @param FormId Ignored by this implementation. 104 @param BufferLengthTemp On input, the size of input buffer. On output, it 105 is the size of FW_HII_FORMSET_TEMPLATE. 106 @param Buffer The buffer designed to receive the form(s). 107 108 @retval EFI_SUCCESS Buffer filled with the requested forms. BufferLength 109 was updated. 110 @retval EFI_INVALID_PARAMETER The handle is unknown. 111 @retval EFI_NOT_FOUND A form on the requested handle cannot be found with the 112 requested FormId. 113 @retval EFI_BUFFER_TOO_SMALL The buffer provided was not large enough to allow the form to be stored. 114 115 **/ 116 EFI_STATUS 117 EFIAPI 118 HiiGetForms ( 119 IN EFI_HII_PROTOCOL *This, 120 IN FRAMEWORK_EFI_HII_HANDLE Handle, 121 IN EFI_FORM_ID FormId, 122 IN OUT UINTN *BufferLengthTemp, 123 OUT UINT8 *Buffer 124 ) 125 { 126 HII_THUNK_PRIVATE_DATA *Private; 127 HII_THUNK_CONTEXT *ThunkContext; 128 FW_HII_FORMSET_TEMPLATE *OutputFormSet; 129 130 if (*BufferLengthTemp < sizeof(FW_HII_FORMSET_TEMPLATE)) { 131 *BufferLengthTemp = sizeof(FW_HII_FORMSET_TEMPLATE); 132 return EFI_BUFFER_TOO_SMALL; 133 } 134 135 Private = HII_THUNK_PRIVATE_DATA_FROM_THIS(This); 136 137 ThunkContext = FwHiiHandleToThunkContext (Private, Handle); 138 139 if (ThunkContext == NULL) { 140 return EFI_NOT_FOUND; 141 } 142 143 OutputFormSet = (FW_HII_FORMSET_TEMPLATE *) Buffer; 144 145 CopyMem (OutputFormSet, &FormSetTemplate, sizeof (FW_HII_FORMSET_TEMPLATE)); 146 CopyMem (&OutputFormSet->FormSet.Guid, &ThunkContext->TagGuid, sizeof (EFI_GUID)); 147 148 if (ThunkContext->FormSet != NULL) { 149 OutputFormSet->FormSet.Class = ThunkContext->FormSet->Class; 150 OutputFormSet->FormSet.SubClass = ThunkContext->FormSet->SubClass; 151 OutputFormSet->FormSet.Help = ThunkContext->FormSet->Help; 152 OutputFormSet->FormSet.FormSetTitle = ThunkContext->FormSet->FormSetTitle; 153 } 154 155 return EFI_SUCCESS; 156 } 157 158 159 /** 160 161 This function allows a program to extract the NV Image 162 that represents the default storage image 163 164 165 @param This A pointer to the EFI_HII_PROTOCOL instance. 166 @param Handle The HII handle from which will have default data retrieved. 167 UINTN - Mask used to retrieve the default image. 168 @param DefaultMask EDES_TODO: Add parameter description 169 @param VariablePackList Callee allocated, tightly-packed, link list data 170 structure that contain all default varaible packs 171 from the Hii Database. 172 173 @retval EFI_NOT_FOUND If Hii database does not contain any default images. 174 @retval EFI_INVALID_PARAMETER Invalid input parameter. 175 @retval EFI_SUCCESS Operation successful. 176 177 **/ 178 EFI_STATUS 179 EFIAPI 180 HiiGetDefaultImage ( 181 IN EFI_HII_PROTOCOL *This, 182 IN FRAMEWORK_EFI_HII_HANDLE Handle, 183 IN UINTN DefaultMask, 184 OUT EFI_HII_VARIABLE_PACK_LIST **VariablePackList 185 ) 186 { 187 LIST_ENTRY *UefiDefaults; 188 EFI_STATUS Status; 189 HII_THUNK_PRIVATE_DATA *Private; 190 HII_THUNK_CONTEXT *ThunkContext; 191 192 Private = HII_THUNK_PRIVATE_DATA_FROM_THIS(This); 193 194 ThunkContext = FwHiiHandleToThunkContext (Private, Handle); 195 if (ThunkContext == NULL) { 196 ASSERT (FALSE); 197 return EFI_INVALID_PARAMETER; 198 } 199 200 UefiDefaults = NULL; 201 Status = UefiIfrGetBufferTypeDefaults (ThunkContext, &UefiDefaults); 202 if (EFI_ERROR (Status)) { 203 goto Done; 204 } 205 206 Status = UefiDefaultsToFwDefaults (UefiDefaults, DefaultMask, ThunkContext->FormSet->DefaultVarStoreId, VariablePackList); 207 208 Done: 209 FreeDefaultList (UefiDefaults); 210 211 return Status; 212 } 213 214 /** 215 This function update the FormCallbackProtocol cached in Config Access 216 private context data. 217 218 @param CallbackHandle The EFI Handle on which the Framework FormCallbackProtocol is 219 installed. 220 @param ThunkContext The Thunk Context. 221 222 @retval EFI_SUCCESS The update is successful. 223 @retval EFI_INVALID_PARAMETER If no Framework FormCallbackProtocol is located on CallbackHandle. 224 225 **/ 226 EFI_STATUS 227 UpdateFormCallBack ( 228 IN EFI_HANDLE CallbackHandle, 229 IN CONST HII_THUNK_CONTEXT *ThunkContext 230 ) 231 { 232 EFI_STATUS Status; 233 EFI_FORM_CALLBACK_PROTOCOL *FormCallbackProtocol; 234 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccessProtocol; 235 EFI_HANDLE UefiDriverHandle; 236 CONFIG_ACCESS_PRIVATE *ConfigAccessPrivate; 237 238 Status = gBS->HandleProtocol ( 239 CallbackHandle, 240 &gEfiFormCallbackProtocolGuid, 241 (VOID **) &FormCallbackProtocol 242 ); 243 if (EFI_ERROR (Status)) { 244 return EFI_INVALID_PARAMETER; 245 } 246 247 Status = mHiiDatabase->GetPackageListHandle ( 248 mHiiDatabase, 249 ThunkContext->UefiHiiHandle, 250 &UefiDriverHandle 251 ); 252 ASSERT_EFI_ERROR (Status); 253 Status = gBS->HandleProtocol ( 254 UefiDriverHandle, 255 &gEfiHiiConfigAccessProtocolGuid, 256 (VOID **) &ConfigAccessProtocol 257 ); 258 ASSERT_EFI_ERROR (Status); 259 260 ConfigAccessPrivate = CONFIG_ACCESS_PRIVATE_FROM_PROTOCOL (ConfigAccessProtocol); 261 262 ConfigAccessPrivate->FormCallbackProtocol = FormCallbackProtocol; 263 264 return EFI_SUCCESS; 265 } 266 267 268 /** 269 Get the package data from the Package List. 270 271 @param HiiPackageList Package List. 272 @param PackageIndex The index of the Package in the Package List. 273 @param BufferLen The Length of the Pacage data. 274 @param Buffer On output, the Package data. 275 276 @return EFI_NOT_FOUND No Package is found for PackageIndex. 277 @return EFI_SUCCESS The package data is returned. 278 279 **/ 280 EFI_STATUS 281 GetPackageData ( 282 IN EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList, 283 IN UINT32 PackageIndex, 284 OUT UINT32 *BufferLen, 285 OUT EFI_HII_PACKAGE_HEADER **Buffer 286 ) 287 { 288 UINT32 Index; 289 EFI_HII_PACKAGE_HEADER *Package; 290 UINT32 Offset; 291 UINT32 PackageListLength; 292 EFI_HII_PACKAGE_HEADER PackageHeader; 293 294 ASSERT(HiiPackageList != NULL); 295 296 if ((BufferLen == NULL) || (Buffer == NULL)) { 297 return EFI_INVALID_PARAMETER; 298 } 299 300 ZeroMem (&PackageHeader, sizeof (PackageHeader)); 301 Package = NULL; 302 Index = 0; 303 Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER); 304 CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32)); 305 while (Offset < PackageListLength) { 306 Package = (EFI_HII_PACKAGE_HEADER *) (((UINT8 *) HiiPackageList) + Offset); 307 CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER)); 308 if (Index == PackageIndex) { 309 break; 310 } 311 Offset += PackageHeader.Length; 312 Index++; 313 } 314 if (Offset >= PackageListLength) { 315 // 316 // no package found in this Package List 317 // 318 return EFI_NOT_FOUND; 319 } 320 321 *BufferLen = PackageHeader.Length; 322 *Buffer = Package; 323 return EFI_SUCCESS; 324 } 325 326 /** 327 Check if Label exist in the IFR form package and return the FormSet GUID 328 and Form ID. 329 330 @param Package The Package Header. 331 @param Label The Label ID. 332 @param FormsetGuid Returns the FormSet GUID. 333 @param FormId Returns the Form ID. 334 335 @retval EFI_SUCCESS The FORM ID is found. 336 @retval EFI_NOT_FOUND The FORM ID is not found. 337 **/ 338 EFI_STATUS 339 LocateLabel ( 340 IN CONST EFI_HII_PACKAGE_HEADER *Package, 341 IN EFI_FORM_LABEL Label, 342 OUT EFI_GUID *FormsetGuid, 343 OUT EFI_FORM_ID *FormId 344 ) 345 { 346 UINTN Offset; 347 EFI_IFR_OP_HEADER *IfrOpHdr; 348 EFI_GUID InternalFormSetGuid; 349 EFI_FORM_ID InternalFormId; 350 BOOLEAN GetFormSet; 351 BOOLEAN GetForm; 352 EFI_IFR_GUID_LABEL *LabelOpcode; 353 354 IfrOpHdr = (EFI_IFR_OP_HEADER *)((UINT8 *) Package + sizeof (EFI_HII_PACKAGE_HEADER)); 355 Offset = sizeof (EFI_HII_PACKAGE_HEADER); 356 357 InternalFormId= 0; 358 ZeroMem (&InternalFormSetGuid, sizeof (EFI_GUID)); 359 GetFormSet = FALSE; 360 GetForm = FALSE; 361 362 while (Offset < Package->Length) { 363 switch (IfrOpHdr->OpCode) { 364 case EFI_IFR_FORM_SET_OP : 365 CopyMem (&InternalFormSetGuid, &((EFI_IFR_FORM_SET *) IfrOpHdr)->Guid, sizeof (EFI_GUID)); 366 GetFormSet = TRUE; 367 break; 368 369 case EFI_IFR_FORM_OP: 370 CopyMem (&InternalFormId, &((EFI_IFR_FORM *) IfrOpHdr)->FormId, sizeof (EFI_FORM_ID)); 371 GetForm = TRUE; 372 break; 373 374 case EFI_IFR_GUID_OP : 375 LabelOpcode = (EFI_IFR_GUID_LABEL *) IfrOpHdr; 376 // 377 // If it is an Label opcode. 378 // 379 if ((LabelOpcode->ExtendOpCode == EFI_IFR_EXTEND_OP_LABEL) && (CompareMem (&LabelOpcode->Guid, &mTianoHiiIfrGuid, sizeof (EFI_GUID)) == 0)) { 380 if (CompareMem (&Label, &LabelOpcode->Number, sizeof (UINT16)) == 0) { 381 ASSERT (GetForm && GetFormSet); 382 CopyGuid (FormsetGuid, &InternalFormSetGuid); 383 *FormId = InternalFormId; 384 return EFI_SUCCESS; 385 } 386 } 387 break; 388 default : 389 break; 390 } 391 392 // 393 // Go to the next Op-Code 394 // 395 Offset += IfrOpHdr->Length; 396 IfrOpHdr = (EFI_IFR_OP_HEADER *) ((CHAR8 *) (IfrOpHdr) + IfrOpHdr->Length); 397 } 398 399 return EFI_NOT_FOUND; 400 } 401 402 /** 403 Find the first EFI_FORM_LABEL in FormSets for a given EFI_HII_HANLDE defined. 404 405 EFI_FORM_LABEL is a specific to Tiano implementation. The current implementation 406 does not restrict labels with same label value to be duplicated in either FormSet 407 scope or Form scope. This function will only locate the FIRST EFI_FORM_LABEL 408 with value as the same as the input Label in the Formset registered with UefiHiiHandle. The FormSet GUID 409 and Form ID is returned if such Label is found. 410 411 @param Handle Uefi Hii Handle to be searched. 412 @param Label The first Label ID to be found. 413 @param FormsetGuid The matched FormSet GUID. 414 @param FormId The matched Form ID. 415 416 @retval EFI_INVALID_PARAMETER If UefiHiiHandle is not a valid handle. 417 @retval EFI_NOT_FOUND The package list identified by UefiHiiHandle deos not contain FormSet or 418 Form ID with value Label found in all Form Sets in the pacakge list. 419 @retval EFI_SUCCESS The first found Form ID is returned in FormId. 420 **/ 421 EFI_STATUS 422 LocateFormId ( 423 IN EFI_HII_HANDLE Handle, 424 IN EFI_FORM_LABEL Label, 425 OUT EFI_GUID *FormsetGuid, 426 OUT EFI_FORM_ID *FormId 427 ) 428 { 429 EFI_STATUS Status; 430 EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList; 431 UINT32 Index; 432 UINTN BufferSize; 433 EFI_HII_PACKAGE_HEADER PackageHeader; 434 EFI_HII_PACKAGE_HEADER *Package; 435 UINT32 PackageLength; 436 437 BufferSize = 0; 438 HiiPackageList = NULL; 439 Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList); 440 if (Status == EFI_BUFFER_TOO_SMALL) { 441 HiiPackageList = AllocatePool (BufferSize); 442 ASSERT (HiiPackageList != NULL); 443 444 Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList); 445 if (EFI_ERROR (Status)) { 446 goto Done; 447 } 448 } 449 450 for (Index = 0; ; Index++) { 451 Status = GetPackageData (HiiPackageList, Index, &PackageLength, &Package); 452 if (!EFI_ERROR (Status)) { 453 CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER)); 454 if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) { 455 Status = LocateLabel (Package, Label, FormsetGuid, FormId); 456 if (!EFI_ERROR(Status)) { 457 break; 458 } 459 } 460 } else { 461 break; 462 } 463 } 464 465 466 Done: 467 FreePool (HiiPackageList); 468 469 return Status; 470 } 471 472 /** 473 This function allows the caller to update a form that has 474 previously been registered with the EFI HII database. 475 476 477 @param This EDES_TODO: Add parameter description 478 @param Handle Hii Handle associated with the Formset to modify 479 @param Label Update information starting immediately after this label in the IFR 480 @param AddData If TRUE, add data. If FALSE, remove data 481 @param Data If adding data, this is the pointer to the data to add 482 483 @retval EFI_SUCCESS Update success. 484 @retval Other Update fail. 485 486 **/ 487 EFI_STATUS 488 EFIAPI 489 HiiThunkUpdateForm ( 490 IN EFI_HII_PROTOCOL *This, 491 IN FRAMEWORK_EFI_HII_HANDLE Handle, 492 IN EFI_FORM_LABEL Label, 493 IN BOOLEAN AddData, 494 IN EFI_HII_UPDATE_DATA *Data 495 ) 496 { 497 EFI_STATUS Status; 498 HII_THUNK_PRIVATE_DATA *Private; 499 HII_THUNK_CONTEXT *ThunkContext; 500 EFI_HII_HANDLE UefiHiiHandle; 501 EFI_GUID FormsetGuid; 502 EFI_FORM_ID FormId; 503 EFI_TPL OldTpl; 504 VOID *StartOpCodeHandle; 505 VOID *EndOpCodeHandle; 506 EFI_IFR_GUID_LABEL *StartLabel; 507 EFI_IFR_GUID_LABEL *EndLabel; 508 509 OldTpl = gBS->RaiseTPL (TPL_NOTIFY); 510 511 mInFrameworkUpdatePakcage = TRUE; 512 Status = EFI_SUCCESS; 513 514 Private = HII_THUNK_PRIVATE_DATA_FROM_THIS(This); 515 516 ThunkContext = FwHiiHandleToThunkContext (Private, Handle); 517 518 if (ThunkContext == NULL) { 519 Status = EFI_NOT_FOUND; 520 goto Done; 521 } 522 523 if (Data->FormSetUpdate) { 524 Status = UpdateFormCallBack ((EFI_HANDLE) (UINTN) Data->FormCallbackHandle, ThunkContext); 525 if (EFI_ERROR (Status)) { 526 goto Done; 527 } 528 } 529 530 if (ThunkContext->IfrPackageCount == 0) { 531 ASSERT (FALSE); 532 Status = EFI_INVALID_PARAMETER; 533 goto Done; 534 } else { 535 UefiHiiHandle = ThunkContext->UefiHiiHandle; 536 } 537 538 Status = LocateFormId (UefiHiiHandle, Label, &FormsetGuid, &FormId); 539 if (EFI_ERROR (Status)) { 540 // 541 // Can't find the label. 542 // 543 goto Done; 544 } 545 546 // 547 // Init OpCode Handle 548 // 549 StartOpCodeHandle = HiiAllocateOpCodeHandle (); 550 ASSERT (StartOpCodeHandle != NULL); 551 552 EndOpCodeHandle = HiiAllocateOpCodeHandle (); 553 ASSERT (EndOpCodeHandle != NULL); 554 555 // 556 // Create Hii Extend Label OpCode as the start opcode 557 // 558 StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL)); 559 StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; 560 StartLabel->Number = Label; 561 562 // 563 // Create Hii Extend Label OpCode as the end opcode 564 // 565 EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL)); 566 EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; 567 EndLabel->Number = 0xffff; 568 569 if (AddData) { 570 if (Data->DataCount != 0) { 571 572 ThunkContext = UefiHiiHandleToThunkContext (Private, UefiHiiHandle); 573 ASSERT (ThunkContext != NULL); 574 Status = FwUpdateDataToUefiUpdateData (ThunkContext, Data, StartOpCodeHandle); 575 ASSERT_EFI_ERROR (Status); 576 577 Status = HiiUpdateForm (UefiHiiHandle, &FormsetGuid, FormId, StartOpCodeHandle, NULL); 578 ASSERT_EFI_ERROR (Status); 579 } 580 } else { 581 // 582 // Delete Opcode starting from Labe in FormId found 583 // 584 Status = HiiUpdateForm (UefiHiiHandle, &FormsetGuid, FormId, StartOpCodeHandle, EndOpCodeHandle); 585 ASSERT_EFI_ERROR (Status); 586 } 587 588 HiiFreeOpCodeHandle (StartOpCodeHandle); 589 HiiFreeOpCodeHandle (EndOpCodeHandle); 590 591 Done: 592 593 mInFrameworkUpdatePakcage = FALSE; 594 595 gBS->RestoreTPL (OldTpl); 596 597 return Status; 598 } 599