Home | History | Annotate | Download | only in context_switch
      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