vista 64bit - how do I share memory between the kernel and the userspace?

I’m porting an xp driver to Vista 64bit.
The driver maps between BARs of a PCI device, to virtual kernel memory, and than to user virtual memory, in order to allow high speed memory access from user mode (The BARs contains framebuffer data).
The user memory is attached to a single process.

a rough sketch of the code I’m using:
<-------------8<-------------
@prepareHardware
Descriptor = WdfCmResourceListGetDescriptor(ResourcesRaw,i);
switch (Descriptor->Type)
{
case CmResourceTypeMemory:
memLength = Descriptor->u.Memory.Length;
pBarInfo->Physical = Descriptor->u.Memory.Start;
pBarInfo->pKVa = MmMapIoSpace(pBarInfo->Physical, barSize, MmNonCached);
break;
pBarInfo->pMdl = IoAllocateMdl( pBarInfo->pKVa, barSize, FALSE, FALSE, NULL);
MmBuildMdlForNonPagedPool(pBarInfo->pMdl);
}

when the user passes an ioctl to get access to a BAR:
pVaddr = MmMapLockedPagesSpecifyCache(
pBarInfo->pMdl,
UserMode,
MmNonCached,
NULL, //TODO - see if I can specify a base address here
FALSE,
HighPagePriority);
and pVaddr is returned.
-------------8<------------->
In windows XP 32bit, the driver works as expected, and the shared memory is easily written an written to.
In vista 64bit, the shared memory address is read successfully (I’ve tested it by using winDbg to modify the memory, and than read it), but writing to the memory either fails with a “read-only error”, or return a bucketfull of 0xffffffffffs.

What need I do in order to allow writing to the shared memory?

Notes:

  1. I need shared memory because access speed is critical.
  2. I’ve skimmed through the forum, didn’t find an answer, sorry if this is a duplicate.
  3. I’m pretty new to this whole kernel writing thing, there’s probably some mix ups with the concepts, somewhere in the above text.

Thanks in advance!

>The driver maps between BARs of a PCI device, to virtual kernel memory, and than to user virtual memory,

Incredibly poor design - it is almost the same thing as modifying IO permission bitmap in TSS in order to allow applications to access device IO ports…

Anton Bassov

What will be a better design?
From what I’ve gathered from the forum, using IOCTLs is a lot slower that using direct memory access.
Thank in advance!
Tomer

> using IOCTLs is a lot slower that using direct memory access.

First of all, it depends on what you mean by “direct memory access”. If you mean DMA… well, this is from the totally different field - in any case, you cannot do it from an application. However, if you mean shared buffer, then the above statement is, in most cases, wrong. Don’t forget that you have to synchronize memory access to the shared buffer, which will eliminate all performance benefits you are expecting to get. The only situation when this statement is right is the one when you have to do HUGE transfers (probably, so large that you are even not sure you will always be able to find a contigious space to hold your buffer) at a high rate…

Anton Bassov

You’re right, I didn’t mean DMA, but using shared memory - I fill the some portions of the BAR with code for an embedded cpu, and use other portions as a register file.
The hardware I’m using is an alpha version, most of it will be replaced, changed, and moved in pretty short time - I need something quick and dirty.

About the design - It’s far from perfect, I’d appreciate some pointers to a better design.

Another questions - why is this code working on windows xp, but not in vista 64? I guess it related to security, but I didn’t find anything relevant in the WDK documentation (expect using RtlCmDecodeMemIoResource - the returned values are the same as returned from using Descriptor memory structures).

Thanks!
Tomer

> You’re right, I didn’t mean DMA, but using shared memory - I fill the some
portions

of the BAR with code for an embedded cpu, and use other portions as a register
file.

Then why not use IOCTLs for this? this is not a framebuffer, this is firmware
which is usually not so large.


Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
xxxxx@storagecraft.com
http://www.storagecraft.com

I have no thought of PCI BARs or MmMapIoSpace but instead of posting pseudo
code it may help you to post the real thing. That’s because the failure may
depend on the actual tactics of your syntax. For instance you have some
unreachable code there below the break statement, it’s not clear if that is
for real or not. It’s not clear if you are checking the outcome of function
calls or if you call MmMapLockedPagesSpecifyCache from within a try/except
block as you should with UserMode.

//Daniel

