Re: MMX for kernel

rohrer keith w (kwrohrer@cs.uiuc.edu)
Fri, 7 Feb 1997 11:59:41 -0600 (CST)


> The really important point (which I think Jason didn't understand) is
> that the FPU registers *aren't* saved and restored across task
> switches. The kernel plays a lazy evaluation game; there is a pointer
> which points to the task which last used the FPU, and if the task that
> is currently running isn't that task, the FPU is set to be
> *invalidated*, which causes the i386 hardware to perform a fault to the
> kernel when an FPU instruction is attempted. At that point, the kernel
> saves the FPU registers for the old task, loads the FPU registers for
> the currently running task, and restarts the instruction.
[snip]
> As a result, though, if the kernel wants to use the FPU registers, it
> absolutely will have to save and then restore them, to avoid screwing up
> the above scheme.
Saving the old registers is necessary, assuming the last process to use
the FPU is still alive (otherwise it's a no-op). However, a later restore
should be already handled by the existing code, so long as we can pretend
to be just another task...separate from our "user space persona", if any.
That last might be the tricky part...

> Actually, what we could do is put in better logic to
> determine whether or not the FPU is in use by a task (which is harder
> than you think because crt0 does zero them out, so you have to filter
> out that case), and then if the FPU isn't in use, you wouldn't need to
> restore the FPU right away.
Not "in use by a task", but "in use by this task" (or even "in use by this
task in user space" if we let the compiler worry about nested usage
of the FPU within the kernel). I assume that either this kernel-level FPU
usage happens with interrupts off, or that it already handles the
possibility of a context switch to and back from some other FPU-using
process. To determine whether you want to restore the FPU registers
immediately, before you start using the FPU you should check and
see if the current task was the last FPU user. If it was, then you
may as well restore the FPU registers when you finish, and leave the
387 valid (the current task should already still be the last user); if
it was not, invalidate the FPU and set the last user to some flavor of
"none", so that nothing bothers to save the garbage you'll never use again.
A stricter test (useful in the case of multiple processes using the FPU
lightly) would be to see if the current task was the last FPU user and
the 387 is still valid (i.e. it used the FPU this timeslice); if so,
you certainly want to restore the FPU immediately, and if not, you may
wish to put off the restore.

> (You'd still have to do the lazy save, to
> avoid losing the current FPU state.)
True, assuming the current FPU state belongs to a live process.

In summary: see if we need to restore immediately by seeing if our user-
level FPU usage was recent, and make sure we won't bother to save the
dirty FPU registers once we're done with them (I'd hope this is done
already...).

Keith