OvmfPkg/PlatformPei: program MSR_IA32_FEATURE_CONTROL from fw_cfg

Under certain circumstances, QEMU exposes the "etc/msr_feature_control"
fw_cfg file, with a 64-bit little endian value. The firmware is supposed
to write this value to MSR_IA32_FEATURE_CONTROL (0x3a), on all processors,
on the normal and the S3 resume boot paths.

Utilize EFI_PEI_MPSERVICES_PPI to implement this feature.

Cc: Jeff Fan <jeff.fan@intel.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Michael Kinney <michael.d.kinney@intel.com>
Fixes: https://github.com/tianocore/edk2/issues/97
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: Jeff Fan <jeff.fan@intel.com>
Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
This commit is contained in:
Laszlo Ersek 2016-07-07 15:02:11 +02:00
parent f0e6a56a9a
commit dbab994991
4 changed files with 142 additions and 0 deletions

@ -0,0 +1,134 @@
/**@file
Install a callback when necessary for setting the Feature Control MSR on all
processors.
Copyright (C) 2016, Red Hat, Inc.
This program and the accompanying materials are licensed and made available
under the terms and conditions of the BSD License which accompanies this
distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include <Library/DebugLib.h>
#include <Library/PeiServicesLib.h>
#include <Library/QemuFwCfgLib.h>
#include <Ppi/MpServices.h>
#include <Register/Msr/Core2Msr.h>
#include "Platform.h"
//
// The value to be written to the Feature Control MSR, retrieved from fw_cfg.
//
STATIC UINT64 mFeatureControlValue;
/**
Write the Feature Control MSR on an Application Processor or the Boot
Processor.
All APs execute this function in parallel. The BSP executes the function
separately.
@param[in,out] WorkSpace Pointer to the input/output argument workspace
shared by all processors.
**/
STATIC
VOID
EFIAPI
WriteFeatureControl (
IN OUT VOID *WorkSpace
)
{
AsmWriteMsr64 (MSR_CORE2_FEATURE_CONTROL, mFeatureControlValue);
}
/**
Notification function called when EFI_PEI_MP_SERVICES_PPI becomes available.
@param[in] PeiServices Indirect reference to the PEI Services Table.
@param[in] NotifyDescriptor Address of the notification descriptor data
structure.
@param[in] Ppi Address of the PPI that was installed.
@return Status of the notification. The status code returned from this
function is ignored.
**/
STATIC
EFI_STATUS
EFIAPI
OnMpServicesAvailable (
IN EFI_PEI_SERVICES **PeiServices,
IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
IN VOID *Ppi
)
{
EFI_PEI_MP_SERVICES_PPI *MpServices;
EFI_STATUS Status;
DEBUG ((EFI_D_VERBOSE, "%a: %a\n", gEfiCallerBaseName, __FUNCTION__));
//
// Write the MSR on all the APs in parallel.
//
MpServices = Ppi;
Status = MpServices->StartupAllAPs (
(CONST EFI_PEI_SERVICES **)PeiServices,
MpServices,
WriteFeatureControl, // Procedure
FALSE, // SingleThread
0, // TimeoutInMicroSeconds: inf.
NULL // ProcedureArgument
);
if (EFI_ERROR (Status) && Status != EFI_NOT_STARTED) {
DEBUG ((EFI_D_ERROR, "%a: StartupAllAps(): %r\n", __FUNCTION__, Status));
return Status;
}
//
// Now write the MSR on the BSP too.
//
WriteFeatureControl (NULL);
return EFI_SUCCESS;
}
//
// Notification object for registering the callback, for when
// EFI_PEI_MP_SERVICES_PPI becomes available.
//
STATIC CONST EFI_PEI_NOTIFY_DESCRIPTOR mMpServicesNotify = {
EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | // Flags
EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
&gEfiPeiMpServicesPpiGuid, // Guid
OnMpServicesAvailable // Notify
};
VOID
InstallFeatureControlCallback (
VOID
)
{
EFI_STATUS Status;
FIRMWARE_CONFIG_ITEM FwCfgItem;
UINTN FwCfgSize;
Status = QemuFwCfgFindFile ("etc/msr_feature_control", &FwCfgItem,
&FwCfgSize);
if (EFI_ERROR (Status) || FwCfgSize != sizeof mFeatureControlValue) {
//
// Nothing to do.
//
return;
}
QemuFwCfgSelectItem (FwCfgItem);
QemuFwCfgReadBytes (sizeof mFeatureControlValue, &mFeatureControlValue);
Status = PeiServicesNotifyPpi (&mMpServicesNotify);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "%a: failed to set up MP Services callback: %r\n",
__FUNCTION__, Status));
}
}

@ -612,6 +612,7 @@ InitializePlatform (
}
MiscInitialization ();
InstallFeatureControlCallback ();
return EFI_SUCCESS;
}

@ -73,6 +73,11 @@ PeiFvInitialization (
VOID
);
VOID
InstallFeatureControlCallback (
VOID
);
EFI_STATUS
InitializeXen (
VOID

@ -30,6 +30,7 @@
[Sources]
Cmos.c
FeatureControl.c
Fv.c
MemDetect.c
Platform.c
@ -104,6 +105,7 @@
[Ppis]
gEfiPeiMasterBootModePpiGuid
gEfiPeiMpServicesPpiGuid
[Depex]
TRUE