From dbab994991c76dc4b9414a3d80997b64b0fdf9c5 Mon Sep 17 00:00:00 2001 From: Laszlo Ersek Date: Thu, 7 Jul 2016 15:02:11 +0200 Subject: [PATCH] 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 Cc: Jordan Justen Cc: Michael Kinney Fixes: https://github.com/tianocore/edk2/issues/97 Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Laszlo Ersek Reviewed-by: Jeff Fan Reviewed-by: Jordan Justen --- OvmfPkg/PlatformPei/FeatureControl.c | 134 +++++++++++++++++++++++++++ OvmfPkg/PlatformPei/Platform.c | 1 + OvmfPkg/PlatformPei/Platform.h | 5 + OvmfPkg/PlatformPei/PlatformPei.inf | 2 + 4 files changed, 142 insertions(+) create mode 100644 OvmfPkg/PlatformPei/FeatureControl.c diff --git a/OvmfPkg/PlatformPei/FeatureControl.c b/OvmfPkg/PlatformPei/FeatureControl.c new file mode 100644 index 0000000000..b91d9888a9 --- /dev/null +++ b/OvmfPkg/PlatformPei/FeatureControl.c @@ -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 +#include +#include +#include +#include + +#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)); + } +} diff --git a/OvmfPkg/PlatformPei/Platform.c b/OvmfPkg/PlatformPei/Platform.c index 75f7480ac7..ca1e6dc7e3 100644 --- a/OvmfPkg/PlatformPei/Platform.c +++ b/OvmfPkg/PlatformPei/Platform.c @@ -612,6 +612,7 @@ InitializePlatform ( } MiscInitialization (); + InstallFeatureControlCallback (); return EFI_SUCCESS; } diff --git a/OvmfPkg/PlatformPei/Platform.h b/OvmfPkg/PlatformPei/Platform.h index bb988ea19e..eda765be30 100644 --- a/OvmfPkg/PlatformPei/Platform.h +++ b/OvmfPkg/PlatformPei/Platform.h @@ -73,6 +73,11 @@ PeiFvInitialization ( VOID ); +VOID +InstallFeatureControlCallback ( + VOID + ); + EFI_STATUS InitializeXen ( VOID diff --git a/OvmfPkg/PlatformPei/PlatformPei.inf b/OvmfPkg/PlatformPei/PlatformPei.inf index 5d765baaeb..776a4ab11f 100644 --- a/OvmfPkg/PlatformPei/PlatformPei.inf +++ b/OvmfPkg/PlatformPei/PlatformPei.inf @@ -30,6 +30,7 @@ [Sources] Cmos.c + FeatureControl.c Fv.c MemDetect.c Platform.c @@ -104,6 +105,7 @@ [Ppis] gEfiPeiMasterBootModePpiGuid + gEfiPeiMpServicesPpiGuid [Depex] TRUE -- 2.39.2