linux/tools/testing/selftests/powerpc/context_switch/cp_abort.c
<<
>>
Prefs
   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
  39int 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
  56void copy(void *i)
  57{
  58        asm volatile(str(COPY(0, %0, 1))";"
  59                        :
  60                        : "b" (i)
  61                        : "memory"
  62                    );
  63}
  64
  65int 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
 107int main(int argc, char *argv[])
 108{
 109        return test_harness(test_cp_abort, "cp_abort");
 110}
 111