Mapping scattered pages into process address space

I’m working in Windows 2000 and I want to allocate a collection of
pages into a contiguous region in the user mode of a given process.
The PCI device is capable of scatter-gather access to pages. What I
would like to do is allocate (with AllocateCommonBuffer) pages that
I can map into a contiguous region in the application memory. This
memory, shared with the device and the application, then acts similar
to a frame buffer.

I know about the ZwMapViewOfSection to map a contiguous region of
physical memory. This is the technique I use under NT. However, I
want to be a little easier on the O/S and dynamically allocate the
buffer in page size chunks. Problem is, I can’t find a way to map
page sized chunks into the process address space.

This is trivially easy under Linux: the mmap system call creates
a vma, that my driver can attach a nopage function to. Then I hand
the pages to the process as it touches them.

Is there *any* way under Windows 2000 to map a scattered collection
of pages into a contiguous region in a given process? If not, I’ll
just go back to using ZwMapViewOfSection and preallocating a big,
physically continuous buffer that can be mapped. That’s painful,
though.

Steve Williams “The woods are lovely, dark and deep.
xxxxx@icarus.com But I have promises to keep,
xxxxx@picturel.com and lines to code before I sleep,
http://www.picturel.com And lines to code before I sleep.”


You are currently subscribed to ntdev as: $subst(‘Recip.EmailAddr’)
To unsubscribe send a blank email to leave-ntdev-$subst(‘Recip.MemberIDChar’)@lists.osr.com

Steve,

I’m not sure if this is really what you’re asking for, but
MmMapLockedPages can be used to map pages that are described by an MDL
into either user-mode or kernel-mode.

I hope that helped.

Regards,
Youssef

-----Original Message-----
From: Stephen Williams [mailto:xxxxx@icarus.com]
Sent: Friday, August 03, 2001 2:50 PM
To: NT Developers Interest List
Subject: [ntdev] Mapping scattered pages into process address space

I’m working in Windows 2000 and I want to allocate a collection of
pages into a contiguous region in the user mode of a given process.
The PCI device is capable of scatter-gather access to pages. What I
would like to do is allocate (with AllocateCommonBuffer) pages that
I can map into a contiguous region in the application memory. This
memory, shared with the device and the application, then acts similar
to a frame buffer.

I know about the ZwMapViewOfSection to map a contiguous region of
physical memory. This is the technique I use under NT. However, I
want to be a little easier on the O/S and dynamically allocate the
buffer in page size chunks. Problem is, I can’t find a way to map
page sized chunks into the process address space.

This is trivially easy under Linux: the mmap system call creates
a vma, that my driver can attach a nopage function to. Then I hand
the pages to the process as it touches them.

Is there *any* way under Windows 2000 to map a scattered collection
of pages into a contiguous region in a given process? If not, I’ll
just go back to using ZwMapViewOfSection and preallocating a big,
physically continuous buffer that can be mapped. That’s painful,
though.

Steve Williams “The woods are lovely, dark and deep.
xxxxx@icarus.com But I have promises to keep,
xxxxx@picturel.com and lines to code before I sleep,
http://www.picturel.com And lines to code before I sleep.”


You are currently subscribed to ntdev as: xxxxx@microsoft.com
To unsubscribe send a blank email to leave-ntdev-$subst(‘Recip.MemberIDChar’)@lists.osr.com


You are currently subscribed to ntdev as: $subst(‘Recip.EmailAddr’)
To unsubscribe send a blank email to leave-ntdev-$subst(‘Recip.MemberIDChar’)@lists.osr.com

xxxxx@microsoft.com said:

I’m not sure if this is really what you’re asking for, but
MmMapLockedPages can be used to map pages that are described by an MDL
into either user-mode or kernel-mode.

That’s close, but how to I make an MDL for a bunch of pages that I’ve
previously allocated by AllocateCommonBuffer? These pages need to somehow
be collected into a single MDL that I can then pass to MmMapLockedPages.
I thought about calling MmMapLockedPages once for each page, but that
won’t necessarily place the pages contiguously in the user mode address
space.

IoAllocateMdl creates an MDL from contiguous memory, but the pages
at hand are scattered, possibly even allocated at different times.
I can’t find any other way to make useful mdls.

Steve Williams “The woods are lovely, dark and deep.
xxxxx@icarus.com But I have promises to keep,
xxxxx@picturel.com and lines to code before I sleep,
http://www.picturel.com And lines to code before I sleep.”


