1 /* 2 * Adapted from Anton Blanchard's context switch microbenchmark. 3 * 4 * Copyright 2009, Anton Blanchard, IBM Corporation. 5 * Copyright 2016, Mikey Neuling, Chris Smart, IBM Corporation. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 10 * 2 of the License, or (at your option) any later version. 11 * 12 * This program tests the copy paste abort functionality of a P9 13 * (or later) by setting up two processes on the same CPU, one 14 * which executes the copy instruction and the other which 15 * executes paste. 16 * 17 * The paste instruction should never succeed, as the cp_abort 18 * instruction is called by the kernel during a context switch. 19 * 20 */ 21 22 #define _GNU_SOURCE 23 24 #include <stdio.h> 25 #include <unistd.h> 26 #include <stdlib.h> 27 #include "utils.h" 28 #include <sched.h> 29 30 #define READ_FD 0 31 #define WRITE_FD 1 32 33 #define NUM_LOOPS 1000 34 35 /* This defines the "paste" instruction from Power ISA 3.0 Book II, section 4.4. */ 36 #define PASTE(RA, RB, L, RC) \ 37 .long (0x7c00070c | (RA) << (31-15) | (RB) << (31-20) | (L) << (31-10) | (RC) << (31-31)) 38 39 int paste(void *i) 40 { 41 int cr; 42 43 asm volatile(str(PASTE(0, %1, 1, 1))";" 44 "mfcr %0;" 45 : "=r" (cr) 46 : "b" (i) 47 : "memory" 48 ); 49 return cr; 50 } 51 52 /* This defines the "copy" instruction from Power ISA 3.0 Book II, section 4.4. */ 53 #define COPY(RA, RB, L) \ 54 .long (0x7c00060c | (RA) << (31-15) | (RB) << (31-20) | (L) << (31-10)) 55 56 void copy(void *i) 57 { 58 asm volatile(str(COPY(0, %0, 1))";" 59 : 60 : "b" (i) 61 : "memory" 62 ); 63 } 64 65 int test_cp_abort(void) 66 { 67 /* 128 bytes for a full cache line */ 68 char buf[128] __cacheline_aligned; 69 cpu_set_t cpuset; 70 int fd1[2], fd2[2], pid; 71 char c; 72 73 /* only run this test on a P9 or later */ 74 SKIP_IF(!have_hwcap2(PPC_FEATURE2_ARCH_3_00)); 75 76 /* 77 * Run both processes on the same CPU, so that copy is more likely 78 * to leak into a paste. 79 */ 80 CPU_ZERO(&cpuset); 81 CPU_SET(pick_online_cpu(), &cpuset); 82 FAIL_IF(sched_setaffinity(0, sizeof(cpuset), &cpuset)); 83 84 FAIL_IF(pipe(fd1) || pipe(fd2)); 85 86 pid = fork(); 87 FAIL_IF(pid < 0); 88 89 if (!pid) { 90 for (int i = 0; i < NUM_LOOPS; i++) { 91 FAIL_IF((write(fd1[WRITE_FD], &c, 1)) != 1); 92 FAIL_IF((read(fd2[READ_FD], &c, 1)) != 1); 93 /* A paste succeeds if CR0 EQ bit is set */ 94 FAIL_IF(paste(buf) & 0x20000000); 95 } 96 } else { 97 for (int i = 0; i < NUM_LOOPS; i++) { 98 FAIL_IF((read(fd1[READ_FD], &c, 1)) != 1); 99 copy(buf); 100 FAIL_IF((write(fd2[WRITE_FD], &c, 1) != 1)); 101 } 102 } 103 return 0; 104 105 } 106 107 int main(int argc, char *argv[]) 108 { 109 return test_harness(test_cp_abort, "cp_abort"); 110 } 111