proc0 kernel thread for FPU initialization values.
--- /dev/null
+/*
+ * Copyright (c) 2018 Alexander Bluhm <bluhm@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
--- /dev/null
+# $OpenBSD: Makefile,v 1.1.1.1 2018/08/21 18:35:18 bluhm Exp $
+
+PROGS = fenv fdump fdfl feget fxproc0
+SRCS_fenv = fenv.S
+LDADD_fenv = -nostdlib -nopie
+LDADD_fdfl = -lm
+LDADD_feget = -lm
+LDADD_fxproc0 = -lkvm
+CFLAGS = -O2 ${PIPE} ${DEBUG}
+CFLAGS += -Wformat -Wno-compare-distinct-pointer-types
+WARNINGS = yes
+CLEANFILES = *.out
+
+MODEL != sysctl -n hw.model | tr -c '[:alnum:]' '_'
+ALLOWKMEM != sysctl -n kern.allowkmem
+
+REGRESS_TARGETS += run-regress-fenv
+run-regress-fenv: fenv fdump
+ @echo '\n======== $@ ========'
+.if ${MODEL:C/.*_AMD_Opteron_.*/opteron/} != opteron
+ # Load FPU environment directly at _start and write it.
+ # Read FPU environment and print it to stdout.
+ ./fenv | ./fdump >fenv.out
+ diff ${.CURDIR}/fenv_t.ok fenv.out
+.else
+ # Early AMD Opteron processors behave differently.
+ @echo SKIPPED
+.endif
+
+REGRESS_TARGETS += run-regress-fdfl
+run-regress-fdfl: fdfl
+ @echo '\n======== $@ ========'
+ # Print default libm FPU environment to stdout.
+ ./fdfl >fdfl.out
+ diff ${.CURDIR}/fenv_t.ok fdfl.out
+
+REGRESS_TARGETS += run-regress-feget
+run-regress-feget: feget
+ @echo '\n======== $@ ========'
+.if ${MODEL:C/.*_AMD_Opteron_.*/opteron/} != opteron
+ # Get FPU environment via libm and print it to stdout.
+ ./feget >feget.out
+ diff ${.CURDIR}/fenv_t.ok feget.out
+.else
+ # Early AMD Opteron processors behave differently.
+ @echo SKIPPED
+.endif
+
+REGRESS_TARGETS += run-regress-fxproc0
+run-regress-fxproc0: fxproc0
+ @echo '\n======== $@ ========'
+.if ${ALLOWKMEM}
+ # Read FPU storage area from proc0 via /dev/mem and print it to stdout.
+ ${SUDO} ./fxproc0 >fxproc0.out
+ diff ${.CURDIR}/fxsave64.ok fxproc0.out
+.else
+ # Set sysctl kern.allowkmem=1 for additional tests.
+ @echo SKIPPED
+.endif
+
+.include <bsd.regress.mk>
--- /dev/null
+The OpenBSD test regress/lib/libm/fenv prints strange values from
+the Intel and AMD FPU using the libm function fegetenv(3). Implement
+more detailed checks.
+
+Load the FPU enviroment directy after exec with an assembly program.
+Get the FPU default FPU status from libm.
+Load the FPU enviroment with fegetenv(3).
+Read the FPU storage area from proc0 via /dev/mem.
--- /dev/null
+/* $OpenBSD: fdfl.c,v 1.1.1.1 2018/08/21 18:35:18 bluhm Exp $ */
+/*
+ * Copyright (c) 2018 Alexander Bluhm <bluhm@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+
+#include <fenv.h>
+#include <stdio.h>
+
+int
+main(int argc, char *argv[])
+{
+ size_t i;
+
+ printf("control\t%08x\n", FE_DFL_ENV->__x87.__control);
+ printf("status\t%08x\n", FE_DFL_ENV->__x87.__status);
+ printf("tag\t%08x\n", FE_DFL_ENV->__x87.__tag);
+ for (i = 0; i < nitems(FE_DFL_ENV->__x87.__others); i++)
+ printf("others[%zu]\t%08x\n", i, FE_DFL_ENV->__x87.__others[i]);
+ printf("mxcsr\t%08x\n", FE_DFL_ENV->__mxcsr);
+
+ return 0;
+}
--- /dev/null
+/* $OpenBSD: fdump.c,v 1.1.1.1 2018/08/21 18:35:18 bluhm Exp $ */
+/*
+ * Copyright (c) 2018 Alexander Bluhm <bluhm@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+
+#include <err.h>
+#include <fenv.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int
+main(int argc, char *argv[])
+{
+ struct {
+ fenv_t fenv;
+ /* Try to read more and check env length. */
+ char pad[1];
+ } buf;
+ fenv_t *fenv = &buf.fenv;
+ ssize_t len;
+ size_t i;
+
+ len = read(0, &buf, sizeof(buf));
+ if (len < 0 )
+ err(1, "read");
+ if (len != sizeof(fenv_t))
+ errx(1, "read len %zd is not size %zu", len, sizeof(fenv_t));
+
+ printf("control\t%08x\n", fenv->__x87.__control);
+ printf("status\t%08x\n", fenv->__x87.__status);
+ printf("tag\t%08x\n", fenv->__x87.__tag);
+ for (i = 0; i < nitems(fenv->__x87.__others); i++) {
+ printf("others[%zu]\t%08x\n", i, fenv->__x87.__others[i]);
+ }
+ printf("mxcsr\t%08x\n", fenv->__mxcsr);
+
+ return 0;
+}
--- /dev/null
+/* $OpenBSD: feget.c,v 1.1.1.1 2018/08/21 18:35:18 bluhm Exp $ */
+/*
+ * Copyright (c) 2018 Alexander Bluhm <bluhm@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+
+#include <err.h>
+#include <fenv.h>
+#include <stdio.h>
+
+int
+main(int argc, char *argv[])
+{
+ fenv_t fenv;
+ size_t i;
+
+ if (fegetenv(&fenv))
+ err(1, "fegetenv");
+
+ printf("control\t%08x\n", fenv.__x87.__control);
+ printf("status\t%08x\n", fenv.__x87.__status);
+ printf("tag\t%08x\n", fenv.__x87.__tag);
+ for (i = 0; i < nitems(fenv.__x87.__others); i++)
+ printf("others[%zu]\t%08x\n", i, fenv.__x87.__others[i]);
+ printf("mxcsr\t%08x\n", fenv.__mxcsr);
+
+ return 0;
+}
--- /dev/null
+/* $OpenBSD: fenv.S,v 1.1.1.1 2018/08/21 18:35:18 bluhm Exp $ */
+/*
+ * Copyright (c) 2018 Alexander Bluhm <bluhm@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/syscall.h>
+
+ .section .note.openbsd.ident, "a"
+ .p2align 2
+ .long 8
+ .long 4
+ .long 1
+ .ascii "OpenBSD\0"
+ .long 0
+ .previous
+
+ .data
+env:
+ .long 1 /* __control */
+ .long 1 /* __status */
+ .long 1 /* __tag */
+ .long 1 /* __others 0 */
+ .long 1 /* __others 1 */
+ .long 1 /* __others 2 */
+ .long 1 /* __others 3 */
+mxcsr:
+ .long 1 /* __mxcsr */
+env_end:
+
+ .text
+ .align 8
+ .global _start
+_start:
+ fnstenv env
+ stmxcsr mxcsr
+ mov $SYS_write, %rax
+ mov $1, %rdi
+ mov $env, %rsi
+ mov $(env_end-env), %rdx
+ syscall
+ mov $SYS_exit, %rax
+ mov $0, %rdi
+ syscall
--- /dev/null
+control ffff037f
+status ffff0000
+tag ffffffff
+others[0] 00000000
+others[1] 00000000
+others[2] 00000000
+others[3] ffff0000
+mxcsr 00001f80
--- /dev/null
+/* $OpenBSD: fxproc0.c,v 1.1.1.1 2018/08/21 18:35:18 bluhm Exp $ */
+/*
+ * Copyright (c) 2018 Alexander Bluhm <bluhm@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <machine/fpu.h>
+#include <machine/pcb.h>
+
+#include <err.h>
+#include <fcntl.h>
+#include <kvm.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+void __dead usage(void);
+void fenv_proc(kvm_t *, unsigned long);
+
+void __dead
+usage(void)
+{
+ fprintf(stderr, "usage: %s [-M core] [-N system]\n", getprogname());
+ exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+ char errbuf[_POSIX2_LINE_MAX];
+ char *memf, *nlistf;
+ kvm_t *kd;
+ int ch;
+ struct nlist nl[] = { { .n_name = "_proc0" }, { .n_name = NULL } };
+
+ memf = nlistf = NULL;
+ while ((ch = getopt(argc, argv, "M:N:")) != -1) {
+ switch(ch) {
+ case 'M':
+ memf = optarg;
+ break;
+ case 'N':
+ nlistf = optarg;
+ break;
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+ if (argc)
+ usage();
+
+ kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf);
+ if (kd == NULL)
+ errx(1, "kvm_openfiles: %s", errbuf);
+ if (kvm_nlist(kd, nl) == -1)
+ errx(1, "kvm_nlist: %s", kvm_geterr(kd));
+ if (nl[0].n_type == 0)
+ errx(1, "name '%s' has type %d", nl[0].n_name, nl[0].n_type);
+ fenv_proc(kd, nl[0].n_value);
+
+ if (kvm_close(kd) == -1)
+ errx(1, "kvm_close: %s", kvm_geterr(kd));
+ return 0;
+}
+
+void
+fenv_proc(kvm_t *kd, unsigned long p)
+{
+ struct proc proc;
+ struct user user;
+ struct fxsave64 *fxs = &user.u_pcb.pcb_savefpu.fp_fxsave;
+ size_t i;
+
+ if (kvm_read(kd, p, &proc, sizeof(proc)) == -1)
+ errx(1, "kvm_read proc: %s", kvm_geterr(kd));
+ if (kvm_read(kd, (u_long)proc.p_addr, &user, sizeof(user)) == -1)
+ errx(1, "kvm_read user: %s", kvm_geterr(kd));
+
+ if (fxs != &fxs->fx_fcw)
+ errx(1, "fxsave start %p, fx_fcw start %p",
+ &fxs, &fxs->fx_fcw);
+ printf("fcw\t%04x\n", fxs->fx_fcw);
+ printf("fsw\t%04x\n", fxs->fx_fsw);
+ printf("ftw\t%02x\n", fxs->fx_ftw);
+ printf("unused1\t%02x\n", fxs->fx_unused1);
+ printf("fop\t%04x\n", fxs->fx_fop);
+ printf("rip\t%016llx\n", fxs->fx_rip);
+ printf("rdp\t%016llx\n", fxs->fx_rdp);
+ printf("mxcsr\t%08x\n", fxs->fx_mxcsr);
+ printf("mxcsr_mask\t%08x\n", fxs->fx_mxcsr_mask);
+ if (&fxs->fx_mxcsr_mask + 1 != fxs->fx_st)
+ errx(1, "fx_mxcsr_mask end %p, fx_st start %p",
+ &fxs->fx_mxcsr_mask + 1, fxs->fx_st);
+ for (i = 0; i < nitems(fxs->fx_st); i++)
+ printf("st[%zu]\t%016llx:%016llx\n", i,
+ fxs->fx_st[i][1], fxs->fx_st[i][0]);
+ if (&fxs->fx_st[i] != fxs->fx_xmm)
+ errx(1, "fx_st end %p, fx_xmm start %p",
+ &fxs->fx_st[i], fxs->fx_xmm);
+ for (i = 0; i < nitems(fxs->fx_xmm); i++)
+ printf("xmm[%zu]\t%016llx:%016llx\n", i,
+ fxs->fx_xmm[i][1], fxs->fx_xmm[i][0]);
+ if (&fxs->fx_xmm[i] != fxs->fx_unused3)
+ errx(1, "fx_xmm end %p, fx_unused3 start %p",
+ &fxs->fx_xmm[i], fxs->fx_unused3);
+ for (i = 0; i < nitems(fxs->fx_unused3); i++)
+ printf("unused3[%zu]\t%02x\n", i, fxs->fx_unused3[i]);
+ if (&fxs->fx_unused3[i] != fxs + 1)
+ errx(1, "fx_unused3 end %p, fxsave end %p",
+ &fxs->fx_unused3[i], fxs + 1);
+}
--- /dev/null
+fcw 037f
+fsw 0000
+ftw 00
+unused1 00
+fop 0000
+rip 0000000000000000
+rdp 0000000000000000
+mxcsr 00001f80
+mxcsr_mask 0000ffff
+st[0] 0000000000000000:0000000000000000
+st[1] 0000000000000000:0000000000000000
+st[2] 0000000000000000:0000000000000000
+st[3] 0000000000000000:0000000000000000
+st[4] 0000000000000000:0000000000000000
+st[5] 0000000000000000:0000000000000000
+st[6] 0000000000000000:0000000000000000
+st[7] 0000000000000000:0000000000000000
+xmm[0] 0000000000000000:0000000000000000
+xmm[1] 0000000000000000:0000000000000000
+xmm[2] 0000000000000000:0000000000000000
+xmm[3] 0000000000000000:0000000000000000
+xmm[4] 0000000000000000:0000000000000000
+xmm[5] 0000000000000000:0000000000000000
+xmm[6] 0000000000000000:0000000000000000
+xmm[7] 0000000000000000:0000000000000000
+xmm[8] 0000000000000000:0000000000000000
+xmm[9] 0000000000000000:0000000000000000
+xmm[10] 0000000000000000:0000000000000000
+xmm[11] 0000000000000000:0000000000000000
+xmm[12] 0000000000000000:0000000000000000
+xmm[13] 0000000000000000:0000000000000000
+xmm[14] 0000000000000000:0000000000000000
+xmm[15] 0000000000000000:0000000000000000
+unused3[0] 00
+unused3[1] 00
+unused3[2] 00
+unused3[3] 00
+unused3[4] 00
+unused3[5] 00
+unused3[6] 00
+unused3[7] 00
+unused3[8] 00
+unused3[9] 00
+unused3[10] 00
+unused3[11] 00
+unused3[12] 00
+unused3[13] 00
+unused3[14] 00
+unused3[15] 00
+unused3[16] 00
+unused3[17] 00
+unused3[18] 00
+unused3[19] 00
+unused3[20] 00
+unused3[21] 00
+unused3[22] 00
+unused3[23] 00
+unused3[24] 00
+unused3[25] 00
+unused3[26] 00
+unused3[27] 00
+unused3[28] 00
+unused3[29] 00
+unused3[30] 00
+unused3[31] 00
+unused3[32] 00
+unused3[33] 00
+unused3[34] 00
+unused3[35] 00
+unused3[36] 00
+unused3[37] 00
+unused3[38] 00
+unused3[39] 00
+unused3[40] 00
+unused3[41] 00
+unused3[42] 00
+unused3[43] 00
+unused3[44] 00
+unused3[45] 00
+unused3[46] 00
+unused3[47] 00
+unused3[48] 00
+unused3[49] 00
+unused3[50] 00
+unused3[51] 00
+unused3[52] 00
+unused3[53] 00
+unused3[54] 00
+unused3[55] 00
+unused3[56] 00
+unused3[57] 00
+unused3[58] 00
+unused3[59] 00
+unused3[60] 00
+unused3[61] 00
+unused3[62] 00
+unused3[63] 00
+unused3[64] 00
+unused3[65] 00
+unused3[66] 00
+unused3[67] 00
+unused3[68] 00
+unused3[69] 00
+unused3[70] 00
+unused3[71] 00
+unused3[72] 00
+unused3[73] 00
+unused3[74] 00
+unused3[75] 00
+unused3[76] 00
+unused3[77] 00
+unused3[78] 00
+unused3[79] 00
+unused3[80] 00
+unused3[81] 00
+unused3[82] 00
+unused3[83] 00
+unused3[84] 00
+unused3[85] 00
+unused3[86] 00
+unused3[87] 00
+unused3[88] 00
+unused3[89] 00
+unused3[90] 00
+unused3[91] 00
+unused3[92] 00
+unused3[93] 00
+unused3[94] 00
+unused3[95] 00