From owner-freebsd-drivers@FreeBSD.ORG Mon Jan 7 17:25:42 2013 Return-Path: Delivered-To: freebsd-drivers@freebsd.org Received: from mx1.freebsd.org (mx1.FreeBSD.org [8.8.178.115]) by hub.freebsd.org (Postfix) with ESMTP id 05377A46; Mon, 7 Jan 2013 17:25:42 +0000 (UTC) (envelope-from rj@cyclaero.com) Received: from mo6-p00-ob.rzone.de (mo6-p00-ob.rzone.de [IPv6:2a01:238:20a:202:5300::1]) by mx1.freebsd.org (Postfix) with ESMTP id 6DFBF8F7; Mon, 7 Jan 2013 17:25:41 +0000 (UTC) X-RZG-AUTH: :O2kGeEG7b/pS1E6gSHOyjPKyNsg/5l1He+DgCy9/8FSej6CwUysqfN3Dd+qW8pifIOtG X-RZG-CLASS-ID: mo00 Received: from rolf.projectworld.net (b150f525.virtua.com.br [177.80.245.37]) by smtp.strato.de (jored mo31) (RZmta 31.11 DYNA|AUTH) with (AES128-SHA encrypted) ESMTPA id e0713dp07G3WDi ; Mon, 7 Jan 2013 18:25:36 +0100 (CET) Subject: Re: How to map device addresses into user space Mime-Version: 1.0 (Apple Message framework v1283) Content-Type: text/plain; charset=iso-8859-1 From: "Dr. Rolf Jansen" In-Reply-To: <201301071011.49234.jhb@freebsd.org> Date: Mon, 7 Jan 2013 15:25:33 -0200 Content-Transfer-Encoding: quoted-printable Message-Id: References: <033249A9-9C77-426F-BCA2-3A22CC4F9391@cyclaero.com> <201301071011.49234.jhb@freebsd.org> To: freebsd-drivers@freebsd.org X-Mailer: Apple Mail (2.1283) X-BeenThere: freebsd-drivers@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: Writing device drivers for FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 07 Jan 2013 17:25:42 -0000 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