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