selftests/powerpc: Add ptrace tests for TAR, PPR, DSCR registers
authorAnshuman Khandual <khandual@linux.vnet.ibm.com>
Fri, 30 Sep 2016 02:32:56 +0000 (10:32 +0800)
committerMichael Ellerman <mpe@ellerman.id.au>
Thu, 17 Nov 2016 06:11:49 +0000 (17:11 +1100)
This patch adds ptrace interface test for TAR, PPR, DSCR
registers. This also adds ptrace interface based helper
functions related to TAR, PPR, DSCR register access.

Signed-off-by: Anshuman Khandual <khandual@linux.vnet.ibm.com>
Signed-off-by: Simon Guo <wei.guo.simon@gmail.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
tools/testing/selftests/powerpc/ptrace/.gitignore
tools/testing/selftests/powerpc/ptrace/Makefile
tools/testing/selftests/powerpc/ptrace/ptrace-tar.c [new file with mode: 0644]
tools/testing/selftests/powerpc/ptrace/ptrace-tar.h [new file with mode: 0644]
tools/testing/selftests/powerpc/ptrace/ptrace.h

index e85470e020deafef73a71ea184e2af66137388af..ce9431343ff86a7314c30737e9a8d2d62e11e689 100644 (file)
@@ -1,3 +1,4 @@
 ptrace-gpr
 ptrace-tm-gpr
-ptrace-tm-spd-gpr
\ No newline at end of file
+ptrace-tm-spd-gpr
+ptrace-tar
\ No newline at end of file
index d246e286fb54345e4bf0889c25e2e44af75392a5..c1060ff71e15fca9067291fc4ec1b22f431f4e2a 100644 (file)
@@ -1,4 +1,5 @@
-TEST_PROGS := ptrace-gpr ptrace-tm-gpr ptrace-tm-spd-gpr
+TEST_PROGS := ptrace-gpr ptrace-tm-gpr ptrace-tm-spd-gpr \
+              ptrace-tar
 
 include ../../lib.mk
 
