325 lines
7.9 KiB
C
325 lines
7.9 KiB
C
|
/*++ @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.
|
||
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||
|
|
||
|
**/
|
||
|
|
||
|
#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;
|
||
|
}
|
||
|
|
||
|
|