]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.c
Check in driver to produce CPU I/O 2 Protocol for IA32 and X64 architecture.
[mirror_edk2.git] / UefiCpuPkg / CpuIo2Dxe / CpuIo2Dxe.c
CommitLineData
3ca55ed4 1/** @file\r
2 Produces the CPU I/O 2 Protocol.\r
3\r
4Copyright (c) 2009, 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 "CpuIo2Dxe.h"\r
16\r
17EFI_HANDLE mHandle = NULL;\r
18EFI_CPU_IO2_PROTOCOL mCpuIo = {\r
19 {\r
20 CpuMemoryServiceRead,\r
21 CpuMemoryServiceWrite\r
22 },\r
23 {\r
24 CpuIoServiceRead,\r
25 CpuIoServiceWrite\r
26 }\r
27};\r
28\r
29/**\r
30 Worker function to check the validation of parameters for CPU I/O interface functions.\r
31\r
32 This function check the validation of parameters for CPU I/O interface functions.\r
33\r
34 @param Width Width of the Mmio/Io operation\r
35 @param Address Base address of the Mmio/Io operation\r
36 @param Count Count of the number of accesses to perform\r
37 @param Buffer Pointer to the buffer to read from memory\r
38 @param Limit Maximum address supported\r
39\r
40 @retval EFI_INVALID_PARAMETER Buffer is NULL\r
41 @retval EFI_UNSUPPORTED The address range specified by Width, Address and Count is invalid\r
42 @retval EFI_UNSUPPORTED The memory buffer is not aligned\r
43 @retval EFI_SUCCESS Parameters are valid\r
44\r
45**/\r
46EFI_STATUS\r
47CpuIoCheckParameter (\r
48 IN EFI_CPU_IO_PROTOCOL_WIDTH Width,\r
49 IN UINT64 Address,\r
50 IN UINTN Count,\r
51 IN VOID *Buffer,\r
52 IN UINT64 Limit\r
53 )\r
54{\r
55 UINTN AlignMask;\r
56\r
57 if (Buffer == NULL) {\r
58 return EFI_INVALID_PARAMETER;\r
59 }\r
60\r
61 if (Address > Limit) {\r
62 return EFI_UNSUPPORTED;\r
63 }\r
64\r
65 //\r
66 // For FiFo type, the target address won't increase during the access,\r
67 // so treat count as 1\r
68 //\r
69 if (Width >= EfiCpuIoWidthFifoUint8 && Width <= EfiCpuIoWidthFifoUint64) {\r
70 Count = 1;\r
71 }\r
72\r
73 Width = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03);\r
74 if (Address - 1 + (UINT32)(1 << Width) * Count > Limit) {\r
75 return EFI_UNSUPPORTED;\r
76 }\r
77\r
78 AlignMask = (1 << Width) - 1;\r
79 if ((UINTN) Buffer & AlignMask) {\r
80 return EFI_UNSUPPORTED;\r
81 }\r
82\r
83 return EFI_SUCCESS;\r
84}\r
85\r
86/**\r
87 Worker function to update access width and count for access to the unaligned address.\r
88 Unaligned Io/MmIo address access, break up the request into word by word or byte by byte.\r
89\r
90 @param Address Base address of the Mmio/Io operation\r
91 @param PtrWidth Pointer to width of the Mmio/Io operation\r
92 Out, this value will be updated for access to the unaligned address.\r
93 @param PtrCount Pointer to count of the number of accesses to perform\r
94 Out, this value will be updated for access to the unaligned address.\r
95**/\r
96VOID\r
97CpuIoUpdateWidthCount (\r
98 IN UINT64 Address,\r
99 IN OUT EFI_CPU_IO_PROTOCOL_WIDTH *PtrWidth,\r
100 IN OUT UINTN *PtrCount\r
101 )\r
102{\r
103 EFI_CPU_IO_PROTOCOL_WIDTH BufferWidth;\r
104 UINTN BufferCount;\r
105\r
106 BufferWidth = *PtrWidth;\r
107 BufferCount = *PtrCount;\r
108 \r
109 switch (BufferWidth) {\r
110 case EfiCpuIoWidthUint8:\r
111 break;\r
112\r
113 case EfiCpuIoWidthUint16:\r
114 if ((Address & 0x01) == 0) {\r
115 break;\r
116 } else {\r
117 BufferCount = BufferCount * 2;\r
118 BufferWidth = EfiCpuIoWidthUint8;\r
119 }\r
120 break;\r
121\r
122 case EfiCpuIoWidthUint32:\r
123 if ((Address & 0x03) == 0) {\r
124 break;\r
125 } else if ((Address & 0x01) == 0) {\r
126 BufferCount = BufferCount * 2;\r
127 BufferWidth = EfiCpuIoWidthUint16;\r
128 } else {\r
129 BufferCount = BufferCount * 4;\r
130 BufferWidth = EfiCpuIoWidthUint8;\r
131 }\r
132 break;\r
133\r
134 case EfiCpuIoWidthUint64:\r
135 if ((Address & 0x07) == 0) {\r
136 break;\r
137 } else if ((Address & 0x03) == 0) {\r
138 BufferCount = BufferCount * 2;\r
139 BufferWidth = EfiCpuIoWidthUint32;\r
140 } else if ((Address & 0x01) == 0) {\r
141 BufferCount = BufferCount * 4;\r
142 BufferWidth = EfiCpuIoWidthUint16;\r
143 } else {\r
144 BufferCount = BufferCount * 8;\r
145 BufferWidth = EfiCpuIoWidthUint8;\r
146 }\r
147 break;\r
148\r
149 default:\r
150 return;\r
151 }\r
152\r
153 *PtrWidth = BufferWidth;\r
154 *PtrCount = BufferCount;\r
155\r
156 return;\r
157}\r
158\r
159/**\r
160 Worker function to perform memory mapped I/O read/write\r
161\r
162 This function provides private services to perform memory mapped I/O read/write.\r
163\r
164 @param Width Width of the memory mapped I/O operation\r
165 @param Count Count of the number of accesses to perform\r
166 @param DestinationStrideFlag Boolean flag indicates if the destination is to be incremented\r
167 @param Destination Destination of the memory mapped I/O operation\r
168 @param SourceStrideFlag Boolean flag indicates if the source is to be incremented\r
169 @param Source Source of the memory mapped I/O operation\r
170\r
171 @retval EFI_SUCCESS Successful operation\r
172 @retval EFI_INVALID_PARAMETER Width is invalid\r
173\r
174**/\r
175EFI_STATUS\r
176CpuIoMemRW (\r
177 IN EFI_CPU_IO_PROTOCOL_WIDTH Width,\r
178 IN UINTN Count,\r
179 IN BOOLEAN DestinationStrideFlag,\r
180 OUT PTR Destination,\r
181 IN BOOLEAN SourceStrideFlag,\r
182 IN PTR Source\r
183 )\r
184{\r
185 UINTN Stride;\r
186 UINTN DestinationStride;\r
187 UINTN SourceStride;\r
188\r
189 Width = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03);\r
190 Stride = (UINT32)(1 << Width);\r
191 DestinationStride = DestinationStrideFlag ? Stride : 0;\r
192 SourceStride = SourceStrideFlag ? Stride : 0;\r
193\r
194 //\r
195 // Loop for each iteration and move the data\r
196 //\r
197 switch (Width) {\r
198 case EfiCpuIoWidthUint8:\r
199 for (; Count > 0; Count--, Destination.Buf += DestinationStride, Source.Buf += SourceStride) {\r
200 MmioWrite8((UINTN)Destination.Ui8 , MmioRead8((UINTN)Source.Ui8));\r
201 }\r
202 break;\r
203\r
204 case EfiCpuIoWidthUint16:\r
205 for (; Count > 0; Count--, Destination.Buf += DestinationStride, Source.Buf += SourceStride) {\r
206 MmioWrite16((UINTN)Destination.Ui16 , MmioRead16((UINTN)Source.Ui16));\r
207 }\r
208 break;\r
209\r
210 case EfiCpuIoWidthUint32:\r
211 for (; Count > 0; Count--, Destination.Buf += DestinationStride, Source.Buf += SourceStride) {\r
212 MmioWrite32((UINTN)Destination.Ui32 , MmioRead32((UINTN)Source.Ui32));\r
213 }\r
214 break;\r
215\r
216 case EfiCpuIoWidthUint64:\r
217 for (; Count > 0; Count--, Destination.Buf += DestinationStride, Source.Buf += SourceStride) {\r
218 MmioWrite64((UINTN)Destination.Ui64 , MmioRead64((UINTN)Source.Ui64));\r
219 }\r
220 break;\r
221\r
222 default:\r
223 return EFI_INVALID_PARAMETER;\r
224 }\r
225\r
226 return EFI_SUCCESS;\r
227}\r
228\r
229/**\r
230 Enables a driver to read memory-mapped registers in the PI System memory space.\r
231\r
232 @param[in] This A pointer to the EFI_CPU_IO2_PROTOCOL instance.\r
233 @param[in] Width Signifies the width of the memory operation.\r
234 @param[in] Address The base address of the memory operation.\r
235 @param[in] Count The number of memory operations to perform. The number of bytes moved\r
236 is Width size * Count, starting at Address.\r
237 @param[out] Buffer The destination buffer to store the results.\r
238\r
239 @retval EFI_SUCCESS The data was read from or written to the EFI system.\r
240 @retval EFI_INVALID_PARAMETER Width is invalid for this EFI system. Or Buffer is NULL.\r
241 @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.\r
242 Or,The address range specified by Address, Width, and Count is not valid for this EFI system.\r
243\r
244**/\r
245EFI_STATUS\r
246EFIAPI\r
247CpuMemoryServiceRead (\r
248 IN EFI_CPU_IO2_PROTOCOL *This,\r
249 IN EFI_CPU_IO_PROTOCOL_WIDTH Width,\r
250 IN UINT64 Address,\r
251 IN UINTN Count,\r
252 OUT VOID *Buffer\r
253 )\r
254{\r
255 PTR Source;\r
256 PTR Destination;\r
257 EFI_STATUS Status;\r
258 EFI_CPU_IO_PROTOCOL_WIDTH BufferWidth;\r
259\r
260 Status = CpuIoCheckParameter (Width, Address, Count, Buffer, MAX_ADDRESS);\r
261 if (EFI_ERROR (Status)) {\r
262 return Status;\r
263 }\r
264\r
265 Destination.Buf = Buffer;\r
266 Source.Buf = (VOID *) (UINTN) Address;\r
267 \r
268 //\r
269 // Support access to unaligned mmio address.\r
270 // Break up the request into byte by byte\r
271 //\r
272 BufferWidth = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03);\r
273 CpuIoUpdateWidthCount (Address, &BufferWidth, &Count);\r
274\r
275 if (Width >= EfiCpuIoWidthUint8 && Width <= EfiCpuIoWidthUint64) {\r
276 return CpuIoMemRW (BufferWidth, Count, TRUE, Destination, TRUE, Source);\r
277 }\r
278\r
279 if (Width >= EfiCpuIoWidthFifoUint8 && Width <= EfiCpuIoWidthFifoUint64) {\r
280 return CpuIoMemRW (BufferWidth, Count, TRUE, Destination, FALSE, Source);\r
281 }\r
282\r
283 if (Width >= EfiCpuIoWidthFillUint8 && Width <= EfiCpuIoWidthFillUint64) {\r
284 return CpuIoMemRW (BufferWidth, Count, FALSE, Destination, TRUE, Source);\r
285 }\r
286\r
287 return EFI_INVALID_PARAMETER;\r
288}\r
289\r
290/**\r
291 Enables a driver to write memory-mapped registers in the PI System memory space.\r
292\r
293 @param[in] This A pointer to the EFI_CPU_IO2_PROTOCOL instance.\r
294 @param[in] Width Signifies the width of the memory operation.\r
295 @param[in] Address The base address of the memory operation.\r
296 @param[in] Count The number of memory operations to perform. The number of bytes moved\r
297 is Width size * Count, starting at Address.\r
298 @param[in] Buffer The source buffer from which to write data.\r
299\r
300 @retval EFI_SUCCESS The data was read from or written to the EFI system.\r
301 @retval EFI_INVALID_PARAMETER Width is invalid for this EFI system. Or Buffer is NULL.\r
302 @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.\r
303 Or,The address range specified by Address, Width, and Count is not valid for this EFI system.\r
304\r
305**/\r
306EFI_STATUS\r
307EFIAPI\r
308CpuMemoryServiceWrite (\r
309 IN EFI_CPU_IO2_PROTOCOL *This,\r
310 IN EFI_CPU_IO_PROTOCOL_WIDTH Width,\r
311 IN UINT64 Address,\r
312 IN UINTN Count,\r
313 IN VOID *Buffer\r
314 )\r
315{\r
316 PTR Source;\r
317 PTR Destination;\r
318 EFI_STATUS Status;\r
319 EFI_CPU_IO_PROTOCOL_WIDTH BufferWidth;\r
320\r
321 Status = CpuIoCheckParameter (Width, Address, Count, Buffer, MAX_ADDRESS);\r
322 if (EFI_ERROR (Status)) {\r
323 return Status;\r
324 }\r
325\r
326 Destination.Buf = (VOID *) (UINTN) Address;\r
327 Source.Buf = Buffer;\r
328\r
329 //\r
330 // Support access to unaligned mmio address.\r
331 // Break up the request into byte by byte\r
332 //\r
333 BufferWidth = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03);\r
334 CpuIoUpdateWidthCount (Address, &BufferWidth, &Count);\r
335\r
336 if (Width >= EfiCpuIoWidthUint8 && Width <= EfiCpuIoWidthUint64) {\r
337 return CpuIoMemRW (BufferWidth, Count, TRUE, Destination, TRUE, Source);\r
338 }\r
339\r
340 if (Width >= EfiCpuIoWidthFifoUint8 && Width <= EfiCpuIoWidthFifoUint64) {\r
341 return CpuIoMemRW (BufferWidth, Count, FALSE, Destination, TRUE, Source);\r
342 }\r
343\r
344 if (Width >= EfiCpuIoWidthFillUint8 && Width <= EfiCpuIoWidthFillUint64) {\r
345 return CpuIoMemRW (BufferWidth, Count, TRUE, Destination, FALSE, Source);\r
346 }\r
347\r
348 return EFI_INVALID_PARAMETER;\r
349}\r
350\r
351/**\r
352 Enables a driver to read registers in the PI CPU I/O space.\r
353\r
354 @param[in] This A pointer to the EFI_CPU_IO2_PROTOCOL instance.\r
355 @param[in] Width Signifies the width of the I/O operation.\r
356 @param[in] UserAddress The base address of the I/O operation. The caller is responsible\r
357 for aligning the Address if required. \r
358 @param[in] Count The number of I/O operations to perform. The number of bytes moved\r
359 is Width size * Count, starting at Address.\r
360 @param[out] UserBuffer The destination buffer to store the results.\r
361\r
362 @retval EFI_SUCCESS The data was read from or written to the EFI system.\r
363 @retval EFI_INVALID_PARAMETER Width is invalid for this EFI system. Or Buffer is NULL.\r
364 @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.\r
365 Or,The address range specified by Address, Width, and Count is not valid for this EFI system.\r
366\r
367**/\r
368EFI_STATUS\r
369EFIAPI\r
370CpuIoServiceRead (\r
371 IN EFI_CPU_IO2_PROTOCOL *This,\r
372 IN EFI_CPU_IO_PROTOCOL_WIDTH Width,\r
373 IN UINT64 UserAddress,\r
374 IN UINTN Count,\r
375 OUT VOID *UserBuffer\r
376 )\r
377{\r
378 UINTN InStride;\r
379 UINTN OutStride;\r
380 UINTN Address;\r
381 PTR Buffer;\r
382 EFI_STATUS Status;\r
383 EFI_CPU_IO_PROTOCOL_WIDTH BufferWidth; \r
384\r
385 Buffer.Buf = (UINT8 *) UserBuffer;\r
386\r
387 if (Width >= EfiCpuIoWidthMaximum) {\r
388 return EFI_INVALID_PARAMETER;\r
389 }\r
390\r
391 Status = CpuIoCheckParameter (Width, UserAddress, Count, UserBuffer, IA32_MAX_IO_ADDRESS);\r
392 if (EFI_ERROR (Status)) {\r
393 return Status;\r
394 }\r
395\r
396 //\r
397 // Support access to unaligned IO address.\r
398 // Break up the request into byte by byte\r
399 //\r
400 BufferWidth = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03);\r
401 CpuIoUpdateWidthCount (UserAddress, &BufferWidth, &Count);\r
402\r
403 Address = (UINTN) UserAddress;\r
404 InStride = (UINT32)(1 << (BufferWidth & 0x03));\r
405 OutStride = InStride;\r
406 if (Width >= EfiCpuIoWidthFifoUint8 && Width <= EfiCpuIoWidthFifoUint64) {\r
407 InStride = 0;\r
408 }\r
409\r
410 if (Width >= EfiCpuIoWidthFillUint8 && Width <= EfiCpuIoWidthFillUint64) {\r
411 OutStride = 0;\r
412 }\r
413\r
414 //\r
415 // Loop for each iteration and move the data\r
416 //\r
417 switch (BufferWidth) {\r
418 case EfiCpuIoWidthUint8:\r
419 for (; Count > 0; Count--, Buffer.Buf += OutStride, Address += InStride) {\r
420 *Buffer.Ui8 = IoRead8 (Address);\r
421 }\r
422 break;\r
423\r
424 case EfiCpuIoWidthUint16:\r
425 for (; Count > 0; Count--, Buffer.Buf += OutStride, Address += InStride) {\r
426 *Buffer.Ui16 = IoRead16 (Address);\r
427 }\r
428 break;\r
429\r
430 case EfiCpuIoWidthUint32:\r
431 for (; Count > 0; Count--, Buffer.Buf += OutStride, Address += InStride) {\r
432 *Buffer.Ui32 = IoRead32 (Address);\r
433 }\r
434 break;\r
435\r
436 default:\r
437 return EFI_INVALID_PARAMETER;\r
438 }\r
439\r
440 return EFI_SUCCESS;\r
441}\r
442\r
443/**\r
444 Enables a driver to write registers in the PI CPU I/O space.\r
445\r
446 @param[in] This A pointer to the EFI_CPU_IO2_PROTOCOL instance.\r
447 @param[in] Width Signifies the width of the I/O operation.\r
448 @param[in] UserAddress The base address of the I/O operation. The caller is responsible\r
449 for aligning the Address if required. \r
450 @param[in] Count The number of I/O operations to perform. The number of bytes moved\r
451 is Width size * Count, starting at Address.\r
452 @param[in] UserBuffer The source buffer from which to write data.\r
453\r
454 @retval EFI_SUCCESS The data was read from or written to the EFI system.\r
455 @retval EFI_INVALID_PARAMETER Width is invalid for this EFI system. Or Buffer is NULL.\r
456 @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.\r
457 Or,The address range specified by Address, Width, and Count is not valid for this EFI system.\r
458\r
459**/\r
460EFI_STATUS\r
461EFIAPI\r
462CpuIoServiceWrite (\r
463 IN EFI_CPU_IO2_PROTOCOL *This,\r
464 IN EFI_CPU_IO_PROTOCOL_WIDTH Width,\r
465 IN UINT64 UserAddress,\r
466 IN UINTN Count,\r
467 IN VOID *UserBuffer\r
468 )\r
469{\r
470 UINTN InStride;\r
471 UINTN OutStride;\r
472 UINTN Address;\r
473 PTR Buffer;\r
474 EFI_STATUS Status;\r
475 EFI_CPU_IO_PROTOCOL_WIDTH BufferWidth;\r
476\r
477 Buffer.Buf = (UINT8 *) UserBuffer;\r
478\r
479 if (Width >= EfiCpuIoWidthMaximum) {\r
480 return EFI_INVALID_PARAMETER;\r
481 }\r
482\r
483 Status = CpuIoCheckParameter (Width, UserAddress, Count, UserBuffer, IA32_MAX_IO_ADDRESS);\r
484 if (EFI_ERROR (Status)) {\r
485 return Status;\r
486 }\r
487\r
488 //\r
489 // Support access to unaligned IO address.\r
490 // Break up the request into byte by byte\r
491 //\r
492 BufferWidth = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03);\r
493 CpuIoUpdateWidthCount (UserAddress, &BufferWidth, &Count);\r
494\r
495 Address = (UINTN) UserAddress;\r
496 InStride = (UINT32)(1 << (BufferWidth & 0x03));\r
497 OutStride = InStride;\r
498 if (Width >= EfiCpuIoWidthFifoUint8 && Width <= EfiCpuIoWidthFifoUint64) {\r
499 InStride = 0;\r
500 }\r
501\r
502 if (Width >= EfiCpuIoWidthFillUint8 && Width <= EfiCpuIoWidthFillUint64) {\r
503 OutStride = 0;\r
504 }\r
505\r
506 //\r
507 // Loop for each iteration and move the data\r
508 //\r
509 switch (BufferWidth) {\r
510 case EfiCpuIoWidthUint8:\r
511 for (; Count > 0; Count--, Buffer.Buf += OutStride, Address += InStride) {\r
512 IoWrite8 (Address, *Buffer.Ui8);\r
513 }\r
514 break;\r
515\r
516 case EfiCpuIoWidthUint16:\r
517 for (; Count > 0; Count--, Buffer.Buf += OutStride, Address += InStride) {\r
518 IoWrite16 (Address, *Buffer.Ui16);\r
519 }\r
520 break;\r
521\r
522 case EfiCpuIoWidthUint32:\r
523 for (; Count > 0; Count--, Buffer.Buf += OutStride, Address += InStride) {\r
524 IoWrite32 (Address, *Buffer.Ui32);\r
525 }\r
526 break;\r
527\r
528 default:\r
529 return EFI_INVALID_PARAMETER;\r
530 }\r
531\r
532 return EFI_SUCCESS;\r
533}\r
534\r
535/**\r
536 Entrypoint of CPU I/O 2 DXE module.\r
537 \r
538 @param ImageHandle The firmware allocated handle for the EFI image.\r
539 @param SystemTable A pointer to the EFI System Table.\r
540 \r
541 @retval EFI_SUCCESS The entry point is executed successfully.\r
542\r
543**/\r
544EFI_STATUS\r
545EFIAPI\r
546CpuIo2Initialize (\r
547 IN EFI_HANDLE ImageHandle,\r
548 IN EFI_SYSTEM_TABLE *SystemTable\r
549 )\r
550{\r
551 EFI_STATUS Status;\r
552\r
553 Status = gBS->InstallProtocolInterface (\r
554 &mHandle,\r
555 &gEfiCpuIo2ProtocolGuid,\r
556 EFI_NATIVE_INTERFACE,\r
557 &mCpuIo\r
558 );\r
559 ASSERT_EFI_ERROR (Status);\r
560\r
561 return Status;\r
562}\r