Implement the functions feenableexcept(), fedisableexcept() and
fegetexcept(), non-standard glibc functions which allows controlling
which FPU events generate a floating point exception.

Signed-off-by: Nadav Har'El <[email protected]>
---
 arch/aarch64/feexcept.cc | 34 ++++++++++++++++++++++++
 arch/x64/feexcept.cc     | 69 ++++++++++++++++++++++++++++++++++++++++++++++++
 Makefile                 |  1 +
 3 files changed, 104 insertions(+)
 create mode 100644 arch/aarch64/feexcept.cc
 create mode 100644 arch/x64/feexcept.cc

diff --git a/arch/aarch64/feexcept.cc b/arch/aarch64/feexcept.cc
new file mode 100644
index 0000000..647f0a5
--- /dev/null
+++ b/arch/aarch64/feexcept.cc
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2017 ScyllaDB, Ltd.
+ *
+ * This work is open source software, licensed under the terms of the
+ * BSD license as described in the LICENSE file in the top-level directory.
+ */
+
+#include <osv/types.h>
+#include <osv/stubbing.hh>
+#include <fenv.h>
+// Note that musl's fenv.h does not define feenableexcept and friends, so
+// we need to 'extern "C"' them here, as no header file does this.
+
+extern "C"
+int feenableexcept(int mask)
+{
+    WARN_STUBBED();
+    // The feenableexcept says it returns -1 on failure.
+    return -1;
+}
+
+extern "C"
+int fedisableexcept(int mask)
+{
+    WARN_STUBBED();
+    return -1;
+}
+
+extern "C"
+int fegetexcept()
+{
+    WARN_STUBBED();
+    return -1;
+}
diff --git a/arch/x64/feexcept.cc b/arch/x64/feexcept.cc
new file mode 100644
index 0000000..38399d8
--- /dev/null
+++ b/arch/x64/feexcept.cc
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2017 ScyllaDB, Ltd.
+ *
+ * This work is open source software, licensed under the terms of the
+ * BSD license as described in the LICENSE file in the top-level directory.
+ */
+
+#include <osv/types.h>
+#include <fenv.h>
+// Note that musl's fenv.h does not define feenableexcept and friends, so
+// we need to 'extern "C"' them here, as no header file does this.
+
+extern "C"
+int feenableexcept(int mask)
+{
+    // The feenableexcept() manual page suggests that -1 should be returned
+    // on failure, and theoretically this could include the case that invalid
+    // bits are passed in mask. But in practice, the Linux implementation
+    // simply ignores invalid bits, and never returns -1.
+    mask &= FE_ALL_EXCEPT;
+
+    // Update the the x87 control word. Note that:
+    // 1. We need to leave the other bits (non-exception related) unchanged.
+    // 2. A 1 bit means disable exception (opposite of our "mask")
+    // 3. This function is supposed to only enable exceptions.
+    // not those to enable (as "mask" specifies)
+    u16 cw;
+    asm volatile("fstcw %0" : "=m"(cw));
+    // Save the previous set of enabled exceptions, for returning later.
+    int ret = (~cw) & FE_ALL_EXCEPT;
+    cw &= ~mask;
+    asm volatile("fldcw %0" : : "m"(cw));
+
+    // Also update the SSE control and status register (here the relevant
+    // bits start at bit 7).
+    u32 csr;
+    asm volatile("stmxcsr %0" : "=m"(csr));
+    csr &= ~(mask << 7);
+    asm volatile("ldmxcsr %0" : : "m"(csr));
+
+    return ret;
+}
+
+extern "C"
+int fedisableexcept(int mask)
+{
+    mask &= FE_ALL_EXCEPT;
+
+    u16 cw;
+    asm volatile("fstcw %0" : "=m"(cw));
+    int ret = (~cw) & FE_ALL_EXCEPT;
+    cw |= mask;
+    asm volatile("fldcw %0" : : "m"(cw));
+
+    u32 csr;
+    asm volatile("stmxcsr %0" : "=m"(csr));
+    csr |= mask << 7;
+    asm volatile("ldmxcsr %0" : : "m"(csr));
+
+    return ret;
+}
+
+extern "C"
+int fegetexcept()
+{
+    u16 cw;
+    asm volatile("fstcw %0" : "=m"(cw));
+    return (~cw) & FE_ALL_EXCEPT;
+}
diff --git a/Makefile b/Makefile
index 7ee113b..c0d8254 100644
--- a/Makefile
+++ b/Makefile
@@ -849,6 +849,7 @@ objects += arch/$(arch)/interrupt.o
 objects += arch/$(arch)/pci.o
 objects += arch/$(arch)/msi.o
 objects += arch/$(arch)/power.o
+objects += arch/$(arch)/feexcept.o
 
 $(out)/arch/x64/string-ssse3.o: CXXFLAGS += -mssse3
 
-- 
2.9.3

-- 
You received this message because you are subscribed to the Google Groups "OSv 
Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to