The code posted is only a rough sketch of the API I use - the actual work is seperated between several
functions. I do use try/catch blocks.
By quick and dirty, I mean, with minimal changes to the driver and the supporting user-mode libraries - I
want it to work, so development in the user-mode can move on - than I’ll have the time to fix the
implementation, which I agree is far from perfect.
The BAR is a 2mb general purpose block of memory, that contains a register file, embedded cpu, a framebuffer
(a buffer that holds a frame), and a shadow copy mechanism that catches traffic between the host and the GPU.
Thanks!
the relevant code (copy pasted, with all the ugly, ugly debug code):
NTSTATUS PrepareHardware(IN WDFDEVICE Device, IN WDFCMRESLIST ResourcesRaw,
IN WDFCMRESLIST ResourcesTranslated)
/*++
Routine Description:
This callback function is called upon EvtDevicePrepareHardware event trigger
Arguments:
Device - Handle to the framework device object
ResourcesRaw - List of raw resources allocated to the device.
ResourcesTranslated - List of translated resources allocated to the device.
Return Value:
NTSTATUS
–*/
{
ULONG Count;
ULONG i;
NTSTATUS status = STATUS_SUCCESS;
PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor;
BOOLEAN bar0FoundFlag = FALSE;
PhwCONTROL_DATA PhwControlData;
PPCI_BAR_INFO pBarInfo = NULL;
PVOID pVaddr = NULL;
ULONG_PTR BarNumberOfBytes;
USHORT barFlags;
#if defined (AMD64)
ULONGLONG amd64start = 0x00;
ULONGLONG amd64Length;
PULONGLONG pAmd64start = &amd64start;
#endif
PAGED_CODE ();
KdPrint((DRIVERNAME “—> PrepareHardware\n”));
UNREFERENCED_PARAMETER(ResourcesTranslated);
Count = WdfCmResourceListGetCount(ResourcesRaw);
KdPrint((DRIVERNAME “Count of raw resources is: %d\n”,Count));
//Go over the the resources. It is guaranteed that the resources will arrive in the
//order they appear in the configuration space, hence the first memory resource is
//BAR 0
for (i = 0;i {
Descriptor = WdfCmResourceListGetDescriptor(ResourcesRaw,i);
hw (Descriptor->Type)
{
case CmResourceTypeMemory:
KdPrint((DRIVERNAME “Resource Type CmResourceTypeMemory\n”));
if (0 == i)
{
KdPrint((DRIVERNAME “bar0: “)); //DEBUGING THE DEBUG
}
barFlags = Descriptor->Flags;
KdPrint((DRIVERNAME “Memory: (%x) Length: d(%d)\n”, Descriptor-
>u.Memory.Start.QuadPart,Descriptor->u.Memory.Length));
KdPrint((DRIVERNAME “------------ Flags: %0x(%0x) [before 64bit cm
assignment]\n”, barFlags));
Descriptor->Flags |= CM_RESOURCE_MEMORY_LARGE_64;
barFlags = Descriptor->Flags;
KdPrint((DRIVERNAME “------------ Flags: %0x(%0x) [after 64bit cm
assignment]\n”, barFlags));
KdPrint((DRIVERNAME “------------ Length: 0x(%0x)\n”, Descriptor-
>u.Memory.Length)); //DEBUG
KdPrint((DRIVERNAME “------------ Length: p(%p)\n”, Descriptor-
>u.Memory.Length)); //DEBUG
//AMD64 Vista specific code
#if defined (AMD64)
KdPrint((”-=-=-= Vista64bit information=-=-=-=\n”));
amd64Length = RtlCmDecodeMemIoResource(Descriptor, pAmd64start);
KdPrint((DRIVERNAME “------------ Length(64): l64(%l64)\n”, amd64Length));
//DEBUG
KdPrint((DRIVERNAME “------------ Length(64): lld(%lld)\n”, amd64Length));
//DEBUG
KdPrint((DRIVERNAME “------------ Length(64): lld(%lld)\n”, amd64Length));
//DEBUG
KdPrint((DRIVERNAME “------------ Length(64): p(%p)\n”,amd64Length)); //DEBUG
KdPrint((DRIVERNAME “------------ Memory(64): llx(%llx)\n”, *pAmd64start));
//DEBUG
KdPrint((“-=-=-= End Vista64bit information=-=-=-=\n”));
#endif
bar0FoundFlag = TRUE;
break;
default:
KdPrint((DRIVERNAME “Skipping non memory reaource type\n”));
}
if( TRUE == bar0FoundFlag ) //terrible hack, remove this crap
{
break;
}
}
//update BAR 0 information and map it to kernel space
PhwControlData = GetData(Device);
if( (TRUE == bar0FoundFlag) && (TRUE == IsDeviceUSPort(PhwControlData)))
{
pBarInfo = &PhwControlData->Bar0;
// Map physical address into kerenl virtual space.
#if defined (AMD64)
BarNumberOfBytes = amd64Length;
pBarInfo->Physical = Descriptor->u.Memory64.Start;
#else
BarNumberOfBytes = HW_US_BAR0_SIZE;
pBarInfo->Physical = Descriptor->u.Memory.Start;
#endif
KdPrint((DRIVERNAME “starting to map address 0x%lx.\n”,pBarInfo->Physical.QuadPart));
pBarInfo->pKVa = MmMapIoSpace( pBarInfo->Physical,
BarNumberOfBytes,
MmNonCached);
// Check that the mapping succedded.
if(NULL == pBarInfo->pKVa)
{
KdPrint((DRIVERNAME “ERROR: BAR mapping into kernel space failed.\n”));
return STATUS_INSUFFICIENT_RESOURCES;
}
}
KdPrint((DRIVERNAME “<—PrepareHardware\n”));
return status;
}
NTSTATUS
hwControl_BARMap(
in WDFREQUEST Request,
in WDFQUEUE Queue,
in PULONG_PTR inBuf,
in PULONG_PTR outBuf,
__out PULONG_PTR pInfo,
WDFDEVICE hwControlDevice
)
{
NTSTATUS status = STATUS_SUCCESS;
PVOID pVaddr = NULL;
WDFDEVICE hDevice;
PPCI_BAR_INFO pBarInfo = NULL;
PCTL_BAR_MAP_hw pInParams = (PCTL_BAR_MAP_hw)inBuf;
ULONG BarNumberOfBytes;
PhwCONTROL_DATA PhwControl_Data;
BarNumberOfBytes = HW_US_BAR0_SIZE;
KdPrint((DRIVERNAME “–> hwControl_BARMap\n”));
PhwControl_Data = hwControlGetData(hwControlDevice);
pBarInfo = &PhwControl_Data->Bar0;
//if(TRUE == PhwControl_Data->barMappedFlag)
//{
// //BAR is already mapped , return an error indicating
// // Set Return values
// *(outBuf) = E__HW_OK;
// // return E__HW_BAR_ALREADY_MAPPED;
// return status;
//}
// Build MDL for the kernel address.
if (BarNumberOfBytes > (PAGE_SIZE * (65535 - sizeof(MDL)) / sizeof(ULONG_PTR)) )
{
KdPrint((DRIVERNAME “hwControl_BARMap:: oh hai, ur barnumberofbytes is tu big bi : %d \n”,
BarNumberOfBytes > (PAGE_SIZE * (65535 - sizeof(MDL)) / sizeof(ULONG_PTR))));
}
pBarInfo->pMdl = IoAllocateMdl( pBarInfo->pKVa,
BarNumberOfBytes,
FALSE,
FALSE,
NULL);
// Check that MDL allocation succeeded.
if(NULL == pBarInfo->pMdl)
{
KdPrint((DRIVERNAME “ERROR: MDL allocation failed.\n”));
MmUnmapIoSpace(pBarInfo->pKVa, BarNumberOfBytes);
return STATUS_INSUFFICIENT_RESOURCES;
}
// Build the MDL
MmBuildMdlForNonPagedPool(pBarInfo->pMdl);
try {
// Map to user space.
pVaddr = MmMapLockedPagesSpecifyCache(
pBarInfo->pMdl,
UserMode,
MmNonCached,
NULL,
FALSE,
HighPagePriority);
}
except (EXCEPTION_EXECUTE_HANDLER)
{
KdPrint((DRIVERNAME “ERROR: User space mapping failed.\n”));
IoFreeMdl(pBarInfo->pMdl);
MmUnmapIoSpace(pBarInfo->pKVa, BarNumberOfBytes);
return STATUS_INSUFFICIENT_RESOURCES;
}
// Check that the mapping succedded.
if(NULL == pVaddr)
{
KdPrint((DRIVERNAME “ERROR: User space mapping failed.\n”));
IoFreeMdl(pBarInfo->pMdl);
MmUnmapIoSpace(pBarInfo->pKVa, BarNumberOfBytes);
return STATUS_INSUFFICIENT_RESOURCES;
}
pBarInfo->pUVa = pVaddr;
/PhwControl_Data->barMappedFlag = TRUE;/
KdPrint((DRIVERNAME “User Virtual -Mapped address is 0x%p.\n",pVaddr));
KdPrint((DRIVERNAME " User Virtual -size %d.\n”, BarNumberOfBytes));
KdPrint((DRIVERNAME “Kernel virtual -address is 0x%p\n", pBarInfo->pKVa));
KdPrint((DRIVERNAME " Kernel physical -address is 0x%p\n”, pBarInfo->Physical));
// Set Return values
*(outBuf) = E__HW_OK;
outBuf++;
*(outBuf) = (ULONG_PTR)(pBarInfo->pUVa);
*pInfo += sizeof(PULONG_PTR);
KdPrint((DRIVERNAME “User Virtual -Mapped address is 0x%p.\n",pVaddr));
KdPrint((DRIVERNAME " User Virtual -size %d.\n”, BarNumberOfBytes));
KdPrint((DRIVERNAME “Kernel virtual -address is 0x%p\n", pBarInfo->pKVa));
KdPrint((DRIVERNAME " Kernel physical -address is 0x%p\n”, pBarInfo->Physical));
KdPrint((DRIVERNAME “<– hwControl_BARMap, mapped user virtual address: %llx\n”, pBarInfo->pUVa));
return status;
}