]> git.proxmox.com Git - mirror_edk2.git/blob - UefiPayloadPkg/SmmControlRuntimeDxe/SmmControlRuntimeDxe.c
OvmfPkg: raise DXEFV size to 13 MB in the traditional platform FDFs
[mirror_edk2.git] / UefiPayloadPkg / SmmControlRuntimeDxe / SmmControlRuntimeDxe.c
1 /** @file
2 This module produces the SMM Control2 Protocol
3
4 Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include <PiDxe.h>
10 #include <Protocol/SmmControl2.h>
11 #include <Library/DebugLib.h>
12 #include <Library/UefiBootServicesTableLib.h>
13 #include <Library/IoLib.h>
14 #include <Library/HobLib.h>
15 #include <Library/UefiRuntimeLib.h>
16 #include <Library/BaseMemoryLib.h>
17 #include <Guid/SmmRegisterInfoGuid.h>
18
19 #define SMM_DATA_PORT 0xB3
20 #define SMM_CONTROL_PORT 0xB2
21
22 typedef struct {
23 UINT8 GblBitOffset;
24 UINT8 ApmBitOffset;
25 UINT32 Address;
26 } SMM_CONTROL2_REG;
27
28 SMM_CONTROL2_REG mSmiCtrlReg;
29
30 /**
31 Invokes SMI activation from either the preboot or runtime environment.
32
33 This function generates an SMI.
34
35 @param[in] This The EFI_SMM_CONTROL2_PROTOCOL instance.
36 @param[in,out] CommandPort The value written to the command port.
37 @param[in,out] DataPort The value written to the data port.
38 @param[in] Periodic Optional mechanism to engender a periodic stream.
39 @param[in] ActivationInterval Optional parameter to repeat at this period one
40 time or, if the Periodic Boolean is set, periodically.
41
42 @retval EFI_SUCCESS The SMI has been engendered.
43 @retval EFI_DEVICE_ERROR The timing is unsupported.
44 @retval EFI_INVALID_PARAMETER The activation period is unsupported.
45 @retval EFI_INVALID_PARAMETER The last periodic activation has not been cleared.
46 @retval EFI_NOT_STARTED The MM base service has not been initialized.
47 **/
48 EFI_STATUS
49 EFIAPI
50 Activate (
51 IN CONST EFI_SMM_CONTROL2_PROTOCOL *This,
52 IN OUT UINT8 *CommandPort OPTIONAL,
53 IN OUT UINT8 *DataPort OPTIONAL,
54 IN BOOLEAN Periodic OPTIONAL,
55 IN EFI_SMM_PERIOD ActivationInterval OPTIONAL
56 )
57 {
58 UINT32 SmiEn;
59 UINT32 SmiEnableBits;
60
61 if (Periodic) {
62 return EFI_INVALID_PARAMETER;
63 }
64
65 SmiEn = IoRead32 (mSmiCtrlReg.Address);
66 SmiEnableBits = (1 << mSmiCtrlReg.GblBitOffset) | (1 << mSmiCtrlReg.ApmBitOffset);
67 if ((SmiEn & SmiEnableBits) != SmiEnableBits) {
68 //
69 // Set the "global SMI enable" bit and APM bit
70 //
71 IoWrite32 (mSmiCtrlReg.Address, SmiEn | SmiEnableBits);
72 }
73
74 IoWrite8 (SMM_DATA_PORT, DataPort == NULL ? 0 : *DataPort);
75 IoWrite8 (SMM_CONTROL_PORT, CommandPort == NULL ? 0 : *CommandPort);
76 return EFI_SUCCESS;
77 }
78
79 /**
80 Clears an SMI.
81
82 @param This Pointer to an instance of EFI_SMM_CONTROL2_PROTOCOL
83 @param Periodic TRUE to indicate a periodical SMI
84
85 @return Return value from SmmClear ()
86
87 **/
88 EFI_STATUS
89 EFIAPI
90 Deactivate (
91 IN CONST EFI_SMM_CONTROL2_PROTOCOL *This,
92 IN BOOLEAN Periodic
93 )
94 {
95 if (Periodic) {
96 return EFI_INVALID_PARAMETER;
97 }
98
99 //
100 // Temporarily do nothing here
101 //
102 return EFI_SUCCESS;
103 }
104
105 ///
106 /// SMM COntrol2 Protocol instance
107 ///
108 EFI_SMM_CONTROL2_PROTOCOL mSmmControl2 = {
109 Activate,
110 Deactivate,
111 0
112 };
113
114 /**
115 Get specified SMI register based on given register ID
116
117 @param[in] SmmRegister SMI related register array from bootloader
118 @param[in] Id The register ID to get.
119
120 @retval NULL The register is not found or the format is not expected.
121 @return smi register
122
123 **/
124 PLD_GENERIC_REGISTER *
125 GetSmmCtrlRegById (
126 IN PLD_SMM_REGISTERS *SmmRegister,
127 IN UINT32 Id
128 )
129 {
130 UINT32 Index;
131 PLD_GENERIC_REGISTER *PldReg;
132
133 PldReg = NULL;
134 for (Index = 0; Index < SmmRegister->Count; Index++) {
135 if (SmmRegister->Registers[Index].Id == Id) {
136 PldReg = &SmmRegister->Registers[Index];
137 break;
138 }
139 }
140
141 if (PldReg == NULL) {
142 DEBUG ((DEBUG_INFO, "Register %d not found.\n", Id));
143 return NULL;
144 }
145
146 //
147 // Checking the register if it is expected.
148 //
149 if ((PldReg->Address.AccessSize != EFI_ACPI_3_0_DWORD) ||
150 (PldReg->Address.Address == 0) ||
151 (PldReg->Address.RegisterBitWidth != 1) ||
152 (PldReg->Address.AddressSpaceId != EFI_ACPI_3_0_SYSTEM_IO) ||
153 (PldReg->Value != 1))
154 {
155 DEBUG ((DEBUG_INFO, "Unexpected SMM register.\n"));
156 DEBUG ((DEBUG_INFO, "AddressSpaceId= 0x%x\n", PldReg->Address.AddressSpaceId));
157 DEBUG ((DEBUG_INFO, "RegBitWidth = 0x%x\n", PldReg->Address.RegisterBitWidth));
158 DEBUG ((DEBUG_INFO, "RegBitOffset = 0x%x\n", PldReg->Address.RegisterBitOffset));
159 DEBUG ((DEBUG_INFO, "AccessSize = 0x%x\n", PldReg->Address.AccessSize));
160 DEBUG ((DEBUG_INFO, "Address = 0x%lx\n", PldReg->Address.Address));
161 return NULL;
162 }
163
164 return PldReg;
165 }
166
167 /**
168 Fixup data pointers so that the services can be called in virtual mode.
169
170 @param[in] Event The event registered.
171 @param[in] Context Event context.
172
173 **/
174 VOID
175 EFIAPI
176 SmmControlVirtualAddressChangeEvent (
177 IN EFI_EVENT Event,
178 IN VOID *Context
179 )
180 {
181 EfiConvertPointer (0x0, (VOID **)&(mSmmControl2.Trigger));
182 EfiConvertPointer (0x0, (VOID **)&(mSmmControl2.Clear));
183 }
184
185 /**
186 This function installs EFI_SMM_CONTROL2_PROTOCOL.
187
188 @param ImageHandle Handle for the image of this driver
189 @param SystemTable Pointer to the EFI System Table
190
191 @retval EFI_UNSUPPORTED There's no Intel ICH on this platform
192 @return The status returned from InstallProtocolInterface().
193
194 **/
195 EFI_STATUS
196 EFIAPI
197 SmmControlEntryPoint (
198 IN EFI_HANDLE ImageHandle,
199 IN EFI_SYSTEM_TABLE *SystemTable
200 )
201 {
202 EFI_STATUS Status;
203 EFI_HOB_GUID_TYPE *GuidHob;
204 PLD_SMM_REGISTERS *SmmRegister;
205 PLD_GENERIC_REGISTER *SmiGblEnReg;
206 PLD_GENERIC_REGISTER *SmiApmEnReg;
207 EFI_EVENT Event;
208
209 GuidHob = GetFirstGuidHob (&gSmmRegisterInfoGuid);
210 if (GuidHob == NULL) {
211 return EFI_UNSUPPORTED;
212 }
213
214 SmmRegister = (PLD_SMM_REGISTERS *)(GET_GUID_HOB_DATA (GuidHob));
215 SmiGblEnReg = GetSmmCtrlRegById (SmmRegister, REGISTER_ID_SMI_GBL_EN);
216 if (SmiGblEnReg == NULL) {
217 DEBUG ((DEBUG_ERROR, "SMI global enable reg not found.\n"));
218 return EFI_NOT_FOUND;
219 }
220
221 mSmiCtrlReg.Address = (UINT32)SmiGblEnReg->Address.Address;
222 mSmiCtrlReg.GblBitOffset = SmiGblEnReg->Address.RegisterBitOffset;
223
224 SmiApmEnReg = GetSmmCtrlRegById (SmmRegister, REGISTER_ID_SMI_APM_EN);
225 if (SmiApmEnReg == NULL) {
226 DEBUG ((DEBUG_ERROR, "SMI APM enable reg not found.\n"));
227 return EFI_NOT_FOUND;
228 }
229
230 if (SmiApmEnReg->Address.Address != mSmiCtrlReg.Address) {
231 DEBUG ((DEBUG_ERROR, "SMI APM EN and SMI GBL EN are expected to have same register base\n"));
232 DEBUG ((DEBUG_ERROR, "APM:0x%x, GBL:0x%x\n", SmiApmEnReg->Address.Address, mSmiCtrlReg.Address));
233 return EFI_UNSUPPORTED;
234 }
235
236 mSmiCtrlReg.ApmBitOffset = SmiApmEnReg->Address.RegisterBitOffset;
237
238 //
239 // Install our protocol interfaces on the device's handle
240 //
241 Status = gBS->InstallMultipleProtocolInterfaces (
242 &ImageHandle,
243 &gEfiSmmControl2ProtocolGuid,
244 &mSmmControl2,
245 NULL
246 );
247 ASSERT_EFI_ERROR (Status);
248
249 Status = gBS->CreateEventEx (
250 EVT_NOTIFY_SIGNAL,
251 TPL_NOTIFY,
252 SmmControlVirtualAddressChangeEvent,
253 NULL,
254 &gEfiEventVirtualAddressChangeGuid,
255 &Event
256 );
257 return Status;
258 }