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] "=r" (cptr1) 78 : [sprn_texasr] "i" (SPRN_TEXASR) 79 : "memory", "r0", "r1", "r2", "r3", "r4", 80 "r8", "r9", "r10", "r11", "r31" 81 ); 82 83 /* There are 2 32bit instructions before tbegin. */ 84 tfhar += 12; 85 86 if (result) { 87 if (!cptr->flag) 88 goto trans; 89 90 ret = validate_tm_spr((struct tm_spr_regs *)&cptr->regs); 91 shmdt((void *)cptr); 92 shmdt((void *)cptr1); 93 if (ret) 94 exit(1); 95 exit(0); 96 } 97 shmdt((void *)cptr); 98 shmdt((void *)cptr1); 99 exit(1); 100 } 101 102 int trace_tm_spr(pid_t child) 103 { 104 FAIL_IF(start_trace(child)); 105 FAIL_IF(show_tm_spr(child, (struct tm_spr_regs *)&pptr->regs)); 106 107 printf("TFHAR: %lx TEXASR: %lx TFIAR: %lx\n", pptr->regs.tm_tfhar, 108 pptr->regs.tm_texasr, pptr->regs.tm_tfiar); 109 110 pptr->flag = 1; 111 FAIL_IF(stop_trace(child)); 112 113 return TEST_PASS; 114 } 115 116 int ptrace_tm_spr(void) 117 { 118 pid_t pid; 119 int ret, status; 120 121 SKIP_IF(!have_htm()); 122 shm_id = shmget(IPC_PRIVATE, sizeof(struct shared), 0777|IPC_CREAT); 123 shm_id1 = shmget(IPC_PRIVATE, sizeof(int), 0777|IPC_CREAT); 124 pid = fork(); 125 if (pid < 0) { 126 perror("fork() failed"); 127 return TEST_FAIL; 128 } 129 130 if (pid == 0) 131 tm_spr(); 132 133 if (pid) { 134 pptr = (struct shared *)shmat(shm_id, NULL, 0); 135 pptr1 = (int *)shmat(shm_id1, NULL, 0); 136 137 while (!pptr1[0]) 138 asm volatile("" : : : "memory"); 139 ret = trace_tm_spr(pid); 140 if (ret) { 141 kill(pid, SIGKILL); 142 shmdt((void *)pptr); 143 shmdt((void *)pptr1); 144 shmctl(shm_id, IPC_RMID, NULL); 145 shmctl(shm_id1, IPC_RMID, NULL); 146 return TEST_FAIL; 147 } 148 149 shmdt((void *)pptr); 150 shmdt((void *)pptr1); 151 ret = wait(&status); 152 shmctl(shm_id, IPC_RMID, NULL); 153 shmctl(shm_id1, IPC_RMID, NULL); 154 if (ret != pid) { 155 printf("Child's exit status not captured\n"); 156 return TEST_FAIL; 157 } 158 159 return (WIFEXITED(status) && WEXITSTATUS(status)) ? TEST_FAIL : 160 TEST_PASS; 161 } 162 return TEST_PASS; 163 } 164 165 int main(int argc, char *argv[]) 166 { 167 return test_harness(ptrace_tm_spr, "ptrace_tm_spr"); 168 } 169