Subject: Re: mmap for pseudo devices.
To: None <tech-kern@netbsd.org>
From: Jason R Thorpe <thorpej@zembu.com>
List: tech-kern
Date: 03/14/2000 08:27:08
On Tue, Mar 14, 2000 at 06:28:34PM +1100, Darren Reed wrote:
> Are there any examples/docs on how to implement mmap in a pseudo driver
> to facilitate mmap'ing of an array, etc, via mmap(2) ? "man -k mmap"
> only shows up the man page for bus_dma(9) and mmap(2)...and neither do
> any of the `stubs' under /usr/share/lkm provide any clues...
It's pretty trivial, although just about everything uses machine-dependent
macros to do all of it. For a pseudo-device, you don't have to.
I'm assuming your device is a character device ... so, you will be using
the device pager (don't worry; the VM system hides all of this from you,
really :-)
The first thing you need to do is pick some arbitrary offsets for your
mmap interface. Like "mmap offset 0-M gives object A, N-O gives object B",
etc.
Then your mmap routine would look something like this:
int
foommap(dev, off, prot)
dev_t dev;
int off, prot;
{
if (off & PAGE_MASK)
panic("foommap");
if ((u_int)off >= FOO_REGION1_MMAP_OFFSET &&
(u_int)off < (FOO_REGION1_MMAP_OFFSET + FOO_REGION1_SIZE))
return (atop(FOO_REGION1_ADDR + ((u_int)off -
FOO_REGION1_MMAP_OFFSET)));
if ((u_int)off >= FOO_REGION2_MMAP_OFFSET &&
(u_int)off < (FOO_REGION2_MMAP_OFFSET + FOO_REGION2_SIZE))
return (atop(FOO_REGION1_ADDR + ((u_int)off -
FOO_REGION2_MMAP_OFFSET)));
/* Page not found. */
return (-1);
}
Now, of course, this is slightly more complicated by the fact that you are
going to be mmap'ing what are simply kernel memory objects (it is a
pseudo-device, after all).
In order to make this work, you're going to want to make sure you allocate
the memory objects to be mmap'd on page-aligned boundaries. If you are
allocating something >= PAGE_SIZE in size, this is guaranteed. Otherwise,
you are going to have to use uvm_km_alloc(), and round your allocation size
up to page size.
Then, it would look a bit more like this:
int
foommap(dev, off, prot)
dev_t dev;
int off, prot;
{
paddr_t pa;
if (off & PAGE_MASK)
panic("foommap: offset not page aligned");
if ((u_int)off >= FOO_REGION1_MMAP_OFFSET &&
(u_int)off < (FOO_REGION1_MMAP_OFFSET + FOO_REGION1_SIZE)) {
if ((vaddr_t)foo_object1 & PAGE_MASK)
panic("foommap: foo_object1 not page aligned");
if (pmap_extract(pmap_kernel(), foo_object1 +
(u_int)off - FOO_REGION1_MMAP_OFFSET, &pa) == FALSE)
panic("foommap: foo_object1 page not mapped");
return (atop(pa));
}
if ((u_int)off >= FOO_REGION2_MMAP_OFFSET &&
(u_int)off < (FOO_REGION2_MMAP_OFFSET + FOO_REGION2_SIZE)) {
if ((vaddr_t)foo_object2 & PAGE_MASK)
panic("foommap: foo_object2 not page aligned");
if (pmap_extract(pmap_kernel(), foo_object2 +
(u_int)off - FOO_REGION2_MMAP_OFFSET, &pa) == FALSE)
panic("foommap: foo_object2 page not mapped");
return (atop(pa));
}
/* Page not found. */
return (-1);
}
Clear as mud? :-)
--
-- Jason R. Thorpe <thorpej@zembu.com>