On Thu, Oct 07, 2004 at 10:15:58AM +0900, Atsushi Nemoto wrote:
> >>>>> On Wed, 6 Oct 2004 15:09:36 -0700, Jun Sun <email@example.com> said:
> >> I found a potential problem in math emulation. The math-emu uses
> >> put_user/get_user to fetch the instruction or to emulate load/store
> >> fp-regs. The put_user/get_user can sleep then we can lose fpu
> >> ownership on it. It it happened, subsequent restore_fp will cause
> >> CpU exception which not allowed in kernel.
> jsun> I don't feel good about this patch. If emulator loses FPU
> jsun> ownership it should get it back, not the caller of emulator.
> Hmm... Inserting following 2 lines after each get_user, put_user (and
> do_dsemulret, mips_dsemul, cond_resched) in cp1emu.c is better?
> if (!is_fpu_owner())
> Actually, FPU might be lost in get_user, so get_user should get it
> back? I don't think so. Similarly, getting it back by the caller of
> emulator is not so bad, I think. Maintenance of FPU ownership is not
> emulator's work, isn't it?
This problem is apparently bigger than I thought.
The FPU context is treated as a "half-way" process context in that
it is saved when a process is switched out and only restored on demand
when process uses FPU again.
Since only user code is allowed to use FPU, current kernel assumes
restoring FPU registers must be triggered by user code.
Preemption in the middle FPU manipulation in kernel can cause trouble to above
assumptions but we can avoid it by using proper disable_preemption and
Now we basically face another trouble, i.e., put_user/get_user.
Maybe the easy way out is to allow FPU trap in kernel. What do you
think? The idea sounds dangerous but seems to be OK for the suitations
we are discussing here.
The other approach is basically your fix. That is, if we are in the middle
of a block FPU manipulations, we ensure we have consistent FPU state
after each operation that could potentially switch the current process out.
As to where should we put the "if (....) own_fpu()", I think it should be
put right after the operation we could be switched out, i.e., get_user()/
put_user() in this case.
BTW, it is safe to disable preemption before calling anything functions
that could potentially block or switch current process out.