From owner-freebsd-hackers@FreeBSD.ORG Tue Oct 23 12:00:53 2007 Return-Path: Delivered-To: freebsd-hackers@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id BA7D816A417 for ; Tue, 23 Oct 2007 12:00:53 +0000 (UTC) (envelope-from Danovitsch@vitsch.net) Received: from VM01.Vitsch.net (vm01.vitsch.net [85.17.51.140]) by mx1.freebsd.org (Postfix) with ESMTP id 665A113C481 for ; Tue, 23 Oct 2007 12:00:52 +0000 (UTC) (envelope-from Danovitsch@vitsch.net) Received: from Tuinhuisje.Vitsch.net ([217.166.176.2]) by VM01.Vitsch.net (8.13.8/8.13.8) with ESMTP id l9NBwOlN066107; Tue, 23 Oct 2007 13:58:25 +0200 (CEST) (envelope-from Danovitsch@vitsch.net) Received: from [192.168.72.251] (81-171-30-78.dsl.fiberworld.nl [81.171.30.78] (may be forged)) (authenticated bits=0) by Tuinhuisje.Vitsch.net (8.13.1/8.13.1) with ESMTP id l9NBxlUa015665; Tue, 23 Oct 2007 13:59:49 +0200 (CEST) (envelope-from Danovitsch@vitsch.net) From: "Daan Vreeken [PA4DAN]" Organization: Vitsch Electronics To: "Issei Suzuki" Date: Tue, 23 Oct 2007 13:59:32 +0200 User-Agent: KMail/1.9.7 References: <200710222211.51590.Danovitsch@vitsch.net> <337dbc4d0710222252o1817e359k393a398de2315677@mail.gmail.com> In-Reply-To: <337dbc4d0710222252o1817e359k393a398de2315677@mail.gmail.com> MIME-Version: 1.0 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit Content-Disposition: inline Message-Id: <200710231359.32979.Danovitsch@vitsch.net> Cc: freebsd-hackers@freebsd.org Subject: Re: Floating point in interrupt handler X-BeenThere: freebsd-hackers@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Technical Discussions relating to FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 23 Oct 2007 12:00:53 -0000 On Tuesday 23 October 2007 07:52:41 Issei Suzuki wrote: > 2007/10/23, Daan Vreeken [PA4DAN] : > > So I've added asm inline functions to use the FPU's fsin and fcos > > operands. At the start of my loop function I (try to) save the FPU state > > with the following code : > > td = curthread; > > npxgetregs(td, &fpu_state); > > At the end of the function I restore the FPU state with : > > npxsetregs(td, &fpu_state); > > > > In between I currently have : > > // create a 500Hz sine wave, modulate it with a 2Hz sine wave and > > // let it have a 10.0 Volt amplitude > > t += 0.0001; > > set_dac_voltage(card, 0, > > fp_sin(500 * 2 * M_PI * t) * fp_sin(2 * 2 * M_PI * t) * 10.0); > > > > As uggly as the code may seem, it works and the output of the acquisition > > board shows the expected signal on a scope. While the code seems to do > > what it should, the kernel floods the console with the following message > > : kernel trap 22 with interrupts disabled > > In FreeBSD, FPU context switch is delayed until FPU is used for the > first time after user thread is switched. To achieve this, T_DNA > (FPU device not available trap) is used as follows. > > (Before switching thread) > 1. Save FPU state and enable DNA trap (npxsave() @ /sys/i386/isa/npx.c). > After this, DNA trap occurs when you access FPU. > (Switch to another user thread) > 2. User thread accesses FPU. > 3. T_DNA trap occurs, and npxdna() @ /sys/i386/isa/npx.c is called. > 4. Initialize FPU state (1st time) or restore FPU state (2nd times or > later). 5. Return to user mode, and user thread access FPU again. > > So, to use FPU in kernel, you must clear T_DNA trap and initialize FPU > registers first. > > Reading these functions may help you, I think. > > /sys/i386/isa/npx.c > start_emulating() > stop_emulating() > npxdna() Thanks for the insights, this has helped a lot. If I understand the code correctly, there are 2 options when the kernel arrives at hardclock() : o The current process is using the FPU (fpcurthread != NULL) o The current process hasn't used the FPU (yet) since it has been switched to (fpcurthread == NULL) In the first case, FPU instructions can be used and will not result in a trap, but we should save/restore the FPU state before using them so userland doesn't get confused. In the last case FPU instructions result in a trap, so we need stop/start_emulating(), but as no one is using the FPU, there is no need to save/restore it's state. With this in mind I've come up with the following code : At the start of the function : // check FPU state on entry if (PCPU_GET(fpcurthread) != NULL) { // someone is using the FPU // save it's state and remember to put it back later restore = 1; fpusave(&fpu_state); } else { // no one is using the FPU // enable use of FPU instructions, no need to save it's state restore = 0; stop_emulating(); } // init FPU state every time we get here, as we don't know who has // been playing with it in between calls fninit(); control = __INITIAL_NPXCW__; fldcw(&control); Then we do some floating point arithmetic. And at the end of the function : // restore FPU state before we leave if (restore) { // restore FPU registers to what they were fpurstor(&fpu_state); } else { // no one was using the FPU, so re-enable the FPU trap start_emulating(); } With this code trap-22 has stopped to trigger within my function. The FPU instructions still seem to be executed correctly in my function and when adding a couple of printf()'s I can see it fpusave() and fpurstor() when interrupting a userland process that uses the FPU. Does this look reasonable to everyone? Thanks, -- Daan