2 This driver effectuates OVMF's platform configuration settings and exposes
5 Copyright (C) 2014, Red Hat, Inc.
6 Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
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
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.
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>
33 #include "PlatformConfig.h"
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
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.
48 // Hence let's just stick with the tradition -- use a dedicated vendor device
49 // path, with the driver's FILE_GUID.
53 VENDOR_DEVICE_PATH VendorDevicePath
;
54 EFI_DEVICE_PATH_PROTOCOL End
;
58 STATIC PKG_DEVICE_PATH mPkgDevicePath
= {
64 (UINT8
) (sizeof (VENDOR_DEVICE_PATH
) ),
65 (UINT8
) (sizeof (VENDOR_DEVICE_PATH
) >> 8)
72 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
74 (UINT8
) (END_DEVICE_PATH_LENGTH
),
75 (UINT8
) (END_DEVICE_PATH_LENGTH
>> 8)
81 // The configuration interface between the HII engine (form display etc) and
84 STATIC EFI_HII_CONFIG_ACCESS_PROTOCOL mConfigAccess
;
87 // The handle representing our list of packages after installation.
89 STATIC EFI_HII_HANDLE mInstalledPackages
;
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.
95 // - The strings package receives its C identifier from the driver's BASE_NAME,
98 // - The forms package receives its C identifier from the VFR file's basename,
102 extern UINT8 PlatformDxeStrings
[];
103 extern UINT8 PlatformFormsBin
[];
106 // We want to be notified about GOP installations until we find one GOP
107 // interface that lets us populate the form.
109 STATIC EFI_EVENT mGopEvent
;
112 // The registration record underneath this pointer allows us to iterate through
113 // the GOP instances one by one.
115 STATIC VOID
*mGopTracker
;
118 // Cache the resolutions we get from the GOP.
125 STATIC UINTN mNumGopModes
;
126 STATIC GOP_MODE
*mGopModes
;
130 Load the persistent platform configuration and translate it to binary form
133 If the platform configuration is missing, then the function fills in a
136 @param[out] MainFormState Binary form/widget state after translation.
138 @retval EFI_SUCCESS Form/widget state ready.
139 @return Error codes from underlying functions.
144 PlatformConfigToFormState (
145 OUT MAIN_FORM_STATE
*MainFormState
149 PLATFORM_CONFIG PlatformConfig
;
150 UINT64 OptionalElements
;
153 ZeroMem (MainFormState
, sizeof *MainFormState
);
155 Status
= PlatformConfigLoad (&PlatformConfig
, &OptionalElements
);
158 if (OptionalElements
& PLATFORM_CONFIG_F_GRAPHICS_RESOLUTION
) {
160 // Format the preferred resolution as text.
162 UnicodeSPrintAsciiFormat (
163 (CHAR16
*) MainFormState
->CurrentPreferredResolution
,
164 sizeof MainFormState
->CurrentPreferredResolution
,
166 (INT64
) PlatformConfig
.HorizontalResolution
,
167 (INT64
) PlatformConfig
.VerticalResolution
);
170 // Try to locate it in the drop-down list too. This may not succeed, but
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
;
184 // fall through otherwise
188 UnicodeSPrintAsciiFormat (
189 (CHAR16
*) MainFormState
->CurrentPreferredResolution
,
190 sizeof MainFormState
->CurrentPreferredResolution
,
203 This function is called by the HII machinery when it fetches the form state.
205 See the precise documentation in the UEFI spec.
207 @param[in] This The Config Access Protocol instance.
209 @param[in] Request A <ConfigRequest> format UCS-2 string describing the
212 @param[out] Progress A pointer into Request on output, identifying the query
213 element where processing failed.
215 @param[out] Results A <MultiConfigAltResp> format UCS-2 string that has
216 all values filled in for the names in the Request
219 @retval EFI_SUCCESS Extraction of form state in <MultiConfigAltResp>
221 @return Status codes from underlying functions.
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
234 MAIN_FORM_STATE MainFormState
;
237 DEBUG ((EFI_D_VERBOSE
, "%a: Request=\"%s\"\n", __FUNCTION__
, Request
));
239 Status
= PlatformConfigToFormState (&MainFormState
);
240 if (EFI_ERROR (Status
)) {
246 // Answer the textual request keying off the binary form state.
248 Status
= gHiiConfigRouting
->BlockToConfig (gHiiConfigRouting
, Request
,
249 (VOID
*) &MainFormState
, sizeof MainFormState
,
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
));
255 DEBUG ((EFI_D_VERBOSE
, "%a: Results=\"%s\"\n", __FUNCTION__
, *Results
));
265 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL
*This
,
266 IN CONST EFI_STRING Configuration
,
267 OUT EFI_STRING
*Progress
270 DEBUG ((EFI_D_VERBOSE
, "%a: Configuration=\"%s\"\n", __FUNCTION__
,
280 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL
*This
,
281 IN EFI_BROWSER_ACTION Action
,
282 IN EFI_QUESTION_ID QuestionId
,
284 IN OUT EFI_IFR_TYPE_VALUE
*Value
,
285 OUT EFI_BROWSER_ACTION_REQUEST
*ActionRequest
288 DEBUG ((EFI_D_VERBOSE
, "%a: Action=0x%Lx QuestionId=%d Type=%d\n",
289 __FUNCTION__
, (UINT64
) Action
, QuestionId
, Type
));
291 if (Action
!= EFI_BROWSER_ACTION_CHANGED
) {
292 return EFI_UNSUPPORTED
;
295 switch (QuestionId
) {
296 case QUESTION_SAVE_EXIT
:
297 *ActionRequest
= EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT
;
300 case QUESTION_DISCARD_EXIT
:
301 *ActionRequest
= EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT
;
313 Query and save all resolutions supported by the GOP.
315 @param[in] Gop The Graphics Output Protocol instance to query.
317 @param[out] NumGopModes The number of modes supported by the GOP. On output,
318 this parameter will be positive.
320 @param[out] GopModes On output, a dynamically allocated array containing
321 the resolutions returned by the GOP. The caller is
322 responsible for freeing the array after use.
324 @retval EFI_UNSUPPORTED No modes found.
325 @retval EFI_OUT_OF_RESOURCES Failed to allocate GopModes.
326 @return Error codes from Gop->QueryMode().
333 IN EFI_GRAPHICS_OUTPUT_PROTOCOL
*Gop
,
334 OUT UINTN
*NumGopModes
,
335 OUT GOP_MODE
**GopModes
341 if (Gop
->Mode
->MaxMode
== 0) {
342 return EFI_UNSUPPORTED
;
344 *NumGopModes
= Gop
->Mode
->MaxMode
;
346 *GopModes
= AllocatePool (Gop
->Mode
->MaxMode
* sizeof **GopModes
);
347 if (*GopModes
== NULL
) {
348 return EFI_OUT_OF_RESOURCES
;
351 for (ModeNumber
= 0; ModeNumber
< Gop
->Mode
->MaxMode
; ++ModeNumber
) {
352 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION
*Info
;
355 Status
= Gop
->QueryMode (Gop
, ModeNumber
, &SizeOfInfo
, &Info
);
356 if (EFI_ERROR (Status
)) {
360 (*GopModes
)[ModeNumber
].X
= Info
->HorizontalResolution
;
361 (*GopModes
)[ModeNumber
].Y
= Info
->VerticalResolution
;
368 FreePool (*GopModes
);
375 Create a set of "one-of-many" (ie. "drop down list") option IFR opcodes,
376 based on available GOP resolutions, to be placed under a "one-of-many" (ie.
377 "drop down list") opcode.
379 @param[in] PackageList The package list with the formset and form for
380 which the drop down options are produced. Option
381 names are added as new strings to PackageList.
383 @param[out] OpCodeBuffer On output, a dynamically allocated opcode buffer
384 with drop down list options corresponding to GOP
385 resolutions. The caller is responsible for freeing
386 OpCodeBuffer with HiiFreeOpCodeHandle() after use.
388 @param[in] NumGopModes Number of entries in GopModes.
390 @param[in] GopModes Array of resolutions retrieved from the GOP.
392 @retval EFI_SUCESS Opcodes have been successfully produced.
394 @return Status codes from underlying functions. PackageList may
395 have been extended with new strings. OpCodeBuffer is
401 CreateResolutionOptions (
402 IN EFI_HII_HANDLE
*PackageList
,
403 OUT VOID
**OpCodeBuffer
,
404 IN UINTN NumGopModes
,
405 IN GOP_MODE
*GopModes
412 OutputBuffer
= HiiAllocateOpCodeHandle ();
413 if (OutputBuffer
== NULL
) {
414 return EFI_OUT_OF_RESOURCES
;
417 for (ModeNumber
= 0; ModeNumber
< NumGopModes
; ++ModeNumber
) {
418 CHAR16 Desc
[MAXSIZE_RES_CUR
];
419 EFI_STRING_ID NewString
;
422 UnicodeSPrintAsciiFormat (Desc
, sizeof Desc
, "%Ldx%Ld",
423 (INT64
) GopModes
[ModeNumber
].X
, (INT64
) GopModes
[ModeNumber
].Y
);
424 NewString
= HiiSetString (PackageList
, 0 /* new string */, Desc
,
425 NULL
/* for all languages */);
426 if (NewString
== 0) {
427 Status
= EFI_OUT_OF_RESOURCES
;
428 goto FreeOutputBuffer
;
430 OpCode
= HiiCreateOneOfOptionOpCode (OutputBuffer
, NewString
,
431 0 /* Flags */, EFI_IFR_NUMERIC_SIZE_4
, ModeNumber
);
432 if (OpCode
== NULL
) {
433 Status
= EFI_OUT_OF_RESOURCES
;
434 goto FreeOutputBuffer
;
438 *OpCodeBuffer
= OutputBuffer
;
442 HiiFreeOpCodeHandle (OutputBuffer
);
449 Populate the form identified by the (PackageList, FormSetGuid, FormId)
452 The drop down list of video resolutions is generated from (NumGopModes,
455 @retval EFI_SUCESS Form successfully updated.
456 @return Status codes from underlying functions.
463 IN EFI_HII_HANDLE
*PackageList
,
464 IN EFI_GUID
*FormSetGuid
,
465 IN EFI_FORM_ID FormId
,
466 IN UINTN NumGopModes
,
467 IN GOP_MODE
*GopModes
473 EFI_IFR_GUID_LABEL
*Anchor
;
476 OpCodeBuffer2
= NULL
;
479 // 1. Allocate an empty opcode buffer.
481 OpCodeBuffer
= HiiAllocateOpCodeHandle ();
482 if (OpCodeBuffer
== NULL
) {
483 return EFI_OUT_OF_RESOURCES
;
487 // 2. Create a label opcode (which is a Tiano extension) inside the buffer.
488 // The label's number must match the "anchor" label in the form.
490 OpCode
= HiiCreateGuidOpCode (OpCodeBuffer
, &gEfiIfrTianoGuid
,
491 NULL
/* optional copy origin */, sizeof *Anchor
);
492 if (OpCode
== NULL
) {
493 Status
= EFI_OUT_OF_RESOURCES
;
494 goto FreeOpCodeBuffer
;
497 Anchor
->ExtendOpCode
= EFI_IFR_EXTEND_OP_LABEL
;
498 Anchor
->Number
= LABEL_RES_NEXT
;
501 // 3. Create the opcodes inside the buffer that are to be inserted into the
504 // 3.1. Get a list of resolutions.
506 Status
= CreateResolutionOptions (PackageList
, &OpCodeBuffer2
,
507 NumGopModes
, GopModes
);
508 if (EFI_ERROR (Status
)) {
509 goto FreeOpCodeBuffer
;
513 // 3.2. Create a one-of-many question with the above options.
515 OpCode
= HiiCreateOneOfOpCode (
516 OpCodeBuffer
, // create opcode inside this
518 QUESTION_RES_NEXT
, // ID of question,
519 FORMSTATEID_MAIN_FORM
, // identifies form state
521 (UINT16
) OFFSET_OF (MAIN_FORM_STATE
, // value of question stored
522 NextPreferredResolution
), // at this offset,
523 STRING_TOKEN (STR_RES_NEXT
), // Prompt,
524 STRING_TOKEN (STR_RES_NEXT_HELP
), // Help,
526 EFI_IFR_NUMERIC_SIZE_4
, // see sizeof
527 // NextPreferredResolution,
528 OpCodeBuffer2
, // buffer with possible
530 NULL
// DEFAULT opcodes
532 if (OpCode
== NULL
) {
533 Status
= EFI_OUT_OF_RESOURCES
;
534 goto FreeOpCodeBuffer2
;
538 // 4. Update the form with the opcode buffer.
540 Status
= HiiUpdateForm (PackageList
, FormSetGuid
, FormId
,
541 OpCodeBuffer
, // buffer with head anchor, and new contents to be
543 NULL
// buffer with tail anchor, for deleting old
548 HiiFreeOpCodeHandle (OpCodeBuffer2
);
551 HiiFreeOpCodeHandle (OpCodeBuffer
);
558 Load and execute the platform configuration.
560 @retval EFI_SUCCESS Configuration loaded and executed.
561 @return Status codes from PlatformConfigLoad().
566 ExecutePlatformConfig (
571 PLATFORM_CONFIG PlatformConfig
;
572 UINT64 OptionalElements
;
574 Status
= PlatformConfigLoad (&PlatformConfig
, &OptionalElements
);
575 if (EFI_ERROR (Status
)) {
576 DEBUG (((Status
== EFI_NOT_FOUND
) ? EFI_D_VERBOSE
: EFI_D_ERROR
,
577 "%a: failed to load platform config: %r\n", __FUNCTION__
, Status
));
581 if (OptionalElements
& PLATFORM_CONFIG_F_GRAPHICS_RESOLUTION
) {
583 // Pass the preferred resolution to GraphicsConsoleDxe via dynamic PCDs.
585 PcdSet32 (PcdVideoHorizontalResolution
,
586 PlatformConfig
.HorizontalResolution
);
587 PcdSet32 (PcdVideoVerticalResolution
,
588 PlatformConfig
.VerticalResolution
);
596 Notification callback for GOP interface installation.
598 @param[in] Event Event whose notification function is being invoked.
600 @param[in] Context The pointer to the notification function's context, which
601 is implementation-dependent.
612 EFI_GRAPHICS_OUTPUT_PROTOCOL
*Gop
;
614 ASSERT (Event
== mGopEvent
);
617 // Check further GOPs.
623 Status
= gBS
->LocateProtocol (&gEfiGraphicsOutputProtocolGuid
, mGopTracker
,
625 if (EFI_ERROR (Status
)) {
629 Status
= QueryGopModes (Gop
, &mNumGopModes
, &mGopModes
);
630 if (EFI_ERROR (Status
)) {
634 Status
= PopulateForm (mInstalledPackages
, &gOvmfPlatformConfigGuid
,
635 FORMID_MAIN_FORM
, mNumGopModes
, mGopModes
);
636 if (EFI_ERROR (Status
)) {
637 FreePool (mGopModes
);
645 // Success -- so uninstall this callback. Closing the event removes all
646 // pending notifications and all protocol registrations.
648 Status
= gBS
->CloseEvent (mGopEvent
);
649 ASSERT_EFI_ERROR (Status
);
656 Entry point for this driver.
658 @param[in] ImageHandle Image handle of this driver.
659 @param[in] SystemTable Pointer to SystemTable.
661 @retval EFI_SUCESS Driver has loaded successfully.
662 @retval EFI_OUT_OF_RESOURCES Failed to install HII packages.
663 @return Error codes from lower level functions.
669 IN EFI_HANDLE ImageHandle
,
670 IN EFI_SYSTEM_TABLE
*SystemTable
675 ExecutePlatformConfig ();
677 mConfigAccess
.ExtractConfig
= &ExtractConfig
;
678 mConfigAccess
.RouteConfig
= &RouteConfig
;
679 mConfigAccess
.Callback
= &Callback
;
682 // Declare ourselves suitable for HII communication.
684 Status
= gBS
->InstallMultipleProtocolInterfaces (&ImageHandle
,
685 &gEfiDevicePathProtocolGuid
, &mPkgDevicePath
,
686 &gEfiHiiConfigAccessProtocolGuid
, &mConfigAccess
,
688 if (EFI_ERROR (Status
)) {
693 // Publish the HII package list to HII Database.
695 mInstalledPackages
= HiiAddPackages (
696 &gEfiCallerIdGuid
, // PackageListGuid
697 ImageHandle
, // associated DeviceHandle
698 PlatformDxeStrings
, // 1st package
699 PlatformFormsBin
, // 2nd package
702 if (mInstalledPackages
== NULL
) {
703 Status
= EFI_OUT_OF_RESOURCES
;
704 goto UninstallProtocols
;
707 Status
= gBS
->CreateEvent (EVT_NOTIFY_SIGNAL
, TPL_CALLBACK
, &GopInstalled
,
708 NULL
/* Context */, &mGopEvent
);
709 if (EFI_ERROR (Status
)) {
713 Status
= gBS
->RegisterProtocolNotify (&gEfiGraphicsOutputProtocolGuid
,
714 mGopEvent
, &mGopTracker
);
715 if (EFI_ERROR (Status
)) {
720 // Check already installed GOPs.
722 Status
= gBS
->SignalEvent (mGopEvent
);
723 ASSERT_EFI_ERROR (Status
);
728 gBS
->CloseEvent (mGopEvent
);
731 HiiRemovePackages (mInstalledPackages
);
734 gBS
->UninstallMultipleProtocolInterfaces (ImageHandle
,
735 &gEfiDevicePathProtocolGuid
, &mPkgDevicePath
,
736 &gEfiHiiConfigAccessProtocolGuid
, &mConfigAccess
,
744 @param[in] ImageHandle Handle that identifies the image to evict.
746 @retval EFI_SUCCESS The image has been unloaded.
751 IN EFI_HANDLE ImageHandle
754 if (mGopEvent
== NULL
) {
756 // The GOP callback ran successfully and unregistered itself. Release the
757 // resources allocated there.
759 ASSERT (mGopModes
!= NULL
);
760 FreePool (mGopModes
);
763 // Otherwise we need to unregister the callback.
765 ASSERT (mGopModes
== NULL
);
766 gBS
->CloseEvent (mGopEvent
);
770 // Release resources allocated by the entry point.
772 HiiRemovePackages (mInstalledPackages
);
773 gBS
->UninstallMultipleProtocolInterfaces (ImageHandle
,
774 &gEfiDevicePathProtocolGuid
, &mPkgDevicePath
,
775 &gEfiHiiConfigAccessProtocolGuid
, &mConfigAccess
,