]> git.proxmox.com Git - mirror_edk2.git/blobdiff - OvmfPkg/PlatformDxe/Platform.c
UefiCpuPkg/MpInitLib: Remove Executable attribute from MpLib.h
[mirror_edk2.git] / OvmfPkg / PlatformDxe / Platform.c
index a6172a8018761f9a8c97e73eadff9b110a50782a..f2e51960ce8b7c1d00fe76764598e1f55fd5cea8 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
+// 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
+/**\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
+      // 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
+          MainFormState->NextPreferredResolution = (UINT32) ModeNumber;\r
+          break;\r
+        }\r
+      }\r
+\r
+      break;\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
+    break;\r
+\r
+  default:\r
+    return Status;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\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
+\r
+  DEBUG ((DEBUG_VERBOSE, "%a: Request=\"%s\"\n", __FUNCTION__, Request));\r
+\r
+  Status = PlatformConfigToFormState (&MainFormState);\r
+  if (EFI_ERROR (Status)) {\r
+    *Progress = Request;\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Answer the textual request keying off the binary form state.\r
+  //\r
+  Status = gHiiConfigRouting->BlockToConfig (gHiiConfigRouting, Request,\r
+                                (VOID *) &MainFormState, sizeof MainFormState,\r
+                                Results, Progress);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR, "%a: BlockToConfig(): %r, Progress=\"%s\"\n",\r
+      __FUNCTION__, Status, (Status == EFI_DEVICE_ERROR) ? NULL : *Progress));\r
+  } else {\r
+    DEBUG ((DEBUG_VERBOSE, "%a: Results=\"%s\"\n", __FUNCTION__, *Results));\r
+  }\r
+  return Status;\r
+}\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
+  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
+/**\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 ((DEBUG_VERBOSE, "%a: Configuration=\"%s\"\n", __FUNCTION__,\r
+    Configuration));\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 (gHiiConfigRouting, Configuration,\r
+                                (VOID *) &MainFormState, &BlockSize, Progress);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR, "%a: ConfigToBlock(): %r, Progress=\"%s\"\n",\r
+      __FUNCTION__, Status,\r
+      (Status == EFI_BUFFER_TOO_SMALL) ? NULL : *Progress));\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
+  return Status;\r
+}\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 ((DEBUG_VERBOSE, "%a: Action=0x%Lx QuestionId=%d Type=%d\n",\r
+    __FUNCTION__, (UINT64) Action, QuestionId, Type));\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
+/**\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
+  *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
+/**\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 (Desc, sizeof Desc, "%Ldx%Ld",\r
+      (INT64) GopModes[ModeNumber].X, (INT64) GopModes[ModeNumber].Y);\r
+    NewString = HiiSetString (PackageList, 0 /* new string */, Desc,\r
+                  NULL /* for all languages */);\r
+    if (NewString == 0) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      goto FreeOutputBuffer;\r
+    }\r
+    OpCode = HiiCreateOneOfOptionOpCode (OutputBuffer, NewString,\r
+               0 /* Flags */, EFI_IFR_NUMERIC_SIZE_4, ModeNumber);\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
+/**\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 (OpCodeBuffer, &gEfiIfrTianoGuid,\r
+             NULL /* optional copy origin */, sizeof *Anchor);\r
+  if (OpCode == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto FreeOpCodeBuffer;\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 (PackageList, &OpCodeBuffer2,\r
+             NumGopModes, GopModes);\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 (MAIN_FORM_STATE, // value of question stored\r
+                        NextPreferredResolution), //   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 (PackageList, FormSetGuid, 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
 /**\r
   Load and execute the platform configuration.\r
 \r
@@ -35,10 +657,11 @@ ExecutePlatformConfig (
   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
+    DEBUG (((Status == EFI_NOT_FOUND) ? DEBUG_VERBOSE : DEBUG_ERROR,\r
       "%a: failed to load platform config: %r\n", __FUNCTION__, Status));\r
     return Status;\r
   }\r
@@ -47,16 +670,79 @@ ExecutePlatformConfig (
     //\r
     // Pass the preferred resolution to GraphicsConsoleDxe via dynamic PCDs.\r
     //\r
-    PcdSet32 (PcdVideoHorizontalResolution,\r
+    PcdStatus = PcdSet32S (PcdVideoHorizontalResolution,\r
       PlatformConfig.HorizontalResolution);\r
-    PcdSet32 (PcdVideoVerticalResolution,\r
+    ASSERT_RETURN_ERROR (PcdStatus);\r
+\r
+    PcdStatus = PcdSet32S (PcdVideoVerticalResolution,\r
       PlatformConfig.VerticalResolution);\r
+    ASSERT_RETURN_ERROR (PcdStatus);\r
   }\r
 \r
   return EFI_SUCCESS;\r
 }\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 (&gEfiGraphicsOutputProtocolGuid, mGopTracker,\r
+                    (VOID **) &Gop);\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 (mInstalledPackages, &gOvmfPlatformConfigGuid,\r
+               FORMID_MAIN_FORM, mNumGopModes, mGopModes);\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
 /**\r
   Entry point for this driver.\r
 \r
@@ -64,6 +750,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 +761,72 @@ 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 (&ImageHandle,\r
+                  &gEfiDevicePathProtocolGuid,      &mPkgDevicePath,\r
+                  &gEfiHiiConfigAccessProtocolGuid, &mConfigAccess,\r
+                  NULL);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\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 (EVT_NOTIFY_SIGNAL, TPL_CALLBACK, &GopInstalled,\r
+                  NULL /* Context */, &mGopEvent);\r
+  if (EFI_ERROR (Status)) {\r
+    goto RemovePackages;\r
+  }\r
+\r
+  Status = gBS->RegisterProtocolNotify (&gEfiGraphicsOutputProtocolGuid,\r
+                  mGopEvent, &mGopTracker);\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 (ImageHandle,\r
+         &gEfiDevicePathProtocolGuid,      &mPkgDevicePath,\r
+         &gEfiHiiConfigAccessProtocolGuid, &mConfigAccess,\r
+         NULL);\r
+  return Status;\r
 }\r
 \r
 /**\r
@@ -90,5 +842,28 @@ 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 (ImageHandle,\r
+         &gEfiDevicePathProtocolGuid,      &mPkgDevicePath,\r
+         &gEfiHiiConfigAccessProtocolGuid, &mConfigAccess,\r
+         NULL);\r
   return EFI_SUCCESS;\r
 }\r