1 /**@file
2 Install a callback when necessary for setting the Feature Control MSR on all
3 processors.
4
5 Copyright (C) 2016, Red Hat, Inc.
6
7 This program and the accompanying materials are licensed and made available
8 under the terms and conditions of the BSD License which accompanies this
9 distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
13 WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14 **/
15
16 #include <Library/DebugLib.h>
17 #include <Library/PeiServicesLib.h>
18 #include <Library/QemuFwCfgLib.h>
19 #include <Ppi/MpServices.h>
20 #include <Register/Msr/Core2Msr.h>
21
22 #include "Platform.h"
23
24 //
25 // The value to be written to the Feature Control MSR, retrieved from fw_cfg.
26 //
27 STATIC UINT64 mFeatureControlValue;
28
29 /**
30 Write the Feature Control MSR on an Application Processor or the Boot
31 Processor.
32
33 All APs execute this function in parallel. The BSP executes the function
34 separately.
35
36 @param[in,out] WorkSpace Pointer to the input/output argument workspace
37 shared by all processors.
38 **/
39 STATIC
40 VOID
41 EFIAPI
WriteFeatureControl(IN OUT VOID * WorkSpace)42 WriteFeatureControl (
43 IN OUT VOID *WorkSpace
44 )
45 {
46 AsmWriteMsr64 (MSR_CORE2_FEATURE_CONTROL, mFeatureControlValue);
47 }
48
49 /**
50 Notification function called when EFI_PEI_MP_SERVICES_PPI becomes available.
51
52 @param[in] PeiServices Indirect reference to the PEI Services Table.
53 @param[in] NotifyDescriptor Address of the notification descriptor data
54 structure.
55 @param[in] Ppi Address of the PPI that was installed.
56
57 @return Status of the notification. The status code returned from this
58 function is ignored.
59 **/
60 STATIC
61 EFI_STATUS
62 EFIAPI
OnMpServicesAvailable(IN EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_NOTIFY_DESCRIPTOR * NotifyDescriptor,IN VOID * Ppi)63 OnMpServicesAvailable (
64 IN EFI_PEI_SERVICES **PeiServices,
65 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
66 IN VOID *Ppi
67 )
68 {
69 EFI_PEI_MP_SERVICES_PPI *MpServices;
70 EFI_STATUS Status;
71
72 DEBUG ((EFI_D_VERBOSE, "%a: %a\n", gEfiCallerBaseName, __FUNCTION__));
73
74 //
75 // Write the MSR on all the APs in parallel.
76 //
77 MpServices = Ppi;
78 Status = MpServices->StartupAllAPs (
79 (CONST EFI_PEI_SERVICES **)PeiServices,
80 MpServices,
81 WriteFeatureControl, // Procedure
82 FALSE, // SingleThread
83 0, // TimeoutInMicroSeconds: inf.
84 NULL // ProcedureArgument
85 );
86 if (EFI_ERROR (Status) && Status != EFI_NOT_STARTED) {
87 DEBUG ((EFI_D_ERROR, "%a: StartupAllAps(): %r\n", __FUNCTION__, Status));
88 return Status;
89 }
90
91 //
92 // Now write the MSR on the BSP too.
93 //
94 WriteFeatureControl (NULL);
95 return EFI_SUCCESS;
96 }
97
98 //
99 // Notification object for registering the callback, for when
100 // EFI_PEI_MP_SERVICES_PPI becomes available.
101 //
102 STATIC CONST EFI_PEI_NOTIFY_DESCRIPTOR mMpServicesNotify = {
103 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | // Flags
104 EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
105 &gEfiPeiMpServicesPpiGuid, // Guid
106 OnMpServicesAvailable // Notify
107 };
108
109 VOID
InstallFeatureControlCallback(VOID)110 InstallFeatureControlCallback (
111 VOID
112 )
113 {
114 EFI_STATUS Status;
115 FIRMWARE_CONFIG_ITEM FwCfgItem;
116 UINTN FwCfgSize;
117
118 Status = QemuFwCfgFindFile ("etc/msr_feature_control", &FwCfgItem,
119 &FwCfgSize);
120 if (EFI_ERROR (Status) || FwCfgSize != sizeof mFeatureControlValue) {
121 //
122 // Nothing to do.
123 //
124 return;
125 }
126 QemuFwCfgSelectItem (FwCfgItem);
127 QemuFwCfgReadBytes (sizeof mFeatureControlValue, &mFeatureControlValue);
128
129 Status = PeiServicesNotifyPpi (&mMpServicesNotify);
130 if (EFI_ERROR (Status)) {
131 DEBUG ((EFI_D_ERROR, "%a: failed to set up MP Services callback: %r\n",
132 __FUNCTION__, Status));
133 }
134 }
135