This patch adds ptrace interface test for EBB specific
registers. This also adds some generic ptrace interface
based helper functions to be used by other patches later
on in the series.

Signed-off-by: Anshuman Khandual <khand...@linux.vnet.ibm.com>
---
 tools/testing/selftests/powerpc/Makefile           |   2 +-
 tools/testing/selftests/powerpc/ptrace/Makefile    |   7 +
 .../testing/selftests/powerpc/ptrace/ptrace-ebb.c  | 150 ++++++++++++++
 .../testing/selftests/powerpc/ptrace/ptrace-ebb.h  | 103 ++++++++++
 tools/testing/selftests/powerpc/ptrace/ptrace.h    | 225 +++++++++++++++++++++
 5 files changed, 486 insertions(+), 1 deletion(-)
 create mode 100644 tools/testing/selftests/powerpc/ptrace/Makefile
 create mode 100644 tools/testing/selftests/powerpc/ptrace/ptrace-ebb.c
 create mode 100644 tools/testing/selftests/powerpc/ptrace/ptrace-ebb.h
 create mode 100644 tools/testing/selftests/powerpc/ptrace/ptrace.h

diff --git a/tools/testing/selftests/powerpc/Makefile 
b/tools/testing/selftests/powerpc/Makefile
index 03ca2e6..b951314 100644
--- a/tools/testing/selftests/powerpc/Makefile
+++ b/tools/testing/selftests/powerpc/Makefile
@@ -12,7 +12,7 @@ CFLAGS := -Wall -O2 -flto -Wall -Werror 
-DGIT_VERSION='"$(GIT_VERSION)"' -I$(CUR
 
 export CFLAGS
 
-SUB_DIRS = pmu copyloops mm tm primitives stringloops vphn switch_endian dscr
+SUB_DIRS = pmu copyloops mm tm primitives stringloops vphn switch_endian dscr 
ptrace
 
 endif
 
diff --git a/tools/testing/selftests/powerpc/ptrace/Makefile 
b/tools/testing/selftests/powerpc/ptrace/Makefile
new file mode 100644
index 0000000..59386ba
--- /dev/null
+++ b/tools/testing/selftests/powerpc/ptrace/Makefile
@@ -0,0 +1,7 @@
+TEST_PROGS := ptrace-ebb
+all: $(TEST_PROGS)
+
+$(TEST_PROGS): ../harness.c
+ptrace-ebb: ../pmu/event.c ../pmu/lib.c ../pmu/ebb/ebb_handler.S 
../pmu/ebb/busy_loop.S
+clean:
+       rm -f $(TEST_PROGS) *.o
diff --git a/tools/testing/selftests/powerpc/ptrace/ptrace-ebb.c 
b/tools/testing/selftests/powerpc/ptrace/ptrace-ebb.c
new file mode 100644
index 0000000..e1ca608
--- /dev/null
+++ b/tools/testing/selftests/powerpc/ptrace/ptrace-ebb.c
@@ -0,0 +1,150 @@
+/*
+ * Ptrace interface test for EBB
+ *
+ * Copyright (C) 2015 Anshuman Khandual, 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.
+ */
+#include "../pmu/ebb/ebb.h"
+#include "ptrace.h"
+#include "ptrace-ebb.h"
+
+void ebb(void)
+{
+       struct event event;
+
+       event_init_named(&event, 0x1001e, "cycles");
+       event.attr.config |= (1ull << 63);
+        event.attr.exclusive = 1;
+        event.attr.pinned = 1;
+       event.attr.exclude_kernel = 1;
+       event.attr.exclude_hv = 1;
+       event.attr.exclude_idle = 1;
+
+       if (event_open(&event)) {
+               perror("event_open() failed");
+               exit(1);
+       }
+
+       setup_ebb_handler(standard_ebb_callee);
+       mtspr(SPRN_BESCR, 0x8000000100000000ull);
+
+       mb();
+
+       if (ebb_event_enable(&event)) {
+               perror("ebb_event_handler() failed");
+               exit(1);
+       }
+
+       mtspr(SPRN_PMC1, pmc_sample_period(SAMPLE_PERIOD));
+       while(1)
+               core_busy_loop();
+       exit(0);
+}
+
+int validate_ebb(struct ebb_regs *regs)
+{
+       #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+       struct opd *opd = (struct opd *) ebb_handler;
+       #endif
+
+       printf("EBBRR: %lx\n", regs->ebbrr);
+       printf("EBBHR: %lx\n", regs->ebbhr);
+       printf("BESCR: %lx\n", regs->bescr);
+       printf("SIAR:  %lx\n", regs->siar);
+       printf("SDAR:  %lx\n", regs->sdar);
+       printf("SIER:  %lx\n", regs->sier);
+       printf("MMCR2: %lx\n", regs->mmcr2);
+       printf("MMCR0: %lx\n", regs->mmcr0);
+
+       /* Validate EBBHR */
+       #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+       if (regs->ebbhr != opd->entry)
+               return TEST_FAIL;
+       #else
+       if (regs->ebbhr != (unsigned long) ebb_handler)
+               return TEST_FAIL;
+       #endif
+
+       /* Validate SIER */
+       if (regs->sier != SIER_EXP)
+               return TEST_FAIL;
+
+       /* Validate MMCR2 */
+       if (regs->mmcr2 != MMCR2_EXP)
+               return TEST_FAIL;
+
+       /* Validate MMCR0 */
+       if (regs->mmcr0 != MMCR0_EXP)
+               return TEST_FAIL;
+
+       return TEST_PASS;
+}
+
+int trace_ebb(pid_t child)
+{
+       struct ebb_regs regs;
+       int ret;
+
+       sleep(2);
+       ret = start_trace(child);
+       if (ret)
+               return TEST_FAIL;
+
+       ret = show_ebb_registers(child, &regs);
+       if (ret)
+               return TEST_FAIL;
+
+       ret = validate_ebb(&regs);
+       if (ret)
+               return TEST_FAIL;
+
+       ret = stop_trace(child);
+       if (ret)
+               return TEST_FAIL;
+
+       return TEST_PASS;
+}
+
+int ptrace_ebb(void)
+{
+       pid_t pid;
+       int ret, status;
+
+       pid = fork();
+       if (pid < 0) {
+               perror("fork() failed");
+               return TEST_FAIL;
+       }
+
+       if (pid == 0)
+               ebb();
+
+       if (pid) {
+               ret = trace_ebb(pid);
+               if (ret)
+                       return TEST_FAIL;
+
+               kill(pid, SIGKILL);
+               ret = wait(&status);
+               if (ret != pid) {
+                       printf("Child's exit status not captured\n");
+                       return TEST_FAIL;
+               }
+
+               if (WIFEXITED(status)) {
+                       if(WEXITSTATUS(status))
+                               return TEST_FAIL;
+               }
+               return TEST_PASS;
+       }
+       return TEST_PASS;
+}
+
+int main(int argc, char *argv[])
+{
+       return test_harness(ptrace_ebb, "ptrace_ebb");
+}
diff --git a/tools/testing/selftests/powerpc/ptrace/ptrace-ebb.h 
b/tools/testing/selftests/powerpc/ptrace/ptrace-ebb.h
new file mode 100644
index 0000000..9b38edc
--- /dev/null
+++ b/tools/testing/selftests/powerpc/ptrace/ptrace-ebb.h
@@ -0,0 +1,103 @@
+/*
+ * Inspired mostly from the EBB selftest
+ *
+ * Copyright (C) 2015 Anshuman Khandual, 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.
+ */
+#define SAMPLE_PERIOD 100      /* EBB event sample persiod */
+
+/* Standard expected values */
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+#define MMCR0_EXP      0x8000008000000001
+#else
+#define MMCR0_EXP      0x180000080
+#endif
+
+#define MMCR2_EXP      0
+#define SIER_EXP       0x2000000
+
+struct opd
+{
+       u64 entry;
+       u64 toc;
+};
+
+void (*ebb_user_func)(void);
+extern void ebb_handler(void); /* Defined in ebb_handle.S */
+
+void ebb_hook(void)            /* Called by ebb_handler */
+{
+        if (ebb_user_func)
+                ebb_user_func();
+}
+
+void setup_ebb_handler(void (*callee)(void))
+{
+        u64 entry;
+
+#if defined(_CALL_ELF) && _CALL_ELF == 2
+        entry = (u64)ebb_handler;
+#else
+       struct opd *opd;
+
+        opd = (struct opd *)ebb_handler;
+        entry = opd->entry;
+#endif
+        ebb_user_func = callee;
+
+        /* Ensure ebb_user_func is set before we set the handler */
+        mb();
+        mtspr(SPRN_EBBHR, entry);
+
+        /* Make sure the handler is set before we return */
+        mb();
+}
+
+void reset_ebb_with_clear_mask(unsigned long mmcr0_clear_mask)
+{
+        u64 val;
+
+        /* 2) clear MMCR0[PMAO] - docs say BESCR[PMEO] should do this */
+        /* 3) set MMCR0[PMAE]   - docs say BESCR[PME] should do this */
+        val = mfspr(SPRN_MMCR0);
+        mtspr(SPRN_MMCR0, (val & ~mmcr0_clear_mask) | MMCR0_PMAE);
+
+        /* 4) clear BESCR[PMEO] */
+        mtspr(SPRN_BESCRR, BESCR_PMEO);
+
+        /* 5) set BESCR[PME] */
+        mtspr(SPRN_BESCRS, BESCR_PME);
+
+        /* 6) rfebb 1 - done in our caller */
+}
+
+void standard_ebb_callee(void)
+{
+       u64 val;
+
+       val = mfspr(SPRN_BESCR);
+        if (!(val & BESCR_PMEO))
+               printf("Spurious interrupt\n");
+
+       mtspr(SPRN_PMC1, pmc_sample_period(SAMPLE_PERIOD));
+       reset_ebb_with_clear_mask(MMCR0_PMAO | MMCR0_FC);
+}
+
+int ebb_event_enable(struct event *e)
+{
+       int rc;
+
+       mb();
+
+        rc = ioctl(e->fd, PERF_EVENT_IOC_ENABLE);
+        if (rc)
+                return rc;
+        rc = event_read(e);
+
+        mb();
+        return rc;
+}
diff --git a/tools/testing/selftests/powerpc/ptrace/ptrace.h 
b/tools/testing/selftests/powerpc/ptrace/ptrace.h
new file mode 100644
index 0000000..44256d2
--- /dev/null
+++ b/tools/testing/selftests/powerpc/ptrace/ptrace.h
@@ -0,0 +1,225 @@
+/*
+ * Ptrace interface test helper functions
+ *
+ * Copyright (C) 2015 Anshuman Khandual, 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.
+ */
+#include <inttypes.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <malloc.h>
+#include <errno.h>
+#include <time.h>
+#include <sys/ptrace.h>
+#include <sys/ioctl.h>
+#include <sys/uio.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/signal.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/user.h>
+#include <linux/elf.h>
+#include <linux/types.h>
+#include <linux/auxvec.h>
+#include "../reg.h"
+#include "utils.h"
+
+/* ELF core note sections */
+#define NT_PPC_TAR     0x103           /* Target Address Register */
+#define NT_PPC_PPR     0x104           /* Program Priority Register */
+#define NT_PPC_DSCR    0x105           /* Data Stream Control Register */
+#define NT_PPC_EBB     0x106           /* Event Based Branch Registers */
+#define NT_PPC_TM_CGPR 0x107           /* TM checkpointed GPR Registers */
+#define NT_PPC_TM_CFPR 0x108           /* TM checkpointed FPR Registers */
+#define NT_PPC_TM_CVMX 0x109           /* TM checkpointed VMX Registers */
+#define NT_PPC_TM_CVSX 0x10a           /* TM checkpointed VSX Registers */
+#define NT_PPC_TM_SPR  0x10b           /* TM Special Purpose Registers */
+#define NT_PPC_TM_CTAR 0x10c           /* TM checkpointed Target Address 
Register */
+#define NT_PPC_TM_CPPR 0x10d           /* TM checkpointed Program Priority 
Register */
+#define NT_PPC_TM_CDSCR        0x10e           /* TM checkpointed Data Stream 
Control Register */
+
+/* TEXASR register bits */
+#define TEXASR_FC      0xFE00000000000000
+#define TEXASR_FP      0x0100000000000000
+#define TEXASR_DA      0x0080000000000000
+#define TEXASR_NO      0x0040000000000000
+#define TEXASR_FO      0x0020000000000000
+#define TEXASR_SIC     0x0010000000000000
+#define TEXASR_NTC     0x0008000000000000
+#define TEXASR_TC      0x0004000000000000
+#define TEXASR_TIC     0x0002000000000000
+#define TEXASR_IC      0x0001000000000000
+#define TEXASR_IFC     0x0000800000000000
+#define TEXASR_ABT     0x0000000100000000
+#define TEXASR_SPD     0x0000000080000000
+#define TEXASR_HV      0x0000000020000000
+#define TEXASR_PR      0x0000000010000000
+#define TEXASR_FS      0x0000000008000000
+#define TEXASR_TE      0x0000000004000000
+#define TEXASR_ROT     0x0000000002000000
+
+#define TEST_PASS 0
+#define TEST_FAIL 1
+
+struct ebb_regs {
+       unsigned long   ebbrr;
+       unsigned long   ebbhr;
+       unsigned long   bescr;
+       unsigned long   siar;
+       unsigned long   sdar;
+       unsigned long   sier;
+       unsigned long   mmcr2;
+       unsigned long   mmcr0;
+};
+
+struct fpr_regs {
+       unsigned long fpr[32];
+       unsigned long fpscr;
+};
+
+
+/* Basic ptrace operations */
+int start_trace(pid_t child)
+{
+       int ret;
+
+       ret = ptrace(PTRACE_ATTACH, child, NULL, NULL);
+       if (ret) {
+               perror("ptrace(PTRACE_ATTACH) failed");
+               return TEST_FAIL;
+       }
+       ret = waitpid(child, NULL, 0);
+       if (ret != child) {
+               perror("waitpid() failed");
+               return TEST_FAIL;
+       }
+       return TEST_PASS;
+}
+
+int stop_trace(pid_t child)
+{
+       int ret;
+
+       ret = ptrace(PTRACE_DETACH, child, NULL, NULL);
+       if (ret) {
+               perror("ptrace(PTRACE_DETACH) failed");
+               return TEST_FAIL;
+       }
+       return TEST_PASS;
+}
+
+int cont_trace(pid_t child)
+{
+       int ret;
+
+       ret = ptrace(PTRACE_CONT, child, NULL, NULL);
+       if (ret) {
+               perror("ptrace(PTRACE_CONT) failed");
+               return TEST_FAIL;
+       }
+       return TEST_PASS;
+}
+
+/* EBB */
+int show_ebb_registers(pid_t child, struct ebb_regs *regs)
+{
+       struct ebb_regs *ebb;
+       struct iovec iov;
+       int ret;
+
+       ebb = malloc(sizeof(struct ebb_regs));
+       if (!ebb) {
+               perror("malloc() failed");
+               return TEST_FAIL;
+       }
+
+       iov.iov_base = (struct ebb_regs *) ebb;
+       iov.iov_len = sizeof(struct ebb_regs);
+       ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_EBB, &iov);
+       if (ret) {
+               perror("ptrace(PTRACE_GETREGSET) failed");
+               goto fail;
+       }
+
+       if (regs)
+               memcpy(regs, ebb, sizeof(struct ebb_regs));
+
+       free(ebb);
+       return TEST_PASS;
+fail:
+       free(ebb);
+       return TEST_FAIL;
+}
+
+/* Analyse TEXASR after TM failure */
+inline unsigned long get_tfiar(void)
+{
+       unsigned long ret;
+
+       asm volatile("mfspr %0,%1" : "=r" (ret): "i" (SPRN_TFIAR));
+       return ret;
+}
+
+void analyse_texasr(unsigned long texasr)
+{
+       printf("TEXASR: %16lx\t", texasr);
+
+       if (texasr & TEXASR_FP)
+               printf("TEXASR_FP  ");
+
+       if (texasr & TEXASR_DA)
+               printf("TEXASR_DA  ");
+
+       if (texasr & TEXASR_NO)
+               printf("TEXASR_NO  ");
+
+       if (texasr & TEXASR_FO)
+               printf("TEXASR_FO  ");
+
+       if (texasr & TEXASR_SIC)
+               printf("TEXASR_SIC  ");
+
+       if (texasr & TEXASR_NTC)
+               printf("TEXASR_NTC  ");
+
+       if (texasr & TEXASR_TC)
+               printf("TEXASR_TC  ");
+
+       if (texasr & TEXASR_TIC)
+               printf("TEXASR_TIC  ");
+
+       if (texasr & TEXASR_IC)
+               printf("TEXASR_IC  ");
+
+       if (texasr & TEXASR_IFC)
+               printf("TEXASR_IFC  ");
+
+       if (texasr & TEXASR_ABT)
+               printf("TEXASR_ABT  ");
+
+       if (texasr & TEXASR_SPD)
+               printf("TEXASR_SPD  ");
+
+       if (texasr & TEXASR_HV)
+               printf("TEXASR_HV  ");
+
+       if (texasr & TEXASR_PR)
+               printf("TEXASR_PR  ");
+
+       if (texasr & TEXASR_FS)
+               printf("TEXASR_FS  ");
+
+       if (texasr & TEXASR_TE)
+               printf("TEXASR_TE  ");
+
+       if (texasr & TEXASR_ROT)
+               printf("TEXASR_ROT  ");
+
+       printf("TFIAR :%lx\n", get_tfiar());
+}
-- 
2.1.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to