diff --git a/tools/testing/selftests/powerpc/ptrace/ptrace-tar.c b/tools/testing/selftests/powerpc/ptrace/ptrace-tar.c
new file mode 100644 (file)
index 0000000..f9b5069
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * Ptrace test for TAR, PPR, DSCR registers
+ *
+ * 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 "ptrace.h"
+#include "ptrace-tar.h"
+
+/* Tracer and Tracee Shared Data */
+int shm_id;
+int *cptr;
+int *pptr;
+
+void tar(void)
+{
+       unsigned long reg[3];
+       int ret;
+
+       cptr = (int *)shmat(shm_id, NULL, 0);
+       printf("%-30s TAR: %u PPR: %lx DSCR: %u\n",
+                       user_write, TAR_1, PPR_1, DSCR_1);
+
+       mtspr(SPRN_TAR, TAR_1);
+       mtspr(SPRN_PPR, PPR_1);
+       mtspr(SPRN_DSCR, DSCR_1);
+
+       cptr[2] = 1;
+
+       /* Wait on parent */
+       while (!cptr[0])
+               asm volatile("" : : : "memory");
+
+       reg[0] = mfspr(SPRN_TAR);
+       reg[1] = mfspr(SPRN_PPR);
+       reg[2] = mfspr(SPRN_DSCR);
+
+       printf("%-30s TAR: %lu PPR: %lx DSCR: %lu\n",
+                       user_read, reg[0], reg[1], reg[2]);
+
+       /* Unblock the parent now */
+       cptr[1] = 1;
+       shmdt((int *)cptr);
+
+       ret = validate_tar_registers(reg, TAR_2, PPR_2, DSCR_2);
+       if (ret)
+               exit(1);
+       exit(0);
+}
+
+int trace_tar(pid_t child)
+{
+       unsigned long reg[3];
+
+       FAIL_IF(start_trace(child));
+       FAIL_IF(show_tar_registers(child, reg));
+       printf("%-30s TAR: %lu PPR: %lx DSCR: %lu\n",
+                       ptrace_read_running, reg[0], reg[1], reg[2]);
+
+       FAIL_IF(validate_tar_registers(reg, TAR_1, PPR_1, DSCR_1));
+       FAIL_IF(stop_trace(child));
+       return TEST_PASS;
+}
+
+int trace_tar_write(pid_t child)
+{
+       FAIL_IF(start_trace(child));
+       FAIL_IF(write_tar_registers(child, TAR_2, PPR_2, DSCR_2));
+       printf("%-30s TAR: %u PPR: %lx DSCR: %u\n",
+                       ptrace_write_running, TAR_2, PPR_2, DSCR_2);
+
+       FAIL_IF(stop_trace(child));
+       return TEST_PASS;
+}
+
+int ptrace_tar(void)
+{
+       pid_t pid;
+       int ret, status;
+
+       shm_id = shmget(IPC_PRIVATE, sizeof(int) * 3, 0777|IPC_CREAT);
+       pid = fork();
+       if (pid < 0) {
+               perror("fork() failed");
+               return TEST_FAIL;
+       }
+
+       if (pid == 0)
+               tar();
+
+       if (pid) {
+               pptr = (int *)shmat(shm_id, NULL, 0);
+               pptr[0] = 0;
+               pptr[1] = 0;
+
+               while (!pptr[2])
+                       asm volatile("" : : : "memory");
+               ret = trace_tar(pid);
+               if (ret)
+                       return ret;
+
+               ret = trace_tar_write(pid);
+               if (ret)
+                       return ret;
+
+               /* Unblock the child now */
+               pptr[0] = 1;
+
+               /* Wait on child */
+               while (!pptr[1])
+                       asm volatile("" : : : "memory");
+
+               shmdt((int *)pptr);
+
+               ret = wait(&status);
+               shmctl(shm_id, IPC_RMID, NULL);
+               if (ret != pid) {
+                       printf("Child's exit status not captured\n");
+                       return TEST_PASS;
+               }
+
+               return (WIFEXITED(status) && WEXITSTATUS(status)) ? TEST_FAIL :
+                       TEST_PASS;
+       }
+       return TEST_PASS;
+}
+
+int main(int argc, char *argv[])
+{
+       return test_harness(ptrace_tar, "ptrace_tar");
+}
diff --git a/tools/testing/selftests/powerpc/ptrace/ptrace-tar.h b/tools/testing/selftests/powerpc/ptrace/ptrace-tar.h
new file mode 100644 (file)
index 0000000..aed0aac
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * 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 TAR_1   10
+#define TAR_2   20
+#define TAR_3   30
+#define TAR_4   40
+#define TAR_5   50
+
+#define DSCR_1  100
+#define DSCR_2  200
+#define DSCR_3  300
+#define DSCR_4  400
+#define DSCR_5  500
+
+#define PPR_1   0x4000000000000         /* or 31,31,31*/
+#define PPR_2   0x8000000000000         /* or 1,1,1 */
+#define PPR_3   0xc000000000000         /* or 6,6,6 */
+#define PPR_4   0x10000000000000        /* or 2,2,2 */
+
+char *user_read = "[User Read (Running)]";
+char *user_write = "[User Write (Running)]";
+char *ptrace_read_running = "[Ptrace Read (Running)]";
+char *ptrace_write_running = "[Ptrace Write (Running)]";
+char *ptrace_read_ckpt = "[Ptrace Read (Checkpointed)]";
+char *ptrace_write_ckpt = "[Ptrace Write (Checkpointed)]";
+
+int validate_tar_registers(unsigned long *reg, unsigned long tar,
+                               unsigned long ppr, unsigned long dscr)
+{
+       int match = 1;
+
+       if (reg[0] != tar)
+               match = 0;
+
+       if (reg[1] != ppr)
+               match = 0;
+
+       if (reg[2] != dscr)
+               match = 0;
+
+       if (!match)
+               return TEST_FAIL;
+       return TEST_PASS;
+}
index 9ee89eb06df97308078ef52e67a56ffab5dcb02f..fee71b8c1e750af63025cf442c5e7a4494936fad 100644 (file)
@@ -97,6 +97,187 @@ int cont_trace(pid_t child)
        return TEST_PASS;
 }
 
