Browse Source

Add regression test for FPU state

Child proc sets some xmm registers and goes into a tight loop.  Parent proc parses the fpregs file and checks that the xmm registers have the correct values.

Passes with master, fails if I stop the FPU state from being saved.

Signed-off-by: Graham MacDonald <grahamamacdonald@gmail.com>
Graham MacDonald 6 years ago
parent
commit
0e69b79c6c
1 changed files with 84 additions and 0 deletions
  1. 84 0
      sys/src/regress/fpustate.c

+ 84 - 0
sys/src/regress/fpustate.c

@@ -0,0 +1,84 @@
+#include <u.h>
+#include <libc.h>
+
+// Test that the FPU state is correctly saved and available in the /proc/<pid>/fpregs
+
+void
+pass(void) {
+	print("PASS\n");
+	exits("PASS");
+}
+
+void
+fail(const char *msg) {
+	print("FAIL - %s\n", msg);
+	exits("FAIL");
+}
+
+void
+main(void)
+{
+	int childpid = fork();
+	if (childpid > 0) {
+		// Sleep a little to ensure the child is in the infinite loop,
+		// then read the fpregs and kill the child
+		sleep(1000);
+
+		const char *path = smprint("/proc/%d/fpregs", childpid);
+		int fd = open(path, OREAD);
+		if (fd < 0) {
+			fail("Can't open fpregs");
+		}
+
+		// Read fpregs - it would be better to read individual registers
+		// from the file system - update this when it happens
+		const int buflen = 512;
+		char fpregbuf[buflen];
+		if (pread(fd, fpregbuf, buflen, 0) < buflen) {
+			fail("Can't read fpregs");
+		}
+
+		// xmm0 starts at 160, each xmm reg at 16 byte increments
+		int xmm0 = *(int*)(fpregbuf + 160);
+		int xmm1 = *(int*)(fpregbuf + 176);
+		int xmm2 = *(int*)(fpregbuf + 192);
+		int xmm3 = *(int*)(fpregbuf + 208);
+		if (xmm0 != 1 && xmm1 != 2 && xmm2 != 3 && xmm3 != 4) {
+			fail("unexpected values in child's fpreg buffer");
+		}
+
+		path = smprint("/proc/%d/ctl", childpid);
+		fd = open(path, OWRITE);
+		if (fd < 0) {
+			fail("Can't open ctl");
+		}
+
+		fprint(fd, "kill");
+
+		pass();
+
+	} else if (childpid == 0) {
+		// In child
+
+		// Set some xmm variables then run a tight loop waiting for
+		// the parent to read the fpregs and kill the child
+		__asm__ __volatile__(
+			"movq $1, %%rax;"
+			"movq %%rax, %%xmm0;"
+			"movq $2, %%rax;"
+			"movq %%rax, %%xmm1;"
+			"movq $3, %%rax;"
+			"movq %%rax, %%xmm2;"
+			"movq $4, %%rax;"
+			"movq %%rax, %%xmm3;"
+			"loop:"
+			"jmp loop;"
+			: : : "rax", "xmm0", "xmm1", "xmm2", "xmm3");
+
+		fail("Somehow exited the asm loop");
+
+	} else {
+		// Error
+		fail("fork failed");
+	}
+}