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>