123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110 |
- /*
- * 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");
- }
|