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