Subject: FPU context management problem

From: Atsushi Nemoto <[email-masked]>
Date: Tue, 19 Sep 2000 14:52:07 +0900

I'm running kernel 2.2.14 (based on linux-2.2.14-000715.tar.gz) and
found a floating point calculation sometimes results an incorrect
value.

I think the problem is last 'if' statement in setup_sigcontext().

	owned_fp = (current == last_task_used_math);
	err |= __put_user(owned_fp, &sc->sc_ownedfp);

	if (current->used_math) {	/* fp is active.  */
		set_cp0_status(ST0_CU1, ST0_CU1);
		err |= save_fp_context(sc);
		last_task_used_math = NULL;
		regs->cp0_status &= ~ST0_CU1;
		current->used_math = 0;
	}

This code can discard other task's FPU context in certain situations.
The scenario is:

(-2) Task_A executes FP insns.
(-1) Task_B executes FP insns.
(0) Task_C executes FP insns.
# save Task_B's FPU context.
# init Task_C's FPU context.
(1) Context switch (Task_C to Task_A).
(2) Task_A catch a signal.
    setup_sigcontext() and restore_sigcontext() is called.
# Task_A's used_math was 1 and owned_fp was 0,
# so last_task_used_math becomes NULL.
(3) Context switch (Task_A to Task_B).
(4) Task_B executes FP insns.
# restore Task_B's FPU context. (discard Task_C's FPU context)
(5) Context switch (Task_B to Task_C).
(6) Task_C execute FP insns.  (with Task_B's FPU context!)

I modified the 'if' statement as follows and the problem seems to be
fixed.

	if (owned_fp) {	/* fp is active.  */
		...
	}

Is this the right fix?

---
Atsushi Nemoto