Home | History | Annotate | Download | only in PlatformDxe
      1 /** @file
      2   This driver effectuates OVMF's platform configuration settings and exposes
      3   them via HII.
      4 
      5   Copyright (C) 2014, Red Hat, Inc.
      6   Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
      7 
      8   This program and the accompanying materials are licensed and made available
      9   under the terms and conditions of the BSD License which accompanies this
     10   distribution.  The full text of the license may be found at
     11   http://opensource.org/licenses/bsd-license.php
     12 
     13   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
     14   WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     15 **/
     16 
     17 #include <Library/BaseLib.h>
     18 #include <Library/BaseMemoryLib.h>
     19 #include <Library/DebugLib.h>
     20 #include <Library/DevicePathLib.h>
     21 #include <Library/HiiLib.h>
     22 #include <Library/MemoryAllocationLib.h>
     23 #include <Library/PrintLib.h>
     24 #include <Library/UefiBootServicesTableLib.h>
     25 #include <Library/UefiHiiServicesLib.h>
     26 #include <Protocol/DevicePath.h>
     27 #include <Protocol/GraphicsOutput.h>
     28 #include <Protocol/HiiConfigAccess.h>
     29 #include <Guid/MdeModuleHii.h>
     30 #include <Guid/OvmfPlatformConfig.h>
     31 
     32 #include "Platform.h"
     33 #include "PlatformConfig.h"
     34 
     35 //
     36 // The HiiAddPackages() library function requires that any controller (or
     37 // image) handle, to be associated with the HII packages under installation, be
     38 // "decorated" with a device path. The tradition seems to be a vendor device
     39 // path.
     40 //
     41 // We'd like to associate our HII packages with the driver's image handle. The
     42 // first idea is to use the driver image's device path. Unfortunately, loaded
     43 // images only come with an EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL (not the
     44 // usual EFI_DEVICE_PATH_PROTOCOL), ie. a different GUID. In addition, even the
     45 // EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL interface may be NULL, if the image
     46 // has been loaded from an "unnamed" memory source buffer.
     47 //
     48 // Hence let's just stick with the tradition -- use a dedicated vendor device
     49 // path, with the driver's FILE_GUID.
     50 //
     51 #pragma pack(1)
     52 typedef struct {
     53   VENDOR_DEVICE_PATH       VendorDevicePath;
     54   EFI_DEVICE_PATH_PROTOCOL End;
     55 } PKG_DEVICE_PATH;
     56 #pragma pack()
     57 
     58 STATIC PKG_DEVICE_PATH mPkgDevicePath = {
     59   {
     60     {
     61       HARDWARE_DEVICE_PATH,
     62       HW_VENDOR_DP,
     63       {
     64         (UINT8) (sizeof (VENDOR_DEVICE_PATH)     ),
     65         (UINT8) (sizeof (VENDOR_DEVICE_PATH) >> 8)
     66       }
     67     },
     68     EFI_CALLER_ID_GUID
     69   },
     70   {
     71     END_DEVICE_PATH_TYPE,
     72     END_ENTIRE_DEVICE_PATH_SUBTYPE,
     73     {
     74       (UINT8) (END_DEVICE_PATH_LENGTH     ),
     75       (UINT8) (END_DEVICE_PATH_LENGTH >> 8)
     76     }
     77   }
     78 };
     79 
     80 //
     81 // The configuration interface between the HII engine (form display etc) and
     82 // this driver.
     83 //
     84 STATIC EFI_HII_CONFIG_ACCESS_PROTOCOL mConfigAccess;
     85 
     86 //
     87 // The handle representing our list of packages after installation.
     88 //
     89 STATIC EFI_HII_HANDLE mInstalledPackages;
     90 
     91 //
     92 // The arrays below constitute our HII package list. They are auto-generated by
     93 // the VFR compiler and linked into the driver image during the build.
     94 //
     95 // - The strings package receives its C identifier from the driver's BASE_NAME,
     96 //   plus "Strings".
     97 //
     98 // - The forms package receives its C identifier from the VFR file's basename,
     99 //   plus "Bin".
    100 //
    101 //
    102 extern UINT8 PlatformDxeStrings[];
    103 extern UINT8 PlatformFormsBin[];
    104 
    105 //
    106 // We want to be notified about GOP installations until we find one GOP
    107 // interface that lets us populate the form.
    108 //
    109 STATIC EFI_EVENT mGopEvent;
    110 
    111 //
    112 // The registration record underneath this pointer allows us to iterate through
    113 // the GOP instances one by one.
    114 //
    115 STATIC VOID *mGopTracker;
    116 
    117 //
    118 // Cache the resolutions we get from the GOP.
    119 //
    120 typedef struct {
    121   UINT32 X;
    122   UINT32 Y;
    123 } GOP_MODE;
    124 
    125 STATIC UINTN    mNumGopModes;
    126 STATIC GOP_MODE *mGopModes;
    127 
    128 
    129 /**
    130   Load the persistent platform configuration and translate it to binary form
    131   state.
    132 
    133   If the platform configuration is missing, then the function fills in a
    134   default state.
    135 
    136   @param[out] MainFormState  Binary form/widget state after translation.
    137 
    138   @retval EFI_SUCCESS  Form/widget state ready.
    139   @return              Error codes from underlying functions.
    140 **/
    141 STATIC
    142 EFI_STATUS
    143 EFIAPI
    144 PlatformConfigToFormState (
    145   OUT MAIN_FORM_STATE *MainFormState
    146   )
    147 {
    148   EFI_STATUS      Status;
    149   PLATFORM_CONFIG PlatformConfig;
    150   UINT64          OptionalElements;
    151   UINTN           ModeNumber;
    152 
    153   ZeroMem (MainFormState, sizeof *MainFormState);
    154 
    155   Status = PlatformConfigLoad (&PlatformConfig, &OptionalElements);
    156   switch (Status) {
    157   case EFI_SUCCESS:
    158     if (OptionalElements & PLATFORM_CONFIG_F_GRAPHICS_RESOLUTION) {
    159       //
    160       // Format the preferred resolution as text.
    161       //
    162       UnicodeSPrintAsciiFormat (
    163         (CHAR16 *) MainFormState->CurrentPreferredResolution,
    164         sizeof MainFormState->CurrentPreferredResolution,
    165         "%Ldx%Ld",
    166         (INT64) PlatformConfig.HorizontalResolution,
    167         (INT64) PlatformConfig.VerticalResolution);
    168 
    169       //
    170       // Try to locate it in the drop-down list too. This may not succeed, but
    171       // that's fine.
    172       //
    173       for (ModeNumber = 0; ModeNumber < mNumGopModes; ++ModeNumber) {
    174         if (mGopModes[ModeNumber].X == PlatformConfig.HorizontalResolution &&
    175             mGopModes[ModeNumber].Y == PlatformConfig.VerticalResolution) {
    176           MainFormState->NextPreferredResolution = (UINT32) ModeNumber;
    177           break;
    178         }
    179       }
    180 
    181       break;
    182     }
    183     //
    184     // fall through otherwise
    185     //
    186 
    187   case EFI_NOT_FOUND:
    188     UnicodeSPrintAsciiFormat (
    189       (CHAR16 *) MainFormState->CurrentPreferredResolution,
    190       sizeof MainFormState->CurrentPreferredResolution,
    191       "Unset");
    192     break;
    193 
    194   default:
    195     return Status;
    196   }
    197 
    198   return EFI_SUCCESS;
    199 }
    200 
    201 
    202 /**
    203   This function is called by the HII machinery when it fetches the form state.
    204 
    205   See the precise documentation in the UEFI spec.
    206 
    207   @param[in]  This      The Config Access Protocol instance.
    208 
    209   @param[in]  Request   A <ConfigRequest> format UCS-2 string describing the
    210                         query.
    211 
    212   @param[out] Progress  A pointer into Request on output, identifying the query
    213                         element where processing failed.
    214 
    215   @param[out] Results   A <MultiConfigAltResp> format UCS-2 string that has
    216                         all values filled in for the names in the Request
    217                         string.
    218 
    219   @retval EFI_SUCCESS  Extraction of form state in <MultiConfigAltResp>
    220                        encoding successful.
    221   @return              Status codes from underlying functions.
    222 
    223 **/
    224 STATIC
    225 EFI_STATUS
    226 EFIAPI
    227 ExtractConfig (
    228   IN CONST  EFI_HII_CONFIG_ACCESS_PROTOCOL  *This,
    229   IN CONST  EFI_STRING                      Request,
    230   OUT       EFI_STRING                      *Progress,
    231   OUT       EFI_STRING                      *Results
    232 )
    233 {
    234   MAIN_FORM_STATE MainFormState;
    235   EFI_STATUS      Status;
    236 
    237   DEBUG ((EFI_D_VERBOSE, "%a: Request=\"%s\"\n", __FUNCTION__, Request));
    238 
    239   Status = PlatformConfigToFormState (&MainFormState);
    240   if (EFI_ERROR (Status)) {
    241     *Progress = Request;
    242     return Status;
    243   }
    244 
    245   //
    246   // Answer the textual request keying off the binary form state.
    247   //
    248   Status = gHiiConfigRouting->BlockToConfig (gHiiConfigRouting, Request,
    249                                 (VOID *) &MainFormState, sizeof MainFormState,
    250                                 Results, Progress);
    251   if (EFI_ERROR (Status)) {
    252     DEBUG ((EFI_D_ERROR, "%a: BlockToConfig(): %r, Progress=\"%s\"\n",
    253       __FUNCTION__, Status, (Status == EFI_DEVICE_ERROR) ? NULL : *Progress));
    254   } else {
    255     DEBUG ((EFI_D_VERBOSE, "%a: Results=\"%s\"\n", __FUNCTION__, *Results));
    256   }
    257   return Status;
    258 }
    259 
    260 
    261 /**
    262   Interpret the binary form state and save it as persistent platform
    263   configuration.
    264 
    265   @param[in] MainFormState  Binary form/widget state to verify and save.
    266 
    267   @retval EFI_SUCCESS  Platform configuration saved.
    268   @return              Error codes from underlying functions.
    269 **/
    270 STATIC
    271 EFI_STATUS
    272 EFIAPI
    273 FormStateToPlatformConfig (
    274   IN CONST MAIN_FORM_STATE *MainFormState
    275   )
    276 {
    277   EFI_STATUS      Status;
    278   PLATFORM_CONFIG PlatformConfig;
    279   CONST GOP_MODE  *GopMode;
    280 
    281   //
    282   // There's nothing to do with the textual CurrentPreferredResolution field.
    283   // We verify and translate the selection in the drop-down list.
    284   //
    285   if (MainFormState->NextPreferredResolution >= mNumGopModes) {
    286     return EFI_INVALID_PARAMETER;
    287   }
    288   GopMode = mGopModes + MainFormState->NextPreferredResolution;
    289 
    290   ZeroMem (&PlatformConfig, sizeof PlatformConfig);
    291   PlatformConfig.HorizontalResolution = GopMode->X;
    292   PlatformConfig.VerticalResolution   = GopMode->Y;
    293 
    294   Status = PlatformConfigSave (&PlatformConfig);
    295   return Status;
    296 }
    297 
    298 
    299 /**
    300   This function is called by the HII machinery when it wants the driver to
    301   interpret and persist the form state.
    302 
    303   See the precise documentation in the UEFI spec.
    304 
    305   @param[in]  This           The Config Access Protocol instance.
    306 
    307   @param[in]  Configuration  A <ConfigResp> format UCS-2 string describing the
    308                              form state.
    309 
    310   @param[out] Progress       A pointer into Configuration on output,
    311                              identifying the element where processing failed.
    312 
    313   @retval EFI_SUCCESS  Configuration verified, state permanent.
    314 
    315   @return              Status codes from underlying functions.
    316 **/
    317 STATIC
    318 EFI_STATUS
    319 EFIAPI
    320 RouteConfig (
    321   IN CONST  EFI_HII_CONFIG_ACCESS_PROTOCOL  *This,
    322   IN CONST  EFI_STRING                      Configuration,
    323   OUT       EFI_STRING                      *Progress
    324 )
    325 {
    326   MAIN_FORM_STATE MainFormState;
    327   UINTN           BlockSize;
    328   EFI_STATUS      Status;
    329 
    330   DEBUG ((EFI_D_VERBOSE, "%a: Configuration=\"%s\"\n", __FUNCTION__,
    331     Configuration));
    332 
    333   //
    334   // the "read" step in RMW
    335   //
    336   Status = PlatformConfigToFormState (&MainFormState);
    337   if (EFI_ERROR (Status)) {
    338     *Progress = Configuration;
    339     return Status;
    340   }
    341 
    342   //
    343   // the "modify" step in RMW
    344   //
    345   // (Update the binary form state. This update may be partial, which is why in
    346   // general we must pre-load the form state from the platform config.)
    347   //
    348   BlockSize = sizeof MainFormState;
    349   Status = gHiiConfigRouting->ConfigToBlock (gHiiConfigRouting, Configuration,
    350                                 (VOID *) &MainFormState, &BlockSize, Progress);
    351   if (EFI_ERROR (Status)) {
    352     DEBUG ((EFI_D_ERROR, "%a: ConfigToBlock(): %r, Progress=\"%s\"\n",
    353       __FUNCTION__, Status,
    354       (Status == EFI_BUFFER_TOO_SMALL) ? NULL : *Progress));
    355     return Status;
    356   }
    357 
    358   //
    359   // the "write" step in RMW
    360   //
    361   Status = FormStateToPlatformConfig (&MainFormState);
    362   if (EFI_ERROR (Status)) {
    363     *Progress = Configuration;
    364   }
    365   return Status;
    366 }
    367 
    368 
    369 STATIC
    370 EFI_STATUS
    371 EFIAPI
    372 Callback (
    373   IN     CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
    374   IN     EFI_BROWSER_ACTION                     Action,
    375   IN     EFI_QUESTION_ID                        QuestionId,
    376   IN     UINT8                                  Type,
    377   IN OUT EFI_IFR_TYPE_VALUE                     *Value,
    378   OUT    EFI_BROWSER_ACTION_REQUEST             *ActionRequest
    379   )
    380 {
    381   DEBUG ((EFI_D_VERBOSE, "%a: Action=0x%Lx QuestionId=%d Type=%d\n",
    382     __FUNCTION__, (UINT64) Action, QuestionId, Type));
    383 
    384   if (Action != EFI_BROWSER_ACTION_CHANGED) {
    385     return EFI_UNSUPPORTED;
    386   }
    387 
    388   switch (QuestionId) {
    389   case QUESTION_SAVE_EXIT:
    390     *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT;
    391     break;
    392 
    393   case QUESTION_DISCARD_EXIT:
    394     *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT;
    395     break;
    396 
    397   default:
    398     break;
    399   }
    400 
    401   return EFI_SUCCESS;
    402 }
    403 
    404 
    405 /**
    406   Query and save all resolutions supported by the GOP.
    407 
    408   @param[in]  Gop          The Graphics Output Protocol instance to query.
    409 
    410   @param[out] NumGopModes  The number of modes supported by the GOP. On output,
    411                            this parameter will be positive.
    412 
    413   @param[out] GopModes     On output, a dynamically allocated array containing
    414                            the resolutions returned by the GOP. The caller is
    415                            responsible for freeing the array after use.
    416 
    417   @retval EFI_UNSUPPORTED       No modes found.
    418   @retval EFI_OUT_OF_RESOURCES  Failed to allocate GopModes.
    419   @return                       Error codes from Gop->QueryMode().
    420 
    421 **/
    422 STATIC
    423 EFI_STATUS
    424 EFIAPI
    425 QueryGopModes (
    426   IN  EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop,
    427   OUT UINTN                        *NumGopModes,
    428   OUT GOP_MODE                     **GopModes
    429   )
    430 {
    431   EFI_STATUS Status;
    432   UINT32     ModeNumber;
    433 
    434   if (Gop->Mode->MaxMode == 0) {
    435     return EFI_UNSUPPORTED;
    436   }
    437   *NumGopModes = Gop->Mode->MaxMode;
    438 
    439   *GopModes = AllocatePool (Gop->Mode->MaxMode * sizeof **GopModes);
    440   if (*GopModes == NULL) {
    441     return EFI_OUT_OF_RESOURCES;
    442   }
    443 
    444   for (ModeNumber = 0; ModeNumber < Gop->Mode->MaxMode; ++ModeNumber) {
    445     EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
    446     UINTN                                SizeOfInfo;
    447 
    448     Status = Gop->QueryMode (Gop, ModeNumber, &SizeOfInfo, &Info);
    449     if (EFI_ERROR (Status)) {
    450       goto FreeGopModes;
    451     }
    452 
    453     (*GopModes)[ModeNumber].X = Info->HorizontalResolution;
    454     (*GopModes)[ModeNumber].Y = Info->VerticalResolution;
    455     FreePool (Info);
    456   }
    457 
    458   return EFI_SUCCESS;
    459 
    460 FreeGopModes:
    461   FreePool (*GopModes);
    462 
    463   return Status;
    464 }
    465 
    466 
    467 /**
    468   Create a set of "one-of-many" (ie. "drop down list") option IFR opcodes,
    469   based on available GOP resolutions, to be placed under a "one-of-many" (ie.
    470   "drop down list") opcode.
    471 
    472   @param[in]  PackageList   The package list with the formset and form for
    473                             which the drop down options are produced. Option
    474                             names are added as new strings to PackageList.
    475 
    476   @param[out] OpCodeBuffer  On output, a dynamically allocated opcode buffer
    477                             with drop down list options corresponding to GOP
    478                             resolutions. The caller is responsible for freeing
    479                             OpCodeBuffer with HiiFreeOpCodeHandle() after use.
    480 
    481   @param[in]  NumGopModes   Number of entries in GopModes.
    482 
    483   @param[in]  GopModes      Array of resolutions retrieved from the GOP.
    484 
    485   @retval EFI_SUCESS  Opcodes have been successfully produced.
    486 
    487   @return             Status codes from underlying functions. PackageList may
    488                       have been extended with new strings. OpCodeBuffer is
    489                       unchanged.
    490 **/
    491 STATIC
    492 EFI_STATUS
    493 EFIAPI
    494 CreateResolutionOptions (
    495   IN  EFI_HII_HANDLE  *PackageList,
    496   OUT VOID            **OpCodeBuffer,
    497   IN  UINTN           NumGopModes,
    498   IN  GOP_MODE        *GopModes
    499   )
    500 {
    501   EFI_STATUS Status;
    502   VOID       *OutputBuffer;
    503   UINTN      ModeNumber;
    504 
    505   OutputBuffer = HiiAllocateOpCodeHandle ();
    506   if (OutputBuffer == NULL) {
    507     return EFI_OUT_OF_RESOURCES;
    508   }
    509 
    510   for (ModeNumber = 0; ModeNumber < NumGopModes; ++ModeNumber) {
    511     CHAR16        Desc[MAXSIZE_RES_CUR];
    512     EFI_STRING_ID NewString;
    513     VOID          *OpCode;
    514 
    515     UnicodeSPrintAsciiFormat (Desc, sizeof Desc, "%Ldx%Ld",
    516       (INT64) GopModes[ModeNumber].X, (INT64) GopModes[ModeNumber].Y);
    517     NewString = HiiSetString (PackageList, 0 /* new string */, Desc,
    518                   NULL /* for all languages */);
    519     if (NewString == 0) {
    520       Status = EFI_OUT_OF_RESOURCES;
    521       goto FreeOutputBuffer;
    522     }
    523     OpCode = HiiCreateOneOfOptionOpCode (OutputBuffer, NewString,
    524                0 /* Flags */, EFI_IFR_NUMERIC_SIZE_4, ModeNumber);
    525     if (OpCode == NULL) {
    526       Status = EFI_OUT_OF_RESOURCES;
    527       goto FreeOutputBuffer;
    528     }
    529   }
    530 
    531   *OpCodeBuffer = OutputBuffer;
    532   return EFI_SUCCESS;
    533 
    534 FreeOutputBuffer:
    535   HiiFreeOpCodeHandle (OutputBuffer);
    536 
    537   return Status;
    538 }
    539 
    540 
    541 /**
    542   Populate the form identified by the (PackageList, FormSetGuid, FormId)
    543   triplet.
    544 
    545   The drop down list of video resolutions is generated from (NumGopModes,
    546   GopModes).
    547 
    548   @retval EFI_SUCESS  Form successfully updated.
    549   @return             Status codes from underlying functions.
    550 
    551 **/
    552 STATIC
    553 EFI_STATUS
    554 EFIAPI
    555 PopulateForm (
    556   IN  EFI_HII_HANDLE  *PackageList,
    557   IN  EFI_GUID        *FormSetGuid,
    558   IN  EFI_FORM_ID     FormId,
    559   IN  UINTN           NumGopModes,
    560   IN  GOP_MODE        *GopModes
    561   )
    562 {
    563   EFI_STATUS         Status;
    564   VOID               *OpCodeBuffer;
    565   VOID               *OpCode;
    566   EFI_IFR_GUID_LABEL *Anchor;
    567   VOID               *OpCodeBuffer2;
    568 
    569   OpCodeBuffer2 = NULL;
    570 
    571   //
    572   // 1. Allocate an empty opcode buffer.
    573   //
    574   OpCodeBuffer = HiiAllocateOpCodeHandle ();
    575   if (OpCodeBuffer == NULL) {
    576     return EFI_OUT_OF_RESOURCES;
    577   }
    578 
    579   //
    580   // 2. Create a label opcode (which is a Tiano extension) inside the buffer.
    581   // The label's number must match the "anchor" label in the form.
    582   //
    583   OpCode = HiiCreateGuidOpCode (OpCodeBuffer, &gEfiIfrTianoGuid,
    584              NULL /* optional copy origin */, sizeof *Anchor);
    585   if (OpCode == NULL) {
    586     Status = EFI_OUT_OF_RESOURCES;
    587     goto FreeOpCodeBuffer;
    588   }
    589   Anchor               = OpCode;
    590   Anchor->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
    591   Anchor->Number       = LABEL_RES_NEXT;
    592 
    593   //
    594   // 3. Create the opcodes inside the buffer that are to be inserted into the
    595   // form.
    596   //
    597   // 3.1. Get a list of resolutions.
    598   //
    599   Status = CreateResolutionOptions (PackageList, &OpCodeBuffer2,
    600              NumGopModes, GopModes);
    601   if (EFI_ERROR (Status)) {
    602     goto FreeOpCodeBuffer;
    603   }
    604 
    605   //
    606   // 3.2. Create a one-of-many question with the above options.
    607   //
    608   OpCode = HiiCreateOneOfOpCode (
    609              OpCodeBuffer,                        // create opcode inside this
    610                                                   //   opcode buffer,
    611              QUESTION_RES_NEXT,                   // ID of question,
    612              FORMSTATEID_MAIN_FORM,               // identifies form state
    613                                                   //   storage,
    614              (UINT16) OFFSET_OF (MAIN_FORM_STATE, // value of question stored
    615                         NextPreferredResolution), //   at this offset,
    616              STRING_TOKEN (STR_RES_NEXT),         // Prompt,
    617              STRING_TOKEN (STR_RES_NEXT_HELP),    // Help,
    618              0,                                   // QuestionFlags,
    619              EFI_IFR_NUMERIC_SIZE_4,              // see sizeof
    620                                                   //   NextPreferredResolution,
    621              OpCodeBuffer2,                       // buffer with possible
    622                                                   //   choices,
    623              NULL                                 // DEFAULT opcodes
    624              );
    625   if (OpCode == NULL) {
    626     Status = EFI_OUT_OF_RESOURCES;
    627     goto FreeOpCodeBuffer2;
    628   }
    629 
    630   //
    631   // 4. Update the form with the opcode buffer.
    632   //
    633   Status = HiiUpdateForm (PackageList, FormSetGuid, FormId,
    634              OpCodeBuffer, // buffer with head anchor, and new contents to be
    635                            // inserted at it
    636              NULL          // buffer with tail anchor, for deleting old
    637                            // contents up to it
    638              );
    639 
    640 FreeOpCodeBuffer2:
    641   HiiFreeOpCodeHandle (OpCodeBuffer2);
    642 
    643 FreeOpCodeBuffer:
    644   HiiFreeOpCodeHandle (OpCodeBuffer);
    645 
    646   return Status;
    647 }
    648 
    649 
    650 /**
    651   Load and execute the platform configuration.
    652 
    653   @retval EFI_SUCCESS            Configuration loaded and executed.
    654   @return                        Status codes from PlatformConfigLoad().
    655 **/
    656 STATIC
    657 EFI_STATUS
    658 EFIAPI
    659 ExecutePlatformConfig (
    660   VOID
    661   )
    662 {
    663   EFI_STATUS      Status;
    664   PLATFORM_CONFIG PlatformConfig;
    665   UINT64          OptionalElements;
    666 
    667   Status = PlatformConfigLoad (&PlatformConfig, &OptionalElements);
    668   if (EFI_ERROR (Status)) {
    669     DEBUG (((Status == EFI_NOT_FOUND) ? EFI_D_VERBOSE : EFI_D_ERROR,
    670       "%a: failed to load platform config: %r\n", __FUNCTION__, Status));
    671     return Status;
    672   }
    673 
    674   if (OptionalElements & PLATFORM_CONFIG_F_GRAPHICS_RESOLUTION) {
    675     //
    676     // Pass the preferred resolution to GraphicsConsoleDxe via dynamic PCDs.
    677     //
    678     PcdSet32 (PcdVideoHorizontalResolution,
    679       PlatformConfig.HorizontalResolution);
    680     PcdSet32 (PcdVideoVerticalResolution,
    681       PlatformConfig.VerticalResolution);
    682   }
    683 
    684   return EFI_SUCCESS;
    685 }
    686 
    687 
    688 /**
    689   Notification callback for GOP interface installation.
    690 
    691   @param[in] Event    Event whose notification function is being invoked.
    692 
    693   @param[in] Context  The pointer to the notification function's context, which
    694                       is implementation-dependent.
    695 **/
    696 STATIC
    697 VOID
    698 EFIAPI
    699 GopInstalled (
    700   IN EFI_EVENT Event,
    701   IN VOID      *Context
    702   )
    703 {
    704   EFI_STATUS                   Status;
    705   EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop;
    706 
    707   ASSERT (Event == mGopEvent);
    708 
    709   //
    710   // Check further GOPs.
    711   //
    712   for (;;) {
    713     mNumGopModes = 0;
    714     mGopModes = NULL;
    715 
    716     Status = gBS->LocateProtocol (&gEfiGraphicsOutputProtocolGuid, mGopTracker,
    717                     (VOID **) &Gop);
    718     if (EFI_ERROR (Status)) {
    719       return;
    720     }
    721 
    722     Status = QueryGopModes (Gop, &mNumGopModes, &mGopModes);
    723     if (EFI_ERROR (Status)) {
    724       continue;
    725     }
    726 
    727     Status = PopulateForm (mInstalledPackages, &gOvmfPlatformConfigGuid,
    728                FORMID_MAIN_FORM, mNumGopModes, mGopModes);
    729     if (EFI_ERROR (Status)) {
    730       FreePool (mGopModes);
    731       continue;
    732     }
    733 
    734     break;
    735   }
    736 
    737   //
    738   // Success -- so uninstall this callback. Closing the event removes all
    739   // pending notifications and all protocol registrations.
    740   //
    741   Status = gBS->CloseEvent (mGopEvent);
    742   ASSERT_EFI_ERROR (Status);
    743   mGopEvent = NULL;
    744   mGopTracker = NULL;
    745 }
    746 
    747 
    748 /**
    749   Entry point for this driver.
    750 
    751   @param[in] ImageHandle  Image handle of this driver.
    752   @param[in] SystemTable  Pointer to SystemTable.
    753 
    754   @retval EFI_SUCESS            Driver has loaded successfully.
    755   @retval EFI_OUT_OF_RESOURCES  Failed to install HII packages.
    756   @return                       Error codes from lower level functions.
    757 
    758 **/
    759 EFI_STATUS
    760 EFIAPI
    761 PlatformInit (
    762   IN  EFI_HANDLE        ImageHandle,
    763   IN  EFI_SYSTEM_TABLE  *SystemTable
    764   )
    765 {
    766   EFI_STATUS Status;
    767 
    768   ExecutePlatformConfig ();
    769 
    770   mConfigAccess.ExtractConfig = &ExtractConfig;
    771   mConfigAccess.RouteConfig   = &RouteConfig;
    772   mConfigAccess.Callback      = &Callback;
    773 
    774   //
    775   // Declare ourselves suitable for HII communication.
    776   //
    777   Status = gBS->InstallMultipleProtocolInterfaces (&ImageHandle,
    778                   &gEfiDevicePathProtocolGuid,      &mPkgDevicePath,
    779                   &gEfiHiiConfigAccessProtocolGuid, &mConfigAccess,
    780                   NULL);
    781   if (EFI_ERROR (Status)) {
    782     return Status;
    783   }
    784 
    785   //
    786   // Publish the HII package list to HII Database.
    787   //
    788   mInstalledPackages = HiiAddPackages (
    789                          &gEfiCallerIdGuid,  // PackageListGuid
    790                          ImageHandle,        // associated DeviceHandle
    791                          PlatformDxeStrings, // 1st package
    792                          PlatformFormsBin,   // 2nd package
    793                          NULL                // terminator
    794                          );
    795   if (mInstalledPackages == NULL) {
    796     Status = EFI_OUT_OF_RESOURCES;
    797     goto UninstallProtocols;
    798   }
    799 
    800   Status = gBS->CreateEvent (EVT_NOTIFY_SIGNAL, TPL_CALLBACK, &GopInstalled,
    801                   NULL /* Context */, &mGopEvent);
    802   if (EFI_ERROR (Status)) {
    803     goto RemovePackages;
    804   }
    805 
    806   Status = gBS->RegisterProtocolNotify (&gEfiGraphicsOutputProtocolGuid,
    807                   mGopEvent, &mGopTracker);
    808   if (EFI_ERROR (Status)) {
    809     goto CloseGopEvent;
    810   }
    811 
    812   //
    813   // Check already installed GOPs.
    814   //
    815   Status = gBS->SignalEvent (mGopEvent);
    816   ASSERT_EFI_ERROR (Status);
    817 
    818   return EFI_SUCCESS;
    819 
    820 CloseGopEvent:
    821   gBS->CloseEvent (mGopEvent);
    822 
    823 RemovePackages:
    824   HiiRemovePackages (mInstalledPackages);
    825 
    826 UninstallProtocols:
    827   gBS->UninstallMultipleProtocolInterfaces (ImageHandle,
    828          &gEfiDevicePathProtocolGuid,      &mPkgDevicePath,
    829          &gEfiHiiConfigAccessProtocolGuid, &mConfigAccess,
    830          NULL);
    831   return Status;
    832 }
    833 
    834 /**
    835   Unload the driver.
    836 
    837   @param[in]  ImageHandle  Handle that identifies the image to evict.
    838 
    839   @retval EFI_SUCCESS  The image has been unloaded.
    840 **/
    841 EFI_STATUS
    842 EFIAPI
    843 PlatformUnload (
    844   IN  EFI_HANDLE  ImageHandle
    845   )
    846 {
    847   if (mGopEvent == NULL) {
    848     //
    849     // The GOP callback ran successfully and unregistered itself. Release the
    850     // resources allocated there.
    851     //
    852     ASSERT (mGopModes != NULL);
    853     FreePool (mGopModes);
    854   } else {
    855     //
    856     // Otherwise we need to unregister the callback.
    857     //
    858     ASSERT (mGopModes == NULL);
    859     gBS->CloseEvent (mGopEvent);
    860   }
    861 
    862   //
    863   // Release resources allocated by the entry point.
    864   //
    865   HiiRemovePackages (mInstalledPackages);
    866   gBS->UninstallMultipleProtocolInterfaces (ImageHandle,
    867          &gEfiDevicePathProtocolGuid,      &mPkgDevicePath,
    868          &gEfiHiiConfigAccessProtocolGuid, &mConfigAccess,
    869          NULL);
    870   return EFI_SUCCESS;
    871 }
    872