Commit | Line | Data |
---|---|---|
5bdac52f AK |
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) | |
f36dbfe1 | 79 | : "memory", "r0", "r8", "r31" |
5bdac52f AK |
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 | } |