]> git.proxmox.com Git - mirror_edk2.git/blobdiff - OvmfPkg/PlatformDxe/Platform.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / OvmfPkg / PlatformDxe / Platform.c
index a6172a8018761f9a8c97e73eadff9b110a50782a..e58e75eb220318556f5c4e7dd88ee268c6827730 100644 (file)
   them via HII.\r
 \r
   Copyright (C) 2014, Red Hat, Inc.\r
-  Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>\r
 \r
-  This program and the accompanying materials are licensed and made available\r
-  under the terms and conditions of the BSD License which accompanies this\r
-  distribution.  The full text of the license may be found at\r
-  http://opensource.org/licenses/bsd-license.php\r
-\r
-  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT\r
-  WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
 **/\r
 \r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
 #include <Library/DebugLib.h>\r
+#include <Library/DevicePathLib.h>\r
+#include <Library/HiiLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/PrintLib.h>\r
 #include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiHiiServicesLib.h>\r
+#include <Protocol/DevicePath.h>\r
+#include <Protocol/GraphicsOutput.h>\r
+#include <Protocol/HiiConfigAccess.h>\r
+#include <Guid/MdeModuleHii.h>\r
+#include <Guid/OvmfPlatformConfig.h>\r
 \r
+#include "Platform.h"\r
 #include "PlatformConfig.h"\r
 \r
