isaio.c
来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 778 行 · 第 1/2 页
C
778 行
IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);
//
// Initialize the return values to their defaults
//
*Mapping = NULL;
//
// Make sure the Operation parameter is valid
//
if (Operation < 0 || Operation >= EfiIsaIoOperationMaximum) {
return EFI_INVALID_PARAMETER;
}
//
// See if this is a Slave DMA Operation
//
Master = TRUE;
Read = FALSE;
if (Operation == EfiIsaIoOperationSlaveRead) {
Operation = EfiIsaIoOperationBusMasterRead;
Master = FALSE;
Read = TRUE;
}
if (Operation == EfiIsaIoOperationSlaveWrite) {
Operation = EfiIsaIoOperationBusMasterWrite;
Master = FALSE;
Read = FALSE;
}
if (!Master) {
//
// Make sure that ChannelNumber is a valid channel number
// Channel 4 is used to cascade, so it is illegal.
//
if (ChannelNumber == 4 || ChannelNumber > 7) {
return EFI_INVALID_PARAMETER;
}
//
// This implementation only support COMPATIBLE DMA Transfers
//
if (!(ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_COMPATIBLE)) {
return EFI_INVALID_PARAMETER;
}
if (ChannelAttributes &
(
EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_A |
EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_B |
EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_C
)
) {
return EFI_INVALID_PARAMETER;
}
if (ChannelNumber < 4) {
//
// If this is Channel 0..3, then the width must be 8 bit
//
if (!(ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_8) ||
(ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_16)
) {
return EFI_INVALID_PARAMETER;
}
} else {
//
// If this is Channel 4..7, then the width must be 16 bit
//
if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_8) ||
(!(ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_16))
) {
return EFI_INVALID_PARAMETER;
}
}
//
// Either Demand Mode or Single Mode must be selected, but not both
//
if (ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SINGLE_MODE) {
if (ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_DEMAND_MODE) {
return EFI_INVALID_PARAMETER;
}
} else {
if (!(ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_DEMAND_MODE)) {
return EFI_INVALID_PARAMETER;
}
}
}
//
// Map the HostAddress to a DeviceAddress.
//
PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress;
if ((PhysicalAddress +*NumberOfBytes) > ISA_MAX_MEMORY_ADDRESS) {
//
// Common Buffer operations can not be remapped. If the common buffer
// is above 16MB, then it is not possible to generate a mapping, so return
// an error.
//
if (Operation == EfiIsaIoOperationBusMasterCommonBuffer) {
return EFI_UNSUPPORTED;
}
//
// Allocate an ISA_MAP_INFO structure to remember the mapping when Unmap()
// is called later.
//
IsaMapInfo = EfiLibAllocatePool (sizeof (ISA_MAP_INFO));
if (IsaMapInfo == NULL) {
*NumberOfBytes = 0;
return EFI_OUT_OF_RESOURCES;
}
//
// Return a pointer to the MAP_INFO structure in Mapping
//
*Mapping = IsaMapInfo;
//
// Initialize the MAP_INFO structure
//
IsaMapInfo->Operation = Operation;
IsaMapInfo->NumberOfBytes = *NumberOfBytes;
IsaMapInfo->NumberOfPages = EFI_SIZE_TO_PAGES (*NumberOfBytes);
IsaMapInfo->HostAddress = PhysicalAddress;
IsaMapInfo->MappedHostAddress = ISA_MAX_MEMORY_ADDRESS - 1;
//
// Allocate a buffer below 4GB to map the transfer to.
//
Status = gBS->AllocatePages (
AllocateMaxAddress,
EfiBootServicesData,
IsaMapInfo->NumberOfPages,
&IsaMapInfo->MappedHostAddress
);
if (EFI_ERROR (Status)) {
gBS->FreePool (IsaMapInfo);
*NumberOfBytes = 0;
*Mapping = NULL;
return Status;
}
//
// If this is a read operation from the DMA agents's point of view,
// then copy the contents of the real buffer into the mapped buffer
// so the DMA agent can read the contents of the real buffer.
//
if (Operation == EfiIsaIoOperationBusMasterRead) {
EfiCopyMem (
(VOID *) (UINTN) IsaMapInfo->MappedHostAddress,
(VOID *) (UINTN) IsaMapInfo->HostAddress,
IsaMapInfo->NumberOfBytes
);
}
//
// The DeviceAddress is the address of the maped buffer below 16 MB
//
*DeviceAddress = IsaMapInfo->MappedHostAddress;
} else {
//
// The transfer is below 16 MB, so the DeviceAddress is simply the
// HostAddress
//
*DeviceAddress = PhysicalAddress;
}
//
// If this is a Bus Master operation then return
//
if (Master) {
return EFI_SUCCESS;
}
//
// Figure out what to program into the DMA Channel Mode Register
//
DmaMode = (UINT8) (DMA_MODE_INCREMENT | (ChannelNumber & 0x03));
if (Read) {
DmaMode |= DMA_MODE_READ;
} else {
DmaMode |= DMA_MODE_WRITE;
}
if (ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_AUTO_INITIALIZE) {
DmaMode |= DMA_MODE_AUTO_INITIALIZE;
}
if (ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_DEMAND_MODE) {
DmaMode |= DMA_MODE_DEMAND;
}
if (ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SINGLE_MODE) {
DmaMode |= DMA_MODE_SINGLE;
}
//
// A Slave DMA transfer can not cross a 64K boundary.
// Compute *NumberOfBytes based on this restriction.
//
MaxNumberOfBytes = 0x10000 - ((UINT32) (*DeviceAddress) & 0xffff);
if (*NumberOfBytes > MaxNumberOfBytes) {
*NumberOfBytes = MaxNumberOfBytes;
}
//
// Compute the values to program into the BaseAddress and Count registers
// of the Slave DMA controller
//
if (ChannelNumber < 4) {
BaseAddress = (UINT32) (*DeviceAddress);
Count = (UINT16) (*NumberOfBytes - 1);
} else {
BaseAddress = (UINT32) (((UINT32) (*DeviceAddress) & 0xff0000) | (((UINT32) (*DeviceAddress) & 0xffff) >> 1));
Count = (UINT16) ((*NumberOfBytes - 1) >> 1);
}
//
// Program the DMA Write Single Mask Register for ChannelNumber
// Clear the DMA Byte Pointer Register
//
if (ChannelNumber < 4) {
DmaMask = DMA_SINGLE_MASK_0_3;
DmaClear = DMA_CLEAR_0_3;
DmaChannelMode = DMA_MODE_0_3;
} else {
DmaMask = DMA_SINGLE_MASK_4_7;
DmaClear = DMA_CLEAR_4_7;
DmaChannelMode = DMA_MODE_4_7;
}
Status = WritePort (
This,
DmaMask,
(UINT8) (DMA_CHANNEL_MASK_SELECT | (ChannelNumber & 0x03))
);
if (EFI_ERROR (Status)) {
return Status;
}
Status = WritePort (
This,
DmaClear,
(UINT8) (DMA_CHANNEL_MASK_SELECT | (ChannelNumber & 0x03))
);
if (EFI_ERROR (Status)) {
return Status;
}
Status = WritePort (This, DmaChannelMode, DmaMode);
if (EFI_ERROR (Status)) {
return Status;
}
Status = WriteDmaPort (
This,
DmaRegisters[ChannelNumber].Address,
DmaRegisters[ChannelNumber].Page,
DmaRegisters[ChannelNumber].Count,
BaseAddress,
Count
);
if (EFI_ERROR (Status)) {
return Status;
}
Status = WritePort (
This,
DmaMask,
(UINT8) (ChannelNumber & 0x03)
);
if (EFI_ERROR (Status)) {
return Status;
}
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
IsaIoAllocateBuffer (
IN EFI_INTERFACE_DEFINITION_FOR_ISA_IO *This,
IN EFI_ALLOCATE_TYPE Type,
IN EFI_MEMORY_TYPE MemoryType,
IN UINTN Pages,
OUT VOID **HostAddress,
IN UINT64 Attributes
)
/*++
Routine Description:
Allocates a common buffer for DMA
Arguments:
This - A pointer to the EFI_ISA_IO_PROTOCOL instance.
Type - The type allocation to perform.
MemoryType - The type of memory to allocate.
Pages - The number of pages to allocate.
HostAddress - A pointer to store the base address of the allocated range.
Attributes - The requested bit mask of attributes for the allocated range.
Returns:
EFI_SUCCESS - The requested memory pages were allocated.
EFI_INVALID_PARAMETER - Type is invalid or MemoryType is invalid or HostAddress is NULL
EFI_UNSUPPORTED - Attributes is unsupported or the memory range specified
by HostAddress, Pages, and Type is not available for common buffer use.
EFI_OUT_OF_RESOURCES - The memory pages could not be allocated.
--*/
{
EFI_STATUS Status;
EFI_PHYSICAL_ADDRESS PhysicalAddress;
if (HostAddress == NULL) {
return EFI_INVALID_PARAMETER;
}
if (Type < AllocateAnyPages || Type >= MaxAllocateType) {
return EFI_INVALID_PARAMETER;
}
//
// The only valid memory types are EfiBootServicesData and EfiRuntimeServicesData
//
if (MemoryType != EfiBootServicesData && MemoryType != EfiRuntimeServicesData) {
return EFI_INVALID_PARAMETER;
}
if (Attributes &~(EFI_ISA_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE | EFI_ISA_IO_ATTRIBUTE_MEMORY_CACHED)) {
return EFI_UNSUPPORTED;
}
PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) (ISA_MAX_MEMORY_ADDRESS - 1);
if (Type == AllocateAddress) {
if ((UINTN) (*HostAddress) >= ISA_MAX_MEMORY_ADDRESS) {
return EFI_UNSUPPORTED;
} else {
PhysicalAddress = (UINTN) (*HostAddress);
}
}
if (Type == AllocateAnyPages) {
Type = AllocateMaxAddress;
}
Status = gBS->AllocatePages (Type, MemoryType, Pages, &PhysicalAddress);
if (EFI_ERROR (Status)) {
ReportErrorStatusCode (EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR);
return Status;
}
*HostAddress = (VOID *) (UINTN) PhysicalAddress;
return Status;
}
EFI_STATUS
EFIAPI
IsaIoFreeBuffer (
IN EFI_INTERFACE_DEFINITION_FOR_ISA_IO *This,
IN UINTN Pages,
IN VOID *HostAddress
)
/*++
Routine Description:
Frees a common buffer
Arguments:
This - A pointer to the EFI_ISA_IO_PROTOCOL instance.
Pages - The number of pages to free.
HostAddress - The base address of the allocated range.
Returns:
EFI_SUCCESS - The requested memory pages were freed.
EFI_INVALID_PARAMETER - The memory was not allocated with EFI_ISA_IO.AllocateBufer().
--*/
{
EFI_STATUS Status;
EFI_PHYSICAL_ADDRESS PhysicalAddress;
PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress;
Status = gBS->FreePages (
PhysicalAddress,
Pages
);
if (EFI_ERROR (Status)) {
ReportErrorStatusCode (EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR);
}
return Status;
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?