mirror of
https://github.com/acidanthera/audk.git
synced 2025-04-07 19:45:07 +02:00
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:
parent
f0e6a56a9a
commit
dbab994991
OvmfPkg/PlatformPei
134
OvmfPkg/PlatformPei/FeatureControl.c
Normal file
134
OvmfPkg/PlatformPei/FeatureControl.c
Normal file
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user