On 07/07/16 21:10, Laszlo Ersek wrote:
> 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 <[email protected]>
> Cc: Jordan Justen <[email protected]>
> Cc: Michael Kinney <[email protected]>
> Fixes: https://github.com/tianocore/edk2/issues/97
> Contributed-under: TianoCore Contribution Agreement 1.0
> Signed-off-by: Laszlo Ersek <[email protected]>
> ---
>  OvmfPkg/PlatformPei/PlatformPei.inf  |   2 +
>  OvmfPkg/PlatformPei/Platform.h       |   5 +
>  OvmfPkg/PlatformPei/FeatureControl.c | 134 ++++++++++++++++++++
>  OvmfPkg/PlatformPei/Platform.c       |   1 +
>  4 files changed, 142 insertions(+)
> 
> diff --git a/OvmfPkg/PlatformPei/PlatformPei.inf 
> b/OvmfPkg/PlatformPei/PlatformPei.inf
> index 3556404017fc..8abffde04773 100644
> --- a/OvmfPkg/PlatformPei/PlatformPei.inf
> +++ b/OvmfPkg/PlatformPei/PlatformPei.inf
> @@ -30,6 +30,7 @@ [Defines]
>  
>  [Sources]
>    Cmos.c
> +  FeatureControl.c
>    Fv.c
>    MemDetect.c
>    Platform.c
> @@ -104,6 +105,7 @@ [FeaturePcd]
>  
>  [Ppis]
>    gEfiPeiMasterBootModePpiGuid
> +  gEfiPeiMpServicesPpiGuid
>  
>  [Depex]
>    TRUE
> diff --git a/OvmfPkg/PlatformPei/Platform.h b/OvmfPkg/PlatformPei/Platform.h
> index bb988ea19e7d..eda765be30de 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/FeatureControl.c 
> b/OvmfPkg/PlatformPei/FeatureControl.c
> new file mode 100644
> index 000000000000..508001b2bacf
> --- /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 <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)) {
> +    DEBUG ((EFI_D_ERROR, "%a: StartupAllAps(): %r\n", __FUNCTION__, Status));
> +    return Status;
> +  }

Argh, I always forget that StartupAllAPs() returns EFI_NOT_STARTED in
uniprocessor systems. I'll update this error check to

  EFI_ERROR (Status) && Status != EFI_NOT_STARTED

for version 2 (or before pushing the series, if Jordan deems the series
good enough otherwise).

Thanks & sorry
Laszlo

> +
> +  //
> +  // 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 75f7480ac726..ca1e6dc7e320 100644
> --- a/OvmfPkg/PlatformPei/Platform.c
> +++ b/OvmfPkg/PlatformPei/Platform.c
> @@ -612,6 +612,7 @@ InitializePlatform (
>    }
>  
>    MiscInitialization ();
> +  InstallFeatureControlCallback ();
>  
>    return EFI_SUCCESS;
>  }
> 

_______________________________________________
edk2-devel mailing list
[email protected]
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to