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>