From: bluhm Date: Tue, 21 Aug 2018 18:35:18 +0000 (+0000) Subject: Check the FPU environment of user land processes after exec and the X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=c51236aa248925ccab1615ef1df09fbb65f998df;p=openbsd Check the FPU environment of user land processes after exec and the proc0 kernel thread for FPU initialization values. --- diff --git a/regress/sys/arch/amd64/fpu/LICENSE b/regress/sys/arch/amd64/fpu/LICENSE new file mode 100644 index 00000000000..86956204956 --- /dev/null +++ b/regress/sys/arch/amd64/fpu/LICENSE @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2018 Alexander Bluhm + * + * 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. + */ diff --git a/regress/sys/arch/amd64/fpu/Makefile b/regress/sys/arch/amd64/fpu/Makefile new file mode 100644 index 00000000000..359b13ae031 --- /dev/null +++ b/regress/sys/arch/amd64/fpu/Makefile @@ -0,0 +1,61 @@ +# $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 diff --git a/regress/sys/arch/amd64/fpu/README b/regress/sys/arch/amd64/fpu/README new file mode 100644 index 00000000000..bbee367605a --- /dev/null +++ b/regress/sys/arch/amd64/fpu/README @@ -0,0 +1,8 @@ +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. diff --git a/regress/sys/arch/amd64/fpu/fdfl.c b/regress/sys/arch/amd64/fpu/fdfl.c new file mode 100644 index 00000000000..7e9bf4ec357 --- /dev/null +++ b/regress/sys/arch/amd64/fpu/fdfl.c @@ -0,0 +1,36 @@ +/* $OpenBSD: fdfl.c,v 1.1.1.1 2018/08/21 18:35:18 bluhm Exp $ */ +/* + * Copyright (c) 2018 Alexander Bluhm + * + * 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 + +#include +#include + +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; +} diff --git a/regress/sys/arch/amd64/fpu/fdump.c b/regress/sys/arch/amd64/fpu/fdump.c new file mode 100644 index 00000000000..c18fc1afb18 --- /dev/null +++ b/regress/sys/arch/amd64/fpu/fdump.c @@ -0,0 +1,52 @@ +/* $OpenBSD: fdump.c,v 1.1.1.1 2018/08/21 18:35:18 bluhm Exp $ */ +/* + * Copyright (c) 2018 Alexander Bluhm + * + * 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 + +#include +#include +#include +#include + +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; +} diff --git a/regress/sys/arch/amd64/fpu/feget.c b/regress/sys/arch/amd64/fpu/feget.c new file mode 100644 index 00000000000..f28b15ff714 --- /dev/null +++ b/regress/sys/arch/amd64/fpu/feget.c @@ -0,0 +1,41 @@ +/* $OpenBSD: feget.c,v 1.1.1.1 2018/08/21 18:35:18 bluhm Exp $ */ +/* + * Copyright (c) 2018 Alexander Bluhm + * + * 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 + +#include +#include +#include + +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; +} diff --git a/regress/sys/arch/amd64/fpu/fenv.S b/regress/sys/arch/amd64/fpu/fenv.S new file mode 100644 index 00000000000..1178d15e670 --- /dev/null +++ b/regress/sys/arch/amd64/fpu/fenv.S @@ -0,0 +1,55 @@ +/* $OpenBSD: fenv.S,v 1.1.1.1 2018/08/21 18:35:18 bluhm Exp $ */ +/* + * Copyright (c) 2018 Alexander Bluhm + * + * 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 + + .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 diff --git a/regress/sys/arch/amd64/fpu/fenv_t.ok b/regress/sys/arch/amd64/fpu/fenv_t.ok new file mode 100644 index 00000000000..c4bd94276e3 --- /dev/null +++ b/regress/sys/arch/amd64/fpu/fenv_t.ok @@ -0,0 +1,8 @@ +control ffff037f +status ffff0000 +tag ffffffff +others[0] 00000000 +others[1] 00000000 +others[2] 00000000 +others[3] ffff0000 +mxcsr 00001f80 diff --git a/regress/sys/arch/amd64/fpu/fxproc0.c b/regress/sys/arch/amd64/fpu/fxproc0.c new file mode 100644 index 00000000000..55bddb6c687 --- /dev/null +++ b/regress/sys/arch/amd64/fpu/fxproc0.c @@ -0,0 +1,128 @@ +/* $OpenBSD: fxproc0.c,v 1.1.1.1 2018/08/21 18:35:18 bluhm Exp $ */ +/* + * Copyright (c) 2018 Alexander Bluhm + * + * 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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +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); +} diff --git a/regress/sys/arch/amd64/fpu/fxsave64.ok b/regress/sys/arch/amd64/fpu/fxsave64.ok new file mode 100644 index 00000000000..b57af73d847 --- /dev/null +++ b/regress/sys/arch/amd64/fpu/fxsave64.ok @@ -0,0 +1,129 @@ +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