Clean up DEC files:
[mirror_edk2.git] / UefiCpuPkg / CpuIo2Smm / CpuIo2Smm.c
CommitLineData
173eeac9 1/** @file\r
2 Produces the SMM CPU I/O Protocol.\r
3\r
01a1c0fc
HT
4Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
5This program and the accompanying materials \r
173eeac9 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
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
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
53 @param[in] Count The number of I/O operations to perform.\r
430fbbe0 54 @param[in] Buffer For read operations, the destination buffer to store \r
bc230a23 55 the results. For write operations, the source buffer \r
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
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
dbc225ca 85 if (Width < 0 || 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
95 \r
96 //\r
97 // Check to see if any address associated with this transfer exceeds the maximum \r
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
104 // Since MAX_ADDRESS can be the maximum integer value supported by the CPU and Count \r
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
173eeac9 107 // \r
311004b2 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
116 } else { \r
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
125 \r
126 //\r
127 // Check to see if Address is aligned\r
128 //\r
129 if ((Address & (UINT64)(mStride[Width] - 1)) != 0) {\r
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
bc230a23 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
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
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
147 @param[in] Count The number of I/O operations to perform.\r
148 @param[out] Buffer For read operations, the destination buffer to store \r
149 the results. For write operations, the source buffer \r
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
155 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a \r
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
bc230a23 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
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
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
207 @param[in] Count The number of I/O operations to perform.\r
208 @param[in] Buffer For read operations, the destination buffer to store \r
209 the results. For write operations, the source buffer \r
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
215 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a \r
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
bc230a23 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
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
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
267 @param[in] Count The number of I/O operations to perform.\r
268 @param[out] Buffer For read operations, the destination buffer to store \r
269 the results. For write operations, the source buffer \r
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
275 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a \r
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
bc230a23 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
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
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
326 @param[in] Count The number of I/O operations to perform.\r
327 @param[in] Buffer For read operations, the destination buffer to store \r
328 the results. For write operations, the source buffer \r
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
334 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a \r
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
373 \r
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
411 \r
412 return Status;\r
413}\r