1 /* 2 * Ptrace test TM SPR registers 3 * 4 * Copyright (C) 2015 Anshuman Khandual, IBM Corporation. 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * as published by the Free Software Foundation; either version 9 * 2 of the License, or (at your option) any later version. 10 */ 11 #include "ptrace.h" 12 #include "tm.h" 13 14 /* Tracee and tracer shared data */ 15 struct shared { 16 int flag; 17 struct tm_spr_regs regs; 18 }; 19 unsigned long tfhar; 20 21 int shm_id; 22 struct shared *cptr, *pptr; 23 24 int shm_id1; 25 int *cptr1, *pptr1; 26 27 #define TM_KVM_SCHED 0xe0000001ac000001 28 int validate_tm_spr(struct tm_spr_regs *regs) 29 { 30 FAIL_IF(regs->tm_tfhar != tfhar); 31 FAIL_IF((regs->tm_texasr == TM_KVM_SCHED) && (regs->tm_tfiar != 0)); 32 33 return TEST_PASS; 34 } 35 36 void tm_spr(void) 37 { 38 unsigned long result, texasr; 39 int ret; 40 41 cptr = (struct shared *)shmat(shm_id, NULL, 0); 42 cptr1 = (int *)shmat(shm_id1, NULL, 0); 43 44 trans: 45 cptr1[0] = 0; 46 asm __volatile__( 47 "1: ;" 48 /* TM failover handler should follow "tbegin.;" */ 49 "mflr 31;" 50 "bl 4f;" /* $ = TFHAR - 12 */ 51 "4: ;" 52 "mflr %[tfhar];" 53 "mtlr 31;" 54 55 "tbegin.;" 56 "beq 2f;" 57 58 "tsuspend.;" 59 "li 8, 1;" 60 "sth 8, 0(%[cptr1]);" 61 "tresume.;" 62 "b .;" 63 64 "tend.;" 65 "li 0, 0;" 66 "ori %[res], 0, 0;" 67 "b 3f;" 68 69 "2: ;" 70 71 "li 0, 1;" 72 "ori %[res], 0, 0;" 73 "mfspr %[texasr], %[sprn_texasr];" 74 75 "3: ;" 76 : [tfhar] "=r" (tfhar), [res] "=r" (result), 77 [texasr] "=r" (texasr), [cptr1] "=b" (cptr1) 78 : [sprn_texasr] "i" (SPRN_TEXASR) 79 : "memory", "r0", "r8", "r31" 80 ); 81 82 /* There are 2 32bit instructions before tbegin. */ 83 tfhar += 12; 84 85 if (result) { 86 if (!cptr->flag) 87 goto trans; 88 89 ret = validate_tm_spr((struct tm_spr_regs *)&cptr->regs); 90 shmdt((void *)cptr); 91 shmdt((void *)cptr1); 92 if (ret) 93 exit(1); 94 exit(0); 95 } 96 shmdt((void *)cptr); 97 shmdt((void *)cptr1); 98 exit(1); 99 } 100 101 int trace_tm_spr(pid_t child) 102 { 103 FAIL_IF(start_trace(child)); 104 FAIL_IF(show_tm_spr(child, (struct tm_spr_regs *)&pptr->regs)); 105 106 printf("TFHAR: %lx TEXASR: %lx TFIAR: %lx\n", pptr->regs.tm_tfhar, 107 pptr->regs.tm_texasr, pptr->regs.tm_tfiar); 108 109 pptr->flag = 1; 110 FAIL_IF(stop_trace(child)); 111 112 return TEST_PASS; 113 } 114 115 int ptrace_tm_spr(void) 116 { 117 pid_t pid; 118 int ret, status; 119 120 SKIP_IF(!have_htm()); 121 shm_id = shmget(IPC_PRIVATE, sizeof(struct shared), 0777|IPC_CREAT); 122 shm_id1 = shmget(IPC_PRIVATE, sizeof(int), 0777|IPC_CREAT); 123 pid = fork(); 124 if (pid < 0) { 125 perror("fork() failed"); 126 return TEST_FAIL; 127 } 128 129 if (pid == 0) 130 tm_spr(); 131 132 if (pid) { 133 pptr = (struct shared *)shmat(shm_id, NULL, 0); 134 pptr1 = (int *)shmat(shm_id1, NULL, 0); 135 136 while (!pptr1[0]) 137 asm volatile("" : : : "memory"); 138 ret = trace_tm_spr(pid); 139 if (ret) { 140 kill(pid, SIGKILL); 141 shmdt((void *)pptr); 142 shmdt((void *)pptr1); 143 shmctl(shm_id, IPC_RMID, NULL); 144 shmctl(shm_id1, IPC_RMID, NULL); 145 return TEST_FAIL; 146 } 147 148 shmdt((void *)pptr); 149 shmdt((void *)pptr1); 150 ret = wait(&status); 151 shmctl(shm_id, IPC_RMID, NULL); 152 shmctl(shm_id1, IPC_RMID, NULL); 153 if (ret != pid) { 154 printf("Child's exit status not captured\n"); 155 return TEST_FAIL; 156 } 157 158 return (WIFEXITED(status) && WEXITSTATUS(status)) ? TEST_FAIL : 159 TEST_PASS; 160 } 161 return TEST_PASS; 162 } 163 164 int main(int argc, char *argv[]) 165 { 166 return test_harness(ptrace_tm_spr, "ptrace_tm_spr"); 167 } 168