2004-09-16 14:08:48

by Richard B. Johnson

[permalink] [raw]
Subject: Re: Having problem with mmap system call!!!

On Thu, 16 Sep 2004, Srinivas G. wrote:

> Hi All,
>
> I have a doubt about mmap system call.
>

mmap() works. Otherwise you wouldn't be sending any email.
It is used every time you open an application because that's
how shared libraries work.

You need to return the PHYSICAL address of your camera buffer
to user-space (probably using a driver ioctl()). Then the
user-mode code does ....


#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>

#define HINT 0x20000000
#define PROT (PROT_READ|PROT_WRITE)
#define FLAGS (MAP_FIXED|MAP_SHARED)
#define SHM_FAIL (void *)-1


void *init_shmem(size_t addr, size_t len)
{
int fd;
void *vp;
if((fd = open("/dev/mem", O_RDWR, 0)) < 0)
{
fprintf(stderr, "Can't open memory device\n");
exit(EXIT_FAILURE);
}
if((vp = mmap((caddr_t) HINT, len, PROT, FLAGS, fd, addr)) == SHM_FAIL)
{
fprintf(stderr, "Can't access shared memory\n");
exit(EXIT_FAILURE);
}
(void)close(fd);
return vp;
}

After that, anything the camera writes to its address will
be available in user-mode at the memory-mapped address.
This DOES work. That's how I do direct DMA to user-space
all the time.

Cheers,
Dick Johnson
Penguin : Linux version 2.4.26 on an i686 machine (5570.56 BogoMips).
Note 96.31% of all statistics are fiction.


2004-09-16 14:40:09

by Alan

[permalink] [raw]
Subject: Re: Having problem with mmap system call!!!