wrote in message news:xxxxx@ntdev…
> I’m porting an xp driver to Vista 64bit.
> The driver maps between BARs of a PCI device, to virtual kernel memory,
> and than to user virtual memory, in order to allow high speed memory
> access from user mode (The BARs contains framebuffer data).
> The user memory is attached to a single process.
>
> a rough sketch of the code I’m using:
> <-------------8<-------------
> @prepareHardware
> Descriptor = WdfCmResourceListGetDescriptor(ResourcesRaw,i);
> switch (Descriptor->Type)
> {
> case CmResourceTypeMemory:
> memLength = Descriptor->u.Memory.Length;
> pBarInfo->Physical = Descriptor->u.Memory.Start;
> pBarInfo->pKVa = MmMapIoSpace(pBarInfo->Physical, barSize,
> MmNonCached);
> break;
> pBarInfo->pMdl = IoAllocateMdl( pBarInfo->pKVa, barSize, FALSE, FALSE,
> NULL);
> MmBuildMdlForNonPagedPool(pBarInfo->pMdl);
> }
>
> when the user passes an ioctl to get access to a BAR:
> pVaddr = MmMapLockedPagesSpecifyCache(
> pBarInfo->pMdl,
> UserMode,
> MmNonCached,
> NULL, //TODO - see if I can specify a base address here
> FALSE,
> HighPagePriority);
> and pVaddr is returned.
> -------------8<------------->
> In windows XP 32bit, the driver works as expected, and the shared memory
> is easily written an written to.
> In vista 64bit, the shared memory address is read successfully (I’ve
> tested it by using winDbg to modify the memory, and than read it), but
> writing to the memory either fails with a “read-only error”, or return a
> bucketfull of 0xffffffffffs.
>
> What need I do in order to allow writing to the shared memory?
>
> Notes:
> 1. I need shared memory because access speed is critical.
> 2. I’ve skimmed through the forum, didn’t find an answer, sorry if this is
> a duplicate.
> 3. I’m pretty new to this whole kernel writing thing, there’s probably
> some mix ups with the concepts, somewhere in the above text.
>
> Thanks in advance!
>
>
>

I have the similar situation…I also need to share memory between the kernel mode driver and the user mode application.

Can you please share some codes sample with me ?
Best regards, - Dan Ma> Date: Tue, 15 Jul 2008 07:35:54 -0400> From: xxxxx@gmail.com> To: xxxxx@lists.osr.com> Subject: [ntdev] vista 64bit - how do I share memory between the kernel and the userspace?> > I’m porting an xp driver to Vista 64bit.> The driver maps between BARs of a PCI device, to virtual kernel memory, and than to user virtual memory, in order to allow high speed memory access from user mode (The BARs contains framebuffer data). > The user memory is attached to a single process.> > a rough sketch of the code I’m using:> <-------------8<-------------> @prepareHardware> Descriptor = WdfCmResourceListGetDescriptor(ResourcesRaw,i);> switch (Descriptor->Type)> { > case CmResourceTypeMemory:> memLength = Descriptor->u.Memory.Length;> pBarInfo->Physical = Descriptor->u.Memory.Start;> pBarInfo->pKVa = MmMapIoSpace(pBarInfo->Physical, barSize, MmNonCached);> break;> pBarInfo->pMdl = IoAllocateMdl( pBarInfo->pKVa, barSize, FALSE, FALSE, NULL);> MmBuildMdlForNonPagedPool(pBarInfo->pMdl);> }> > when the user passes an ioctl to get access to a BAR:> pVaddr = MmMapLockedPagesSpecifyCache(> pBarInfo->pMdl,> UserMode,> MmNonCached,> NULL, //TODO - see if I can specify a base address here> FALSE,> HighPagePriority);> and pVaddr is returned.> -------------8<------------->> In windows XP 32bit, the driver works as expected, and the shared memory is easily written an written to.> In vista 64bit, the shared memory address is read successfully (I’ve tested it by using winDbg to modify the memory, and than read it), but writing to the memory either fails with a “read-only error”, or return a bucketfull of 0xffffffffffs.> > What need I do in order to allow writing to the shared memory?> > Notes:> 1. I need shared memory because access speed is critical.> 2. I’ve skimmed through the forum, didn’t find an answer, sorry if this is a duplicate.> 3. I’m pretty new to this whole kernel writing thing, there’s probably some mix ups with the concepts, somewhere in the above text.> > Thanks in advance!> > > > —> NTDEV is sponsored by OSR> > For our schedule of WDF, WDM, debugging and other seminars visit: > http://www.osr.com/seminars\> > To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer


ÐÂÄê»»ÐÂÑÕ£¬¿ìÀ´×±°ç×Ô¼ºµÄMSN¸øÐÄÒǵÄTAÒ»¸ö¾ªÏ²£¡
http://im.live.cn/emoticons/?ID=18

If you want quick then using shared memory is the wrong way to do this.
IOCTL’s are quick, getting all the shared memory things correct can be a lot
of work. You have not stated why you think you need this except that you
believe it is faster. My experiences say that unless you doing huge
transfers, by the time you put in the coordination of kernel and app and the
handling of failures and out of band events the performance in many cases is
poorer with shared memory.

So take the safe method, use IOCTL’s and standard Windows model, and if
after your hardware is stable perfrormance is too low then start looking at
non-standard solutions.


Don Burn (MVP, Windows DDK)
Windows 2k/XP/2k3 Filesystem and Driver Consulting
Website: http://www.windrvr.com
Blog: http://msmvps.com/blogs/WinDrvr
Remove StopSpam to reply

wrote in message news:xxxxx@ntdev…
> You’re right, I didn’t mean DMA, but using shared memory - I fill the some
> portions of the BAR with code for an embedded cpu, and use other portions
> as a register file.
> The hardware I’m using is an alpha version, most of it will be replaced,
> changed, and moved in pretty short time - I need something quick and
> dirty.
>
> About the design - It’s far from perfect, I’d appreciate some pointers to
> a better design.
>
> Another questions - why is this code working on windows xp, but not in
> vista 64? I guess it related to security, but I didn’t find anything
> relevant in the WDK documentation (expect using RtlCmDecodeMemIoResource -
> the returned values are the same as returned from using Descriptor memory
> structures).
>
> Thanks!
> Tomer
>

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;
}

