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
27 #define IA32_MAX_IO_ADDRESS 0xFFFF
29 EFI_CPU_IO_PROTOCOL mCpuIo
= {
42 IN EFI_CPU_IO_PROTOCOL_WIDTH Width
,
44 IN BOOLEAN DestinationStrideFlag
,
46 IN BOOLEAN SourceStrideFlag
,
53 Private service to perform memory mapped I/O read/write
57 Width - Width of the memory mapped I/O operation
58 Count - Count of the number of accesses to perform
59 DestinationStrideFlag - Boolean flag indicates if the destination is to be incremented
60 Destination - Destination of the memory mapped I/O operation
61 SourceStrideFlag - Boolean flag indicates if the source is to be incremented
62 Source - Source of the memory mapped I/O operation
66 EFI_SUCCESS - Successful operation
67 EFI_INVALID_PARAMETER - Width is invalid
72 UINTN DestinationStride
;
75 Width
= (EFI_CPU_IO_PROTOCOL_WIDTH
) (Width
& 0x03);
76 Stride
= (UINTN
)1 << Width
;
77 DestinationStride
= DestinationStrideFlag
? Stride
: 0;
78 SourceStride
= SourceStrideFlag
? Stride
: 0;
81 // Loop for each iteration and move the data
84 case EfiCpuIoWidthUint8
:
85 for (; Count
> 0; Count
--, Destination
.buf
+= DestinationStride
, Source
.buf
+= SourceStride
) {
87 *Destination
.ui8
= *Source
.ui8
;
92 case EfiCpuIoWidthUint16
:
93 for (; Count
> 0; Count
--, Destination
.buf
+= DestinationStride
, Source
.buf
+= SourceStride
) {
95 *Destination
.ui16
= *Source
.ui16
;
100 case EfiCpuIoWidthUint32
:
101 for (; Count
> 0; Count
--, Destination
.buf
+= DestinationStride
, Source
.buf
+= SourceStride
) {
103 *Destination
.ui32
= *Source
.ui32
;
108 case EfiCpuIoWidthUint64
:
109 for (; Count
> 0; Count
--, Destination
.buf
+= DestinationStride
, Source
.buf
+= SourceStride
) {
111 *Destination
.ui64
= *Source
.ui64
;
117 return EFI_INVALID_PARAMETER
;
125 CpuMemoryServiceRead (
126 IN EFI_CPU_IO_PROTOCOL
*This
,
127 IN EFI_CPU_IO_PROTOCOL_WIDTH Width
,
136 Perform the memory mapped I/O read service
140 This - Pointer to an instance of the CPU I/O Protocol
141 Width - Width of the memory mapped I/O operation
142 Address - Base address of the memory mapped I/O operation
143 Count - Count of the number of accesses to perform
144 Buffer - Pointer to the destination buffer to store the results
148 EFI_SUCCESS - The data was read.
149 EFI_INVALID_PARAMETER - Width is invalid.
150 EFI_INVALID_PARAMETER - Buffer is NULL.
151 EFI_UNSUPPORTED - The Buffer is not aligned for the given Width.
152 EFI_UNSUPPORTED - The address range specified by Address, Width,
153 and Count is not valid.
161 Status
= CpuIoCheckParameter (Width
, Address
, Count
, Buffer
, MAX_ADDRESS
);
162 if (EFI_ERROR (Status
)) {
166 Destination
.buf
= Buffer
;
167 Source
.buf
= (VOID
*) (UINTN
) Address
;
169 if (Width
>= EfiCpuIoWidthUint8
&& Width
<= EfiCpuIoWidthUint64
) {
170 return CpuIoMemRW (Width
, Count
, TRUE
, Destination
, TRUE
, Source
);
173 if (Width
>= EfiCpuIoWidthFifoUint8
&& Width
<= EfiCpuIoWidthFifoUint64
) {
174 return CpuIoMemRW (Width
, Count
, TRUE
, Destination
, FALSE
, Source
);
177 if (Width
>= EfiCpuIoWidthFillUint8
&& Width
<= EfiCpuIoWidthFillUint64
) {
178 return CpuIoMemRW (Width
, Count
, FALSE
, Destination
, TRUE
, Source
);
181 return EFI_INVALID_PARAMETER
;
186 CpuMemoryServiceWrite (
187 IN EFI_CPU_IO_PROTOCOL
*This
,
188 IN EFI_CPU_IO_PROTOCOL_WIDTH Width
,
197 Perform the memory mapped I/O write service
201 This - Pointer to an instance of the CPU I/O Protocol
202 Width - Width of the memory mapped I/O operation
203 Address - Base address of the memory mapped I/O operation
204 Count - Count of the number of accesses to perform
205 Buffer - Pointer to the source buffer from which to write data
209 EFI_SUCCESS - The data was written.
210 EFI_INVALID_PARAMETER - Width is invalid.
211 EFI_INVALID_PARAMETER - Buffer is NULL.
212 EFI_UNSUPPORTED - The Buffer is not aligned for the given Width.
213 EFI_UNSUPPORTED - The address range specified by Address, Width,
214 and Count is not valid.
222 Status
= CpuIoCheckParameter (Width
, Address
, Count
, Buffer
, MAX_ADDRESS
);
223 if (EFI_ERROR (Status
)) {
227 Destination
.buf
= (VOID
*) (UINTN
) Address
;
230 if (Width
>= EfiCpuIoWidthUint8
&& Width
<= EfiCpuIoWidthUint64
) {
231 return CpuIoMemRW (Width
, Count
, TRUE
, Destination
, TRUE
, Source
);
234 if (Width
>= EfiCpuIoWidthFifoUint8
&& Width
<= EfiCpuIoWidthFifoUint64
) {
235 return CpuIoMemRW (Width
, Count
, FALSE
, Destination
, TRUE
, Source
);
238 if (Width
>= EfiCpuIoWidthFillUint8
&& Width
<= EfiCpuIoWidthFillUint64
) {
239 return CpuIoMemRW (Width
, Count
, TRUE
, Destination
, FALSE
, Source
);
242 return EFI_INVALID_PARAMETER
;
248 IN EFI_CPU_IO_PROTOCOL
*This
,
249 IN EFI_CPU_IO_PROTOCOL_WIDTH Width
,
250 IN UINT64 UserAddress
,
258 Perform the port I/O read service
262 This - Pointer to an instance of the CPU I/O Protocol
263 Width - Width of the port I/O operation
264 Address - Base address of the port I/O operation
265 Count - Count of the number of accesses to perform
266 Buffer - Pointer to the destination buffer to store the results
270 EFI_SUCCESS - The data was read.
271 EFI_INVALID_PARAMETER - Width is invalid.
272 EFI_INVALID_PARAMETER - Buffer is NULL.
273 EFI_UNSUPPORTED - The Buffer is not aligned for the given Width.
274 EFI_UNSUPPORTED - The address range specified by Address, Width,
275 and Count is not valid.
285 Buffer
.buf
= (UINT8
*) UserBuffer
;
287 if (Width
>= EfiCpuIoWidthMaximum
) {
288 return EFI_INVALID_PARAMETER
;
291 Status
= CpuIoCheckParameter (Width
, UserAddress
, Count
, UserBuffer
, IA32_MAX_IO_ADDRESS
);
292 if (EFI_ERROR (Status
)) {
296 Address
= (UINTN
) UserAddress
;
297 InStride
= (UINTN
)1 << (Width
& 0x03);
298 OutStride
= InStride
;
299 if (Width
>= EfiCpuIoWidthFifoUint8
&& Width
<= EfiCpuIoWidthFifoUint64
) {
303 if (Width
>= EfiCpuIoWidthFillUint8
&& Width
<= EfiCpuIoWidthFillUint64
) {
307 Width
= (EFI_CPU_IO_PROTOCOL_WIDTH
) (Width
& 0x03);
310 // Loop for each iteration and move the data
313 case EfiCpuIoWidthUint8
:
314 for (; Count
> 0; Count
--, Buffer
.buf
+= OutStride
, Address
+= InStride
) {
315 *Buffer
.ui8
= IoRead8 ((UINTN
) Address
);
319 case EfiCpuIoWidthUint16
:
320 for (; Count
> 0; Count
--, Buffer
.buf
+= OutStride
, Address
+= InStride
) {
321 *Buffer
.ui16
= IoRead16 ((UINTN
) Address
);
325 case EfiCpuIoWidthUint32
:
326 for (; Count
> 0; Count
--, Buffer
.buf
+= OutStride
, Address
+= InStride
) {
327 *Buffer
.ui32
= IoRead32 ((UINTN
) Address
);
332 return EFI_INVALID_PARAMETER
;
341 IN EFI_CPU_IO_PROTOCOL
*This
,
342 IN EFI_CPU_IO_PROTOCOL_WIDTH Width
,
343 IN UINT64 UserAddress
,
351 Perform the port I/O write service
355 This - Pointer to an instance of the CPU I/O Protocol
356 Width - Width of the port I/O operation
357 Address - Base address of the port I/O operation
358 Count - Count of the number of accesses to perform
359 Buffer - Pointer to the source buffer from which to write data
363 EFI_SUCCESS - The data was written.
364 EFI_INVALID_PARAMETER - Width is invalid.
365 EFI_INVALID_PARAMETER - Buffer is NULL.
366 EFI_UNSUPPORTED - The Buffer is not aligned for the given Width.
367 EFI_UNSUPPORTED - The address range specified by Address, Width,
368 and Count is not valid.
378 Buffer
.buf
= (UINT8
*) UserBuffer
;
380 if (Width
>= EfiCpuIoWidthMaximum
) {
381 return EFI_INVALID_PARAMETER
;
384 Status
= CpuIoCheckParameter (Width
, UserAddress
, Count
, UserBuffer
, IA32_MAX_IO_ADDRESS
);
385 if (EFI_ERROR (Status
)) {
389 Address
= (UINTN
) UserAddress
;
390 InStride
= (UINTN
)1 << (Width
& 0x03);
391 OutStride
= InStride
;
392 if (Width
>= EfiCpuIoWidthFifoUint8
&& Width
<= EfiCpuIoWidthFifoUint64
) {
396 if (Width
>= EfiCpuIoWidthFillUint8
&& Width
<= EfiCpuIoWidthFillUint64
) {
400 Width
= (EFI_CPU_IO_PROTOCOL_WIDTH
) (Width
& 0x03);
403 // Loop for each iteration and move the data
406 case EfiCpuIoWidthUint8
:
407 for (; Count
> 0; Count
--, Buffer
.buf
+= OutStride
, Address
+= InStride
) {
408 IoWrite8 ((UINTN
) Address
, *Buffer
.ui8
);
412 case EfiCpuIoWidthUint16
:
413 for (; Count
> 0; Count
--, Buffer
.buf
+= OutStride
, Address
+= InStride
) {
414 IoWrite16 ((UINTN
) Address
, *Buffer
.ui16
);
418 case EfiCpuIoWidthUint32
:
419 for (; Count
> 0; Count
--, Buffer
.buf
+= OutStride
, Address
+= InStride
) {
420 IoWrite32 ((UINTN
) Address
, *Buffer
.ui32
);
425 return EFI_INVALID_PARAMETER
;
434 IN EFI_HANDLE ImageHandle
,
435 IN EFI_SYSTEM_TABLE
*SystemTable
441 CpuIo driver entry point.
445 ImageHandle - The firmware allocated handle for the EFI image.
446 SystemTable - A pointer to the EFI System Table.
450 EFI_SUCCESS - The driver was initialized.
451 EFI_OUT_OF_RESOURCES - The request could not be completed due to a lack of resources.
459 Status
= SystemTable
->BootServices
->InstallProtocolInterface (
461 &gEfiCpuIoProtocolGuid
,
462 EFI_NATIVE_INTERFACE
,
465 ASSERT_EFI_ERROR (Status
);
471 CpuIoCheckParameter (
472 IN EFI_CPU_IO_PROTOCOL_WIDTH Width
,
482 Check the validation of parameters for CPU I/O interface functions.
486 Width - Width of the Memory Access
487 Address - Address of the Memory access
488 Count - Count of the number of accesses to perform
489 Buffer - Pointer to the buffer to read from memory
490 Buffer - Memory buffer for the I/O operation
491 Limit - Maximum address supported
495 EFI_INVALID_PARAMETER - Buffer is NULL
496 EFI_UNSUPPORTED - The address range specified by Width, Address and Count is invalid
497 EFI_UNSUPPORTED - The memory buffer is not aligned
498 EFI_SUCCESS - Parameters are OK
504 if (Buffer
== NULL
) {
505 return EFI_INVALID_PARAMETER
;
508 if (Address
> Limit
) {
509 return EFI_UNSUPPORTED
;
513 // For FiFo type, the target address won't increase during the access,
514 // so treat count as 1
516 if (Width
>= EfiCpuIoWidthFifoUint8
&& Width
<= EfiCpuIoWidthFifoUint64
) {
520 Width
= (EFI_CPU_IO_PROTOCOL_WIDTH
) (Width
& 0x03);
521 if (Address
- 1 + ((UINTN
)1 << Width
) * Count
> Limit
) {
522 return EFI_UNSUPPORTED
;
525 AlignMask
= ((UINTN
)1 << Width
) - 1;
526 if ((UINTN
) Buffer
& AlignMask
) {
527 return EFI_UNSUPPORTED
;