+/* TAR, PPR, DSCR */
+int show_tar_registers(pid_t child, unsigned long *out)
+{
+       struct iovec iov;
+       unsigned long *reg;
+       int ret;
+
+       reg = malloc(sizeof(unsigned long));
+       if (!reg) {
+               perror("malloc() failed");
+               return TEST_FAIL;
+       }
+       iov.iov_base = (u64 *) reg;
+       iov.iov_len = sizeof(unsigned long);
+
+       ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TAR, &iov);
+       if (ret) {
+               perror("ptrace(PTRACE_GETREGSET) failed");
+               goto fail;
+       }
+       if (out)
+               out[0] = *reg;
+
+       ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_PPR, &iov);
+       if (ret) {
+               perror("ptrace(PTRACE_GETREGSET) failed");
+               goto fail;
+       }
+       if (out)
+               out[1] = *reg;
+
+       ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_DSCR, &iov);
+       if (ret) {
+               perror("ptrace(PTRACE_GETREGSET) failed");
+               goto fail;
+       }
+       if (out)
+               out[2] = *reg;
+
+       free(reg);
+       return TEST_PASS;
+fail:
+       free(reg);
+       return TEST_FAIL;
+}
+
+int write_tar_registers(pid_t child, unsigned long tar,
+               unsigned long ppr, unsigned long dscr)
+{
+       struct iovec iov;
+       unsigned long *reg;
+       int ret;
+
+       reg = malloc(sizeof(unsigned long));
+       if (!reg) {
+               perror("malloc() failed");
+               return TEST_FAIL;
+       }
+
+       iov.iov_base = (u64 *) reg;
+       iov.iov_len = sizeof(unsigned long);
+
+       *reg = tar;
+       ret = ptrace(PTRACE_SETREGSET, child, NT_PPC_TAR, &iov);
+       if (ret) {
+               perror("ptrace(PTRACE_SETREGSET) failed");
+               goto fail;
+       }
+
+       *reg = ppr;
+       ret = ptrace(PTRACE_SETREGSET, child, NT_PPC_PPR, &iov);
+       if (ret) {
+               perror("ptrace(PTRACE_SETREGSET) failed");
+               goto fail;
+       }
+
+       *reg = dscr;
+       ret = ptrace(PTRACE_SETREGSET, child, NT_PPC_DSCR, &iov);
+       if (ret) {
+               perror("ptrace(PTRACE_SETREGSET) failed");
+               goto fail;
+       }
+
+       free(reg);
+       return TEST_PASS;
+fail:
+       free(reg);
+       return TEST_FAIL;
+}
+
+int show_tm_checkpointed_state(pid_t child, unsigned long *out)
+{
+       struct iovec iov;
+       unsigned long *reg;
+       int ret;
+
+       reg = malloc(sizeof(unsigned long));
+       if (!reg) {
+               perror("malloc() failed");
+               return TEST_FAIL;
+       }
+
+       iov.iov_base = (u64 *) reg;
+       iov.iov_len = sizeof(unsigned long);
+
+       ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TM_CTAR, &iov);
+       if (ret) {
+               perror("ptrace(PTRACE_GETREGSET) failed");
+               goto fail;
+       }
+       if (out)
+               out[0] = *reg;
+
+       ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TM_CPPR, &iov);
+       if (ret) {
+               perror("ptrace(PTRACE_GETREGSET) failed");
+               goto fail;
+       }
+       if (out)
+               out[1] = *reg;
+
+       ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TM_CDSCR, &iov);
+       if (ret) {
+               perror("ptrace(PTRACE_GETREGSET) failed");
+               goto fail;
+       }
+       if (out)
+               out[2] = *reg;
+
+       free(reg);
+       return TEST_PASS;
+
+fail:
+       free(reg);
+       return TEST_FAIL;
+}
+
+int write_ckpt_tar_registers(pid_t child, unsigned long tar,
+               unsigned long ppr, unsigned long dscr)
+{
+       struct iovec iov;
+       unsigned long *reg;
+       int ret;
+
+       reg = malloc(sizeof(unsigned long));
+       if (!reg) {
+               perror("malloc() failed");
+               return TEST_FAIL;
+       }
+
+       iov.iov_base = (u64 *) reg;
+       iov.iov_len = sizeof(unsigned long);
+
+       *reg = tar;
+       ret = ptrace(PTRACE_SETREGSET, child, NT_PPC_TM_CTAR, &iov);
+       if (ret) {
+               perror("ptrace(PTRACE_GETREGSET) failed");
+               goto fail;
+       }
+
+       *reg = ppr;
+       ret = ptrace(PTRACE_SETREGSET, child, NT_PPC_TM_CPPR, &iov);
+       if (ret) {
+               perror("ptrace(PTRACE_GETREGSET) failed");
+               goto fail;
+       }
+
+       *reg = dscr;
+       ret = ptrace(PTRACE_SETREGSET, child, NT_PPC_TM_CDSCR, &iov);
+       if (ret) {
+               perror("ptrace(PTRACE_GETREGSET) failed");
+               goto fail;
+       }
+
+       free(reg);
+       return TEST_PASS;
+fail:
+       free(reg);
+       return TEST_FAIL;
+}
+
 /* FPR */
 int show_fpr(pid_t child, unsigned long *fpr)
 {