Not sure how this WDF stuff works but are you sure you are in the context of
the process in which you map the buffer when hwControl_BARMap is called ?

//Daniel

wrote in message news:xxxxx@ntdev…
> 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;
> }
>

Daniel is right, hwControl_BARMap may not necessarily run in the context of the app if the WDFQUEUE which presented the request is power managed. In WDF you perform in caller context operations in EvtIoInCallerContext (registered by calling WdfDeviceInitSetIoInCallerContextCallback)

d

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@resplendence.com
Sent: Tuesday, July 15, 2008 7:39 AM
To: Windows System Software Devs Interest List
Subject: Re:[ntdev] vista 64bit - how do I share memory between the kernel and the userspace?

Not sure how this WDF stuff works but are you sure you are in the context of
the process in which you map the buffer when hwControl_BARMap is called ?

//Daniel

wrote in message news:xxxxx@ntdev…
> 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;
> }
>


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

Thanks for your replies!
Maybe I’ve misunderstood:
hwControl_BARMap is initialized by an ioctl from the user-mode library,

code snippet:
switch (IoControlCode)
{
case IOCTL_HW_BAR_MAP:
status = HwControl_BARMap( Request, Queue,(PULONG_PTR)requestInBuffer,(PULONG_PTR)requestOutBuffer,
&information,LucidSwitchControlDevice);



}

I managed to use the user virtual address in order to read values from the bar (I’ve modified them in the kernel virtual address space using WinDbg), but couldn’t write to those addresses.
please note that I’ve managed to use the same exact code in XP 32bit, to read and write from the BARs.

Thanks in advance!

Doron Holan answered my post! I’m now 1/n th of a celebrity! :slight_smile:

madada wrote:

I have the similar situation…I also need to share memory between the
kernel mode driver and the user mode application.

Can you please share some codes sample with me ?

Apparently, you didn’t read the read of the thread, which explains why
this is almost always a bad idea.

WHY do you think you need to share memory? What is the product?


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

My situation is:

The filter driver (Windows Filter Platform based) will intercept a specific network traffic, then the driver will send the buffer to a user mode filter module and wait until the user mode filter module tell the driver: “hey, I filtered buffer out already”. Then the driver continue to send the filtered buffer out.

What I am thinking is driver and user application share memory, and use event to sync.
Best regards, - Dan Ma> Date: Tue, 15 Jul 2008 09:38:58 -0700> From: xxxxx@probo.com> To: xxxxx@lists.osr.com> Subject: Re: [ntdev] vista 64bit - how do I share memory between the kernel and the userspace?> > madada wrote:> > I have the similar situation…I also need to share memory between the > > kernel mode driver and the user mode application.> > > > Can you please share some codes sample with me ?> > Apparently, you didn’t read the read of the thread, which explains why > this is almost always a bad idea.> > WHY do you think you need to share memory? What is the product?> > – > Tim Roberts, xxxxx@probo.com> Providenza & Boekelheide, Inc.> > > —> NTDEV is sponsored by OSR> > For our schedule of WDF, WDM, debugging and other seminars visit: > http://www.osr.com/seminars\> > To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer


MSN ÖÐÎÄÍø£¬×îÐÂʱÉÐÉú»î×ÊѶ£¬°×Áì¾Û¼¯ÃÅ»§¡£
http://cn.msn.com