You are currently subscribed to ntdev as: $subst(‘Recip.EmailAddr’)
To unsubscribe send a blank email to leave-ntdev-$subst(‘Recip.MemberIDChar’)@lists.osr.com

There is a sample in the Win2K and XP DDK
(src\kernel\agp\agplib\intrface.c) that shows how to combines a list of
MDLs that describe some set of physical memory pages into a single MDL
that describes the same set of pages.

Make sure you use IoAllocateMdl instead of MmCreateMdl. We will fix our
sample sometime in the future.

Good Luck,
Eliyas

-----Original Message-----
From: Stephen Williams [mailto:xxxxx@icarus.com]
Sent: Friday, August 03, 2001 4:12 PM
To: NT Developers Interest List
Subject: [ntdev] RE: Mapping scattered pages into process address space

xxxxx@microsoft.com said:

I’m not sure if this is really what you’re asking for, but
MmMapLockedPages can be used to map pages that are described by an MDL
into either user-mode or kernel-mode.

That’s close, but how to I make an MDL for a bunch of pages that I’ve
previously allocated by AllocateCommonBuffer? These pages need to
somehow
be collected into a single MDL that I can then pass to MmMapLockedPages.
I thought about calling MmMapLockedPages once for each page, but that
won’t necessarily place the pages contiguously in the user mode address
space.

IoAllocateMdl creates an MDL from contiguous memory, but the pages
at hand are scattered, possibly even allocated at different times.
I can’t find any other way to make useful mdls.

Steve Williams “The woods are lovely, dark and deep.
xxxxx@icarus.com But I have promises to keep,
xxxxx@picturel.com and lines to code before I sleep,
http://www.picturel.com And lines to code before I sleep.”


You are currently subscribed to ntdev as: xxxxx@microsoft.com
To unsubscribe send a blank email to leave-ntdev-$subst(‘Recip.MemberIDChar’)@lists.osr.com


You are currently subscribed to ntdev as: $subst(‘Recip.EmailAddr’)
To unsubscribe send a blank email to leave-ntdev-$subst(‘Recip.MemberIDChar’)@lists.osr.com

> IoAllocateMdl creates an MDL from contiguous memory, but the pages

at hand are scattered, possibly even allocated at different times.

Common buffer pages are never scattered.
Just use IoAllocateMdl/MmBuildMdlForNonPagedPool on the common buffer’s
virtual address.

Max


You are currently subscribed to ntdev as: $subst(‘Recip.EmailAddr’)
To unsubscribe send a blank email to leave-ntdev-$subst(‘Recip.MemberIDChar’)@lists.osr.com

xxxxx@storagecraft.com said:

Common buffer pages are never scattered.

They are if you allocate them a page at a time, as needed.

Steve Williams “The woods are lovely, dark and deep.
xxxxx@icarus.com But I have promises to keep,
xxxxx@picturel.com and lines to code before I sleep,
http://www.picturel.com And lines to code before I sleep.”


You are currently subscribed to ntdev as: $subst(‘Recip.EmailAddr’)
To unsubscribe send a blank email to leave-ntdev-$subst(‘Recip.MemberIDChar’)@lists.osr.com

> xxxxx@storagecraft.com said:

> Common buffer pages are never scattered.

They are if you allocate them a page at a time, as needed.

Is it a good practice?
Why not allocate the single, but large common buffer?

IIRC allocating/freeing common buffers constantly at run time is a bad idea.
The good idea is to allocate 1 common buffer (maybe large) in
DriverEntry/MN_START_DEVICE and do not deallocate it during
DriverUnload/MN_REMOVE_DEVICE.

If you need DMAble memory at run time - allocate some memory, build a MDL
and pass it through IoMapTransfer/GetScatterGatherList.

Max


You are currently subscribed to ntdev as: $subst(‘Recip.EmailAddr’)
To unsubscribe send a blank email to leave-ntdev-$subst(‘Recip.MemberIDChar’)@lists.osr.com

That’s true they would be. But then the documents caution against doing
that, for very good reasons. The recommended method is to allocate them
during driver initialization and then manage them yourself.

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Stephen Williams
Sent: Saturday, August 04, 2001 1:34 PM
To: NT Developers Interest List
Subject: [ntdev] RE: Mapping scattered pages into process address space

xxxxx@storagecraft.com said:

Common buffer pages are never scattered.

They are if you allocate them a page at a time, as needed.

Steve Williams “The woods are lovely, dark and deep.
xxxxx@icarus.com But I have promises to keep,
xxxxx@picturel.com and lines to code before I sleep,
http://www.picturel.com And lines to code before I sleep.”