On Iau, 2004-09-16 at 15:07, Richard B. Johnson wrote:
> if((vp = mmap((caddr_t) HINT, len, PROT, FLAGS, fd, addr)) == SHM_FAIL)
> {
> fprintf(stderr, "Can't access shared memory\n");
> exit(EXIT_FAILURE);

SHM_FAIL is the wrong error check btw.

It is much better to do this in the driver than do nasty user mode hacks
using /dev/mem. When you do it kernel driver side you end up with a
cleaner mmap interface, a sensible permissions model and the hardware
device pages mapped directly and nicely into the app

2004-09-16 14:55:26

by Richard B. Johnson

[permalink] [raw]
Subject: Re: Having problem with mmap system call!!!

On Thu, 16 Sep 2004, Alan Cox wrote:

> On Iau, 2004-09-16 at 15:07, Richard B. Johnson wrote:
> > if((vp = mmap((caddr_t) HINT, len, PROT, FLAGS, fd, addr)) == SHM_FAIL)
> > {
> > fprintf(stderr, "Can't access shared memory\n");
> > exit(EXIT_FAILURE);
>
> SHM_FAIL is the wrong error check btw.
>

MAP_FAILED only appeared in real late 'C' runtime library headers.
That's why the code defines SHM_FAIL, which is also correct, but
doesn't cause a redefinition error.

> It is much better to do this in the driver than do nasty user mode hacks
> using /dev/mem. When you do it kernel driver side you end up with a
> cleaner mmap interface, a sensible permissions model and the hardware
> device pages mapped directly and nicely into the app
>

Well that's really nice. Now, how do you do that? The kernel DS
is not the user DS so you end up with a kernel hack instead of
a user hack?

Cheers,
Dick Johnson
Penguin : Linux version 2.4.26 on an i686 machine (5570.56 BogoMips).
Note 96.31% of all statistics are fiction.

2004-09-16 17:06:44

by Alan

[permalink] [raw]
Subject: Re: Having problem with mmap system call!!!

On Iau, 2004-09-16 at 15:54, Richard B. Johnson wrote:
> > SHM_FAIL is the wrong error check btw.
> >
>
> MAP_FAILED only appeared in real late 'C' runtime library headers.
> That's why the code defines SHM_FAIL, which is also correct, but
> doesn't cause a redefinition error.

SuS doesn't permit the use of SHM_FAIL. And you don't get redefinition
errors if you use ds

> Well that's really nice. Now, how do you do that? The kernel DS
> is not the user DS so you end up with a kernel hack instead of
> a user hack?

Who cares about DS ? the user space page tables get mapped, its how all
mmap functions work. A simple example is the sound drivers (2.4
drivers/sound) which kmalloc a buffer of kernel space then make it
mappable to the user

2004-09-16 18:21:56

by Richard B. Johnson

[permalink] [raw]
Subject: Re: Having problem with mmap system call!!!

On Thu, 16 Sep 2004, Alan Cox wrote:

> On Iau, 2004-09-16 at 15:54, Richard B. Johnson wrote:
> > > SHM_FAIL is the wrong error check btw.
> > >
> >
> > MAP_FAILED only appeared in real late 'C' runtime library headers.
> > That's why the code defines SHM_FAIL, which is also correct, but
> > doesn't cause a redefinition error.
>
> SuS doesn't permit the use of SHM_FAIL. And you don't get redefinition
> errors if you use ds
>
> > Well that's really nice. Now, how do you do that? The kernel DS
> > is not the user DS so you end up with a kernel hack instead of
> > a user hack?
>
> Who cares about DS ? the user space page tables get mapped, its how all
> mmap functions work. A simple example is the sound drivers (2.4
> drivers/sound) which kmalloc a buffer of kernel space then make it
> mappable to the user
>

Alan,
Here is some code from a video driver.

static int vino_mmap(struct file *file, struct vm_area_struct *vma)
{
struct video_device *dev = video_devdata(file);
struct vino_device *v = dev->priv;
unsigned long start = vma->vm_start;
unsigned long size = vma->vm_end - vma->vm_start;
int i, err = 0;

if (down_interruptible(&v->sem))
return -EINTR;
if (size > v->page_count * PAGE_SIZE) {
err = -EINVAL;
goto out;
}
for (i = 0; i < v->page_count; i++) {
unsigned long page = virt_to_phys((void *)v->desc[i]);
if (remap_page_range(start, page, PAGE_SIZE, PAGE_READONLY)) {
err = -EAGAIN;
goto out;
}
start += PAGE_SIZE;
if (size <= PAGE_SIZE) break;
size -= PAGE_SIZE;
}
out:
up(&v->sem);
return err;

}

I deliberately used this as a sample so you can't say what
you usually say... Anyway are you aware that ...

unsigned long size = vma->vm_end - vma->vm_start;

... ends up being 32 bytes longer than the length the user-mode
code put into mmap()?

That's why I use a driver ioctl() to return the physical address
and the length so user-mode code can mmap() without the hassle
of "optimizations" (read kernel bugs) mucking with buffers,
especially those then end up overlapping because of bugs like
above.

Now, if somebody is having trouble with mmap(), it is quite
a bit better I believe, to reduce the basic user-mode mem-mapping
to its lowest common denominator. Therefore, I showed what was
guaranteed to work.

Cheers,
Dick Johnson
Penguin : Linux version 2.4.26 on an i686 machine (5570.56 BogoMips).
Note 96.31% of all statistics are fiction.

2004-09-16 21:04:41

by Alan

[permalink] [raw]
Subject: Re: Having problem with mmap system call!!!

On Iau, 2004-09-16 at 19:13, Richard B. Johnson wrote:

> for (i = 0; i < v->page_count; i++) {
> unsigned long page = virt_to_phys((void *)v->desc[i]);
> if (remap_page_range(start, page, PAGE_SIZE, PAGE_READONLY)) {
> err = -EAGAIN;
> goto out;
> }
> start += PAGE_SIZE;

Actually thats a nice example of how easy it is to implement mmap
properly.


> you usually say... Anyway are you aware that ...
>
> unsigned long size = vma->vm_end - vma->vm_start;
>
> ... ends up being 32 bytes longer than the length the user-mode
> code put into mmap()?

Its page aligned, that is what mmap() says happens.