Re: Mapping kernel memory into user space

Linus Torvalds (torvalds@cs.helsinki.fi)
Wed, 17 Jul 1996 07:09:55 +0300 (EET DST)


On Tue, 16 Jul 1996 Thomas.Koenig@ciw.uni-karlsruhe.de wrote writing for
Hubert Schreier:
>
> I am writing a device driver for a PCI video capture board that writes image
> data directly into the memory of the computer. As it is impossible to obtain
> large contiguos memory areas in kernel space, I use blocks of 4k and program
> the framegrabber's processor to write to them. To obtain fast acces to the
> image data, I want to use memory mapped acces. However, I cannot figure out
> how to map these 4k blocks to a contiguos area in user space memory. For
> allocating the blocks I use
>
> get_free_page();
>
> The driver works fine when using my read(), which copies the data to user
> memory via memcpy_to_fs(). In the drivers mmap() function, I tried to
> subsequently map the blocks to user space via remap_page_range(). This does
> not work at all, not even for the first page.

Don't use remap_page_range, what you should do instead is to just have a
"nopage()" handler in your driver, and when the mm layer then calls you
for a page, you give the appropriate page to the mm layer.

Look into the file "mm/filemap.c", and look at how the code uses "struct
vm_operations_struct". You don't need "swapin/swapout" - just leave those
as NULL, and the mm code will do the right thing.

(in fact, look at the "private" mapping struct: it _only_ contains the
"nopage" function, and that may be enough for you too. You may want to
add the "unmap" and "sync" entries if you need to start any write-back IO
to the device, though).

> Q1: How can I map non-contiguos memory pages in kernel space to a
> contiguos area in user space?

Let the mm layer worry about that, and call you when the user accesses a
page it can't find - then it will call your "nopage" function, and you
just return the correct page for the offset given.

Note that memory mapping devices is subtle, so you should read the
appropriate parts of filemap.c file closely, but you should also remember
that filemap.c does a lot of things you don't actually need (writing the data
back to a shared file, handling the file cache etc).

> Q2: Is there a way to use shared memory, so I could use XShmPutImage()
> to write to a window?

No. If you want that, then you shouldn't mmap() the device, instead you
should just create a shared memory area in your application and do a
"read()" on the device. The device could look up the physical addresses
of the pages etc.. HOWEVER: BE VERY CAREFUL WHEN DOING THIS!

> Q3: Which flags for get_free_page() insure that the pages won't be
> swapped out?

The kernel never swaps out kernel data, so get_free_page() needs no such
flags.

The kernel _will_ swap out the pages that are mapped in user space, but
that just means you should increase the usage counter of the page (with
"atomic_inc(&mmem_map[PAGE_NR(page)].count)") before handing it off to
the memory manager in your "nopage" routine. That way the page won't
actually disappear from under you (it might get unmapped from the page
tables, but even that is unlikely).

Linus