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
+ @retval EFI_SUCCESS Configuration loaded and executed.\r
+ @return Status codes from PlatformConfigLoad().\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+ExecutePlatformConfig (\r
+ VOID\r
+ )\r
+{\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) ? DEBUG_VERBOSE : DEBUG_ERROR,\r
+ "%a: failed to load platform config: %r\n", __FUNCTION__, Status));\r
+ return Status;\r
+ }\r
+\r
+ if (OptionalElements & PLATFORM_CONFIG_F_GRAPHICS_RESOLUTION) {\r
+ //\r
+ // Pass the preferred resolution to GraphicsConsoleDxe via dynamic PCDs.\r
+ //\r
+ PcdStatus = PcdSet32S (PcdVideoHorizontalResolution,\r
+ PlatformConfig.HorizontalResolution);\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
@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
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
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