ref: 1ee52184b94b4b608e715ffbc6b7da12b704e756
parent: 2ceb1b254eeb3e4c4f530c64c74e2fcedd53058b
author: mia soweli <mia@soweli.net>
date: Tue Aug 12 14:54:31 EDT 2025
fpu: add missing fpu.c
--- /dev/null
+++ b/sys/src/9/omap/fpu.c
@@ -1,0 +1,310 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "ureg.h"
+
+void
+fpuinit(void)
+{+ m->fpstate = FPinit;
+ m->fpsave = nil;
+ fpoff();
+}
+
+static FPalloc*
+fpalloc(FPalloc *link)
+{+ FPalloc *a;
+
+ while((a = mallocalign(sizeof(FPalloc), 16, 0, 0)) == nil){+ int x = spllo();
+ if(up != nil && !waserror()){+ resrcwait("no memory for FPalloc");+ poperror();
+ }
+ splx(x);
+ }
+ a->link = link;
+ return a;
+}
+
+static void
+fpfree(FPalloc *a)
+{+ free(a);
+}
+
+
+/*
+ * Protect or save FPU state and setup new state
+ * (lazily in the case of user process) for the kernel.
+ * All syscalls, traps and interrupts (except mathtrap()!)
+ * are handled between fpukenter() and fpukexit(),
+ * so they can use floating point and vector instructions.
+ */
+void
+fpukenter(Ureg*)
+{+ if(up == nil){+ switch(m->fpstate){+ case FPactive:
+ fpsave(m->fpsave);
+ /* wet floor */
+ case FPinactive:
+ m->fpstate = FPinit;
+ }
+ return;
+ }
+
+ switch(up->fpstate){+ case FPactive:
+ up->fpstate = FPprotected;
+ fpoff();
+ /* wet floor */
+ case FPprotected:
+ return;
+ }
+
+ switch(up->kfpstate){+ case FPactive:
+ fpsave(up->kfpsave);
+ /* wet floor */
+ case FPinactive:
+ up->kfpstate = FPinit;
+ }
+}
+
+void
+fpukexit(Ureg *ureg)
+{+ FPalloc *a;
+
+ if(up == nil){+ switch(m->fpstate){+ case FPactive:
+ fpoff();
+ /* wet floor */
+ case FPinactive:
+ a = m->fpsave;
+ m->fpsave = a->link;
+ fpfree(a);
+ }
+ m->fpstate = m->fpsave != nil? FPinactive: FPinit;
+ return;
+ }
+
+ if(up->fpstate == FPprotected){+ if(userureg(ureg)){+ up->fpstate = FPactive;
+ fpon();
+ }
+ return;
+ }
+
+ switch(up->kfpstate){+ case FPactive:
+ fpoff();
+ /* wet floor */
+ case FPinactive:
+ a = up->kfpsave;
+ up->kfpsave = a->link;
+ fpfree(a);
+ }
+ up->kfpstate = up->kfpsave != nil? FPinactive: FPinit;
+}
+
+void
+fpuprocsetup(Proc *p)
+{+ FPalloc *a;
+
+ p->fpstate = FPinit;
+ while((a = p->fpsave) != nil) {+ p->fpsave = a->link;
+ fpfree(a);
+ }
+}
+
+void
+fpuprocfork(Proc *p)
+{+ int s;
+
+ s = splhi();
+ switch(up->fpstate & ~FPnotify){+ case FPprotected:
+ fpon();
+ /* wet floor */
+ case FPactive:
+ fpsave(up->fpsave);
+ up->fpstate = FPinactive;
+ /* wet floor */
+ case FPinactive:
+ if(p->fpsave == nil)
+ p->fpsave = fpalloc(nil);
+ memmove(p->fpsave, up->fpsave, sizeof(FPsave));
+ p->fpstate = FPinactive;
+ }
+ splx(s);
+}
+
+void
+fpuprocsave(Proc *p)
+{+ if(p->state == Moribund){+ FPalloc *a;
+
+ if(p->fpstate == FPactive || p->kfpstate == FPactive)
+ fpoff();
+ p->fpstate = p->kfpstate = FPinit;
+ while((a = p->fpsave) != nil) {+ p->fpsave = a->link;
+ fpfree(a);
+ }
+ while((a = p->kfpsave) != nil) {+ p->kfpsave = a->link;
+ fpfree(a);
+ }
+ return;
+ }
+ if(p->kfpstate == FPactive){+ fpsave(p->kfpsave);
+ p->kfpstate = FPinactive;
+ return;
+ }
+ if(p->fpstate == FPprotected)
+ fpon();
+ else if(p->fpstate != FPactive)
+ return;
+ fpsave(p->fpsave);
+ p->fpstate = FPinactive;
+}
+
+void
+fpuprocrestore(Proc*)
+{+ /*
+ * when the scheduler switches,
+ * we can discard its fp state.
+ */
+ switch(m->fpstate){+ case FPactive:
+ fpoff();
+ /* wet floor */
+ case FPinactive:
+ fpfree(m->fpsave);
+ m->fpsave = nil;
+ m->fpstate = FPinit;
+ }
+}
+
+void
+fpunotify(Proc *p)
+{+ fpuprocsave(p);
+ p->fpstate |= FPnotify;
+}
+
+void
+fpunoted(Proc *p)
+{+ FPalloc *o;
+
+ if(p->fpstate & FPnotify) {+ p->fpstate &= ~FPnotify;
+ } else if((o = p->fpsave->link) != nil) {+ fpfree(p->fpsave);
+ p->fpsave = o;
+ p->fpstate = FPinactive;
+ } else {+ p->fpstate = FPinit;
+ }
+}
+
+FPsave*
+notefpsave(Proc *p)
+{+ if(p->fpsave == nil)
+ return nil;
+ if(p->fpstate == (FPinactive|FPnotify)){+ p->fpsave = fpalloc(p->fpsave);
+ memmove(p->fpsave, p->fpsave->link, sizeof(FPsave));
+ p->fpstate = FPinactive;
+ }
+ return p->fpsave->link;
+}
+
+void
+mathtrap(Ureg *ureg)
+{+ if(!userureg(ureg)){+ if(up == nil){+ switch(m->fpstate){+ case FPinit:
+ m->fpsave = fpalloc(m->fpsave);
+ m->fpstate = FPactive;
+ fpinit();
+ break;
+ case FPinactive:
+ fprestore(m->fpsave);
+ m->fpstate = FPactive;
+ break;
+ default:
+ panic("floating point error in irq");+ }
+ return;
+ }
+
+ if(up->fpstate == FPprotected){+ fpon();
+ fpsave(up->fpsave);
+ up->fpstate = FPinactive;
+ }
+
+ switch(up->kfpstate){+ case FPinit:
+ up->kfpsave = fpalloc(up->kfpsave);
+ up->kfpstate = FPactive;
+ fpinit();
+ break;
+ case FPinactive:
+ fprestore(up->kfpsave);
+ up->kfpstate = FPactive;
+ break;
+ default:
+ panic("floating point error in trap");+ }
+ return;
+ }
+
+ switch(up->fpstate){+ case FPinit|FPnotify:
+ /* wet floor */
+ case FPinit:
+ if(up->fpsave == nil)
+ up->fpsave = fpalloc(nil);
+ up->fpstate = FPactive;
+ fpinit();
+ break;
+ case FPinactive|FPnotify:
+ spllo();
+ qlock(&up->debug);
+ notefpsave(up);
+ qunlock(&up->debug);
+ splhi();
+ /* wet floor */
+ case FPinactive:
+ fprestore(up->fpsave);
+ up->fpstate = FPactive;
+ break;
+ case FPprotected:
+ up->fpstate = FPactive;
+ fpon();
+ break;
+ case FPactive:
+ postnote(up, 1, "sys: floating point error", NDebug);
+ break;
+ }
+}
--
⑨