]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.c
UefiCpuPkg: Clean up source files
[mirror_edk2.git] / UefiCpuPkg / CpuIo2Smm / CpuIo2Smm.c
CommitLineData
173eeac9 1/** @file\r
2 Produces the SMM CPU I/O Protocol.\r
3\r
7367cc6c
LG
4Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>\r
5This program and the accompanying materials\r
6are licensed and made available under the terms and conditions of the BSD License\r
7which accompanies this distribution. The full text of the license may be found at\r
8http://opensource.org/licenses/bsd-license.php\r
9\r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
173eeac9 12\r
13**/\r
14\r
430fbbe0 15#include "CpuIo2Smm.h"\r
173eeac9 16\r
17//\r
18// Handle for the SMM CPU I/O Protocol\r
19//\r
20EFI_HANDLE mHandle = NULL;\r
21\r
22//\r
23// SMM CPU I/O Protocol instance\r
24//\r
25EFI_SMM_CPU_IO2_PROTOCOL mSmmCpuIo2 = {\r
26 {\r
27 CpuMemoryServiceRead,\r
28 CpuMemoryServiceWrite\r
29 },\r
30 {\r
31 CpuIoServiceRead,\r
32 CpuIoServiceWrite\r
33 }\r
34};\r
35\r
36//\r
37// Lookup table for increment values based on transfer widths\r
38//\r
39UINT8 mStride[] = {\r
40 1, // SMM_IO_UINT8\r
41 2, // SMM_IO_UINT16\r
42 4, // SMM_IO_UINT32\r
43 8 // SMM_IO_UINT64\r
44};\r
45\r
46/**\r
47 Check parameters to a SMM CPU I/O Protocol service request.\r
48\r
bc230a23 49 @param[in] MmioOperation TRUE for an MMIO operation, FALSE for I/O Port operation.\r
50 @param[in] Width Signifies the width of the I/O operations.\r
7367cc6c
LG
51 @param[in] Address The base address of the I/O operations. The caller is\r
52 responsible for aligning the Address if required.\r
bc230a23 53 @param[in] Count The number of I/O operations to perform.\r
7367cc6c
LG
54 @param[in] Buffer For read operations, the destination buffer to store\r
55 the results. For write operations, the source buffer\r
bc230a23 56 from which to write data.\r
57\r
58 @retval EFI_SUCCESS The data was read from or written to the device.\r
59 @retval EFI_UNSUPPORTED The Address is not valid for this system.\r
60 @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.\r
7367cc6c 61\r
173eeac9 62**/\r
63EFI_STATUS\r
64CpuIoCheckParameter (\r
65 IN BOOLEAN MmioOperation,\r
66 IN EFI_SMM_IO_WIDTH Width,\r
67 IN UINT64 Address,\r
68 IN UINTN Count,\r
69 IN VOID *Buffer\r
70 )\r
71{\r
72 UINT64 MaxCount;\r
73 UINT64 Limit;\r
74\r
75 //\r
76 // Check to see if Buffer is NULL\r
77 //\r
78 if (Buffer == NULL) {\r
79 return EFI_INVALID_PARAMETER;\r
80 }\r
81\r
82 //\r
83 // Check to see if Width is in the valid range\r
84 //\r
3d78c020 85 if ((UINT32)Width > SMM_IO_UINT64) {\r
173eeac9 86 return EFI_INVALID_PARAMETER;\r
87 }\r
88\r
89 //\r
90 // Check to see if Width is in the valid range for I/O Port operations\r
91 //\r
92 if (!MmioOperation && (Width == SMM_IO_UINT64)) {\r
93 return EFI_INVALID_PARAMETER;\r
94 }\r
7367cc6c 95\r
173eeac9 96 //\r
7367cc6c 97 // Check to see if any address associated with this transfer exceeds the maximum\r
173eeac9 98 // allowed address. The maximum address implied by the parameters passed in is\r
99 // Address + Size * Count. If the following condition is met, then the transfer\r
100 // is not supported.\r
101 //\r
102 // Address + Size * Count > (MmioOperation ? MAX_ADDRESS : MAX_IO_PORT_ADDRESS) + 1\r
103 //\r
7367cc6c 104 // Since MAX_ADDRESS can be the maximum integer value supported by the CPU and Count\r
173eeac9 105 // can also be the maximum integer value supported by the CPU, this range\r
311004b2 106 // check must be adjusted to avoid all overflow conditions.\r
7367cc6c
LG
107 //\r
108 // The following form of the range check is equivalent but assumes that\r
173eeac9 109 // MAX_ADDRESS and MAX_IO_PORT_ADDRESS are of the form (2^n - 1).\r
110 //\r
111 Limit = (MmioOperation ? MAX_ADDRESS : MAX_IO_PORT_ADDRESS);\r
112 if (Count == 0) {\r
113 if (Address > Limit) {\r
114 return EFI_UNSUPPORTED;\r
115 }\r
7367cc6c 116 } else {\r
173eeac9 117 MaxCount = RShiftU64 (Limit, Width);\r
118 if (MaxCount < (Count - 1)) {\r
119 return EFI_UNSUPPORTED;\r
120 }\r
121 if (Address > LShiftU64 (MaxCount - Count + 1, Width)) {\r
122 return EFI_UNSUPPORTED;\r
123 }\r
124 }\r
7367cc6c 125\r
173eeac9 126 //\r
127 // Check to see if Address is aligned\r
128 //\r
8491e302 129 if ((Address & ((UINT64)mStride[Width] - 1)) != 0) {\r
173eeac9 130 return EFI_UNSUPPORTED;\r
131 }\r
132\r
133 return EFI_SUCCESS;\r
134}\r
135\r
136/**\r
137 Reads memory-mapped registers.\r
138\r
7367cc6c
LG
139 The I/O operations are carried out exactly as requested. The caller is\r
140 responsible for any alignment and I/O width issues that the bus, device,\r
bc230a23 141 platform, or type of I/O might require.\r
142\r
143 @param[in] This The EFI_SMM_CPU_IO2_PROTOCOL instance.\r
144 @param[in] Width Signifies the width of the I/O operations.\r
7367cc6c
LG
145 @param[in] Address The base address of the I/O operations. The caller is\r
146 responsible for aligning the Address if required.\r
bc230a23 147 @param[in] Count The number of I/O operations to perform.\r
7367cc6c
LG
148 @param[out] Buffer For read operations, the destination buffer to store\r
149 the results. For write operations, the source buffer\r
bc230a23 150 from which to write data.\r
151\r
152 @retval EFI_SUCCESS The data was read from or written to the device.\r
153 @retval EFI_UNSUPPORTED The Address is not valid for this system.\r
154 @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.\r
7367cc6c 155 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a\r
bc230a23 156 lack of resources\r
173eeac9 157\r
158**/\r
159EFI_STATUS\r
160EFIAPI\r
161CpuMemoryServiceRead (\r
162 IN CONST EFI_SMM_CPU_IO2_PROTOCOL *This,\r
163 IN EFI_SMM_IO_WIDTH Width,\r
164 IN UINT64 Address,\r
165 IN UINTN Count,\r
166 OUT VOID *Buffer\r
167 )\r
168{\r
169 EFI_STATUS Status;\r
170 UINT8 Stride;\r
171 UINT8 *Uint8Buffer;\r
172\r
173 Status = CpuIoCheckParameter (TRUE, Width, Address, Count, Buffer);\r
174 if (EFI_ERROR (Status)) {\r
175 return Status;\r
176 }\r
177\r
178 //\r
179 // Select loop based on the width of the transfer\r
180 //\r
181 Stride = mStride[Width];\r
182 for (Uint8Buffer = Buffer; Count > 0; Address += Stride, Uint8Buffer += Stride, Count--) {\r
183 if (Width == SMM_IO_UINT8) {\r
184 *Uint8Buffer = MmioRead8 ((UINTN)Address);\r
185 } else if (Width == SMM_IO_UINT16) {\r
186 *((UINT16 *)Uint8Buffer) = MmioRead16 ((UINTN)Address);\r
187 } else if (Width == SMM_IO_UINT32) {\r
188 *((UINT32 *)Uint8Buffer) = MmioRead32 ((UINTN)Address);\r
189 } else if (Width == SMM_IO_UINT64) {\r
190 *((UINT64 *)Uint8Buffer) = MmioRead64 ((UINTN)Address);\r
191 }\r
192 }\r
193 return EFI_SUCCESS;\r
194}\r
195\r
196/**\r
197 Writes memory-mapped registers.\r
198\r
7367cc6c
LG
199 The I/O operations are carried out exactly as requested. The caller is\r
200 responsible for any alignment and I/O width issues that the bus, device,\r
bc230a23 201 platform, or type of I/O might require.\r
202\r
203 @param[in] This The EFI_SMM_CPU_IO2_PROTOCOL instance.\r
204 @param[in] Width Signifies the width of the I/O operations.\r
7367cc6c
LG
205 @param[in] Address The base address of the I/O operations. The caller is\r
206 responsible for aligning the Address if required.\r
bc230a23 207 @param[in] Count The number of I/O operations to perform.\r
7367cc6c
LG
208 @param[in] Buffer For read operations, the destination buffer to store\r
209 the results. For write operations, the source buffer\r
bc230a23 210 from which to write data.\r
211\r
212 @retval EFI_SUCCESS The data was read from or written to the device.\r
213 @retval EFI_UNSUPPORTED The Address is not valid for this system.\r
214 @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.\r
7367cc6c 215 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a\r
bc230a23 216 lack of resources\r
173eeac9 217\r
218**/\r
219EFI_STATUS\r
220EFIAPI\r
221CpuMemoryServiceWrite (\r
222 IN CONST EFI_SMM_CPU_IO2_PROTOCOL *This,\r
223 IN EFI_SMM_IO_WIDTH Width,\r
224 IN UINT64 Address,\r
225 IN UINTN Count,\r
226 IN VOID *Buffer\r
227 )\r
228{\r
229 EFI_STATUS Status;\r
230 UINT8 Stride;\r
231 UINT8 *Uint8Buffer;\r
232\r
233 Status = CpuIoCheckParameter (TRUE, Width, Address, Count, Buffer);\r
234 if (EFI_ERROR (Status)) {\r
235 return Status;\r
236 }\r
237\r
238 //\r
239 // Select loop based on the width of the transfer\r
240 //\r
241 Stride = mStride[Width];\r
242 for (Uint8Buffer = Buffer; Count > 0; Address += Stride, Uint8Buffer += Stride, Count--) {\r
243 if (Width == SMM_IO_UINT8) {\r
244 MmioWrite8 ((UINTN)Address, *Uint8Buffer);\r
245 } else if (Width == SMM_IO_UINT16) {\r
246 MmioWrite16 ((UINTN)Address, *((UINT16 *)Uint8Buffer));\r
247 } else if (Width == SMM_IO_UINT32) {\r
248 MmioWrite32 ((UINTN)Address, *((UINT32 *)Uint8Buffer));\r
249 } else if (Width == SMM_IO_UINT64) {\r
250 MmioWrite64 ((UINTN)Address, *((UINT64 *)Uint8Buffer));\r
251 }\r
252 }\r
253 return EFI_SUCCESS;\r
254}\r
255\r
256/**\r
257 Reads I/O registers.\r
258\r
7367cc6c
LG
259 The I/O operations are carried out exactly as requested. The caller is\r
260 responsible for any alignment and I/O width issues that the bus, device,\r
bc230a23 261 platform, or type of I/O might require.\r
262\r
263 @param[in] This The EFI_SMM_CPU_IO2_PROTOCOL instance.\r
264 @param[in] Width Signifies the width of the I/O operations.\r
7367cc6c
LG
265 @param[in] Address The base address of the I/O operations. The caller is\r
266 responsible for aligning the Address if required.\r
bc230a23 267 @param[in] Count The number of I/O operations to perform.\r
7367cc6c
LG
268 @param[out] Buffer For read operations, the destination buffer to store\r
269 the results. For write operations, the source buffer\r
bc230a23 270 from which to write data.\r
271\r
272 @retval EFI_SUCCESS The data was read from or written to the device.\r
273 @retval EFI_UNSUPPORTED The Address is not valid for this system.\r
274 @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.\r
7367cc6c 275 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a\r
bc230a23 276 lack of resources\r
173eeac9 277\r
278**/\r
279EFI_STATUS\r
280EFIAPI\r
281CpuIoServiceRead (\r
282 IN CONST EFI_SMM_CPU_IO2_PROTOCOL *This,\r
283 IN EFI_SMM_IO_WIDTH Width,\r
284 IN UINT64 Address,\r
285 IN UINTN Count,\r
286 OUT VOID *Buffer\r
287 )\r
288{\r
289 EFI_STATUS Status;\r
290 UINT8 Stride;\r
291 UINT8 *Uint8Buffer;\r
292\r
293 Status = CpuIoCheckParameter (FALSE, Width, Address, Count, Buffer);\r
294 if (EFI_ERROR (Status)) {\r
295 return Status;\r
296 }\r
297\r
298 //\r
299 // Select loop based on the width of the transfer\r
300 //\r
301 Stride = mStride[Width];\r
302 for (Uint8Buffer = Buffer; Count > 0; Address += Stride, Uint8Buffer += Stride, Count--) {\r
303 if (Width == SMM_IO_UINT8) {\r
304 *Uint8Buffer = IoRead8 ((UINTN)Address);\r
305 } else if (Width == SMM_IO_UINT16) {\r
306 *((UINT16 *)Uint8Buffer) = IoRead16 ((UINTN)Address);\r
307 } else if (Width == SMM_IO_UINT32) {\r
308 *((UINT32 *)Uint8Buffer) = IoRead32 ((UINTN)Address);\r
309 }\r
310 }\r
311\r
312 return EFI_SUCCESS;\r
313}\r
314\r
315/**\r
316 Write I/O registers.\r
317\r
7367cc6c
LG
318 The I/O operations are carried out exactly as requested. The caller is\r
319 responsible for any alignment and I/O width issues that the bus, device,\r
bc230a23 320 platform, or type of I/O might require.\r
321\r
322 @param[in] This The EFI_SMM_CPU_IO2_PROTOCOL instance.\r
323 @param[in] Width Signifies the width of the I/O operations.\r
7367cc6c
LG
324 @param[in] Address The base address of the I/O operations. The caller is\r
325 responsible for aligning the Address if required.\r
bc230a23 326 @param[in] Count The number of I/O operations to perform.\r
7367cc6c
LG
327 @param[in] Buffer For read operations, the destination buffer to store\r
328 the results. For write operations, the source buffer\r
bc230a23 329 from which to write data.\r
330\r
331 @retval EFI_SUCCESS The data was read from or written to the device.\r
332 @retval EFI_UNSUPPORTED The Address is not valid for this system.\r
333 @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.\r
7367cc6c 334 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a\r
bc230a23 335 lack of resources\r
173eeac9 336\r
337**/\r
338EFI_STATUS\r
339EFIAPI\r
340CpuIoServiceWrite (\r
341 IN CONST EFI_SMM_CPU_IO2_PROTOCOL *This,\r
342 IN EFI_SMM_IO_WIDTH Width,\r
343 IN UINT64 Address,\r
344 IN UINTN Count,\r
345 IN VOID *Buffer\r
346 )\r
347{\r
348 EFI_STATUS Status;\r
349 UINT8 Stride;\r
350 UINT8 *Uint8Buffer;\r
351\r
352 //\r
353 // Make sure the parameters are valid\r
354 //\r
355 Status = CpuIoCheckParameter (FALSE, Width, Address, Count, Buffer);\r
356 if (EFI_ERROR (Status)) {\r
357 return Status;\r
358 }\r
359\r
360 //\r
361 // Select loop based on the width of the transfer\r
362 //\r
363 Stride = mStride[Width];\r
364 for (Uint8Buffer = (UINT8 *)Buffer; Count > 0; Address += Stride, Uint8Buffer += Stride, Count--) {\r
365 if (Width == SMM_IO_UINT8) {\r
366 IoWrite8 ((UINTN)Address, *Uint8Buffer);\r
367 } else if (Width == SMM_IO_UINT16) {\r
368 IoWrite16 ((UINTN)Address, *((UINT16 *)Uint8Buffer));\r
369 } else if (Width == SMM_IO_UINT32) {\r
370 IoWrite32 ((UINTN)Address, *((UINT32 *)Uint8Buffer));\r
371 }\r
372 }\r
7367cc6c 373\r
173eeac9 374 return EFI_SUCCESS;\r
375}\r
376\r
377/**\r
378 The module Entry Point SmmCpuIoProtocol driver\r
379\r
bc230a23 380 @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
381 @param[in] SystemTable A pointer to the EFI System Table.\r
173eeac9 382\r
bc230a23 383 @retval EFI_SUCCESS The entry point is executed successfully.\r
384 @retval Other Some error occurs when executing this entry point.\r
173eeac9 385\r
386**/\r
387EFI_STATUS\r
388EFIAPI\r
389SmmCpuIo2Initialize (\r
390 IN EFI_HANDLE ImageHandle,\r
391 IN EFI_SYSTEM_TABLE *SystemTable\r
392 )\r
430fbbe0 393{\r
173eeac9 394 EFI_STATUS Status;\r
395\r
396 //\r
397 // Copy the SMM CPU I/O Protocol instance into the System Management System Table\r
398 //\r
399 CopyMem (&gSmst->SmmIo, &mSmmCpuIo2, sizeof (mSmmCpuIo2));\r
400\r
401 //\r
402 // Install the SMM CPU I/O Protocol into the SMM protocol database\r
403 //\r
404 Status = gSmst->SmmInstallProtocolInterface (\r
405 &mHandle,\r
406 &gEfiSmmCpuIo2ProtocolGuid,\r
407 EFI_NATIVE_INTERFACE,\r
408 &mSmmCpuIo2\r
409 );\r
410 ASSERT_EFI_ERROR (Status);\r
7367cc6c 411\r
173eeac9 412 return Status;\r
413}\r