+//\r
+// The HiiAddPackages() library function requires that any controller (or\r
+// image) handle, to be associated with the HII packages under installation, be\r
+// "decorated" with a device path. The tradition seems to be a vendor device\r
+// path.\r
+//\r
+// We'd like to associate our HII packages with the driver's image handle. The\r
+// first idea is to use the driver image's device path. Unfortunately, loaded\r
+// images only come with an EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL (not the\r
+// usual EFI_DEVICE_PATH_PROTOCOL), ie. a different GUID. In addition, even the\r
+// EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL interface may be NULL, if the image\r
+// has been loaded from an "unnamed" memory source buffer.\r
+//\r
+// Hence let's just stick with the tradition -- use a dedicated vendor device\r
+// path, with the driver's FILE_GUID.\r
+//\r
+#pragma pack(1)\r
+typedef struct {\r
+  VENDOR_DEVICE_PATH          VendorDevicePath;\r
+  EFI_DEVICE_PATH_PROTOCOL    End;\r
+} PKG_DEVICE_PATH;\r
+#pragma pack()\r
+\r
+STATIC PKG_DEVICE_PATH  mPkgDevicePath = {\r
+  {\r
+    {\r
+      HARDWARE_DEVICE_PATH,\r
+      HW_VENDOR_DP,\r
+      {\r
+        (UINT8)(sizeof (VENDOR_DEVICE_PATH)),\r
+        (UINT8)(sizeof (VENDOR_DEVICE_PATH) >> 8)\r
+      }\r
+    },\r
+    EFI_CALLER_ID_GUID\r
+  },\r
+  {\r
+    END_DEVICE_PATH_TYPE,\r
+    END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
+    {\r
+      (UINT8)(END_DEVICE_PATH_LENGTH),\r
+      (UINT8)(END_DEVICE_PATH_LENGTH >> 8)\r
+    }\r
+  }\r
+};\r
+\r
+//\r
+// The configuration interface between the HII engine (form display etc) and\r
+// this driver.\r
+//\r
+STATIC EFI_HII_CONFIG_ACCESS_PROTOCOL  mConfigAccess;\r
+\r
+//\r
+// The handle representing our list of packages after installation.\r
+//\r
+STATIC EFI_HII_HANDLE  mInstalledPackages;\r
+\r
+//\r
+// The arrays below constitute our HII package list. They are auto-generated by\r
+// the VFR compiler and linked into the driver image during the build.\r
+//\r
+// - The strings package receives its C identifier from the driver's BASE_NAME,\r
+//   plus "Strings".\r
+//\r
+// - The forms package receives its C identifier from the VFR file's basename,\r
+//   plus "Bin".\r
+//\r
+//\r
+extern UINT8  PlatformDxeStrings[];\r
+extern UINT8  PlatformFormsBin[];\r
+\r
+//\r
+// We want to be notified about GOP installations until we find one GOP\r
+// interface that lets us populate the form.\r
+//\r
+STATIC EFI_EVENT  mGopEvent;\r
+\r
+//\r
+// The registration record underneath this pointer allows us to iterate through\r
+// the GOP instances one by one.\r
+//\r
+STATIC VOID  *mGopTracker;\r
+\r
+//\r
+// The driver image handle, used to obtain the device path for <ConfigHdr>.\r
+//\r
+STATIC EFI_HANDLE  mImageHandle;\r
+\r
+//\r
+// Cache the resolutions we get from the GOP.\r
+//\r
+typedef struct {\r
+  UINT32    X;\r
+  UINT32    Y;\r
+} GOP_MODE;\r
+\r
+STATIC UINTN     mNumGopModes;\r
+STATIC GOP_MODE  *mGopModes;\r
+\r
+/**\r
+  Load the persistent platform configuration and translate it to binary form\r
+  state.\r
+\r
+  If the platform configuration is missing, then the function fills in a\r
+  default state.\r
+\r
+  @param[out] MainFormState  Binary form/widget state after translation.\r
+\r
+  @retval EFI_SUCCESS  Form/widget state ready.\r
+  @return              Error codes from underlying functions.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+PlatformConfigToFormState (\r
+  OUT MAIN_FORM_STATE  *MainFormState\r
+  )\r
+{\r
+  EFI_STATUS       Status;\r
+  PLATFORM_CONFIG  PlatformConfig;\r
+  UINT64           OptionalElements;\r
+  UINTN            ModeNumber;\r
+\r
+  ZeroMem (MainFormState, sizeof *MainFormState);\r
+\r
+  Status = PlatformConfigLoad (&PlatformConfig, &OptionalElements);\r
+  switch (Status) {\r
+    case EFI_SUCCESS:\r
+      if (OptionalElements & PLATFORM_CONFIG_F_GRAPHICS_RESOLUTION) {\r
+        //\r
+        // Format the preferred resolution as text.\r
+        //\r
+        UnicodeSPrintAsciiFormat (\r
+          (CHAR16 *)MainFormState->CurrentPreferredResolution,\r
+          sizeof MainFormState->CurrentPreferredResolution,\r
+          "%Ldx%Ld",\r
+          (INT64)PlatformConfig.HorizontalResolution,\r
+          (INT64)PlatformConfig.VerticalResolution\r
+          );\r
+\r
+        //\r
+        // Try to locate it in the drop-down list too. This may not succeed, but\r
+        // that's fine.\r
+        //\r
+        for (ModeNumber = 0; ModeNumber < mNumGopModes; ++ModeNumber) {\r
+          if ((mGopModes[ModeNumber].X == PlatformConfig.HorizontalResolution) &&\r
+              (mGopModes[ModeNumber].Y == PlatformConfig.VerticalResolution))\r
+          {\r
+            MainFormState->NextPreferredResolution = (UINT32)ModeNumber;\r
+            break;\r
+          }\r
+        }\r
+\r
+        break;\r
+      }\r
+\r
+    //\r
+    // fall through otherwise\r
+    //\r
+\r
+    case EFI_NOT_FOUND:\r
+      UnicodeSPrintAsciiFormat (\r
+        (CHAR16 *)MainFormState->CurrentPreferredResolution,\r
+        sizeof MainFormState->CurrentPreferredResolution,\r
+        "Unset"\r
+        );\r
+      break;\r
+\r
+    default:\r
+      return Status;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  This function is called by the HII machinery when it fetches the form state.\r
+\r
+  See the precise documentation in the UEFI spec.\r
+\r
+  @param[in]  This      The Config Access Protocol instance.\r
+\r
+  @param[in]  Request   A <ConfigRequest> format UCS-2 string describing the\r
+                        query.\r
+\r
+  @param[out] Progress  A pointer into Request on output, identifying the query\r
+                        element where processing failed.\r
+\r
+  @param[out] Results   A <MultiConfigAltResp> format UCS-2 string that has\r
+                        all values filled in for the names in the Request\r
+                        string.\r
+\r
+  @retval EFI_SUCCESS  Extraction of form state in <MultiConfigAltResp>\r
+                       encoding successful.\r
+  @return              Status codes from underlying functions.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+ExtractConfig (\r
+  IN CONST  EFI_HII_CONFIG_ACCESS_PROTOCOL  *This,\r
+  IN CONST  EFI_STRING                      Request,\r
+  OUT       EFI_STRING                      *Progress,\r
+  OUT       EFI_STRING                      *Results\r
+  )\r
+{\r
+  MAIN_FORM_STATE  MainFormState;\r
+  EFI_STATUS       Status;\r
+  EFI_STRING       ConfigRequestHdr;\r
+  EFI_STRING       ConfigRequest;\r
+  UINTN            Size;\r
+  BOOLEAN          AllocatedRequest;\r
+\r
+  DEBUG ((DEBUG_VERBOSE, "%a: Request=\"%s\"\n", __FUNCTION__, Request));\r
+\r
+  if ((Progress == NULL) || (Results == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  ConfigRequestHdr = NULL;\r
+  ConfigRequest    = NULL;\r
+  Size             = 0;\r
+  AllocatedRequest = FALSE;\r
+\r
+  //\r
+  // Check if <ConfigHdr> matches the GUID and name\r
+  //\r
+  *Progress = Request;\r
+  if ((Request != NULL) &&\r
+      !HiiIsConfigHdrMatch (\r
+         Request,\r
+         &gOvmfPlatformConfigGuid,\r
+         mHiiFormName\r
+         )\r
+      )\r
+  {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  Status = PlatformConfigToFormState (&MainFormState);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) {\r
+    //\r
+    // Request has no <RequestElement>, so construct full request string.\r
+    // Allocate and fill a buffer large enough to hold <ConfigHdr>\r
+    // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a\r
+    // null terminator.\r
+    //\r
+    ConfigRequestHdr = HiiConstructConfigHdr (\r
+                         &gOvmfPlatformConfigGuid,\r
+                         mVariableName,\r
+                         mImageHandle\r
+                         );\r
+    if (ConfigRequestHdr == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    Size             = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16);\r
+    ConfigRequest    = AllocateZeroPool (Size);\r
+    AllocatedRequest = TRUE;\r
+    if (ConfigRequest == NULL) {\r
+      FreePool (ConfigRequestHdr);\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    UnicodeSPrint (\r
+      ConfigRequest,\r
+      Size,\r
+      L"%s&OFFSET=0&WIDTH=%016LX",\r
+      ConfigRequestHdr,\r
+      sizeof MainFormState\r
+      );\r
+    FreePool (ConfigRequestHdr);\r
+  } else {\r
+    ConfigRequest = Request;\r
+  }\r
+\r
+  //\r
+  // Answer the textual request keying off the binary form state.\r
+  //\r
+  Status = gHiiConfigRouting->BlockToConfig (\r
+                                gHiiConfigRouting,\r
+                                ConfigRequest,\r
+                                (VOID *)&MainFormState,\r
+                                sizeof MainFormState,\r
+                                Results,\r
+                                Progress\r
+                                );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((\r
+      DEBUG_ERROR,\r
+      "%a: BlockToConfig(): %r, Progress=\"%s\"\n",\r
+      __FUNCTION__,\r
+      Status,\r
+      (Status == EFI_DEVICE_ERROR) ? NULL : *Progress\r
+      ));\r
+  } else {\r
+    DEBUG ((DEBUG_VERBOSE, "%a: Results=\"%s\"\n", __FUNCTION__, *Results));\r
+  }\r
+\r
+  //\r
+  // If we used a newly allocated ConfigRequest, update Progress to point to\r
+  // original Request instead of ConfigRequest.\r
+  //\r
+  if (Request == NULL) {\r
+    *Progress = NULL;\r
+  } else if (StrStr (Request, L"OFFSET") == NULL) {\r
+    if (EFI_ERROR (Status)) {\r
+      //\r
+      // Since we constructed ConfigRequest, failure can only occur if there\r
+      // is not enough memory. In this case, we point Progress to the first\r
+      // character of Request.\r
+      //\r
+      *Progress = Request;\r
+    } else {\r
+      //\r
+      // In case of success, we point Progress to the null terminator of\r
+      // Request.\r
+      //\r
+      *Progress = Request + StrLen (Request);\r
+    }\r
+  }\r
+\r
+  if (AllocatedRequest) {\r
+    FreePool (ConfigRequest);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Interpret the binary form state and save it as persistent platform\r
+  configuration.\r
+\r
+  @param[in] MainFormState  Binary form/widget state to verify and save.\r
+\r
+  @retval EFI_SUCCESS  Platform configuration saved.\r
+  @return              Error codes from underlying functions.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+FormStateToPlatformConfig (\r
+  IN CONST MAIN_FORM_STATE  *MainFormState\r
+  )\r
+{\r
+  EFI_STATUS       Status;\r
+  PLATFORM_CONFIG  PlatformConfig;\r
+  CONST GOP_MODE   *GopMode;\r
+\r
+  //\r
+  // There's nothing to do with the textual CurrentPreferredResolution field.\r
+  // We verify and translate the selection in the drop-down list.\r
+  //\r
+  if (MainFormState->NextPreferredResolution >= mNumGopModes) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  GopMode = mGopModes + MainFormState->NextPreferredResolution;\r
+\r
+  ZeroMem (&PlatformConfig, sizeof PlatformConfig);\r
+  PlatformConfig.HorizontalResolution = GopMode->X;\r
+  PlatformConfig.VerticalResolution   = GopMode->Y;\r
+\r
+  Status = PlatformConfigSave (&PlatformConfig);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  This function is called by the HII machinery when it wants the driver to\r
+  interpret and persist the form state.\r
+\r
+  See the precise documentation in the UEFI spec.\r
+\r
+  @param[in]  This           The Config Access Protocol instance.\r
+\r
+  @param[in]  Configuration  A <ConfigResp> format UCS-2 string describing the\r
+                             form state.\r
+\r
+  @param[out] Progress       A pointer into Configuration on output,\r
+                             identifying the element where processing failed.\r
+\r
+  @retval EFI_SUCCESS  Configuration verified, state permanent.\r
+\r
+  @return              Status codes from underlying functions.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+RouteConfig (\r
+  IN CONST  EFI_HII_CONFIG_ACCESS_PROTOCOL  *This,\r
+  IN CONST  EFI_STRING                      Configuration,\r
+  OUT       EFI_STRING                      *Progress\r
+  )\r
+{\r
+  MAIN_FORM_STATE  MainFormState;\r
+  UINTN            BlockSize;\r
+  EFI_STATUS       Status;\r
+\r
+  DEBUG ((\r
+    DEBUG_VERBOSE,\r
+    "%a: Configuration=\"%s\"\n",\r
+    __FUNCTION__,\r
+    Configuration\r
+    ));\r
+\r
+  if ((Progress == NULL) || (Configuration == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Check if <ConfigHdr> matches the GUID and name\r
+  //\r
+  *Progress = Configuration;\r
+  if ((Configuration != NULL) &&\r
+      !HiiIsConfigHdrMatch (\r
+         Configuration,\r
+         &gOvmfPlatformConfigGuid,\r
+         mHiiFormName\r
+         )\r
+      )\r
+  {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  //\r
+  // the "read" step in RMW\r
+  //\r
+  Status = PlatformConfigToFormState (&MainFormState);\r
+  if (EFI_ERROR (Status)) {\r
+    *Progress = Configuration;\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // the "modify" step in RMW\r
+  //\r
+  // (Update the binary form state. This update may be partial, which is why in\r
+  // general we must pre-load the form state from the platform config.)\r
+  //\r
+  BlockSize = sizeof MainFormState;\r
+  Status    = gHiiConfigRouting->ConfigToBlock (\r
+                                   gHiiConfigRouting,\r
+                                   Configuration,\r
+                                   (VOID *)&MainFormState,\r
+                                   &BlockSize,\r
+                                   Progress\r
+                                   );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((\r
+      DEBUG_ERROR,\r
+      "%a: ConfigToBlock(): %r, Progress=\"%s\"\n",\r
+      __FUNCTION__,\r
+      Status,\r
+      (Status == EFI_BUFFER_TOO_SMALL) ? NULL : *Progress\r
+      ));\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // the "write" step in RMW\r
+  //\r
+  Status = FormStateToPlatformConfig (&MainFormState);\r
+  if (EFI_ERROR (Status)) {\r
+    *Progress = Configuration;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+Callback (\r
+  IN     CONST EFI_HII_CONFIG_ACCESS_PROTOCOL  *This,\r
+  IN     EFI_BROWSER_ACTION                    Action,\r
+  IN     EFI_QUESTION_ID                       QuestionId,\r
+  IN     UINT8                                 Type,\r
+  IN OUT EFI_IFR_TYPE_VALUE                    *Value,\r
+  OUT    EFI_BROWSER_ACTION_REQUEST            *ActionRequest\r
+  )\r
+{\r
+  DEBUG ((\r
+    DEBUG_VERBOSE,\r
+    "%a: Action=0x%Lx QuestionId=%d Type=%d\n",\r
+    __FUNCTION__,\r
+    (UINT64)Action,\r
+    QuestionId,\r
+    Type\r
+    ));\r
+\r
+  if (Action != EFI_BROWSER_ACTION_CHANGED) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  switch (QuestionId) {\r
+    case QUESTION_SAVE_EXIT:\r
+      *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT;\r
+      break;\r
+\r
+    case QUESTION_DISCARD_EXIT:\r
+      *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT;\r
+      break;\r
+\r
+    default:\r
+      break;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Query and save all resolutions supported by the GOP.\r
+\r
+  @param[in]  Gop          The Graphics Output Protocol instance to query.\r
+\r
+  @param[out] NumGopModes  The number of modes supported by the GOP. On output,\r
+                           this parameter will be positive.\r
+\r
+  @param[out] GopModes     On output, a dynamically allocated array containing\r
+                           the resolutions returned by the GOP. The caller is\r
+                           responsible for freeing the array after use.\r
+\r
+  @retval EFI_UNSUPPORTED       No modes found.\r
+  @retval EFI_OUT_OF_RESOURCES  Failed to allocate GopModes.\r
+  @return                       Error codes from Gop->QueryMode().\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+QueryGopModes (\r
+  IN  EFI_GRAPHICS_OUTPUT_PROTOCOL  *Gop,\r
+  OUT UINTN                         *NumGopModes,\r
+  OUT GOP_MODE                      **GopModes\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINT32      ModeNumber;\r
+\r
+  if (Gop->Mode->MaxMode == 0) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  *NumGopModes = Gop->Mode->MaxMode;\r
+\r
+  *GopModes = AllocatePool (Gop->Mode->MaxMode * sizeof **GopModes);\r
+  if (*GopModes == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  for (ModeNumber = 0; ModeNumber < Gop->Mode->MaxMode; ++ModeNumber) {\r
+    EFI_GRAPHICS_OUTPUT_MODE_INFORMATION  *Info;\r
+    UINTN                                 SizeOfInfo;\r
+\r
+    Status = Gop->QueryMode (Gop, ModeNumber, &SizeOfInfo, &Info);\r
+    if (EFI_ERROR (Status)) {\r
+      goto FreeGopModes;\r
+    }\r
+\r
+    (*GopModes)[ModeNumber].X = Info->HorizontalResolution;\r
+    (*GopModes)[ModeNumber].Y = Info->VerticalResolution;\r
+    FreePool (Info);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+\r
+FreeGopModes:\r
+  FreePool (*GopModes);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Create a set of "one-of-many" (ie. "drop down list") option IFR opcodes,\r
+  based on available GOP resolutions, to be placed under a "one-of-many" (ie.\r
+  "drop down list") opcode.\r
+\r
+  @param[in]  PackageList   The package list with the formset and form for\r
+                            which the drop down options are produced. Option\r
+                            names are added as new strings to PackageList.\r
+\r
+  @param[out] OpCodeBuffer  On output, a dynamically allocated opcode buffer\r
+                            with drop down list options corresponding to GOP\r
+                            resolutions. The caller is responsible for freeing\r
+                            OpCodeBuffer with HiiFreeOpCodeHandle() after use.\r
+\r
+  @param[in]  NumGopModes   Number of entries in GopModes.\r
+\r
+  @param[in]  GopModes      Array of resolutions retrieved from the GOP.\r
+\r
+  @retval EFI_SUCESS  Opcodes have been successfully produced.\r
+\r
+  @return             Status codes from underlying functions. PackageList may\r
+                      have been extended with new strings. OpCodeBuffer is\r
+                      unchanged.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+CreateResolutionOptions (\r
+  IN  EFI_HII_HANDLE  PackageList,\r
+  OUT VOID            **OpCodeBuffer,\r
+  IN  UINTN           NumGopModes,\r
+  IN  GOP_MODE        *GopModes\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  VOID        *OutputBuffer;\r
+  UINTN       ModeNumber;\r
+\r
+  OutputBuffer = HiiAllocateOpCodeHandle ();\r
+  if (OutputBuffer == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  for (ModeNumber = 0; ModeNumber < NumGopModes; ++ModeNumber) {\r
+    CHAR16         Desc[MAXSIZE_RES_CUR];\r
+    EFI_STRING_ID  NewString;\r
+    VOID           *OpCode;\r
+\r
+    UnicodeSPrintAsciiFormat (\r
+      Desc,\r
+      sizeof Desc,\r
+      "%Ldx%Ld",\r
+      (INT64)GopModes[ModeNumber].X,\r
+      (INT64)GopModes[ModeNumber].Y\r
+      );\r
+    NewString = HiiSetString (\r
+                  PackageList,\r
+                  0 /* new string */,\r
+                  Desc,\r
+                  NULL /* for all languages */\r
+                  );\r
+    if (NewString == 0) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      goto FreeOutputBuffer;\r
+    }\r
+\r
+    OpCode = HiiCreateOneOfOptionOpCode (\r
+               OutputBuffer,\r
+               NewString,\r
+               0 /* Flags */,\r
+               EFI_IFR_NUMERIC_SIZE_4,\r
+               ModeNumber\r
+               );\r
+    if (OpCode == NULL) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      goto FreeOutputBuffer;\r
+    }\r
+  }\r
+\r
+  *OpCodeBuffer = OutputBuffer;\r
+  return EFI_SUCCESS;\r
+\r
+FreeOutputBuffer:\r
+  HiiFreeOpCodeHandle (OutputBuffer);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Populate the form identified by the (PackageList, FormSetGuid, FormId)\r
+  triplet.\r
+\r
+  The drop down list of video resolutions is generated from (NumGopModes,\r
+  GopModes).\r
+\r
+  @retval EFI_SUCESS  Form successfully updated.\r
+  @return             Status codes from underlying functions.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+PopulateForm (\r
+  IN  EFI_HII_HANDLE  PackageList,\r
+  IN  EFI_GUID        *FormSetGuid,\r
+  IN  EFI_FORM_ID     FormId,\r
+  IN  UINTN           NumGopModes,\r
+  IN  GOP_MODE        *GopModes\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  VOID                *OpCodeBuffer;\r
+  VOID                *OpCode;\r
+  EFI_IFR_GUID_LABEL  *Anchor;\r
+  VOID                *OpCodeBuffer2;\r
+\r
+  OpCodeBuffer2 = NULL;\r
+\r
+  //\r
+  // 1. Allocate an empty opcode buffer.\r
+  //\r
+  OpCodeBuffer = HiiAllocateOpCodeHandle ();\r
+  if (OpCodeBuffer == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  //\r
+  // 2. Create a label opcode (which is a Tiano extension) inside the buffer.\r
+  // The label's number must match the "anchor" label in the form.\r
+  //\r
+  OpCode = HiiCreateGuidOpCode (\r
+             OpCodeBuffer,\r
+             &gEfiIfrTianoGuid,\r
+             NULL /* optional copy origin */,\r
+             sizeof *Anchor\r
+             );\r
+  if (OpCode == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto FreeOpCodeBuffer;\r
+  }\r
+\r
+  Anchor               = OpCode;\r
+  Anchor->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;\r
+  Anchor->Number       = LABEL_RES_NEXT;\r
+\r
+  //\r
+  // 3. Create the opcodes inside the buffer that are to be inserted into the\r
+  // form.\r
+  //\r
+  // 3.1. Get a list of resolutions.\r
+  //\r
+  Status = CreateResolutionOptions (\r
+             PackageList,\r
+             &OpCodeBuffer2,\r
+             NumGopModes,\r
+             GopModes\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    goto FreeOpCodeBuffer;\r
+  }\r
+\r
+  //\r
+  // 3.2. Create a one-of-many question with the above options.\r
+  //\r
+  OpCode = HiiCreateOneOfOpCode (\r
+             OpCodeBuffer,                        // create opcode inside this\r
+                                                  //   opcode buffer,\r
+             QUESTION_RES_NEXT,                   // ID of question,\r
+             FORMSTATEID_MAIN_FORM,               // identifies form state\r
+                                                  //   storage,\r
+             (UINT16)OFFSET_OF (\r
+                       MAIN_FORM_STATE,           // value of question stored\r
+                       NextPreferredResolution\r
+                       ),                         //   at this offset,\r
+             STRING_TOKEN (STR_RES_NEXT),         // Prompt,\r
+             STRING_TOKEN (STR_RES_NEXT_HELP),    // Help,\r
+             0,                                   // QuestionFlags,\r
+             EFI_IFR_NUMERIC_SIZE_4,              // see sizeof\r
+                                                  //   NextPreferredResolution,\r
+             OpCodeBuffer2,                       // buffer with possible\r
+                                                  //   choices,\r
+             NULL                                 // DEFAULT opcodes\r
+             );\r
+  if (OpCode == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto FreeOpCodeBuffer2;\r
+  }\r
+\r
+  //\r
+  // 4. Update the form with the opcode buffer.\r
+  //\r
+  Status = HiiUpdateForm (\r
+             PackageList,\r
+             FormSetGuid,\r
+             FormId,\r
+             OpCodeBuffer, // buffer with head anchor, and new contents to be\r
+                           // inserted at it\r
+             NULL          // buffer with tail anchor, for deleting old\r
+                           // contents up to it\r
+             );\r
+\r
+FreeOpCodeBuffer2:\r
+  HiiFreeOpCodeHandle (OpCodeBuffer2);\r
+\r
+FreeOpCodeBuffer:\r
+  HiiFreeOpCodeHandle (OpCodeBuffer);\r
+\r
+  return Status;\r
+}\r
+\r
 /**\r
   Load and execute the platform configuration.\r
 \r
@@ -32,14 +825,19 @@ ExecutePlatformConfig (
   VOID\r
   )\r
 {\r
-  EFI_STATUS      Status;\r
-  PLATFORM_CONFIG PlatformConfig;\r
-  UINT64          OptionalElements;\r
+  EFI_STATUS       Status;\r
+  PLATFORM_CONFIG  PlatformConfig;\r
+  UINT64           OptionalElements;\r
+  RETURN_STATUS    PcdStatus;\r
 \r
   Status = PlatformConfigLoad (&PlatformConfig, &OptionalElements);\r
   if (EFI_ERROR (Status)) {\r
-    DEBUG (((Status == EFI_NOT_FOUND) ? EFI_D_VERBOSE : EFI_D_ERROR,\r
-      "%a: failed to load platform config: %r\n", __FUNCTION__, Status));\r
+    DEBUG ((\r
+      (Status == EFI_NOT_FOUND) ? DEBUG_VERBOSE : DEBUG_ERROR,\r
+      "%a: failed to load platform config: %r\n",\r
+      __FUNCTION__,\r
+      Status\r
+      ));\r
     return Status;\r
   }\r
 \r
@@ -47,15 +845,91 @@ ExecutePlatformConfig (
     //\r
     // Pass the preferred resolution to GraphicsConsoleDxe via dynamic PCDs.\r
     //\r
-    PcdSet32 (PcdVideoHorizontalResolution,\r
-      PlatformConfig.HorizontalResolution);\r
-    PcdSet32 (PcdVideoVerticalResolution,\r
-      PlatformConfig.VerticalResolution);\r
+    PcdStatus = PcdSet32S (\r
+                  PcdVideoHorizontalResolution,\r
+                  PlatformConfig.HorizontalResolution\r
+                  );\r
+    ASSERT_RETURN_ERROR (PcdStatus);\r
+\r
+    PcdStatus = PcdSet32S (\r
+                  PcdVideoVerticalResolution,\r
+                  PlatformConfig.VerticalResolution\r
+                  );\r
+    ASSERT_RETURN_ERROR (PcdStatus);\r
+\r
+    PcdStatus = PcdSet8S (PcdVideoResolutionSource, 1);\r
+    ASSERT_RETURN_ERROR (PcdStatus);\r
   }\r
 \r
   return EFI_SUCCESS;\r
 }\r
 \r
+/**\r
+  Notification callback for GOP interface installation.\r
+\r
+  @param[in] Event    Event whose notification function is being invoked.\r
+\r
+  @param[in] Context  The pointer to the notification function's context, which\r
+                      is implementation-dependent.\r
+**/\r
+STATIC\r
+VOID\r
+EFIAPI\r
+GopInstalled (\r
+  IN EFI_EVENT  Event,\r
+  IN VOID       *Context\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  EFI_GRAPHICS_OUTPUT_PROTOCOL  *Gop;\r
+\r
+  ASSERT (Event == mGopEvent);\r
+\r
+  //\r
+  // Check further GOPs.\r
+  //\r
+  for ( ; ;) {\r
+    mNumGopModes = 0;\r
+    mGopModes    = NULL;\r
+\r
+    Status = gBS->LocateProtocol (\r
+                    &gEfiGraphicsOutputProtocolGuid,\r
+                    mGopTracker,\r
+                    (VOID **)&Gop\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      return;\r
+    }\r
+\r
+    Status = QueryGopModes (Gop, &mNumGopModes, &mGopModes);\r
+    if (EFI_ERROR (Status)) {\r
+      continue;\r
+    }\r
+\r
+    Status = PopulateForm (\r
+               mInstalledPackages,\r
+               &gOvmfPlatformConfigGuid,\r
+               FORMID_MAIN_FORM,\r
+               mNumGopModes,\r
+               mGopModes\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      FreePool (mGopModes);\r
+      continue;\r
+    }\r
+\r
+    break;\r
+  }\r
+\r
+  //\r
+  // Success -- so uninstall this callback. Closing the event removes all\r
+  // pending notifications and all protocol registrations.\r
+  //\r
+  Status = gBS->CloseEvent (mGopEvent);\r
+  ASSERT_EFI_ERROR (Status);\r
+  mGopEvent   = NULL;\r
+  mGopTracker = NULL;\r
+}\r
 \r
 /**\r
   Entry point for this driver.\r
@@ -64,6 +938,8 @@ ExecutePlatformConfig (
   @param[in] SystemTable  Pointer to SystemTable.\r
 \r
   @retval EFI_SUCESS            Driver has loaded successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  Failed to install HII packages.\r
+  @return                       Error codes from lower level functions.\r
 \r
 **/\r
 EFI_STATUS\r
@@ -73,8 +949,93 @@ PlatformInit (
   IN  EFI_SYSTEM_TABLE  *SystemTable\r
   )\r
 {\r
+  EFI_STATUS  Status;\r
+\r
   ExecutePlatformConfig ();\r
+\r
+  mConfigAccess.ExtractConfig = &ExtractConfig;\r
+  mConfigAccess.RouteConfig   = &RouteConfig;\r
+  mConfigAccess.Callback      = &Callback;\r
+\r
+  //\r
+  // Declare ourselves suitable for HII communication.\r
+  //\r
+  Status = gBS->InstallMultipleProtocolInterfaces (\r
+                  &ImageHandle,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  &mPkgDevicePath,\r
+                  &gEfiHiiConfigAccessProtocolGuid,\r
+                  &mConfigAccess,\r
+                  NULL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Save the driver image handle.\r
+  //\r
+  mImageHandle = ImageHandle;\r
+\r
+  //\r
+  // Publish the HII package list to HII Database.\r
+  //\r
+  mInstalledPackages = HiiAddPackages (\r
+                         &gEfiCallerIdGuid,  // PackageListGuid\r
+                         ImageHandle,        // associated DeviceHandle\r
+                         PlatformDxeStrings, // 1st package\r
+                         PlatformFormsBin,   // 2nd package\r
+                         NULL                // terminator\r
+                         );\r
+  if (mInstalledPackages == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto UninstallProtocols;\r
+  }\r
+\r
+  Status = gBS->CreateEvent (\r
+                  EVT_NOTIFY_SIGNAL,\r
+                  TPL_CALLBACK,\r
+                  &GopInstalled,\r
+                  NULL /* Context */,\r
+                  &mGopEvent\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto RemovePackages;\r
+  }\r
+\r
+  Status = gBS->RegisterProtocolNotify (\r
+                  &gEfiGraphicsOutputProtocolGuid,\r
+                  mGopEvent,\r
+                  &mGopTracker\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto CloseGopEvent;\r
+  }\r
+\r
+  //\r
+  // Check already installed GOPs.\r
+  //\r
+  Status = gBS->SignalEvent (mGopEvent);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
   return EFI_SUCCESS;\r
+\r
+CloseGopEvent:\r
+  gBS->CloseEvent (mGopEvent);\r
+\r
+RemovePackages:\r
+  HiiRemovePackages (mInstalledPackages);\r
+\r
+UninstallProtocols:\r
+  gBS->UninstallMultipleProtocolInterfaces (\r
+         ImageHandle,\r
+         &gEfiDevicePathProtocolGuid,\r
+         &mPkgDevicePath,\r
+         &gEfiHiiConfigAccessProtocolGuid,\r
+         &mConfigAccess,\r
+         NULL\r
+         );\r
+  return Status;\r
 }\r
 \r
 /**\r
@@ -90,5 +1051,32 @@ PlatformUnload (
   IN  EFI_HANDLE  ImageHandle\r
   )\r
 {\r
+  if (mGopEvent == NULL) {\r
+    //\r
+    // The GOP callback ran successfully and unregistered itself. Release the\r
+    // resources allocated there.\r
+    //\r
+    ASSERT (mGopModes != NULL);\r
+    FreePool (mGopModes);\r
+  } else {\r
+    //\r
+    // Otherwise we need to unregister the callback.\r
+    //\r
+    ASSERT (mGopModes == NULL);\r
+    gBS->CloseEvent (mGopEvent);\r
+  }\r
+\r
+  //\r
+  // Release resources allocated by the entry point.\r
+  //\r
+  HiiRemovePackages (mInstalledPackages);\r
+  gBS->UninstallMultipleProtocolInterfaces (\r
+         ImageHandle,\r
+         &gEfiDevicePathProtocolGuid,\r
+         &mPkgDevicePath,\r
+         &gEfiHiiConfigAccessProtocolGuid,\r
+         &mConfigAccess,\r
+         NULL\r
+         );\r
   return EFI_SUCCESS;\r
 }\r