Hi,

As once discussed with Heikki, and after a first missed attempt, here
is a patch for x86 which attempts to cope correctly with Linux (non
real-time) drivers using FPU in kernel-space.

I tested it on my laptop without drivers using FPU, and it appears to
work correctly, but it would be nice if people that had problems with
the previous attempt (if I remember correctly, on old pentiums and on
AMD processors) could test this patch.

Thanks in advance.

--
                                                 Gilles Chanteperdrix
Index: include/asm-i386/system.h
===================================================================
--- include/asm-i386/system.h	(revision 1704)
+++ include/asm-i386/system.h	(working copy)
@@ -69,6 +69,7 @@
     /* FPU context bits for root thread. */
     unsigned is_root: 1;
     unsigned ts_usedfpu: 1;
+    unsigned cr0_ts: 1;
 
 } xnarchtcb_t;
 
Index: include/asm-i386/bits/pod.h
===================================================================
--- include/asm-i386/bits/pod.h	(revision 1704)
+++ include/asm-i386/bits/pod.h	(working copy)
@@ -44,6 +44,7 @@
 	/* Remember the preempted Linux task pointer. */
 	rootcb->user_task = rootcb->active_task = current;
 	rootcb->ts_usedfpu = wrap_test_fpu_used(current) != 0;
+	rootcb->cr0_ts = (read_cr0() & 8) != 0;
 	/* So that xnarch_save_fpu() will operate on the right FPU area. */
 	rootcb->fpup = &rootcb->user_task->thread.i387;
 }
@@ -265,12 +266,21 @@
 {
 	struct task_struct *task = tcb->user_task;
 
-	if (task) {
-		if (!wrap_test_fpu_used(task))
+	if (!tcb->is_root) {
+		if (task) {
+			/* fpu not used or already saved by __switch_to. */
+			if (!wrap_test_fpu_used(task))
+				return;
+
+			/* Tell Linux that we already saved the state of the FPU
+		   	hardware of this task. */
+			wrap_clear_fpu_used(task);
+		}
+	} else {
+		if (tcb->cr0_ts || 
+		    (tcb->ts_usedfpu && !wrap_test_fpu_used(task)))
 			return;
 
-		/* Tell Linux that we already saved the state of the FPU
-		   hardware of this task. */
 		wrap_clear_fpu_used(task);
 	}
 
@@ -298,13 +308,14 @@
 			wrap_set_fpu_used(task);
 		}
 	} else {
-		/* Restore state of FPU if TS_USEFPU bit was armed. */
-		if (!tcb->ts_usedfpu) {
+		/* Restore state of FPU only if TS bit in cr0 was clear. */
+		if (tcb->cr0_ts) {
 			stts();
 			return;
 		}
 
-		wrap_set_fpu_used(task);
+		if (tcb->ts_usedfpu)
+			wrap_set_fpu_used(task);
 	}
 
 	/* Restore the FPU hardware with valid fp registers from a
@@ -336,7 +347,7 @@
 			}
 		}
 	} else {
-		if (!tcb->ts_usedfpu)
+		if (tcb->cr0_ts)
 			return;
 
 		xnarch_restore_fpu(tcb);
_______________________________________________
Xenomai-core mailing list
Xenomai-core@gna.org
https://mail.gna.org/listinfo/xenomai-core

Reply via email to