📄 pcidppublic.c
字号:
//*****************************************************************************
// THIS CODE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
// OR IMPLIED. THIS CODE IS LABELED "OPEN SOFTWARE" AND MAY BE FREELY USED,
// REPRODUCED, MODIFIED, AND/OR REDISTRIBUTED WITH THE STIPULATION THAT THIS
// NOTICE REMAIN INTACT. REDISTRIBUTION OF ANY KIND IMPLIES THAT ALL
// MODIFICATIONS FALL UNDER THIS "OPEN SOFTWARE" LABEL.
//
// Copyright (C) 2000, Foxen Solutions
// Copyright (C) 2000, FXN
//
// All Rights Reserved.
//*****************************************************************************
//
// This is PCIDPPublic.c. It contains those PCIDP kernel routines published
// for use by an application using the IoDeviceControl system service.
#include "PCIDPInc.h"
#include "PCIDP.h"
// ----------------------------------------------------------------------------
// PCIDPGetDriverVersion
// ----------------------------------------------------------------------------
VOID PCIDPGetDriverVersion(
IN OUT PIRP Irp,
OUT PVOID IoBuffer,
IN ULONG OutputBufferLength
){
// Define variables.
NTSTATUS NTStatus;
pPCIDP00_GET_VERSION_RECV IoOutput;
// Initialize variables.
IoOutput = (pPCIDP00_GET_VERSION_RECV)IoBuffer;
// Check for adequate output buffer space.
if(OutputBufferLength >= sizeof(PCIDP00_GET_VERSION_RECV)){
NTStatus = STATUS_SUCCESS;
IoOutput->Version = 0x20010615;
Irp->IoStatus.Information = sizeof(PCIDP00_GET_VERSION_RECV);
}
else
NTStatus = STATUS_INVALID_BUFFER_SIZE;
Irp->IoStatus.Status = NTStatus;
}
// ----------------------------------------------------------------------------
// PDIDPMapBaseRegs
// ----------------------------------------------------------------------------
VOID PCIDPMapBaseRegs(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PIRP Irp,
IN OUT PVOID IoBuffer,
IN ULONG InputBufferLength,
IN ULONG OutputBufferLength
){
// Define variables.
ULONG PCIAddress;
ULONG Length;
ULONG LengthOut;
ULONG BusNumber;
ULONG VirtualAddress;
ULONG MappedLength;
ULONG MapIndex;
UNICODE_STRING PhysicalMemoryUnicodeString;
OBJECT_ATTRIBUTES ObjectAttributes;
BOOLEAN HALStatus;
PHYSICAL_ADDRESS LongLength;
PHYSICAL_ADDRESS FullPCIAddress;
PHYSICAL_ADDRESS FullPCIAddressEnd;
PHYSICAL_ADDRESS FullLogicalAddress;
PHYSICAL_ADDRESS FullLogicalAddressEnd;
PHYSICAL_ADDRESS SectionOffset;
NTSTATUS NTStatus;
HANDLE PhysicalMemoryHandle;
PVOID PhysicalMemorySection;
ULONG MemorySpace;
ULONG MemorySpaceEnd;
pPCIDP00_MAP_BASE_REGS_SEND IoInput;
pPCIDP00_MAP_BASE_REGS_RECV IoOutput;
pPCIDP_EXTENSION ObjExt;
// Initialize variables.
NTStatus = STATUS_SUCCESS;
PhysicalMemoryHandle = NULL;
PhysicalMemorySection = NULL;
MemorySpace = 0;
MemorySpaceEnd = 0;
IoInput = (pPCIDP00_MAP_BASE_REGS_SEND)IoBuffer;
IoOutput = (pPCIDP00_MAP_BASE_REGS_RECV)IoBuffer;
ObjExt = (pPCIDP_EXTENSION)DeviceObject->DeviceExtension;
// Make sure the buffer lengths are of sufficient size to handle
// the transactions.
if((InputBufferLength < sizeof(PCIDP00_MAP_BASE_REGS_SEND)) ||
(OutputBufferLength < sizeof(PCIDP00_MAP_BASE_REGS_RECV))){
NTStatus = STATUS_INVALID_BUFFER_SIZE;
goto ExitA;
}
// Check for a valid Base Address Register index and that its value
// is non-zero.
if(IoInput->RegNumber > 5){
NTStatus = STATUS_INVALID_PARAMETER;
goto ExitA;
}
if((ObjExt->BaseAddresses[IoInput->RegNumber] & 0xFFFFFFFE) == 0){
NTStatus = STATUS_INVALID_ADDRESS;
goto ExitA;
}
// First check to see if the address is for I/O space. If it is, we
// can't map it. Just return the I/O Address so the application can
// use an I/O access driver to read and write from this space.
if((ObjExt->BaseAddresses[IoInput->RegNumber] & 1) == 1){
IoOutput->IOSpace = 1;
IoOutput->Length = IoInput->Length;
IoOutput->Address = ObjExt->BaseAddresses[IoInput->RegNumber] & 0xFFFFFFFE;
Irp->IoStatus.Information = sizeof(PCIDP00_MAP_BASE_REGS_RECV);
goto ExitA;
}
// Create the full path name for the physical memory object.
RtlInitUnicodeString(
IN &PhysicalMemoryUnicodeString,
IN L"\\Device\\PhysicalMemory"
);
// Initialize the physical memory object attributes.
InitializeObjectAttributes(
OUT &ObjectAttributes, // Object attributes structure
IN &PhysicalMemoryUnicodeString, // Full path name of the object
IN OBJ_CASE_INSENSITIVE, // Object attribute
IN (HANDLE) NULL, // Root directory is N/A
IN (PSECURITY_DESCRIPTOR) NULL // Security descriptor is N/A
);
// Get a handle to the physical memory object.
NTStatus = ZwOpenSection(
OUT &PhysicalMemoryHandle, // Handle to the physical memory object
IN SECTION_ALL_ACCESS, // Allow full access to the memory
IN &ObjectAttributes // Object attributes structure
);
if(NTStatus != STATUS_SUCCESS) goto ExitA;
// Validate access on the object's handle and get a pointer to the object's
// body.
NTStatus = ObReferenceObjectByHandle(
IN PhysicalMemoryHandle,
IN SECTION_ALL_ACCESS,
IN (POBJECT_TYPE) NULL,
IN KernelMode,
OUT &PhysicalMemorySection,
OUT (POBJECT_HANDLE_INFORMATION) NULL
);
if(NTStatus != STATUS_SUCCESS) goto ExitB;
// Translate the address from a PCI address to a system logical address.
// Initialize the PCI full physical addresses that will be translated.
FullPCIAddress.HighPart = 0;
FullPCIAddress.LowPart = ObjExt->BaseAddresses[IoInput->RegNumber];
FullPCIAddressEnd = RtlLargeIntegerAdd (
IN FullPCIAddress,
IN RtlConvertUlongToLargeInteger(IoInput->Length)
);
// Translate the full PCI physical addresses into corresponding full system
// logical addresses.
NTStatus = STATUS_ACCESS_DENIED;
HALStatus = HalTranslateBusAddress(
IN PCIBus, // bus type
IN ObjExt->BusNumber, // bus number
IN FullPCIAddress, // bus address
IN &MemorySpace, // I/O or memory space
OUT &FullLogicalAddress // system logical address
);
if(HALStatus == FALSE) goto ExitB;
HALStatus = HalTranslateBusAddress(
IN PCIBus, // bus type
IN ObjExt->BusNumber, // bus number
IN FullPCIAddressEnd, // bus address
IN &MemorySpaceEnd, // I/O or memory space
OUT &FullLogicalAddressEnd // system logical address
);
if(HALStatus == FALSE) goto ExitB;
// Calculate the length of the memory to be mapped.
LongLength = RtlLargeIntegerSubtract(
IN FullLogicalAddressEnd,
IN FullLogicalAddress
);
Length = LongLength.LowPart;
LengthOut = LongLength.LowPart;
// Now map the system logical address in this process' virtual address
// space.
VirtualAddress = 0;
SectionOffset = FullLogicalAddress;
NTStatus = ZwMapViewOfSection(
IN PhysicalMemoryHandle, //section handle
IN (HANDLE) -1, //process handle
IN OUT (PVOID*)&VirtualAddress, //base address (virtual address)
IN 0L, //zero bits
IN Length, //commit size
IN OUT &SectionOffset, //section offset
IN OUT &LengthOut, //view size
IN ViewShare, //inherit disposition (0)
IN 0, //allocation type
IN PAGE_READWRITE | PAGE_NOCACHE //protect
);
// Mapping the section above rounded the logical address down to
// the nearest 64 K boundary. Now return a virtual address pointing
// to our request area by adding in the offset from the beginning
// of the section.
if(NTStatus == STATUS_SUCCESS){
IoOutput->IOSpace = 0;
IoOutput->Address = VirtualAddress +
((ULONG)FullLogicalAddress.LowPart - (ULONG)SectionOffset.LowPart);
IoOutput->Length = LengthOut -
((ULONG)FullLogicalAddress.LowPart - (ULONG)SectionOffset.LowPart);
Irp->IoStatus.Information = sizeof(PCIDP00_MAP_BASE_REGS_RECV);
}
ExitB:
ZwClose(PhysicalMemoryHandle);
ExitA:
Irp->IoStatus.Status = NTStatus;
}
// ----------------------------------------------------------------------------
// PCIDPUnMap unmaps a region of virtual memory from physical memory
// that was mapped earlier using the PCIDPMapBaseRegs routines.
// ----------------------------------------------------------------------------
VOID PCIDPUnMap(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PIRP Irp,
IN PVOID IoBuffer,
IN ULONG InputBufferLength
){
// Define variables.
ULONG i;
NTSTATUS NTStatus;
pPCIDP00_UNMAP_SEND IoInput;
pPCIDP_EXTENSION ObjExt;
// Initialize variables.
NTStatus = STATUS_SUCCESS;
IoInput = (pPCIDP00_UNMAP_SEND)IoBuffer;
ObjExt = (pPCIDP_EXTENSION)DeviceObject->DeviceExtension;
if(InputBufferLength >= sizeof(PCIDP00_UNMAP_SEND)){
// Don't try to unmap from I/O space but it's not a failure either.
for(i=0; i<6; i++){
if(IoInput->VirtualAddress == (ObjExt->BaseAddresses[i] & 0xFFFFFFFE))
break;
}
if(i>=6){
NTStatus = ZwUnmapViewOfSection(
IN (HANDLE) -1,
IN (PVOID)IoInput->VirtualAddress
);
}
}
else
NTStatus = STATUS_INVALID_BUFFER_SIZE;
Irp->IoStatus.Status = NTStatus;
}
// ----------------------------------------------------------------------------
// PDIDPMapDMAMem
// ----------------------------------------------------------------------------
VOID PCIDPMapDMAMem(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PIRP Irp,
OUT PVOID IoBuffer,
IN ULONG OutputBufferLength
){
NTSTATUS NTStatus;
pPCIDP00_MAP_DMA_MEM_RECV IoOutput;
pPCIDP_EXTENSION ObjExt;
// Initialize variables.
IoOutput = (pPCIDP00_MAP_DMA_MEM_RECV)IoBuffer;
ObjExt = (pPCIDP_EXTENSION)DeviceObject->DeviceExtension;
if(OutputBufferLength >= sizeof(PCIDP00_MAP_DMA_MEM_RECV)){
if(ObjExt->MDL){
IoOutput->LinearAddress = (unsigned long)MmMapLockedPages(
ObjExt->MDL,
UserMode
);
if(IoOutput->LinearAddress != 0){
IoOutput->PhysicalAddress = ObjExt->PhysicalDMAAddress;
Irp->IoStatus.Information = sizeof(PCIDP00_MAP_DMA_MEM_RECV);
NTStatus = STATUS_SUCCESS;
}
else
NTStatus = STATUS_NO_MEMORY;
}
else
NTStatus = STATUS_NO_MEMORY;
}
else
NTStatus = STATUS_INVALID_BUFFER_SIZE;
Irp->IoStatus.Status = NTStatus;
}
// ----------------------------------------------------------------------------
// PCIDPCancelMapDMA
// ----------------------------------------------------------------------------
VOID PCIDPCancelMapDMA(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PIRP Irp,
IN PVOID IoBuffer,
IN ULONG InputBufferLength
){
KIRQL CancelSpin;
pPCIDP00_UNMAP_DMA_SEND IoInput;
pPCIDP_EXTENSION ObjExt;
pLINKED_LIST LLEntry;
NTSTATUS NTStatus;
// Initialize variables.
IoInput = (pPCIDP00_UNMAP_DMA_SEND)IoBuffer;
ObjExt = (pPCIDP_EXTENSION)DeviceObject->DeviceExtension;
//ObjExt->MemoryBase[0x1C5E]++; //debug
// Get an empty linked list entry.
LLEntry = GetFreeEntry(ObjExt);
if(LLEntry != NULL){
// Set up a cancel routine that unmaps the DMA should the application fail
// to do so.
IoMarkIrpPending (Irp);
IoAcquireCancelSpinLock (&CancelSpin);
IoSetCancelRoutine (Irp, PCIDPCancelMapDMARoutine);
IoReleaseCancelSpinLock (CancelSpin);
// Add this IRP to the linked list
// Save the linear address required to unmap DMA memory in Type.
LLEntry->RegisteredInterrupt.Irp = Irp;
LLEntry->RegisteredInterrupt.Type = (ULONG)IoInput->LinearAddress;
InsertEntry(ObjExt, LLEntry);
//ObjExt->MemoryBase[0x1C5F]++; //debug
//ObjExt->MemoryBase[0x1C60] = (ULONG)IoInput->LinearAddress; //debug
// Return with I/O pending.
NTStatus = STATUS_PENDING;
}
else
NTStatus = STATUS_NO_MEMORY;
// Return with current status.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -