On Tuesday 23 October 2007 07:52:41 Issei Suzuki wrote: > 2007/10/23, Daan Vreeken [PA4DAN] <[EMAIL PROTECTED]>: > > 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 _______________________________________________ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "[EMAIL PROTECTED]"