Floating point in interrupt handler
M. Warner Losh
imp at bsdimp.com
Sat Oct 27 10:39:01 PDT 2007
In message: <200710271853.44167.Danovitsch at vitsch.net>
"Daan Vreeken [PA4DAN]" <Danovitsch at vitsch.net> writes:
: Hi Warner,
:
: On Wednesday 24 October 2007 23:15:13 you wrote:
: > In message: <200710222211.51590.Danovitsch at vitsch.net>
: >
: > "Daan Vreeken [PA4DAN]" <Danovitsch at vitsch.net> writes:
: > : But what I haven't found is a description of exactly what the kernel is
: > : missing to allow floating point operations to be done there.
: >
: > FPU context is assumed to only change in user processes. You'd have
: > to fix the FPU state saving code to cope with it changing everywhere,
: > or you'd have to explicitly put the goo to save/restore it around the
: > FP you want to do in the kernel.
:
: Issei Suzuki pointed me into the right direction in his reply. (The following
: text is an exact copy of the reply I sent to Issei, but I'll just copy it
: here to show the code)
: If I understand the npx 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?
My concern here would be to make sure that your code doesn't migrate
from one CPU to another. Other than that, I think it is OK.
Warner
More information about the freebsd-hackers
mailing list