3 Copyright (c) 2004 - 2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 This is the code that publishes the CPU I/O Protocol.
18 The intent herein is to have a single I/O service that can load
19 as early as possible, extend into runtime, and be layered upon by
20 the implementations of architectural protocols and the PCI Root
26 #include "CpuIoAccess.h"
28 #define IA32_MAX_IO_ADDRESS 0xFFFF
30 EFI_CPU_IO_PROTOCOL mCpuIo
= {
44 IN EFI_CPU_IO_PROTOCOL_WIDTH Width
,
46 IN BOOLEAN DestinationStrideFlag
,
48 IN BOOLEAN SourceStrideFlag
,
55 Private service to perform memory mapped I/O read/write
59 Width - Width of the memory mapped I/O operation
60 Count - Count of the number of accesses to perform
61 DestinationStrideFlag - Boolean flag indicates if the destination is to be incremented
62 Destination - Destination of the memory mapped I/O operation
63 SourceStrideFlag - Boolean flag indicates if the source is to be incremented
64 Source - Source of the memory mapped I/O operation
68 EFI_SUCCESS - Successful operation
69 EFI_INVALID_PARAMETER - Width is invalid
74 UINTN DestinationStride
;
78 Stride
= (UINTN
)1 << Width
;
79 DestinationStride
= DestinationStrideFlag
? Stride
: 0;
80 SourceStride
= SourceStrideFlag
? Stride
: 0;
83 // Loop for each iteration and move the data
86 case EfiCpuIoWidthUint8
:
87 for (; Count
> 0; Count
--, Destination
.buf
+= DestinationStride
, Source
.buf
+= SourceStride
) {
89 *Destination
.ui8
= *Source
.ui8
;
94 case EfiCpuIoWidthUint16
:
95 for (; Count
> 0; Count
--, Destination
.buf
+= DestinationStride
, Source
.buf
+= SourceStride
) {
97 *Destination
.ui16
= *Source
.ui16
;
102 case EfiCpuIoWidthUint32
:
103 for (; Count
> 0; Count
--, Destination
.buf
+= DestinationStride
, Source
.buf
+= SourceStride
) {
105 *Destination
.ui32
= *Source
.ui32
;
110 case EfiCpuIoWidthUint64
:
111 for (; Count
> 0; Count
--, Destination
.buf
+= DestinationStride
, Source
.buf
+= SourceStride
) {
113 *Destination
.ui64
= *Source
.ui64
;
119 return EFI_INVALID_PARAMETER
;
127 CpuMemoryServiceRead (
128 IN EFI_CPU_IO_PROTOCOL
*This
,
129 IN EFI_CPU_IO_PROTOCOL_WIDTH Width
,
138 Perform the memory mapped I/O read service
142 This - Pointer to an instance of the CPU I/O Protocol
143 Width - Width of the memory mapped I/O operation
144 Address - Base address of the memory mapped I/O operation
145 Count - Count of the number of accesses to perform
146 Buffer - Pointer to the destination buffer to store the results
150 EFI_SUCCESS - The data was read.
151 EFI_INVALID_PARAMETER - Width is invalid.
152 EFI_INVALID_PARAMETER - Buffer is NULL.
153 EFI_UNSUPPORTED - The Buffer is not aligned for the given Width.
154 EFI_UNSUPPORTED - The address range specified by Address, Width,
155 and Count is not valid.
163 Status
= CpuIoCheckParameter (Width
, Address
, Count
, Buffer
, EFI_MAX_ADDRESS
);
164 if (EFI_ERROR (Status
)) {
168 Destination
.buf
= Buffer
;
169 Source
.buf
= (VOID
*) (UINTN
) Address
;
171 if (Width
>= EfiCpuIoWidthUint8
&& Width
<= EfiCpuIoWidthUint64
) {
172 return CpuIoMemRW (Width
, Count
, TRUE
, Destination
, TRUE
, Source
);
175 if (Width
>= EfiCpuIoWidthFifoUint8
&& Width
<= EfiCpuIoWidthFifoUint64
) {
176 return CpuIoMemRW (Width
, Count
, TRUE
, Destination
, FALSE
, Source
);
179 if (Width
>= EfiCpuIoWidthFillUint8
&& Width
<= EfiCpuIoWidthFillUint64
) {
180 return CpuIoMemRW (Width
, Count
, FALSE
, Destination
, TRUE
, Source
);
183 return EFI_INVALID_PARAMETER
;
188 CpuMemoryServiceWrite (
189 IN EFI_CPU_IO_PROTOCOL
*This
,
190 IN EFI_CPU_IO_PROTOCOL_WIDTH Width
,
199 Perform the memory mapped I/O write service
203 This - Pointer to an instance of the CPU I/O Protocol
204 Width - Width of the memory mapped I/O operation
205 Address - Base address of the memory mapped I/O operation
206 Count - Count of the number of accesses to perform
207 Buffer - Pointer to the source buffer from which to write data
211 EFI_SUCCESS - The data was written.
212 EFI_INVALID_PARAMETER - Width is invalid.
213 EFI_INVALID_PARAMETER - Buffer is NULL.
214 EFI_UNSUPPORTED - The Buffer is not aligned for the given Width.
215 EFI_UNSUPPORTED - The address range specified by Address, Width,
216 and Count is not valid.
224 Status
= CpuIoCheckParameter (Width
, Address
, Count
, Buffer
, EFI_MAX_ADDRESS
);
225 if (EFI_ERROR (Status
)) {
229 Destination
.buf
= (VOID
*) (UINTN
) Address
;
232 if (Width
>= EfiCpuIoWidthUint8
&& Width
<= EfiCpuIoWidthUint64
) {
233 return CpuIoMemRW (Width
, Count
, TRUE
, Destination
, TRUE
, Source
);
236 if (Width
>= EfiCpuIoWidthFifoUint8
&& Width
<= EfiCpuIoWidthFifoUint64
) {
237 return CpuIoMemRW (Width
, Count
, FALSE
, Destination
, TRUE
, Source
);
240 if (Width
>= EfiCpuIoWidthFillUint8
&& Width
<= EfiCpuIoWidthFillUint64
) {
241 return CpuIoMemRW (Width
, Count
, TRUE
, Destination
, FALSE
, Source
);
244 return EFI_INVALID_PARAMETER
;
250 IN EFI_CPU_IO_PROTOCOL
*This
,
251 IN EFI_CPU_IO_PROTOCOL_WIDTH Width
,
252 IN UINT64 UserAddress
,
260 Perform the port I/O read service
264 This - Pointer to an instance of the CPU I/O Protocol
265 Width - Width of the port I/O operation
266 Address - Base address of the port I/O operation
267 Count - Count of the number of accesses to perform
268 Buffer - Pointer to the destination buffer to store the results
272 EFI_SUCCESS - The data was read.
273 EFI_INVALID_PARAMETER - Width is invalid.
274 EFI_INVALID_PARAMETER - Buffer is NULL.
275 EFI_UNSUPPORTED - The Buffer is not aligned for the given Width.
276 EFI_UNSUPPORTED - The address range specified by Address, Width,
277 and Count is not valid.
287 Buffer
.buf
= (UINT8
*) UserBuffer
;
289 if (Width
>= EfiCpuIoWidthMaximum
) {
290 return EFI_INVALID_PARAMETER
;
293 Status
= CpuIoCheckParameter (Width
, UserAddress
, Count
, UserBuffer
, IA32_MAX_IO_ADDRESS
);
294 if (EFI_ERROR (Status
)) {
298 Address
= (UINTN
) UserAddress
;
299 InStride
= (UINTN
)1 << (Width
& 0x03);
300 OutStride
= InStride
;
301 if (Width
>= EfiCpuIoWidthFifoUint8
&& Width
<= EfiCpuIoWidthFifoUint64
) {
305 if (Width
>= EfiCpuIoWidthFillUint8
&& Width
<= EfiCpuIoWidthFillUint64
) {
309 Width
= Width
& 0x03;
312 // Loop for each iteration and move the data
315 case EfiCpuIoWidthUint8
:
316 for (; Count
> 0; Count
--, Buffer
.buf
+= OutStride
, Address
+= InStride
) {
317 *Buffer
.ui8
= CpuIoRead8 ((UINT16
) Address
);
321 case EfiCpuIoWidthUint16
:
322 for (; Count
> 0; Count
--, Buffer
.buf
+= OutStride
, Address
+= InStride
) {
323 *Buffer
.ui16
= CpuIoRead16 ((UINT16
) Address
);
327 case EfiCpuIoWidthUint32
:
328 for (; Count
> 0; Count
--, Buffer
.buf
+= OutStride
, Address
+= InStride
) {
329 *Buffer
.ui32
= CpuIoRead32 ((UINT16
) Address
);
334 return EFI_INVALID_PARAMETER
;
343 IN EFI_CPU_IO_PROTOCOL
*This
,
344 IN EFI_CPU_IO_PROTOCOL_WIDTH Width
,
345 IN UINT64 UserAddress
,
353 Perform the port I/O write service
357 This - Pointer to an instance of the CPU I/O Protocol
358 Width - Width of the port I/O operation
359 Address - Base address of the port I/O operation
360 Count - Count of the number of accesses to perform
361 Buffer - Pointer to the source buffer from which to write data
365 EFI_SUCCESS - The data was written.
366 EFI_INVALID_PARAMETER - Width is invalid.
367 EFI_INVALID_PARAMETER - Buffer is NULL.
368 EFI_UNSUPPORTED - The Buffer is not aligned for the given Width.
369 EFI_UNSUPPORTED - The address range specified by Address, Width,
370 and Count is not valid.
380 Buffer
.buf
= (UINT8
*) UserBuffer
;
382 if (Width
>= EfiCpuIoWidthMaximum
) {
383 return EFI_INVALID_PARAMETER
;
386 Status
= CpuIoCheckParameter (Width
, UserAddress
, Count
, UserBuffer
, IA32_MAX_IO_ADDRESS
);
387 if (EFI_ERROR (Status
)) {
391 Address
= (UINTN
) UserAddress
;
392 InStride
= (UINTN
)1 << (Width
& 0x03);
393 OutStride
= InStride
;
394 if (Width
>= EfiCpuIoWidthFifoUint8
&& Width
<= EfiCpuIoWidthFifoUint64
) {
398 if (Width
>= EfiCpuIoWidthFillUint8
&& Width
<= EfiCpuIoWidthFillUint64
) {
402 Width
= Width
& 0x03;
405 // Loop for each iteration and move the data
408 case EfiCpuIoWidthUint8
:
409 for (; Count
> 0; Count
--, Buffer
.buf
+= OutStride
, Address
+= InStride
) {
410 CpuIoWrite8 ((UINT16
) Address
, *Buffer
.ui8
);
414 case EfiCpuIoWidthUint16
:
415 for (; Count
> 0; Count
--, Buffer
.buf
+= OutStride
, Address
+= InStride
) {
416 CpuIoWrite16 ((UINT16
) Address
, *Buffer
.ui16
);
420 case EfiCpuIoWidthUint32
:
421 for (; Count
> 0; Count
--, Buffer
.buf
+= OutStride
, Address
+= InStride
) {
422 CpuIoWrite32 ((UINT16
) Address
, *Buffer
.ui32
);
427 return EFI_INVALID_PARAMETER
;
436 IN EFI_HANDLE ImageHandle
,
437 IN EFI_SYSTEM_TABLE
*SystemTable
443 CpuIo driver entry point.
447 ImageHandle - The firmware allocated handle for the EFI image.
448 SystemTable - A pointer to the EFI System Table.
452 EFI_SUCCESS - The driver was initialized.
453 EFI_OUT_OF_RESOURCES - The request could not be completed due to a lack of resources.
461 Status
= SystemTable
->BootServices
->InstallProtocolInterface (
463 &gEfiCpuIoProtocolGuid
,
464 EFI_NATIVE_INTERFACE
,
467 ASSERT_EFI_ERROR (Status
);
473 CpuIoCheckParameter (
474 IN EFI_CPU_IO_PROTOCOL_WIDTH Width
,
484 Check the validation of parameters for CPU I/O interface functions.
488 Width - Width of the Memory Access
489 Address - Address of the Memory access
490 Count - Count of the number of accesses to perform
491 Buffer - Pointer to the buffer to read from memory
492 Buffer - Memory buffer for the I/O operation
493 Limit - Maximum address supported
497 EFI_INVALID_PARAMETER - Buffer is NULL
498 EFI_UNSUPPORTED - The address range specified by Width, Address and Count is invalid
499 EFI_UNSUPPORTED - The memory buffer is not aligned
500 EFI_SUCCESS - Parameters are OK
506 if (Buffer
== NULL
) {
507 return EFI_INVALID_PARAMETER
;
510 if (Address
> Limit
) {
511 return EFI_UNSUPPORTED
;
515 // For FiFo type, the target address won't increase during the access,
516 // so treat count as 1
518 if (Width
>= EfiCpuIoWidthFifoUint8
&& Width
<= EfiCpuIoWidthFifoUint64
) {
522 Width
= Width
& 0x03;
523 if (Address
- 1 + ((UINTN
)1 << Width
) * Count
> Limit
) {
524 return EFI_UNSUPPORTED
;
527 AlignMask
= ((UINTN
)1 << Width
) - 1;
528 if ((UINTN
) Buffer
& AlignMask
) {
529 return EFI_UNSUPPORTED
;