| /*++ @file | |
| This is the code that publishes the CPU I/O Protocol. | |
| The intent herein is to have a single I/O service that can load | |
| as early as possible, extend into runtime, and be layered upon by | |
| the implementations of architectural protocols and the PCI Root | |
| Bridge I/O Protocol. | |
| Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR> | |
| Portions copyright (c) 2011, Apple Inc. All rights reserved. | |
| This program and the accompanying materials | |
| are licensed and made available under the terms and conditions of the BSD License | |
| which accompanies this distribution. The full text of the license may be found at | |
| http://opensource.org/licenses/bsd-license.php | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| **/ | |
| #include <PiDxe.h> | |
| #include <Protocol/Cpu.h> | |
| #include <Protocol/CpuIo2.h> | |
| #include <Library/BaseLib.h> | |
| #include <Library/DebugLib.h> | |
| #include <Library/HiiLib.h> | |
| #include <Library/UefiLib.h> | |
| #include <Library/UefiDriverEntryPoint.h> | |
| #include <Library/BaseMemoryLib.h> | |
| #include <Library/MemoryAllocationLib.h> | |
| #include <Library/UefiBootServicesTableLib.h> | |
| #include <CpuDriver.h> | |
| #define IA32_MAX_IO_ADDRESS 0xFFFF | |
| #define IA32_MAX_MEM_ADDRESS 0xFFFFFFFF | |
| EFI_STATUS | |
| CpuIoCheckAddressRange ( | |
| IN EFI_CPU_IO_PROTOCOL_WIDTH Width, | |
| IN UINT64 Address, | |
| IN UINTN Count, | |
| IN VOID *Buffer, | |
| IN UINT64 Limit | |
| ); | |
| EFI_STATUS | |
| EFIAPI | |
| CpuMemoryServiceRead ( | |
| IN EFI_CPU_IO2_PROTOCOL *This, | |
| IN EFI_CPU_IO_PROTOCOL_WIDTH Width, | |
| IN UINT64 Address, | |
| IN UINTN Count, | |
| IN OUT VOID *Buffer | |
| ) | |
| /*++ | |
| Routine Description: | |
| Perform the Memory Access Read service for the CPU I/O Protocol | |
| Arguments: | |
| Pointer to an instance of the CPU I/O Protocol | |
| Width of the Memory Access | |
| Address of the Memory access | |
| Count of the number of accesses to perform | |
| Pointer to the buffer to read or write from memory | |
| Returns: | |
| Status | |
| EFI_SUCCESS - The data was read from or written to the EFI | |
| System. | |
| EFI_INVALID_PARAMETER - Width is invalid for this EFI System. | |
| EFI_INVALID_PARAMETER - Buffer is NULL. | |
| EFI_UNSUPPORTED - The Buffer is not aligned for the given Width. | |
| EFI_UNSUPPORTED - The address range specified by Address, Width, | |
| and Count is not valid for this EFI System. | |
| **/ | |
| { | |
| EFI_STATUS Status; | |
| if (!Buffer) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| Status = CpuIoCheckAddressRange (Width, Address, Count, Buffer, IA32_MAX_MEM_ADDRESS); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| // | |
| // Do nothing for Nt32 version | |
| // | |
| return EFI_SUCCESS; | |
| } | |
| EFI_STATUS | |
| EFIAPI | |
| CpuMemoryServiceWrite ( | |
| IN EFI_CPU_IO2_PROTOCOL *This, | |
| IN EFI_CPU_IO_PROTOCOL_WIDTH Width, | |
| IN UINT64 Address, | |
| IN UINTN Count, | |
| IN OUT VOID *Buffer | |
| ) | |
| /*++ | |
| Routine Description: | |
| Perform the Memory Access Read service for the CPU I/O Protocol | |
| Arguments: | |
| Pointer to an instance of the CPU I/O Protocol | |
| Width of the Memory Access | |
| Address of the Memory access | |
| Count of the number of accesses to perform | |
| Pointer to the buffer to read or write from memory | |
| Returns: | |
| Status | |
| EFI_SUCCESS - The data was read from or written to the EFI System. | |
| EFI_INVALID_PARAMETER - Width is invalid for this EFI System. | |
| EFI_INVALID_PARAMETER - Buffer is NULL. | |
| EFI_UNSUPPORTED - The Buffer is not aligned for the given Width. | |
| EFI_UNSUPPORTED - The address range specified by Address, Width, and | |
| Count is not valid for this EFI System. | |
| **/ | |
| { | |
| EFI_STATUS Status; | |
| if (!Buffer) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| Status = CpuIoCheckAddressRange (Width, Address, Count, Buffer, IA32_MAX_MEM_ADDRESS); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| // | |
| // Do nothing for Nt32 version | |
| // | |
| return EFI_SUCCESS; | |
| } | |
| EFI_STATUS | |
| EFIAPI | |
| CpuIoServiceRead ( | |
| IN EFI_CPU_IO2_PROTOCOL *This, | |
| IN EFI_CPU_IO_PROTOCOL_WIDTH Width, | |
| IN UINT64 UserAddress, | |
| IN UINTN Count, | |
| IN OUT VOID *UserBuffer | |
| ) | |
| /*++ | |
| Routine Description: | |
| This is the service that implements the I/O read | |
| Arguments: | |
| Pointer to an instance of the CPU I/O Protocol | |
| Width of the Memory Access | |
| Address of the I/O access | |
| Count of the number of accesses to perform | |
| Pointer to the buffer to read or write from I/O space | |
| Returns: | |
| Status | |
| EFI_SUCCESS - The data was read from or written to the EFI System. | |
| EFI_INVALID_PARAMETER - Width is invalid for this EFI System. | |
| EFI_INVALID_PARAMETER - Buffer is NULL. | |
| EFI_UNSUPPORTED - The Buffer is not aligned for the given Width. | |
| EFI_UNSUPPORTED - The address range specified by Address, Width, and | |
| Count is not valid for this EFI System. | |
| **/ | |
| { | |
| UINTN Address; | |
| EFI_STATUS Status; | |
| if (!UserBuffer) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| Address = (UINTN) UserAddress; | |
| if (Width >= EfiCpuIoWidthMaximum) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| Status = CpuIoCheckAddressRange (Width, Address, Count, UserBuffer, IA32_MAX_IO_ADDRESS); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| // | |
| // Do nothing for Nt32 version | |
| // | |
| return EFI_SUCCESS; | |
| } | |
| EFI_STATUS | |
| EFIAPI | |
| CpuIoServiceWrite ( | |
| IN EFI_CPU_IO2_PROTOCOL *This, | |
| IN EFI_CPU_IO_PROTOCOL_WIDTH Width, | |
| IN UINT64 UserAddress, | |
| IN UINTN Count, | |
| IN OUT VOID *UserBuffer | |
| ) | |
| /*++ | |
| Routine Description: | |
| This is the service that implements the I/O Write | |
| Arguments: | |
| Pointer to an instance of the CPU I/O Protocol | |
| Width of the Memory Access | |
| Address of the I/O access | |
| Count of the number of accesses to perform | |
| Pointer to the buffer to read or write from I/O space | |
| Returns: | |
| Status | |
| Status | |
| EFI_SUCCESS - The data was read from or written to the EFI System. | |
| EFI_INVALID_PARAMETER - Width is invalid for this EFI System. | |
| EFI_INVALID_PARAMETER - Buffer is NULL. | |
| EFI_UNSUPPORTED - The Buffer is not aligned for the given Width. | |
| EFI_UNSUPPORTED - The address range specified by Address, Width, and | |
| Count is not valid for this EFI System. | |
| **/ | |
| { | |
| UINTN Address; | |
| EFI_STATUS Status; | |
| if (!UserBuffer) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| Address = (UINTN) UserAddress; | |
| if (Width >= EfiCpuIoWidthMaximum) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| Status = CpuIoCheckAddressRange (Width, Address, Count, UserBuffer, IA32_MAX_IO_ADDRESS); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| // | |
| // Do nothing for Nt32 version | |
| // | |
| return EFI_SUCCESS; | |
| } | |
| /*++ | |
| Routine Description: | |
| Arguments: | |
| Width - TODO: add argument description | |
| Address - TODO: add argument description | |
| Count - TODO: add argument description | |
| Buffer - TODO: add argument description | |
| Limit - TODO: add argument description | |
| Returns: | |
| EFI_UNSUPPORTED - TODO: Add description for return value | |
| EFI_UNSUPPORTED - TODO: Add description for return value | |
| EFI_UNSUPPORTED - TODO: Add description for return value | |
| EFI_SUCCESS - TODO: Add description for return value | |
| **/ | |
| EFI_STATUS | |
| CpuIoCheckAddressRange ( | |
| IN EFI_CPU_IO_PROTOCOL_WIDTH Width, | |
| IN UINT64 Address, | |
| IN UINTN Count, | |
| IN VOID *Buffer, | |
| IN UINT64 Limit | |
| ) | |
| { | |
| UINTN AlignMask; | |
| if (Address > Limit) { | |
| return EFI_UNSUPPORTED; | |
| } | |
| // | |
| // For FiFo type, the target address won't increase during the access, so treat count as 1 | |
| // | |
| if (Width >= EfiCpuIoWidthFifoUint8 && Width <= EfiCpuIoWidthFifoUint64) { | |
| Count = 1; | |
| } | |
| Width = Width & 0x03; | |
| if ((Address - 1 + LShiftU64 (Count, Width)) > Limit) { | |
| return EFI_UNSUPPORTED; | |
| } | |
| AlignMask = (1 << Width) - 1; | |
| if ((UINTN) Buffer & AlignMask) { | |
| return EFI_UNSUPPORTED; | |
| } | |
| return EFI_SUCCESS; | |
| } | |