|
@@ -0,0 +1,110 @@
|
|
|
+/*
|
|
|
+ * Adapted from Anton Blanchard's context switch microbenchmark.
|
|
|
+ *
|
|
|
+ * Copyright 2009, Anton Blanchard, IBM Corporation.
|
|
|
+ * Copyright 2016, Mikey Neuling, Chris Smart, IBM Corporation.
|
|
|
+ *
|
|
|
+ * This program is free software; you can redistribute it and/or
|
|
|
+ * modify it under the terms of the GNU General Public License
|
|
|
+ * as published by the Free Software Foundation; either version
|
|
|
+ * 2 of the License, or (at your option) any later version.
|
|
|
+ *
|
|
|
+ * This program tests the copy paste abort functionality of a P9
|
|
|
+ * (or later) by setting up two processes on the same CPU, one
|
|
|
+ * which executes the copy instruction and the other which
|
|
|
+ * executes paste.
|
|
|
+ *
|
|
|
+ * The paste instruction should never succeed, as the cp_abort
|
|
|
+ * instruction is called by the kernel during a context switch.
|
|
|
+ *
|
|
|
+ */
|
|
|
+
|
|
|
+#define _GNU_SOURCE
|
|
|
+
|
|
|
+#include <stdio.h>
|
|
|
+#include <unistd.h>
|
|
|
+#include <stdlib.h>
|
|
|
+#include "utils.h"
|
|
|
+#include <sched.h>
|
|
|
+
|
|
|
+#define READ_FD 0
|
|
|
+#define WRITE_FD 1
|
|
|
+
|
|
|
+#define NUM_LOOPS 1000
|
|
|
+
|
|
|
+/* This defines the "paste" instruction from Power ISA 3.0 Book II, section 4.4. */
|
|
|
+#define PASTE(RA, RB, L, RC) \
|
|
|
+ .long (0x7c00070c | (RA) << (31-15) | (RB) << (31-20) | (L) << (31-10) | (RC) << (31-31))
|
|
|
+
|
|
|
+int paste(void *i)
|
|
|
+{
|
|
|
+ int cr;
|
|
|
+
|
|
|
+ asm volatile(str(PASTE(0, %1, 1, 1))";"
|
|
|
+ "mfcr %0;"
|
|
|
+ : "=r" (cr)
|
|
|
+ : "b" (i)
|
|
|
+ : "memory"
|
|
|
+ );
|
|
|
+ return cr;
|
|
|
+}
|
|
|
+
|
|
|
+/* This defines the "copy" instruction from Power ISA 3.0 Book II, section 4.4. */
|
|
|
+#define COPY(RA, RB, L) \
|
|
|
+ .long (0x7c00060c | (RA) << (31-15) | (RB) << (31-20) | (L) << (31-10))
|
|
|
+
|
|
|
+void copy(void *i)
|
|
|
+{
|
|
|
+ asm volatile(str(COPY(0, %0, 1))";"
|
|
|
+ :
|
|
|
+ : "b" (i)
|
|
|
+ : "memory"
|
|
|
+ );
|
|
|
+}
|
|
|
+
|
|
|
+int test_cp_abort(void)
|
|
|
+{
|
|
|
+ /* 128 bytes for a full cache line */
|
|
|
+ char buf[128] __cacheline_aligned;
|
|
|
+ cpu_set_t cpuset;
|
|
|
+ int fd1[2], fd2[2], pid;
|
|
|
+ char c;
|
|
|
+
|
|
|
+ /* only run this test on a P9 or later */
|
|
|
+ SKIP_IF(!have_hwcap2(PPC_FEATURE2_ARCH_3_00));
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Run both processes on the same CPU, so that copy is more likely
|
|
|
+ * to leak into a paste.
|
|
|
+ */
|
|
|
+ CPU_ZERO(&cpuset);
|
|
|
+ CPU_SET(pick_online_cpu(), &cpuset);
|
|
|
+ FAIL_IF(sched_setaffinity(0, sizeof(cpuset), &cpuset));
|
|
|
+
|
|
|
+ FAIL_IF(pipe(fd1) || pipe(fd2));
|
|
|
+
|
|
|
+ pid = fork();
|
|
|
+ FAIL_IF(pid < 0);
|
|
|
+
|
|
|
+ if (!pid) {
|
|
|
+ for (int i = 0; i < NUM_LOOPS; i++) {
|
|
|
+ FAIL_IF((write(fd1[WRITE_FD], &c, 1)) != 1);
|
|
|
+ FAIL_IF((read(fd2[READ_FD], &c, 1)) != 1);
|
|
|
+ /* A paste succeeds if CR0 EQ bit is set */
|
|
|
+ FAIL_IF(paste(buf) & 0x20000000);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ for (int i = 0; i < NUM_LOOPS; i++) {
|
|
|
+ FAIL_IF((read(fd1[READ_FD], &c, 1)) != 1);
|
|
|
+ copy(buf);
|
|
|
+ FAIL_IF((write(fd2[WRITE_FD], &c, 1) != 1));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+int main(int argc, char *argv[])
|
|
|
+{
|
|
|
+ return test_harness(test_cp_abort, "cp_abort");
|
|
|
+}
|