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