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