You are currently subscribed to ntdev as: xxxxx@inland.net
To unsubscribe send a blank email to leave-ntdev-$subst(‘Recip.MemberIDChar’)@lists.osr.com


You are currently subscribed to ntdev as: $subst(‘Recip.EmailAddr’)
To unsubscribe send a blank email to leave-ntdev-$subst(‘Recip.MemberIDChar’)@lists.osr.com

It is a bad idea if your allocations are greater than page sized,
otherwise I think it really doesn’t matter.

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Maxim
S. Shatskih
Sent: Saturday, August 04, 2001 5:18 PM
To: NT Developers Interest List
Subject: [ntdev] RE: Mapping scattered pages into process
address space

> xxxxx@storagecraft.com said:
> > Common buffer pages are never scattered.
>
> They are if you allocate them a page at a time, as needed.

Is it a good practice?
Why not allocate the single, but large common buffer?

IIRC allocating/freeing common buffers constantly at run time
is a bad idea. The good idea is to allocate 1 common buffer
(maybe large) in DriverEntry/MN_START_DEVICE and do not
deallocate it during DriverUnload/MN_REMOVE_DEVICE.

If you need DMAble memory at run time - allocate some memory,
build a MDL and pass it through IoMapTransfer/GetScatterGatherList.

Max


You are currently subscribed to ntdev as:
xxxxx@hollistech.com To unsubscribe send a blank email to
leave-ntdev-$subst(‘Recip.MemberIDChar’)@lists.osr.com


You are currently subscribed to ntdev as: $subst(‘Recip.EmailAddr’)
To unsubscribe send a blank email to leave-ntdev-$subst(‘Recip.MemberIDChar’)@lists.osr.com

> xxxxx@storagecraft.com said:

> Common buffer pages are never scattered.

They are if you allocate them a page at a time, as needed.

xxxxx@storagecraft.com said:

Is it a good practice? Why not allocate the single, but large common
buffer?

That’s what I currently do, but these are buffers big enough to hold
a set of images, so that’s a lot of common memory that is not available
to the system once the buffer is allocated. I only want to allocate
the memory when the device is in use, and in amounts dictated by the
application.

Because the buffer is so large, it is nary impossible to allocate
a contiguous buffer that large once the system is running. The memory
is too fragmented.

Under Linux, the driver allocates the memory a page at a time according
to the needs of the application/firmware, and since I allocate it a page
at a time, fragmentation is not an issue. The application uses the mmap
system call, which the driver implements by supplying a vm_ops with the
appropriate funcitons, and I’m golden. Mapping scattered memory into the
application is trivial.

Under NT, this technique simply doesn’t exist to I provide an ioctl to
perform the mmap. I use ZwMapViewOfSection to map a buffer into the
address space of the application, and that works. (This buffer can be
shared by threads/processes.) However, that buffer under NT must be
contiguous.

And since it is contiguous under NT, it is impractical (fragmentation)
to allocate it when the application needs it and I’m forced to make
the user configure the driver (by registry keys) to preallocate the
buffer at driver boot time. This is an extra, useless administrative
step, and a waste of memory because the memory is only needed when the
application is using the board, and different applications may need
different size buffers.

Another possibility is to allocate the memory in the application and
pass it down through an ioctl. The ioctl can pin the memory down and
get the physical addresses needed to pass to the hardware. The problem
I see with this is that the memory may wind up somewhere where the
device can’t get to it (isn’t that what AllocateCommonBuffer is for?)
and then where will I be?

Steve Williams “The woods are lovely, dark and deep.
xxxxx@icarus.com But I have promises to keep,
xxxxx@picturel.com and lines to code before I sleep,
http://www.picturel.com And lines to code before I sleep.”


You are currently subscribed to ntdev as: $subst(‘Recip.EmailAddr’)
To unsubscribe send a blank email to leave-ntdev-$subst(‘Recip.MemberIDChar’)@lists.osr.com

> Another possibility is to allocate the memory in the application and

pass it down through an ioctl.

This looks OK.

get the physical addresses needed to pass to the hardware. The problem
I see with this is that the memory may wind up somewhere where the
device can’t get to it (isn’t that what AllocateCommonBuffer is for?)

Use IoMapTransfer/GetScatterGatherList to manage this memory.

Max


You are currently subscribed to ntdev as: $subst(‘Recip.EmailAddr’)
To unsubscribe send a blank email to leave-ntdev-$subst(‘Recip.MemberIDChar’)@lists.osr.com