Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 7 Jan 2013 15:25:33 -0200
From:      "Dr. Rolf Jansen" <rj@cyclaero.com>
To:        freebsd-drivers@freebsd.org
Subject:   Re: How to map device addresses into user space
Message-ID:  <F62E8A3F-7D16-49F9-9375-5FFE2CBAAF09@cyclaero.com>
In-Reply-To: <201301071011.49234.jhb@freebsd.org>
References:  <DFC983B8-91B2-4ED8-89B0-FC4BD4AB2576@cyclaero.com> <033249A9-9C77-426F-BCA2-3A22CC4F9391@cyclaero.com> <201301071011.49234.jhb@freebsd.org>

next in thread | previous in thread | raw e-mail | index | archive | help
Am 07.01.2013 um 13:11 schrieb John Baldwin:

> On Monday, January 07, 2013 08:52:01 AM Dr. Rolf Jansen wrote:
>=20
>> Am 03.01.2013 um 14:45 schrieb Dr. Rolf Jansen:
>>=20
>>> ...
>>>=20
>>> So, how can I map device addresses into user space on FreeBSD?
>>=20
>> Many Thanks to everybody, who responded.
>>=20
>> I got it working. I wrote a PCI device driver, which in addition to
>> open/close/read/write responds also to ioctl and mmap requests from =
user
>> space. In its pci_attach routine, it assembles a custom address_space
>> struct containing the addresses of the two BAR's of my NI PCI-DAQ =
board
>> and two huge allocated memory regions for DMA...
>>=20
>=20
> Note that if your BARs are not contiguous you can allow mapping of =
things in=20
> the middle.  This is a potentital security hole if your driver can be =
opened=20
> by non-root.

I can understand this. Actually, on the present model of the DAQ board, =
the
BARs are contiguous, and in the present incarnation, my driver can only =
be
addressed by root. Anyway, I want to do it correctly, that means, I =
would
like to avoid right now potential holes bubbling up in the future, when =
using
my driver with other DAQ boards, and in different usage scenarios.

> A more robust approach is to define a virtual address space for=20
> your device. This is also a lot easier to program against in userland.
> For example, you could define offset 0 as mapping to BAR 0 and the =
next chunk
> of virtual address space (the offset) map to BAR 1, etc.:

I did this, but id didn't work out. The 2 BARs are contiguous, and the 2 =
DMA
regions are also, but there is huge gap between BAR and DMA. And =
depending on
which mapping is done first, either the DMAs or the BARs receive invalid =
paddr.
So, I guess, defining a virtual address space is a little bit more =
involved
than simply getting the offsets straight as you lined out.=20

I am still learning things, so please bear with me, if it is a dumb =
question.
How do I define a virtual address space for the device?

> static int
> mydaq_mmap(...)
> {
> 	struct mydaq_softc *sc;  // you should be storing things like =
the pointers
>                             // to your BARs in a softc
>=20
> 	sc =3D dev->si_drv1;
> 	if (offset <=3D rman_get_size(sc->bar0res))
> 		return (rman_get_start(sc->bar0res) + offset);
> 	offset -=3D rman_get_size(sc->bar0res);
> 	if (offset <=3D rman_get_size(sc->bar1res))
> 		return (rman_get_start(sc->bar1res) + offset);
> 	offset -=3D rman_get_size(sc->bar1res);
> 	if (offset <=3D dmaAIBufSize)
> 		return (vtophys(sc->dma[0]) + offset);
> 	offset -=3D dmaAIBufSize;
> 	if (offset <=3D dmaAOBufSize)
> 		return (vtophys(sc->dma[1]) + offset);
> =09
> 	/* Invalid offset */
> 	return (-1);
> }

I guess, you hacked this quickly together, and I picked the concept, so
this is fine. In order to make this working, the addresses should be =
assigned
to the *paddr parameter, and a status code should be returned. In order =
to
check things, of course I applied these minor corrections, but it =
doesn't
work for either the BAR block or the DMA block, depending on which is =
mapped first.

> Also, rman_get_bushandle() is not appropriate to get a virtual =
address, that is an=20
> implementation detail you should not count on.  You could use =
rman_get_virtual(),
> but that is not the best practice.  Using rman_get_start()=20
> to get a PA directly is a better approach.

Yes, this is much more reasonable than my approach. I was already =
concerned about
rman_get_bushandle() making a vaddr from a paddr in kernel space, only =
to translate
it back to a paddr in user space. rman_get_start() is of course much =
better, and I
will change to this, once I got the definition of a virtual address =
space straight.

Many thanks for your very helpful response.

Best regards

Rolf




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?F62E8A3F-7D16-49F9-9375-5FFE2CBAAF09>