diff mbox

[edk2,4/4] OvmfPkg/PlatformPei: program MSR_IA32_FEATURE_CONTROL from fw_cfg

Message ID 1467918647-14721-5-git-send-email-lersek@redhat.com
State Superseded
Headers show

Commit Message

Laszlo Ersek July 7, 2016, 7:10 p.m. UTC
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>

---
 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(+)

-- 
1.8.3.1

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Comments

Laszlo Ersek July 7, 2016, 7:31 p.m. UTC | #1
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 <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>

> ---

>  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
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
diff mbox

Patch

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;
+  }
+
+  //
+  // 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;
 }