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   RETURN_STATUS   PcdStatus;
    667 
    668   Status = PlatformConfigLoad (&PlatformConfig, &OptionalElements);
    669   if (EFI_ERROR (Status)) {
    670     DEBUG (((Status == EFI_NOT_FOUND) ? EFI_D_VERBOSE : EFI_D_ERROR,
    671       "%a: failed to load platform config: %r\n", __FUNCTION__, Status));
    672     return Status;
    673   }
    674 
    675   if (OptionalElements & PLATFORM_CONFIG_F_GRAPHICS_RESOLUTION) {
    676     //
    677     // Pass the preferred resolution to GraphicsConsoleDxe via dynamic PCDs.
    678     //
    679     PcdStatus = PcdSet32S (PcdVideoHorizontalResolution,
    680       PlatformConfig.HorizontalResolution);
    681     ASSERT_RETURN_ERROR (PcdStatus);
    682 
    683     PcdStatus = PcdSet32S (PcdVideoVerticalResolution,
    684       PlatformConfig.VerticalResolution);
    685     ASSERT_RETURN_ERROR (PcdStatus);
    686   }
    687 
    688   return EFI_SUCCESS;
    689 }
    690 
    691 
    692 /**
    693   Notification callback for GOP interface installation.
    694 
    695   @param[in] Event    Event whose notification function is being invoked.
    696 
    697   @param[in] Context  The pointer to the notification function's context, which
    698                       is implementation-dependent.
    699 **/
    700 STATIC
    701 VOID
    702 EFIAPI
    703 GopInstalled (
    704   IN EFI_EVENT Event,
    705   IN VOID      *Context
    706   )
    707 {
    708   EFI_STATUS                   Status;
    709   EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop;
    710 
    711   ASSERT (Event == mGopEvent);
    712 
    713   //
    714   // Check further GOPs.
    715   //
    716   for (;;) {
    717     mNumGopModes = 0;
    718     mGopModes = NULL;
    719 
    720     Status = gBS->LocateProtocol (&gEfiGraphicsOutputProtocolGuid, mGopTracker,
    721                     (VOID **) &Gop);
    722     if (EFI_ERROR (Status)) {
    723       return;
    724     }
    725 
    726     Status = QueryGopModes (Gop, &mNumGopModes, &mGopModes);
    727     if (EFI_ERROR (Status)) {
    728       continue;
    729     }
    730 
    731     Status = PopulateForm (mInstalledPackages, &gOvmfPlatformConfigGuid,
    732                FORMID_MAIN_FORM, mNumGopModes, mGopModes);
    733     if (EFI_ERROR (Status)) {
    734       FreePool (mGopModes);
    735       continue;
    736     }
    737 
    738     break;
    739   }
    740 
    741   //
    742   // Success -- so uninstall this callback. Closing the event removes all
    743   // pending notifications and all protocol registrations.
    744   //
    745   Status = gBS->CloseEvent (mGopEvent);
    746   ASSERT_EFI_ERROR (Status);
    747   mGopEvent = NULL;
    748   mGopTracker = NULL;
    749 }
    750 
    751 
    752 /**
    753   Entry point for this driver.
    754 
    755   @param[in] ImageHandle  Image handle of this driver.
    756   @param[in] SystemTable  Pointer to SystemTable.
    757 
    758   @retval EFI_SUCESS            Driver has loaded successfully.
    759   @retval EFI_OUT_OF_RESOURCES  Failed to install HII packages.
    760   @return                       Error codes from lower level functions.
    761 
    762 **/
    763 EFI_STATUS
    764 EFIAPI
    765 PlatformInit (
    766   IN  EFI_HANDLE        ImageHandle,
    767   IN  EFI_SYSTEM_TABLE  *SystemTable
    768   )
    769 {
    770   EFI_STATUS Status;
    771 
    772   ExecutePlatformConfig ();
    773 
    774   mConfigAccess.ExtractConfig = &ExtractConfig;
    775   mConfigAccess.RouteConfig   = &RouteConfig;
    776   mConfigAccess.Callback      = &Callback;
    777 
    778   //
    779   // Declare ourselves suitable for HII communication.
    780   //
    781   Status = gBS->InstallMultipleProtocolInterfaces (&ImageHandle,
    782                   &gEfiDevicePathProtocolGuid,      &mPkgDevicePath,
    783                   &gEfiHiiConfigAccessProtocolGuid, &mConfigAccess,
    784                   NULL);
    785   if (EFI_ERROR (Status)) {
    786     return Status;
    787   }
    788 
    789   //
    790   // Publish the HII package list to HII Database.
    791   //
    792   mInstalledPackages = HiiAddPackages (
    793                          &gEfiCallerIdGuid,  // PackageListGuid
    794                          ImageHandle,        // associated DeviceHandle
    795                          PlatformDxeStrings, // 1st package
    796                          PlatformFormsBin,   // 2nd package
    797                          NULL                // terminator
    798                          );
    799   if (mInstalledPackages == NULL) {
    800     Status = EFI_OUT_OF_RESOURCES;
    801     goto UninstallProtocols;
    802   }
    803 
    804   Status = gBS->CreateEvent (EVT_NOTIFY_SIGNAL, TPL_CALLBACK, &GopInstalled,
    805                   NULL /* Context */, &mGopEvent);
    806   if (EFI_ERROR (Status)) {
    807     goto RemovePackages;
    808   }
    809 
    810   Status = gBS->RegisterProtocolNotify (&gEfiGraphicsOutputProtocolGuid,
    811                   mGopEvent, &mGopTracker);
    812   if (EFI_ERROR (Status)) {
    813     goto CloseGopEvent;
    814   }
    815 
    816   //
    817   // Check already installed GOPs.
    818   //
    819   Status = gBS->SignalEvent (mGopEvent);
    820   ASSERT_EFI_ERROR (Status);
    821 
    822   return EFI_SUCCESS;
    823 
    824 CloseGopEvent:
    825   gBS->CloseEvent (mGopEvent);
    826 
    827 RemovePackages:
    828   HiiRemovePackages (mInstalledPackages);
    829 
    830 UninstallProtocols:
    831   gBS->UninstallMultipleProtocolInterfaces (ImageHandle,
    832          &gEfiDevicePathProtocolGuid,      &mPkgDevicePath,
    833          &gEfiHiiConfigAccessProtocolGuid, &mConfigAccess,
    834          NULL);
    835   return Status;
    836 }
    837 
    838 /**
    839   Unload the driver.
    840 
    841   @param[in]  ImageHandle  Handle that identifies the image to evict.
    842 
    843   @retval EFI_SUCCESS  The image has been unloaded.
    844 **/
    845 EFI_STATUS
    846 EFIAPI
    847 PlatformUnload (
    848   IN  EFI_HANDLE  ImageHandle
    849   )
    850 {
    851   if (mGopEvent == NULL) {
    852     //
    853     // The GOP callback ran successfully and unregistered itself. Release the
    854     // resources allocated there.
    855     //
    856     ASSERT (mGopModes != NULL);
    857     FreePool (mGopModes);
    858   } else {
    859     //
    860     // Otherwise we need to unregister the callback.
    861     //
    862     ASSERT (mGopModes == NULL);
    863     gBS->CloseEvent (mGopEvent);
    864   }
    865 
    866   //
    867   // Release resources allocated by the entry point.
    868   //
    869   HiiRemovePackages (mInstalledPackages);
    870   gBS->UninstallMultipleProtocolInterfaces (ImageHandle,
    871          &gEfiDevicePathProtocolGuid,      &mPkgDevicePath,
    872          &gEfiHiiConfigAccessProtocolGuid, &mConfigAccess,
    873          NULL);
    874   return EFI_SUCCESS;
    875 }
    876