1 /** @file 2 Implement Functions to convert IFR Opcode in format defined in Framework HII specification to 3 format defined in UEFI HII Specification. 4 5 Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR> 6 This program and the accompanying materials 7 are licensed and made available under the terms and conditions of the BSD License 8 which accompanies this distribution. The full text of the license may be found at 9 http://opensource.org/licenses/bsd-license.php 10 11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 13 14 **/ 15 16 #include "HiiDatabase.h" 17 #include "UefiIfrDefault.h" 18 19 /** 20 The dynamic creation of these opcodes is supported in Framework HII modules. 21 Therefore, Framework HII Thunk module only map these opcode between Framework 22 HII's definitions to UEFI HII's. 23 **/ 24 typedef struct { 25 UINT8 FrameworkIfrOp; 26 UINT8 UefiIfrOp; 27 } IFR_OPCODE_MAP; 28 29 IFR_OPCODE_MAP QuestionOpcodeMap[] = { 30 { FRAMEWORK_EFI_IFR_ONE_OF_OP, EFI_IFR_ONE_OF_OP}, 31 { FRAMEWORK_EFI_IFR_CHECKBOX_OP, EFI_IFR_CHECKBOX_OP}, 32 { FRAMEWORK_EFI_IFR_NUMERIC_OP, EFI_IFR_NUMERIC_OP}, 33 { FRAMEWORK_EFI_IFR_ONE_OF_OPTION_OP, EFI_IFR_ONE_OF_OPTION_OP}, 34 { FRAMEWORK_EFI_IFR_ORDERED_LIST_OP, EFI_IFR_ORDERED_LIST_OP} 35 }; 36 37 /** 38 Translate a Framework Question Opcode to UEFI Question Opcode. 39 40 @param FwOp Framework Opcode. 41 @param UefiOp UEFI Opcode. 42 43 @retval EFI_SUCCESS The UEFI opcode is found and returned. 44 @retval EFI_NOT_FOUND The UEFI opcode is not found. 45 **/ 46 EFI_STATUS 47 QuestionOpFwToUefi ( 48 IN UINT8 FwOp, 49 OUT UINT8 *UefiOp 50 ) 51 { 52 UINTN Index; 53 54 for (Index = 0; Index < ARRAY_SIZE (QuestionOpcodeMap); Index++) { 55 if (FwOp == QuestionOpcodeMap[Index].FrameworkIfrOp) { 56 *UefiOp = QuestionOpcodeMap[Index].UefiIfrOp; 57 return EFI_SUCCESS; 58 } 59 } 60 61 *UefiOp = (UINT8) (EFI_IFR_LAST_OPCODE + 1); 62 return EFI_NOT_FOUND; 63 } 64 65 /** 66 Translate a Framework Question ID to UEFI Question ID. 67 68 @param FormSet FormSet context 69 @param FwOpCode Framework Opcode 70 @param FwQId Framework Question Id 71 @param UefiQId UEFI Question ID. 72 73 @retval EFI_SUCCESS The UEFI Question Id is found and returned. 74 @retval EFI_NOT_FOUND The UEFI Question Id is not found. 75 **/ 76 EFI_STATUS 77 FwQIdToUefiQId ( 78 IN CONST FORM_BROWSER_FORMSET *FormSet, 79 IN UINT8 FwOpCode, 80 IN UINT16 FwQId, 81 OUT UINT16 *UefiQId 82 ) 83 { 84 LIST_ENTRY *FormList; 85 LIST_ENTRY *StatementList; 86 FORM_BROWSER_FORM *Form; 87 FORM_BROWSER_STATEMENT *Statement; 88 FORM_BROWSER_STATEMENT *StatementFound; 89 EFI_STATUS Status; 90 UINT8 UefiOp; 91 92 93 *UefiQId = 0; 94 StatementFound = NULL; 95 96 FormList = GetFirstNode (&FormSet->FormListHead); 97 98 while (!IsNull (&FormSet->FormListHead, FormList)) { 99 Form = FORM_BROWSER_FORM_FROM_LINK (FormList); 100 101 StatementList = GetFirstNode (&Form->StatementListHead); 102 103 while (!IsNull (&Form->StatementListHead, StatementList)) { 104 Statement = FORM_BROWSER_STATEMENT_FROM_LINK (StatementList); 105 if (Statement->VarStoreId != 0 && Statement->Storage->Type == EFI_HII_VARSTORE_BUFFER) { 106 if (FwQId == Statement->VarStoreInfo.VarOffset) { 107 Status = QuestionOpFwToUefi (FwOpCode, &UefiOp); 108 ASSERT_EFI_ERROR (Status); 109 110 if ((UefiOp == Statement->Operand) && (FormSet->DefaultVarStoreId == Statement->VarStoreId)) { 111 // 112 // If ASSERT here, the Framework VFR file has two Questions with all three attibutes the same: 113 // 1) Same Question Type, 114 // 2) Same Variable Storage 115 // 3) Refering to the Same offset in Variable Map (NvMap). 116 // This is ambigurity as FwQIdToUefiQId () can't find which UEFI Question 117 // ID to return. 118 // 119 // One possible solution is to remove the one of the duplicated questions in this Form Set. 120 // 121 ASSERT (StatementFound == NULL); 122 StatementFound= Statement; 123 124 // 125 // Continue the search to check if the Form Set contains more than one questins that has the 3 attributes 126 // with same value. 127 // 128 } 129 } 130 } 131 132 StatementList = GetNextNode (&Form->StatementListHead, StatementList); 133 } 134 135 FormList = GetNextNode (&FormSet->FormListHead, FormList); 136 } 137 138 if (StatementFound != NULL) { 139 *UefiQId = StatementFound->QuestionId; 140 return EFI_SUCCESS; 141 } 142 143 return EFI_NOT_FOUND; 144 } 145 146 /** 147 Assign a Question ID. 148 149 If FwQuestionId is 0, then assign a new question ID. The new question ID 150 is MaxQuestionId incremented by 1. The MaxQuestionId of FormSet is also 151 incremented by 1. 152 153 If FwQuestionId is not 0, then it is used as the Framework Question ID. 154 155 @param FwQuestionId 156 @param FormSet 157 158 @return The Framework Question ID. 159 **/ 160 EFI_QUESTION_ID 161 AssignQuestionId ( 162 IN UINT16 FwQuestionId, 163 IN FORM_BROWSER_FORMSET *FormSet 164 ) 165 { 166 if (FwQuestionId == 0) { 167 FormSet->MaxQuestionId++; 168 return FormSet->MaxQuestionId; 169 } else { 170 return FwQuestionId; 171 } 172 } 173 174 /** 175 Create UEFI HII Text Opcode from a Framework HII Text Opcode. 176 177 @param UefiUpdateDataHandle The newly created UEFI HII opcode is appended to UefiUpdateDataHandle. 178 @param FwOpcode The input Framework Opcode. 179 180 @retval NULL There is not enough space left in Buffer to add the opcode. 181 @retval Other A pointer to the created opcode. 182 183 **/ 184 UINT8 * 185 F2UCreateTextOpCode ( 186 IN OUT VOID *UefiUpdateDataHandle, 187 IN CONST FRAMEWORK_EFI_IFR_TEXT *FwOpcode 188 ) 189 { 190 EFI_IFR_TEXT UTextOpCode; 191 192 if ((FwOpcode->Flags & EFI_IFR_FLAG_INTERACTIVE) == 0) { 193 ZeroMem (&UTextOpCode, sizeof(UTextOpCode)); 194 195 UTextOpCode.Header.OpCode = EFI_IFR_TEXT_OP; 196 UTextOpCode.Header.Length = (UINT8) sizeof (EFI_IFR_TEXT); 197 198 UTextOpCode.Statement.Help = FwOpcode->Help; 199 200 UTextOpCode.Statement.Prompt = FwOpcode->Text; 201 UTextOpCode.TextTwo = FwOpcode->TextTwo; 202 203 return HiiCreateRawOpCodes (UefiUpdateDataHandle, (UINT8 *) &UTextOpCode, sizeof(UTextOpCode)); 204 } else { 205 // 206 // Iteractive Text Opcode is EFI_IFR_ACTION 207 // 208 return HiiCreateActionOpCode (UefiUpdateDataHandle, FwOpcode->Key, FwOpcode->Text, FwOpcode->Help, EFI_IFR_FLAG_CALLBACK, 0); 209 } 210 } 211 212 /** 213 Create UEFI HII Reference Opcode from a Framework HII Reference Opcode. 214 215 @param UefiUpdateDataHandle The newly created UEFI HII opcode is appended to UefiUpdateDataHandle. 216 @param FwOpcode The input Framework Opcode. 217 218 @retval NULL There is not enough space left in Buffer to add the opcode. 219 @retval Other A pointer to the created opcode. 220 221 **/ 222 UINT8 * 223 F2UCreateReferenceOpCode ( 224 IN OUT VOID *UefiUpdateDataHandle, 225 IN CONST FRAMEWORK_EFI_IFR_REF *FwOpcode 226 ) 227 { 228 EFI_IFR_REF UOpcode; 229 230 ZeroMem (&UOpcode, sizeof(UOpcode)); 231 232 UOpcode.Header.Length = (UINT8) sizeof (UOpcode); 233 UOpcode.Header.OpCode = EFI_IFR_REF_OP; 234 235 UOpcode.Question.Header.Prompt = FwOpcode->Prompt; 236 UOpcode.Question.Header.Help = FwOpcode->Help; 237 UOpcode.Question.QuestionId = FwOpcode->Key; 238 239 UOpcode.FormId = FwOpcode->FormId; 240 241 // 242 // We only map EFI_IFR_FLAG_INTERACTIVE and EFI_IFR_FLAG_RESET_REQUIRED to 243 // UEFI IFR Opcode flags. The rest flags are obsolete. 244 // 245 UOpcode.Question.Flags = (UINT8) (FwOpcode->Flags & (EFI_IFR_FLAG_INTERACTIVE | EFI_IFR_FLAG_RESET_REQUIRED)); 246 247 return HiiCreateRawOpCodes (UefiUpdateDataHandle, (UINT8 *) &UOpcode, sizeof(UOpcode)); 248 } 249 250 /** 251 Create UEFI HII "One Of Option" Opcode from a Framework HII "One Of Option" Opcode. 252 253 @param UefiUpdateDataHandle The newly created UEFI HII opcode is appended to UefiUpdateDataHandle. 254 @param FwOpcode The input Framework Opcode. 255 @param Width The size of the One Of Option. 1 bytes or 2 bytes. 256 257 @retval NULL There is not enough space left in Buffer to add the opcode. 258 @retval Other A pointer to the created opcode. 259 260 **/ 261 UINT8 * 262 F2UCreateOneOfOptionOpCode ( 263 IN OUT VOID *UefiUpdateDataHandle, 264 IN CONST FRAMEWORK_EFI_IFR_ONE_OF_OPTION *FwOpcode, 265 IN UINTN Width 266 ) 267 { 268 EFI_IFR_ONE_OF_OPTION UOpcode; 269 270 ZeroMem (&UOpcode, sizeof(UOpcode)); 271 272 UOpcode.Header.Length = (UINT8) sizeof (UOpcode); 273 UOpcode.Header.OpCode = EFI_IFR_ONE_OF_OPTION_OP; 274 275 UOpcode.Option = FwOpcode->Option; 276 CopyMem (&UOpcode.Value.u8, &FwOpcode->Value, Width); 277 278 // 279 // #define EFI_IFR_FLAG_DEFAULT 0x01 280 // #define EFI_IFR_FLAG_MANUFACTURING 0x02 281 // #define EFI_IFR_OPTION_DEFAULT 0x10 282 // #define EFI_IFR_OPTION_DEFAULT_MFG 0x20 283 // 284 UOpcode.Flags = (UINT8) (UOpcode.Flags | (FwOpcode->Flags & (EFI_IFR_FLAG_DEFAULT | EFI_IFR_FLAG_MANUFACTURING)) << 4); 285 286 switch (Width) { 287 case 1: 288 UOpcode.Type = EFI_IFR_TYPE_NUM_SIZE_8; 289 break; 290 291 case 2: 292 UOpcode.Type = EFI_IFR_TYPE_NUM_SIZE_16; 293 break; 294 295 default: 296 ASSERT (FALSE); 297 return NULL; 298 } 299 300 return HiiCreateRawOpCodes (UefiUpdateDataHandle, (UINT8 *) &UOpcode, sizeof(UOpcode)); 301 } 302 303 /** 304 Create a GUID Opcode EFI_IFR_GUID_OPTIONKEY to map the Framework One Of Option callback key 305 to a UEFI Question ID. This information is used to invoke the Framework HII Browser Callback 306 function. The opcode is appened to UefiUpdateDataHandle. 307 308 @param UefiUpdateDataHandle The UEFI Update Data buffer. 309 @param QuestionId The UEFI Question ID. 310 @param OptionValue The value of the "One Of Option". 311 @param KeyValue The Framework "One Of Option" callback key. 312 313 @retval NULL There is not enough space left in Buffer to add the opcode. 314 @retval Other A pointer to the created opcode. 315 **/ 316 UINT8 * 317 CreateGuidOptionKeyOpCode ( 318 IN OUT VOID *UefiUpdateDataHandle, 319 IN EFI_QUESTION_ID QuestionId, 320 IN UINT16 OptionValue, 321 IN EFI_QUESTION_ID KeyValue 322 ) 323 { 324 EFI_IFR_GUID_OPTIONKEY *UOpcode; 325 326 UOpcode = (EFI_IFR_GUID_OPTIONKEY *) HiiCreateGuidOpCode ( 327 UefiUpdateDataHandle, 328 &gEfiIfrFrameworkGuid, 329 NULL, 330 sizeof (EFI_IFR_GUID_OPTIONKEY) 331 ); 332 333 UOpcode->ExtendOpCode = EFI_IFR_EXTEND_OP_OPTIONKEY; 334 UOpcode->QuestionId = QuestionId; 335 CopyMem (&UOpcode->OptionValue, &OptionValue, sizeof (OptionValue)); 336 UOpcode->KeyValue = KeyValue; 337 338 return (UINT8 *) UOpcode; 339 } 340 341 /** 342 Create UEFI HII "One Of" Opcode from a Framework HII "One Of" Opcode. 343 344 @param UefiUpdateDataHandle The newly created UEFI HII opcode is appended to UefiUpdateDataHandle. 345 @param ThunkContext The HII Thunk Context. 346 @param FwOpcode The input Framework Opcode. 347 @param NextFwOpcode Returns the position of the next Framework Opcode after EFI_IFR_END_ONE_OF_OP of 348 the "One Of Option". 349 @param OpcodeCount The number of Opcode for the complete Framework "One Of" Opcode. 350 351 @retval NULL There is not enough space left in Buffer to add the opcode. 352 @retval Other A pointer to the created opcode. 353 354 **/ 355 UINT8 * 356 F2UCreateOneOfOpCode ( 357 IN OUT VOID *UefiUpdateDataHandle, 358 IN HII_THUNK_CONTEXT *ThunkContext, 359 IN CONST FRAMEWORK_EFI_IFR_ONE_OF *FwOpcode, 360 OUT FRAMEWORK_EFI_IFR_OP_HEADER **NextFwOpcode, 361 OUT UINTN *OpcodeCount 362 ) 363 { 364 EFI_STATUS Status; 365 EFI_IFR_ONE_OF UOpcode; 366 FRAMEWORK_EFI_IFR_OP_HEADER *FwOpHeader; 367 FRAMEWORK_EFI_IFR_ONE_OF_OPTION *FwOneOfOp; 368 UINT8 *OpCodeBuffer; 369 UINT8 *OneOfOpCodeBuffer; 370 371 ASSERT (NextFwOpcode != NULL); 372 ASSERT (OpcodeCount != NULL); 373 374 ZeroMem (&UOpcode, sizeof(UOpcode)); 375 *OpcodeCount = 0; 376 377 UOpcode.Header.Length = (UINT8) sizeof (UOpcode); 378 UOpcode.Header.OpCode = EFI_IFR_ONE_OF_OP; 379 UOpcode.Header.Scope = 1; 380 381 UOpcode.Question.Header.Prompt = FwOpcode->Prompt; 382 UOpcode.Question.Header.Help = FwOpcode->Help; 383 UOpcode.Question.VarStoreId = ThunkContext->FormSet->DefaultVarStoreId; 384 UOpcode.Question.VarStoreInfo.VarOffset = FwOpcode->QuestionId; 385 386 // 387 // Go over the Framework IFR binary to get the QuestionId for generated UEFI One Of Option opcode 388 // 389 FwOpHeader = (FRAMEWORK_EFI_IFR_OP_HEADER *) ((UINT8 *) FwOpcode + FwOpcode->Header.Length); 390 while (FwOpHeader->OpCode != EFI_IFR_END_ONE_OF_OP) { 391 ASSERT (FwOpHeader->OpCode == FRAMEWORK_EFI_IFR_ONE_OF_OPTION_OP); 392 393 FwOneOfOp = (FRAMEWORK_EFI_IFR_ONE_OF_OPTION *) FwOpHeader; 394 if ((FwOneOfOp->Flags & EFI_IFR_FLAG_INTERACTIVE) != 0) { 395 UOpcode.Question.Flags |= EFI_IFR_FLAG_CALLBACK; 396 397 if (UOpcode.Question.QuestionId == 0) { 398 Status = FwQIdToUefiQId (ThunkContext->FormSet, FwOpcode->Header.OpCode, FwOpcode->QuestionId, &UOpcode.Question.QuestionId); 399 if (EFI_ERROR (Status)) { 400 UOpcode.Question.QuestionId = AssignQuestionId (FwOneOfOp->Key, ThunkContext->FormSet); 401 } 402 } 403 404 } 405 406 if ((FwOneOfOp->Flags & EFI_IFR_FLAG_RESET_REQUIRED) == EFI_IFR_FLAG_RESET_REQUIRED) { 407 UOpcode.Question.Flags |= EFI_IFR_FLAG_RESET_REQUIRED; 408 } 409 410 FwOpHeader = (FRAMEWORK_EFI_IFR_OP_HEADER *) ((UINT8 *) FwOpHeader + FwOpHeader->Length); 411 } 412 413 414 if (UOpcode.Question.QuestionId == 0) { 415 // 416 // Assign QuestionId if still not assigned. 417 // 418 Status = FwQIdToUefiQId (ThunkContext->FormSet, FwOpcode->Header.OpCode, FwOpcode->QuestionId, &UOpcode.Question.QuestionId); 419 if (EFI_ERROR (Status)) { 420 UOpcode.Question.QuestionId = AssignQuestionId (FwOpcode->QuestionId, ThunkContext->FormSet); 421 } 422 } 423 424 OneOfOpCodeBuffer = HiiCreateRawOpCodes (UefiUpdateDataHandle, (UINT8 *) &UOpcode, sizeof (UOpcode)); 425 if (OneOfOpCodeBuffer == NULL) { 426 return NULL; 427 } 428 *OpcodeCount += 1; 429 430 // 431 // Go over again the Framework IFR binary to build the UEFI One Of Option opcodes. 432 // 433 FwOpHeader = (FRAMEWORK_EFI_IFR_OP_HEADER *) ((UINT8 *) FwOpcode + FwOpcode->Header.Length); 434 while (FwOpHeader->OpCode != EFI_IFR_END_ONE_OF_OP) { 435 436 FwOneOfOp = (FRAMEWORK_EFI_IFR_ONE_OF_OPTION *) FwOpHeader; 437 438 OpCodeBuffer = F2UCreateOneOfOptionOpCode (UefiUpdateDataHandle, (FRAMEWORK_EFI_IFR_ONE_OF_OPTION *) FwOpHeader, FwOpcode->Width); 439 if (OpCodeBuffer == NULL) { 440 return NULL; 441 } 442 443 OpCodeBuffer = CreateGuidOptionKeyOpCode (UefiUpdateDataHandle, UOpcode.Question.QuestionId, FwOneOfOp->Value, FwOneOfOp->Key); 444 if (OpCodeBuffer == NULL) { 445 return NULL; 446 } 447 448 FwOpHeader = (FRAMEWORK_EFI_IFR_OP_HEADER *) ((UINT8 *) FwOpHeader + FwOpHeader->Length); 449 *OpcodeCount += 1; 450 } 451 452 OpCodeBuffer = HiiCreateEndOpCode (UefiUpdateDataHandle); 453 if (OpCodeBuffer != NULL) { 454 *NextFwOpcode = (FRAMEWORK_EFI_IFR_OP_HEADER *)((UINT8 *) FwOpHeader + FwOpHeader->Length); 455 *OpcodeCount += 1; 456 } 457 458 return OneOfOpCodeBuffer; 459 } 460 461 /** 462 Create UEFI HII "Ordered List" Opcode from a Framework HII "Ordered List" Opcode. 463 464 @param UefiUpdateDataHandle The newly created UEFI HII opcode is appended to UefiUpdateDataHandle. 465 @param ThunkContext The HII Thunk Context. 466 @param FwOpcode The input Framework Opcode. 467 @param NextFwOpcode Returns the position of the next Framework Opcode after EFI_IFR_END_ONE_OF_OP of 468 the "Ordered List". 469 @param OpcodeCount The number of Opcode for the complete Framework "Ordered List" Opcode. 470 471 @retval NULL There is not enough space left in Buffer to add the opcode. 472 @retval Other A pointer to the created opcode. 473 474 **/ 475 UINT8 * 476 F2UCreateOrderedListOpCode ( 477 IN OUT VOID *UefiUpdateDataHandle, 478 IN HII_THUNK_CONTEXT *ThunkContext, 479 IN CONST FRAMEWORK_EFI_IFR_ORDERED_LIST *FwOpcode, 480 OUT FRAMEWORK_EFI_IFR_OP_HEADER **NextFwOpcode, 481 OUT UINTN *OpcodeCount 482 ) 483 { 484 EFI_IFR_ORDERED_LIST UOpcode; 485 EFI_STATUS Status; 486 FRAMEWORK_EFI_IFR_OP_HEADER *FwOpHeader; 487 FRAMEWORK_EFI_IFR_ONE_OF_OPTION *FwOneOfOp; 488 UINT8 *OpcodeBuffer; 489 UINT8 *OrderListOpCode; 490 491 ZeroMem (&UOpcode, sizeof(UOpcode)); 492 *OpcodeCount = 0; 493 494 UOpcode.Header.Length = (UINT8) sizeof (UOpcode); 495 UOpcode.Header.OpCode = EFI_IFR_ORDERED_LIST_OP; 496 UOpcode.Header.Scope = 1; 497 498 UOpcode.Question.Header.Prompt = FwOpcode->Prompt; 499 UOpcode.Question.Header.Help = FwOpcode->Help; 500 UOpcode.Question.VarStoreId = ThunkContext->FormSet->DefaultVarStoreId; 501 UOpcode.Question.VarStoreInfo.VarOffset = FwOpcode->QuestionId; 502 503 UOpcode.MaxContainers = FwOpcode->MaxEntries; 504 505 // 506 // Go over the Framework IFR binary to get the QuestionId for generated UEFI One Of Option opcode 507 // 508 FwOpHeader = (FRAMEWORK_EFI_IFR_OP_HEADER *) ((UINT8 *) FwOpcode + FwOpcode->Header.Length); 509 while (FwOpHeader->OpCode != EFI_IFR_END_ONE_OF_OP) { 510 ASSERT (FwOpHeader->OpCode == FRAMEWORK_EFI_IFR_ONE_OF_OPTION_OP); 511 512 FwOneOfOp = (FRAMEWORK_EFI_IFR_ONE_OF_OPTION *) FwOpHeader; 513 if ((FwOneOfOp->Flags & EFI_IFR_FLAG_INTERACTIVE) != 0) { 514 UOpcode.Question.Flags |= EFI_IFR_FLAG_CALLBACK; 515 516 if (UOpcode.Question.QuestionId == 0) { 517 Status = FwQIdToUefiQId (ThunkContext->FormSet, FwOpcode->Header.OpCode, FwOpcode->QuestionId, &UOpcode.Question.QuestionId); 518 if (EFI_ERROR (Status)) { 519 UOpcode.Question.QuestionId = AssignQuestionId (FwOneOfOp->Key, ThunkContext->FormSet); 520 } 521 522 } 523 } 524 525 if ((FwOneOfOp->Flags & EFI_IFR_FLAG_RESET_REQUIRED) == EFI_IFR_FLAG_RESET_REQUIRED) { 526 UOpcode.Question.Flags |= EFI_IFR_FLAG_RESET_REQUIRED; 527 } 528 529 FwOpHeader = (FRAMEWORK_EFI_IFR_OP_HEADER *) ((UINT8 *) FwOpHeader + FwOpHeader->Length); 530 } 531 532 if (UOpcode.Question.QuestionId == 0) { 533 Status = FwQIdToUefiQId (ThunkContext->FormSet, FwOpcode->Header.OpCode, FwOpcode->QuestionId, &UOpcode.Question.QuestionId); 534 if (EFI_ERROR (Status)) { 535 UOpcode.Question.QuestionId = AssignQuestionId (FwOpcode->QuestionId, ThunkContext->FormSet); 536 } 537 } 538 539 OrderListOpCode = HiiCreateRawOpCodes (UefiUpdateDataHandle, (UINT8 *) &UOpcode, sizeof(UOpcode)); 540 if (OrderListOpCode == NULL) { 541 return NULL; 542 } 543 *OpcodeCount += 1; 544 545 FwOpHeader = (FRAMEWORK_EFI_IFR_OP_HEADER *) ((UINT8 *) FwOpcode + FwOpcode->Header.Length); 546 while (FwOpHeader->OpCode != EFI_IFR_END_ONE_OF_OP) { 547 // 548 // Each entry of Order List in Framework HII is always 1 byte in size 549 // 550 OpcodeBuffer = F2UCreateOneOfOptionOpCode (UefiUpdateDataHandle, (CONST FRAMEWORK_EFI_IFR_ONE_OF_OPTION *) FwOpHeader, 1); 551 if (OpcodeBuffer == NULL) { 552 return NULL; 553 } 554 FwOpHeader = (FRAMEWORK_EFI_IFR_OP_HEADER *) ((UINT8 *) FwOpHeader + FwOpHeader->Length); 555 *OpcodeCount += 1; 556 } 557 558 OpcodeBuffer = HiiCreateEndOpCode (UefiUpdateDataHandle); 559 if (OpcodeBuffer != NULL) { 560 *NextFwOpcode = (FRAMEWORK_EFI_IFR_OP_HEADER *)((UINT8 *) FwOpHeader + FwOpHeader->Length); 561 *OpcodeCount += 1; 562 } 563 564 return OrderListOpCode; 565 } 566 567 /** 568 Create UEFI HII CheckBox Opcode from a Framework HII Checkbox Opcode. 569 570 @param UefiUpdateDataHandle The newly created UEFI HII opcode is appended to UefiUpdateDataHandle. 571 @param ThunkContext The HII Thunk Context. 572 @param FwOpcode The input Framework Opcode. 573 574 @retval NULL There is not enough space left in Buffer to add the opcode. 575 @retval Other A pointer to the created opcode. 576 577 **/ 578 UINT8 * 579 F2UCreateCheckBoxOpCode ( 580 IN OUT VOID *UefiUpdateDataHandle, 581 IN HII_THUNK_CONTEXT *ThunkContext, 582 IN CONST FRAMEWORK_EFI_IFR_CHECKBOX *FwOpcode 583 ) 584 { 585 EFI_STATUS Status; 586 EFI_IFR_CHECKBOX UOpcode; 587 588 ZeroMem (&UOpcode, sizeof(UOpcode)); 589 590 UOpcode.Header.Length = (UINT8) sizeof (UOpcode); 591 UOpcode.Header.OpCode = EFI_IFR_CHECKBOX_OP; 592 593 UOpcode.Question.Header.Prompt = FwOpcode->Prompt; 594 UOpcode.Question.Header.Help = FwOpcode->Help; 595 596 if (FwOpcode->Key == 0) { 597 Status = FwQIdToUefiQId (ThunkContext->FormSet, FwOpcode->Header.OpCode, FwOpcode->QuestionId, &UOpcode.Question.QuestionId); 598 if (EFI_ERROR (Status)) { 599 // 600 // Add a new opcode and it will not trigger call back. So we just reuse the FW QuestionId. 601 // 602 UOpcode.Question.QuestionId = AssignQuestionId (FwOpcode->QuestionId, ThunkContext->FormSet); 603 } 604 } else { 605 UOpcode.Question.QuestionId = FwOpcode->Key; 606 } 607 608 // 609 // We map 2 flags: 610 // EFI_IFR_FLAG_INTERACTIVE, 611 // EFI_IFR_FLAG_RESET_REQUIRED, 612 // to UEFI IFR Opcode Question flags. The rest flags are obsolete. 613 // 614 UOpcode.Question.Flags = (UINT8) (FwOpcode->Flags & (EFI_IFR_FLAG_INTERACTIVE | EFI_IFR_FLAG_RESET_REQUIRED)); 615 616 617 UOpcode.Question.VarStoreId = ThunkContext->FormSet->DefaultVarStoreId; 618 UOpcode.Question.VarStoreInfo.VarOffset = FwOpcode->QuestionId; 619 620 // 621 // We also map these 2 flags: 622 // EFI_IFR_FLAG_DEFAULT, 623 // EFI_IFR_FLAG_MANUFACTURING, 624 // to UEFI IFR CheckBox Opcode default flags. 625 // 626 UOpcode.Flags = (UINT8) (FwOpcode->Flags & (EFI_IFR_FLAG_DEFAULT | EFI_IFR_FLAG_MANUFACTURING)); 627 628 return HiiCreateRawOpCodes (UefiUpdateDataHandle, (UINT8 *) &UOpcode, sizeof(UOpcode)); 629 } 630 631 632 /** 633 Create UEFI HII Numeric Opcode from a Framework HII Numeric Opcode. 634 635 @param UefiUpdateDataHandle The newly created UEFI HII opcode is appended to UefiUpdateDataHandle. 636 @param ThunkContext The HII Thunk Context. 637 @param FwOpcode The input Framework Opcode. 638 639 @retval NULL There is not enough space left in Buffer to add the opcode. 640 @retval Other A pointer to the created opcode. 641 642 **/ 643 UINT8 * 644 F2UCreateNumericOpCode ( 645 IN OUT VOID *UefiUpdateDataHandle, 646 IN HII_THUNK_CONTEXT *ThunkContext, 647 IN CONST FRAMEWORK_EFI_IFR_NUMERIC *FwOpcode 648 ) 649 { 650 EFI_STATUS Status; 651 EFI_IFR_NUMERIC UOpcode; 652 EFI_IFR_DEFAULT UOpcodeDefault; 653 UINT8 *NumbericOpCode; 654 UINT8 *OpcodeBuffer; 655 656 ZeroMem (&UOpcode, sizeof(UOpcode)); 657 658 if (FwOpcode->Key == 0) { 659 Status = FwQIdToUefiQId (ThunkContext->FormSet, FwOpcode->Header.OpCode, FwOpcode->QuestionId, &UOpcode.Question.QuestionId); 660 if (EFI_ERROR (Status)) { 661 // 662 // Add a new opcode and it will not trigger call back. So we just reuse the FW QuestionId. 663 // 664 UOpcode.Question.QuestionId = AssignQuestionId (FwOpcode->QuestionId, ThunkContext->FormSet); 665 } 666 } else { 667 UOpcode.Question.QuestionId = FwOpcode->Key; 668 } 669 670 UOpcode.Header.Length = (UINT8) sizeof (UOpcode); 671 UOpcode.Header.OpCode = EFI_IFR_NUMERIC_OP; 672 // 673 // We need to create a nested default value for the UEFI Numeric Opcode. 674 // So turn on the scope. 675 // 676 UOpcode.Header.Scope = 1; 677 678 UOpcode.Question.Header.Prompt = FwOpcode->Prompt; 679 UOpcode.Question.Header.Help = FwOpcode->Help; 680 681 UOpcode.Question.VarStoreId = ThunkContext->FormSet->DefaultVarStoreId; 682 UOpcode.Question.VarStoreInfo.VarOffset = FwOpcode->QuestionId; 683 684 UOpcode.Question.Flags = (UINT8) (FwOpcode->Flags & (EFI_IFR_FLAG_INTERACTIVE | EFI_IFR_FLAG_RESET_REQUIRED)); 685 686 // 687 // Framework Numeric values are all in UINT16 and displayed as decimal. 688 // 689 UOpcode.data.u16.MinValue = FwOpcode->Minimum; 690 UOpcode.data.u16.MaxValue = FwOpcode->Maximum; 691 UOpcode.data.u16.Step = FwOpcode->Step; 692 693 switch (FwOpcode->Width) { 694 case 1: 695 { 696 UOpcode.Flags = EFI_IFR_NUMERIC_SIZE_1 | EFI_IFR_DISPLAY_UINT_DEC; 697 break; 698 } 699 case 2: 700 { 701 UOpcode.Flags = EFI_IFR_NUMERIC_SIZE_2 | EFI_IFR_DISPLAY_UINT_DEC; 702 break; 703 } 704 default: 705 { 706 ASSERT (FALSE); 707 return NULL; 708 } 709 } 710 711 NumbericOpCode = HiiCreateRawOpCodes (UefiUpdateDataHandle, (UINT8 *) &UOpcode, sizeof(UOpcode)); 712 if (NumbericOpCode == NULL) { 713 return NULL; 714 } 715 716 // 717 // We need to create a default value. 718 // 719 ZeroMem (&UOpcodeDefault, sizeof (UOpcodeDefault)); 720 UOpcodeDefault.Header.Length = (UINT8) sizeof (UOpcodeDefault); 721 UOpcodeDefault.Header.OpCode = EFI_IFR_DEFAULT_OP; 722 723 UOpcodeDefault.DefaultId = 0; 724 725 switch (FwOpcode->Width) { 726 case 1: 727 { 728 UOpcodeDefault.Type = EFI_IFR_TYPE_NUM_SIZE_8; 729 break; 730 } 731 case 2: 732 { 733 UOpcodeDefault.Type = EFI_IFR_TYPE_NUM_SIZE_16; 734 break; 735 } 736 } 737 738 CopyMem (&UOpcodeDefault.Value.u8, &FwOpcode->Default, FwOpcode->Width); 739 740 OpcodeBuffer = HiiCreateRawOpCodes (UefiUpdateDataHandle, (UINT8 *) &UOpcodeDefault, sizeof(UOpcodeDefault)); 741 if (OpcodeBuffer == NULL) { 742 return NULL; 743 } 744 745 OpcodeBuffer = HiiCreateEndOpCode (UefiUpdateDataHandle); 746 if (OpcodeBuffer == NULL) { 747 return NULL; 748 } 749 750 return NumbericOpCode; 751 } 752 753 754 /** 755 Create UEFI HII String Opcode from a Framework HII String Opcode. 756 757 @param UefiUpdateDataHandle The newly created UEFI HII opcode is appended to UefiUpdateDataHandle. 758 @param ThunkContext The HII Thunk Context. 759 @param FwOpcode The input Framework Opcode. 760 761 @retval NULL There is not enough space left in Buffer to add the opcode. 762 @retval Other A pointer to the created opcode. 763 764 **/ 765 UINT8 * 766 F2UCreateStringOpCode ( 767 IN OUT VOID *UefiUpdateDataHandle, 768 IN HII_THUNK_CONTEXT *ThunkContext, 769 IN CONST FRAMEWORK_EFI_IFR_STRING *FwOpcode 770 ) 771 { 772 EFI_IFR_STRING UOpcode; 773 EFI_STATUS Status; 774 775 ZeroMem (&UOpcode, sizeof(UOpcode)); 776 777 if (FwOpcode->Key == 0) { 778 Status = FwQIdToUefiQId (ThunkContext->FormSet, FwOpcode->Header.OpCode, FwOpcode->QuestionId, &UOpcode.Question.QuestionId); 779 if (EFI_ERROR (Status)) { 780 // 781 // Add a new opcode and it will not trigger call back. So we just reuse the FW QuestionId. 782 // 783 UOpcode.Question.QuestionId = AssignQuestionId (FwOpcode->QuestionId, ThunkContext->FormSet); 784 } 785 } else { 786 UOpcode.Question.QuestionId = FwOpcode->Key; 787 } 788 789 UOpcode.Header.Length = (UINT8) sizeof (UOpcode); 790 UOpcode.Header.OpCode = EFI_IFR_STRING_OP; 791 792 UOpcode.Question.Header.Prompt = FwOpcode->Prompt; 793 UOpcode.Question.Header.Help = FwOpcode->Help; 794 795 UOpcode.Question.Flags = (UINT8) (FwOpcode->Flags & (EFI_IFR_FLAG_INTERACTIVE | EFI_IFR_FLAG_RESET_REQUIRED)); 796 797 UOpcode.Question.VarStoreId = ThunkContext->FormSet->DefaultVarStoreId; 798 UOpcode.Question.VarStoreInfo.VarOffset = FwOpcode->QuestionId; 799 800 UOpcode.MinSize = FwOpcode->MinSize; 801 UOpcode.MaxSize = FwOpcode->MaxSize; 802 UOpcode.Flags = EFI_IFR_STRING_MULTI_LINE; 803 804 return HiiCreateRawOpCodes (UefiUpdateDataHandle, (UINT8 *) &UOpcode, sizeof(UOpcode)); 805 } 806 807 /** 808 Create UEFI HII Banner Opcode from a Framework HII Banner Opcode. 809 810 @param UefiUpdateDataHandle The newly created UEFI HII opcode is appended to UefiUpdateDataHandle. 811 @param FwOpcode The input Framework Opcode. 812 813 @retval NULL There is not enough space left in Buffer to add the opcode. 814 @retval Other A pointer to the created opcode. 815 816 **/ 817 UINT8 * 818 F2UCreateBannerOpCode ( 819 IN OUT VOID *UefiUpdateDataHandle, 820 IN CONST EFI_IFR_BANNER *FwOpcode 821 ) 822 { 823 EFI_IFR_GUID_BANNER *UOpcode; 824 825 UOpcode = (EFI_IFR_GUID_BANNER *) HiiCreateGuidOpCode ( 826 UefiUpdateDataHandle, 827 &gEfiIfrTianoGuid, 828 NULL, 829 sizeof (EFI_IFR_GUID_BANNER) 830 ); 831 832 UOpcode->ExtendOpCode = EFI_IFR_EXTEND_OP_BANNER; 833 UOpcode->Title = FwOpcode->Title; 834 UOpcode->LineNumber = FwOpcode->LineNumber; 835 UOpcode->Alignment = FwOpcode->Alignment; 836 837 return (UINT8 *) UOpcode; 838 } 839 840 /** 841 Create a Hii Update data Handle used to call IfrLibUpdateForm. 842 843 @param ThunkContext The HII Thunk Context. 844 @param FwUpdateData The Framework Update Data. 845 @param UefiOpCodeHandle The UEFI opcode handle. 846 847 @retval EFI_SUCCESS The UEFI Update Data is created successfully. 848 @retval EFI_UNSUPPORTED There is unsupported opcode in FwUpdateData. 849 @retval EFI_OUT_OF_RESOURCES There is not enough resource. 850 **/ 851 EFI_STATUS 852 FwUpdateDataToUefiUpdateData ( 853 IN HII_THUNK_CONTEXT *ThunkContext, 854 IN CONST EFI_HII_UPDATE_DATA *FwUpdateData, 855 IN VOID *UefiOpCodeHandle 856 ) 857 { 858 FRAMEWORK_EFI_IFR_OP_HEADER *FwOpCode; 859 FRAMEWORK_EFI_IFR_OP_HEADER *NextFwOpCode; 860 UINTN Index; 861 UINTN DataCount; 862 UINT8 *OpCodeBuffer; 863 LIST_ENTRY *StorageList; 864 FORMSET_STORAGE *Storage; 865 FORM_BROWSER_FORMSET *FormSet; 866 CHAR16 *DefaultVarStoreName; 867 UINT16 DefaultVarStoreId; 868 EFI_IFR_VARSTORE_SELECT *SelectVarOp; 869 870 FwOpCode = (FRAMEWORK_EFI_IFR_OP_HEADER *) &FwUpdateData->Data; 871 872 FormSet = ThunkContext->FormSet; 873 DefaultVarStoreId = FormSet->DefaultVarStoreId; 874 DefaultVarStoreName = FormSet->OriginalDefaultVarStoreName; 875 876 for (Index = 0; Index < FwUpdateData->DataCount; Index += DataCount) { 877 switch (FwOpCode->OpCode) { 878 case FRAMEWORK_EFI_IFR_SUBTITLE_OP: 879 OpCodeBuffer = HiiCreateSubTitleOpCode (UefiOpCodeHandle, ((FRAMEWORK_EFI_IFR_SUBTITLE *) FwOpCode)->SubTitle, 0, 0, 0); 880 DataCount = 1; 881 break; 882 883 case FRAMEWORK_EFI_IFR_TEXT_OP: 884 OpCodeBuffer = F2UCreateTextOpCode (UefiOpCodeHandle, (FRAMEWORK_EFI_IFR_TEXT *) FwOpCode); 885 DataCount = 1; 886 break; 887 888 case FRAMEWORK_EFI_IFR_REF_OP: 889 OpCodeBuffer = F2UCreateReferenceOpCode (UefiOpCodeHandle, (FRAMEWORK_EFI_IFR_REF *) FwOpCode); 890 DataCount = 1; 891 break; 892 893 case FRAMEWORK_EFI_IFR_ONE_OF_OP: 894 OpCodeBuffer = F2UCreateOneOfOpCode (UefiOpCodeHandle, ThunkContext, (FRAMEWORK_EFI_IFR_ONE_OF *) FwOpCode, &NextFwOpCode, &DataCount); 895 if (OpCodeBuffer != NULL) { 896 FwOpCode = NextFwOpCode; 897 // 898 // FwOpCode is already updated to point to the next opcode. 899 // 900 continue; 901 } 902 break; 903 904 case FRAMEWORK_EFI_IFR_ORDERED_LIST_OP: 905 OpCodeBuffer = F2UCreateOrderedListOpCode (UefiOpCodeHandle, ThunkContext, (FRAMEWORK_EFI_IFR_ORDERED_LIST *) FwOpCode, &NextFwOpCode, &DataCount); 906 if (OpCodeBuffer != NULL) { 907 FwOpCode = NextFwOpCode; 908 // 909 // FwOpCode is already updated to point to the next opcode. 910 // 911 continue; 912 } 913 break; 914 915 case FRAMEWORK_EFI_IFR_CHECKBOX_OP: 916 OpCodeBuffer = F2UCreateCheckBoxOpCode (UefiOpCodeHandle, ThunkContext, (FRAMEWORK_EFI_IFR_CHECKBOX *) FwOpCode); 917 DataCount = 1; 918 break; 919 920 case FRAMEWORK_EFI_IFR_STRING_OP: 921 OpCodeBuffer = F2UCreateStringOpCode (UefiOpCodeHandle, ThunkContext, (FRAMEWORK_EFI_IFR_STRING *) FwOpCode); 922 DataCount = 1; 923 break; 924 925 case EFI_IFR_BANNER_OP: 926 OpCodeBuffer = F2UCreateBannerOpCode (UefiOpCodeHandle, (EFI_IFR_BANNER *) FwOpCode); 927 DataCount = 1; 928 break; 929 930 case EFI_IFR_END_ONE_OF_OP: 931 OpCodeBuffer = HiiCreateEndOpCode (UefiOpCodeHandle); 932 DataCount = 1; 933 break; 934 935 case FRAMEWORK_EFI_IFR_NUMERIC_OP: 936 OpCodeBuffer = F2UCreateNumericOpCode (UefiOpCodeHandle, ThunkContext, (FRAMEWORK_EFI_IFR_NUMERIC *) FwOpCode); 937 DataCount = 1; 938 break; 939 940 case EFI_IFR_VARSTORE_SELECT_OP: 941 OpCodeBuffer = (UINT8 *) FwOpCode; 942 SelectVarOp = (EFI_IFR_VARSTORE_SELECT *) FwOpCode; 943 // 944 // Check whether the selected VarId is in StorageList. 945 // 946 StorageList = GetFirstNode (&FormSet->StorageListHead); 947 while (!IsNull (&FormSet->StorageListHead, StorageList)) { 948 Storage = FORMSET_STORAGE_FROM_LINK (StorageList); 949 if (Storage->VarStoreId == SelectVarOp->VarId) { 950 break; 951 } 952 StorageList = GetNextNode (&FormSet->StorageListHead, StorageList); 953 } 954 ASSERT (!IsNull (&FormSet->StorageListHead, StorageList)); 955 // 956 // Change VarStoreId to the selected VarId. 957 // 958 FormSet->DefaultVarStoreId = SelectVarOp->VarId; 959 if (SelectVarOp->VarId == DefaultVarStoreId) { 960 FormSet->OriginalDefaultVarStoreName = DefaultVarStoreName; 961 } 962 DataCount = 1; 963 break; 964 965 default: 966 ASSERT (FALSE); 967 return EFI_UNSUPPORTED; 968 } 969 970 if (OpCodeBuffer == NULL) { 971 return EFI_OUT_OF_RESOURCES; 972 } 973 974 FwOpCode = (FRAMEWORK_EFI_IFR_OP_HEADER *)((UINT8 *) FwOpCode + FwOpCode->Length); 975 } 976 977 // 978 // Revert FromSet default varstore ID. 979 // 980 FormSet->DefaultVarStoreId = DefaultVarStoreId; 981 FormSet->OriginalDefaultVarStoreName = DefaultVarStoreName; 982 return EFI_SUCCESS; 983 } 984 985