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
= {
43 IN EFI_CPU_IO_PROTOCOL_WIDTH Width
,
45 IN BOOLEAN DestinationStrideFlag
,
47 IN BOOLEAN SourceStrideFlag
,
54 Private service to perform memory mapped I/O read/write
58 Width - Width of the memory mapped I/O operation
59 Count - Count of the number of accesses to perform
60 DestinationStrideFlag - Boolean flag indicates if the destination is to be incremented
61 Destination - Destination of the memory mapped I/O operation
62 SourceStrideFlag - Boolean flag indicates if the source is to be incremented
63 Source - Source of the memory mapped I/O operation
67 EFI_SUCCESS - Successful operation
68 EFI_INVALID_PARAMETER - Width is invalid
73 UINTN DestinationStride
;
77 Stride
= (UINTN
)1 << Width
;
78 DestinationStride
= DestinationStrideFlag
? Stride
: 0;
79 SourceStride
= SourceStrideFlag
? Stride
: 0;
82 // Loop for each iteration and move the data
85 case EfiCpuIoWidthUint8
:
86 for (; Count
> 0; Count
--, Destination
.buf
+= DestinationStride
, Source
.buf
+= SourceStride
) {
88 *Destination
.ui8
= *Source
.ui8
;
93 case EfiCpuIoWidthUint16
:
94 for (; Count
> 0; Count
--, Destination
.buf
+= DestinationStride
, Source
.buf
+= SourceStride
) {
96 *Destination
.ui16
= *Source
.ui16
;
101 case EfiCpuIoWidthUint32
:
102 for (; Count
> 0; Count
--, Destination
.buf
+= DestinationStride
, Source
.buf
+= SourceStride
) {
104 *Destination
.ui32
= *Source
.ui32
;
109 case EfiCpuIoWidthUint64
:
110 for (; Count
> 0; Count
--, Destination
.buf
+= DestinationStride
, Source
.buf
+= SourceStride
) {
112 *Destination
.ui64
= *Source
.ui64
;
118 return EFI_INVALID_PARAMETER
;
126 CpuMemoryServiceRead (
127 IN EFI_CPU_IO_PROTOCOL
*This
,
128 IN EFI_CPU_IO_PROTOCOL_WIDTH Width
,
137 Perform the memory mapped I/O read service
141 This - Pointer to an instance of the CPU I/O Protocol
142 Width - Width of the memory mapped I/O operation
143 Address - Base address of the memory mapped I/O operation
144 Count - Count of the number of accesses to perform
145 Buffer - Pointer to the destination buffer to store the results
149 EFI_SUCCESS - The data was read.
150 EFI_INVALID_PARAMETER - Width is invalid.
151 EFI_INVALID_PARAMETER - Buffer is NULL.
152 EFI_UNSUPPORTED - The Buffer is not aligned for the given Width.
153 EFI_UNSUPPORTED - The address range specified by Address, Width,
154 and Count is not valid.
162 Status
= CpuIoCheckParameter (Width
, Address
, Count
, Buffer
, EFI_MAX_ADDRESS
);
163 if (EFI_ERROR (Status
)) {
167 Destination
.buf
= Buffer
;
168 Source
.buf
= (VOID
*) (UINTN
) Address
;
170 if (Width
>= EfiCpuIoWidthUint8
&& Width
<= EfiCpuIoWidthUint64
) {
171 return CpuIoMemRW (Width
, Count
, TRUE
, Destination
, TRUE
, Source
);
174 if (Width
>= EfiCpuIoWidthFifoUint8
&& Width
<= EfiCpuIoWidthFifoUint64
) {
175 return CpuIoMemRW (Width
, Count
, TRUE
, Destination
, FALSE
, Source
);
178 if (Width
>= EfiCpuIoWidthFillUint8
&& Width
<= EfiCpuIoWidthFillUint64
) {
179 return CpuIoMemRW (Width
, Count
, FALSE
, Destination
, TRUE
, Source
);
182 return EFI_INVALID_PARAMETER
;
187 CpuMemoryServiceWrite (
188 IN EFI_CPU_IO_PROTOCOL
*This
,
189 IN EFI_CPU_IO_PROTOCOL_WIDTH Width
,
198 Perform the memory mapped I/O write service
202 This - Pointer to an instance of the CPU I/O Protocol
203 Width - Width of the memory mapped I/O operation
204 Address - Base address of the memory mapped I/O operation
205 Count - Count of the number of accesses to perform
206 Buffer - Pointer to the source buffer from which to write data
210 EFI_SUCCESS - The data was written.
211 EFI_INVALID_PARAMETER - Width is invalid.
212 EFI_INVALID_PARAMETER - Buffer is NULL.
213 EFI_UNSUPPORTED - The Buffer is not aligned for the given Width.
214 EFI_UNSUPPORTED - The address range specified by Address, Width,
215 and Count is not valid.
223 Status
= CpuIoCheckParameter (Width
, Address
, Count
, Buffer
, EFI_MAX_ADDRESS
);
224 if (EFI_ERROR (Status
)) {
228 Destination
.buf
= (VOID
*) (UINTN
) Address
;
231 if (Width
>= EfiCpuIoWidthUint8
&& Width
<= EfiCpuIoWidthUint64
) {
232 return CpuIoMemRW (Width
, Count
, TRUE
, Destination
, TRUE
, Source
);
235 if (Width
>= EfiCpuIoWidthFifoUint8
&& Width
<= EfiCpuIoWidthFifoUint64
) {
236 return CpuIoMemRW (Width
, Count
, FALSE
, Destination
, TRUE
, Source
);
239 if (Width
>= EfiCpuIoWidthFillUint8
&& Width
<= EfiCpuIoWidthFillUint64
) {
240 return CpuIoMemRW (Width
, Count
, TRUE
, Destination
, FALSE
, Source
);
243 return EFI_INVALID_PARAMETER
;
249 IN EFI_CPU_IO_PROTOCOL
*This
,
250 IN EFI_CPU_IO_PROTOCOL_WIDTH Width
,
251 IN UINT64 UserAddress
,
259 Perform the port I/O read service
263 This - Pointer to an instance of the CPU I/O Protocol
264 Width - Width of the port I/O operation
265 Address - Base address of the port I/O operation
266 Count - Count of the number of accesses to perform
267 Buffer - Pointer to the destination buffer to store the results
271 EFI_SUCCESS - The data was read.
272 EFI_INVALID_PARAMETER - Width is invalid.
273 EFI_INVALID_PARAMETER - Buffer is NULL.
274 EFI_UNSUPPORTED - The Buffer is not aligned for the given Width.
275 EFI_UNSUPPORTED - The address range specified by Address, Width,
276 and Count is not valid.
286 Buffer
.buf
= (UINT8
*) UserBuffer
;
288 if (Width
>= EfiCpuIoWidthMaximum
) {
289 return EFI_INVALID_PARAMETER
;
292 Status
= CpuIoCheckParameter (Width
, UserAddress
, Count
, UserBuffer
, IA32_MAX_IO_ADDRESS
);
293 if (EFI_ERROR (Status
)) {
297 Address
= (UINTN
) UserAddress
;
298 InStride
= (UINTN
)1 << (Width
& 0x03);
299 OutStride
= InStride
;
300 if (Width
>= EfiCpuIoWidthFifoUint8
&& Width
<= EfiCpuIoWidthFifoUint64
) {
304 if (Width
>= EfiCpuIoWidthFillUint8
&& Width
<= EfiCpuIoWidthFillUint64
) {
308 Width
= Width
& 0x03;
311 // Loop for each iteration and move the data
314 case EfiCpuIoWidthUint8
:
315 for (; Count
> 0; Count
--, Buffer
.buf
+= OutStride
, Address
+= InStride
) {
316 *Buffer
.ui8
= CpuIoRead8 ((UINT16
) Address
);
320 case EfiCpuIoWidthUint16
:
321 for (; Count
> 0; Count
--, Buffer
.buf
+= OutStride
, Address
+= InStride
) {
322 *Buffer
.ui16
= CpuIoRead16 ((UINT16
) Address
);
326 case EfiCpuIoWidthUint32
:
327 for (; Count
> 0; Count
--, Buffer
.buf
+= OutStride
, Address
+= InStride
) {
328 *Buffer
.ui32
= CpuIoRead32 ((UINT16
) Address
);
333 return EFI_INVALID_PARAMETER
;
342 IN EFI_CPU_IO_PROTOCOL
*This
,
343 IN EFI_CPU_IO_PROTOCOL_WIDTH Width
,
344 IN UINT64 UserAddress
,
352 Perform the port I/O write service
356 This - Pointer to an instance of the CPU I/O Protocol
357 Width - Width of the port I/O operation
358 Address - Base address of the port I/O operation
359 Count - Count of the number of accesses to perform
360 Buffer - Pointer to the source buffer from which to write data
364 EFI_SUCCESS - The data was written.
365 EFI_INVALID_PARAMETER - Width is invalid.
366 EFI_INVALID_PARAMETER - Buffer is NULL.
367 EFI_UNSUPPORTED - The Buffer is not aligned for the given Width.
368 EFI_UNSUPPORTED - The address range specified by Address, Width,
369 and Count is not valid.
379 Buffer
.buf
= (UINT8
*) UserBuffer
;
381 if (Width
>= EfiCpuIoWidthMaximum
) {
382 return EFI_INVALID_PARAMETER
;
385 Status
= CpuIoCheckParameter (Width
, UserAddress
, Count
, UserBuffer
, IA32_MAX_IO_ADDRESS
);
386 if (EFI_ERROR (Status
)) {
390 Address
= (UINTN
) UserAddress
;
391 InStride
= (UINTN
)1 << (Width
& 0x03);
392 OutStride
= InStride
;
393 if (Width
>= EfiCpuIoWidthFifoUint8
&& Width
<= EfiCpuIoWidthFifoUint64
) {
397 if (Width
>= EfiCpuIoWidthFillUint8
&& Width
<= EfiCpuIoWidthFillUint64
) {
401 Width
= Width
& 0x03;
404 // Loop for each iteration and move the data
407 case EfiCpuIoWidthUint8
:
408 for (; Count
> 0; Count
--, Buffer
.buf
+= OutStride
, Address
+= InStride
) {
409 CpuIoWrite8 ((UINT16
) Address
, *Buffer
.ui8
);
413 case EfiCpuIoWidthUint16
:
414 for (; Count
> 0; Count
--, Buffer
.buf
+= OutStride
, Address
+= InStride
) {
415 CpuIoWrite16 ((UINT16
) Address
, *Buffer
.ui16
);
419 case EfiCpuIoWidthUint32
:
420 for (; Count
> 0; Count
--, Buffer
.buf
+= OutStride
, Address
+= InStride
) {
421 CpuIoWrite32 ((UINT16
) Address
, *Buffer
.ui32
);
426 return EFI_INVALID_PARAMETER
;
435 IN EFI_HANDLE ImageHandle
,
436 IN EFI_SYSTEM_TABLE
*SystemTable
442 CpuIo driver entry point.
446 ImageHandle - The firmware allocated handle for the EFI image.
447 SystemTable - A pointer to the EFI System Table.
451 EFI_SUCCESS - The driver was initialized.
452 EFI_OUT_OF_RESOURCES - The request could not be completed due to a lack of resources.
460 Status
= SystemTable
->BootServices
->InstallProtocolInterface (
462 &gEfiCpuIoProtocolGuid
,
463 EFI_NATIVE_INTERFACE
,
466 ASSERT_EFI_ERROR (Status
);
472 CpuIoCheckParameter (
473 IN EFI_CPU_IO_PROTOCOL_WIDTH Width
,
483 Check the validation of parameters for CPU I/O interface functions.
487 Width - Width of the Memory Access
488 Address - Address of the Memory access
489 Count - Count of the number of accesses to perform
490 Buffer - Pointer to the buffer to read from memory
491 Buffer - Memory buffer for the I/O operation
492 Limit - Maximum address supported
496 EFI_INVALID_PARAMETER - Buffer is NULL
497 EFI_UNSUPPORTED - The address range specified by Width, Address and Count is invalid
498 EFI_UNSUPPORTED - The memory buffer is not aligned
499 EFI_SUCCESS - Parameters are OK
505 if (Buffer
== NULL
) {
506 return EFI_INVALID_PARAMETER
;
509 if (Address
> Limit
) {
510 return EFI_UNSUPPORTED
;
514 // For FiFo type, the target address won't increase during the access,
515 // so treat count as 1
517 if (Width
>= EfiCpuIoWidthFifoUint8
&& Width
<= EfiCpuIoWidthFifoUint64
) {
521 Width
= Width
& 0x03;
522 if (Address
- 1 + ((UINTN
)1 << Width
) * Count
> Limit
) {
523 return EFI_UNSUPPORTED
;
526 AlignMask
= ((UINTN
)1 << Width
) - 1;
527 if ((UINTN
) Buffer
& AlignMask
) {
528 return EFI_UNSUPPORTED
;