forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-12-19 9370bb92b2d16684ee45cf24e879c93c509162da
kernel/tools/testing/selftests/powerpc/ptrace/ptrace-hwbreak.c
....@@ -20,323 +20,531 @@
2020 #include <signal.h>
2121 #include <sys/types.h>
2222 #include <sys/wait.h>
23
+#include <sys/syscall.h>
24
+#include <linux/limits.h>
2325 #include "ptrace.h"
2426
25
-/* Breakpoint access modes */
26
-enum {
27
- BP_X = 1,
28
- BP_RW = 2,
29
- BP_W = 4,
27
+#define SPRN_PVR 0x11F
28
+#define PVR_8xx 0x00500000
29
+
30
+bool is_8xx;
31
+
32
+/*
33
+ * Use volatile on all global var so that compiler doesn't
34
+ * optimise their load/stores. Otherwise selftest can fail.
35
+ */
36
+static volatile __u64 glvar;
37
+
38
+#define DAWR_MAX_LEN 512
39
+static volatile __u8 big_var[DAWR_MAX_LEN] __attribute__((aligned(512)));
40
+
41
+#define A_LEN 6
42
+#define B_LEN 6
43
+struct gstruct {
44
+ __u8 a[A_LEN]; /* double word aligned */
45
+ __u8 b[B_LEN]; /* double word unaligned */
3046 };
47
+static volatile struct gstruct gstruct __attribute__((aligned(512)));
3148
32
-static pid_t child_pid;
33
-static struct ppc_debug_info dbginfo;
49
+static volatile char cwd[PATH_MAX] __attribute__((aligned(8)));
3450
35
-static void get_dbginfo(void)
51
+static void get_dbginfo(pid_t child_pid, struct ppc_debug_info *dbginfo)
3652 {
37
- int ret;
38
-
39
- ret = ptrace(PPC_PTRACE_GETHWDBGINFO, child_pid, NULL, &dbginfo);
40
- if (ret) {
41
- perror("Can't get breakpoint info\n");
53
+ if (ptrace(PPC_PTRACE_GETHWDBGINFO, child_pid, NULL, dbginfo)) {
54
+ perror("Can't get breakpoint info");
4255 exit(-1);
4356 }
4457 }
4558
46
-static bool hwbreak_present(void)
59
+static bool dawr_present(struct ppc_debug_info *dbginfo)
4760 {
48
- return (dbginfo.num_data_bps != 0);
61
+ return !!(dbginfo->features & PPC_DEBUG_FEATURE_DATA_BP_DAWR);
4962 }
50
-
51
-static bool dawr_present(void)
52
-{
53
- return !!(dbginfo.features & PPC_DEBUG_FEATURE_DATA_BP_DAWR);
54
-}
55
-
56
-static void set_breakpoint_addr(void *addr)
57
-{
58
- int ret;
59
-
60
- ret = ptrace(PTRACE_SET_DEBUGREG, child_pid, 0, addr);
61
- if (ret) {
62
- perror("Can't set breakpoint addr\n");
63
- exit(-1);
64
- }
65
-}
66
-
67
-static int set_hwbreakpoint_addr(void *addr, int range)
68
-{
69
- int ret;
70
-
71
- struct ppc_hw_breakpoint info;
72
-
73
- info.version = 1;
74
- info.trigger_type = PPC_BREAKPOINT_TRIGGER_RW;
75
- info.addr_mode = PPC_BREAKPOINT_MODE_EXACT;
76
- if (range > 0)
77
- info.addr_mode = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE;
78
- info.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
79
- info.addr = (__u64)addr;
80
- info.addr2 = (__u64)addr + range;
81
- info.condition_value = 0;
82
-
83
- ret = ptrace(PPC_PTRACE_SETHWDEBUG, child_pid, 0, &info);
84
- if (ret < 0) {
85
- perror("Can't set breakpoint\n");
86
- exit(-1);
87
- }
88
- return ret;
89
-}
90
-
91
-static int del_hwbreakpoint_addr(int watchpoint_handle)
92
-{
93
- int ret;
94
-
95
- ret = ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, watchpoint_handle);
96
- if (ret < 0) {
97
- perror("Can't delete hw breakpoint\n");
98
- exit(-1);
99
- }
100
- return ret;
101
-}
102
-
103
-#define DAWR_LENGTH_MAX 512
104
-
105
-/* Dummy variables to test read/write accesses */
106
-static unsigned long long
107
- dummy_array[DAWR_LENGTH_MAX / sizeof(unsigned long long)]
108
- __attribute__((aligned(512)));
109
-static unsigned long long *dummy_var = dummy_array;
11063
11164 static void write_var(int len)
11265 {
113
- long long *plval;
114
- char *pcval;
115
- short *psval;
116
- int *pival;
66
+ __u8 *pcvar;
67
+ __u16 *psvar;
68
+ __u32 *pivar;
69
+ __u64 *plvar;
11770
11871 switch (len) {
11972 case 1:
120
- pcval = (char *)dummy_var;
121
- *pcval = 0xff;
73
+ pcvar = (__u8 *)&glvar;
74
+ *pcvar = 0xff;
12275 break;
12376 case 2:
124
- psval = (short *)dummy_var;
125
- *psval = 0xffff;
77
+ psvar = (__u16 *)&glvar;
78
+ *psvar = 0xffff;
12679 break;
12780 case 4:
128
- pival = (int *)dummy_var;
129
- *pival = 0xffffffff;
81
+ pivar = (__u32 *)&glvar;
82
+ *pivar = 0xffffffff;
13083 break;
13184 case 8:
132
- plval = (long long *)dummy_var;
133
- *plval = 0xffffffffffffffffLL;
85
+ plvar = (__u64 *)&glvar;
86
+ *plvar = 0xffffffffffffffffLL;
13487 break;
13588 }
13689 }
13790
13891 static void read_var(int len)
13992 {
140
- char cval __attribute__((unused));
141
- short sval __attribute__((unused));
142
- int ival __attribute__((unused));
143
- long long lval __attribute__((unused));
93
+ __u8 cvar __attribute__((unused));
94
+ __u16 svar __attribute__((unused));
95
+ __u32 ivar __attribute__((unused));
96
+ __u64 lvar __attribute__((unused));
14497
14598 switch (len) {
14699 case 1:
147
- cval = *(char *)dummy_var;
100
+ cvar = (__u8)glvar;
148101 break;
149102 case 2:
150
- sval = *(short *)dummy_var;
103
+ svar = (__u16)glvar;
151104 break;
152105 case 4:
153
- ival = *(int *)dummy_var;
106
+ ivar = (__u32)glvar;
154107 break;
155108 case 8:
156
- lval = *(long long *)dummy_var;
109
+ lvar = (__u64)glvar;
157110 break;
158111 }
159112 }
160113
161
-/*
162
- * Do the r/w accesses to trigger the breakpoints. And run
163
- * the usual traps.
164
- */
165
-static void trigger_tests(void)
114
+static void test_workload(void)
166115 {
167
- int len, ret;
116
+ __u8 cvar __attribute__((unused));
117
+ __u32 ivar __attribute__((unused));
118
+ int len = 0;
168119
169
- ret = ptrace(PTRACE_TRACEME, 0, NULL, 0);
170
- if (ret) {
171
- perror("Can't be traced?\n");
172
- return;
120
+ if (ptrace(PTRACE_TRACEME, 0, NULL, 0)) {
121
+ perror("Child can't be traced?");
122
+ exit(-1);
173123 }
174124
175125 /* Wake up father so that it sets up the first test */
176126 kill(getpid(), SIGUSR1);
177127
178
- /* Test write watchpoints */
179
- for (len = 1; len <= sizeof(long); len <<= 1)
128
+ /* PTRACE_SET_DEBUGREG, WO test */
129
+ for (len = 1; len <= sizeof(glvar); len <<= 1)
180130 write_var(len);
181131
182
- /* Test read/write watchpoints (on read accesses) */
183
- for (len = 1; len <= sizeof(long); len <<= 1)
132
+ /* PTRACE_SET_DEBUGREG, RO test */
133
+ for (len = 1; len <= sizeof(glvar); len <<= 1)
184134 read_var(len);
185135
186
- /* Test when breakpoint is unset */
136
+ /* PTRACE_SET_DEBUGREG, RW test */
137
+ for (len = 1; len <= sizeof(glvar); len <<= 1) {
138
+ if (rand() % 2)
139
+ read_var(len);
140
+ else
141
+ write_var(len);
142
+ }
187143
188
- /* Test write watchpoints */
189
- for (len = 1; len <= sizeof(long); len <<= 1)
190
- write_var(len);
144
+ /* PTRACE_SET_DEBUGREG, Kernel Access Userspace test */
145
+ syscall(__NR_getcwd, &cwd, PATH_MAX);
191146
192
- /* Test read/write watchpoints (on read accesses) */
193
- for (len = 1; len <= sizeof(long); len <<= 1)
194
- read_var(len);
147
+ /* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, WO test */
148
+ write_var(1);
149
+
150
+ /* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, RO test */
151
+ read_var(1);
152
+
153
+ /* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, RW test */
154
+ if (rand() % 2)
155
+ write_var(1);
156
+ else
157
+ read_var(1);
158
+
159
+ /* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, Kernel Access Userspace test */
160
+ syscall(__NR_getcwd, &cwd, PATH_MAX);
161
+
162
+ /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW ALIGNED, WO test */
163
+ gstruct.a[rand() % A_LEN] = 'a';
164
+
165
+ /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW ALIGNED, RO test */
166
+ cvar = gstruct.a[rand() % A_LEN];
167
+
168
+ /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW ALIGNED, RW test */
169
+ if (rand() % 2)
170
+ gstruct.a[rand() % A_LEN] = 'a';
171
+ else
172
+ cvar = gstruct.a[rand() % A_LEN];
173
+
174
+ /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, WO test */
175
+ gstruct.b[rand() % B_LEN] = 'b';
176
+
177
+ /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, RO test */
178
+ cvar = gstruct.b[rand() % B_LEN];
179
+
180
+ /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, RW test */
181
+ if (rand() % 2)
182
+ gstruct.b[rand() % B_LEN] = 'b';
183
+ else
184
+ cvar = gstruct.b[rand() % B_LEN];
185
+
186
+ /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, DAR OUTSIDE, RW test */
187
+ if (rand() % 2)
188
+ *((int *)(gstruct.a + 4)) = 10;
189
+ else
190
+ ivar = *((int *)(gstruct.a + 4));
191
+
192
+ /* PPC_PTRACE_SETHWDEBUG. DAWR_MAX_LEN. RW test */
193
+ if (rand() % 2)
194
+ big_var[rand() % DAWR_MAX_LEN] = 'a';
195
+ else
196
+ cvar = big_var[rand() % DAWR_MAX_LEN];
195197 }
196198
197
-static void check_success(const char *msg)
199
+static void check_success(pid_t child_pid, const char *name, const char *type,
200
+ unsigned long saddr, int len)
198201 {
199
- const char *msg2;
200202 int status;
203
+ siginfo_t siginfo;
204
+ unsigned long eaddr = (saddr + len - 1) | 0x7;
205
+
206
+ saddr &= ~0x7;
201207
202208 /* Wait for the child to SIGTRAP */
203209 wait(&status);
204210
205
- msg2 = "Failed";
211
+ ptrace(PTRACE_GETSIGINFO, child_pid, NULL, &siginfo);
206212
207
- if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) {
208
- msg2 = "Child process hit the breakpoint";
213
+ if (!WIFSTOPPED(status) || WSTOPSIG(status) != SIGTRAP ||
214
+ (unsigned long)siginfo.si_addr < saddr ||
215
+ (unsigned long)siginfo.si_addr > eaddr) {
216
+ printf("%s, %s, len: %d: Fail\n", name, type, len);
217
+ exit(-1);
209218 }
210219
211
- printf("%s Result: [%s]\n", msg, msg2);
220
+ printf("%s, %s, len: %d: Ok\n", name, type, len);
221
+
222
+ if (!is_8xx) {
223
+ /*
224
+ * For ptrace registered watchpoint, signal is generated
225
+ * before executing load/store. Singlestep the instruction
226
+ * and then continue the test.
227
+ */
228
+ ptrace(PTRACE_SINGLESTEP, child_pid, NULL, 0);
229
+ wait(NULL);
230
+ }
212231 }
213232
214
-static void launch_watchpoints(char *buf, int mode, int len,
215
- struct ppc_debug_info *dbginfo, bool dawr)
233
+static void ptrace_set_debugreg(pid_t child_pid, unsigned long wp_addr)
216234 {
217
- const char *mode_str;
218
- unsigned long data = (unsigned long)(dummy_var);
219
- int wh, range;
235
+ if (ptrace(PTRACE_SET_DEBUGREG, child_pid, 0, wp_addr)) {
236
+ perror("PTRACE_SET_DEBUGREG failed");
237
+ exit(-1);
238
+ }
239
+}
220240
221
- data &= ~0x7UL;
241
+static int ptrace_sethwdebug(pid_t child_pid, struct ppc_hw_breakpoint *info)
242
+{
243
+ int wh = ptrace(PPC_PTRACE_SETHWDEBUG, child_pid, 0, info);
222244
223
- if (mode == BP_W) {
224
- data |= (1UL << 1);
225
- mode_str = "write";
226
- } else {
227
- data |= (1UL << 0);
228
- data |= (1UL << 1);
229
- mode_str = "read";
245
+ if (wh <= 0) {
246
+ perror("PPC_PTRACE_SETHWDEBUG failed");
247
+ exit(-1);
248
+ }
249
+ return wh;
250
+}
251
+
252
+static void ptrace_delhwdebug(pid_t child_pid, int wh)
253
+{
254
+ if (ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, wh) < 0) {
255
+ perror("PPC_PTRACE_DELHWDEBUG failed");
256
+ exit(-1);
257
+ }
258
+}
259
+
260
+#define DABR_READ_SHIFT 0
261
+#define DABR_WRITE_SHIFT 1
262
+#define DABR_TRANSLATION_SHIFT 2
263
+
264
+static int test_set_debugreg(pid_t child_pid)
265
+{
266
+ unsigned long wp_addr = (unsigned long)&glvar;
267
+ char *name = "PTRACE_SET_DEBUGREG";
268
+ int len;
269
+
270
+ /* PTRACE_SET_DEBUGREG, WO test*/
271
+ wp_addr &= ~0x7UL;
272
+ wp_addr |= (1UL << DABR_WRITE_SHIFT);
273
+ wp_addr |= (1UL << DABR_TRANSLATION_SHIFT);
274
+ for (len = 1; len <= sizeof(glvar); len <<= 1) {
275
+ ptrace_set_debugreg(child_pid, wp_addr);
276
+ ptrace(PTRACE_CONT, child_pid, NULL, 0);
277
+ check_success(child_pid, name, "WO", wp_addr, len);
230278 }
231279
232
- /* Set DABR_TRANSLATION bit */
233
- data |= (1UL << 2);
280
+ /* PTRACE_SET_DEBUGREG, RO test */
281
+ wp_addr &= ~0x7UL;
282
+ wp_addr |= (1UL << DABR_READ_SHIFT);
283
+ wp_addr |= (1UL << DABR_TRANSLATION_SHIFT);
284
+ for (len = 1; len <= sizeof(glvar); len <<= 1) {
285
+ ptrace_set_debugreg(child_pid, wp_addr);
286
+ ptrace(PTRACE_CONT, child_pid, NULL, 0);
287
+ check_success(child_pid, name, "RO", wp_addr, len);
288
+ }
234289
235
- /* use PTRACE_SET_DEBUGREG breakpoints */
236
- set_breakpoint_addr((void *)data);
290
+ /* PTRACE_SET_DEBUGREG, RW test */
291
+ wp_addr &= ~0x7UL;
292
+ wp_addr |= (1Ul << DABR_READ_SHIFT);
293
+ wp_addr |= (1UL << DABR_WRITE_SHIFT);
294
+ wp_addr |= (1UL << DABR_TRANSLATION_SHIFT);
295
+ for (len = 1; len <= sizeof(glvar); len <<= 1) {
296
+ ptrace_set_debugreg(child_pid, wp_addr);
297
+ ptrace(PTRACE_CONT, child_pid, NULL, 0);
298
+ check_success(child_pid, name, "RW", wp_addr, len);
299
+ }
300
+
301
+ ptrace_set_debugreg(child_pid, 0);
302
+ return 0;
303
+}
304
+
305
+static int test_set_debugreg_kernel_userspace(pid_t child_pid)
306
+{
307
+ unsigned long wp_addr = (unsigned long)cwd;
308
+ char *name = "PTRACE_SET_DEBUGREG";
309
+
310
+ /* PTRACE_SET_DEBUGREG, Kernel Access Userspace test */
311
+ wp_addr &= ~0x7UL;
312
+ wp_addr |= (1Ul << DABR_READ_SHIFT);
313
+ wp_addr |= (1UL << DABR_WRITE_SHIFT);
314
+ wp_addr |= (1UL << DABR_TRANSLATION_SHIFT);
315
+ ptrace_set_debugreg(child_pid, wp_addr);
237316 ptrace(PTRACE_CONT, child_pid, NULL, 0);
238
- sprintf(buf, "Test %s watchpoint with len: %d ", mode_str, len);
239
- check_success(buf);
240
- /* Unregister hw brkpoint */
241
- set_breakpoint_addr(NULL);
317
+ check_success(child_pid, name, "Kernel Access Userspace", wp_addr, 8);
242318
243
- data = (data & ~7); /* remove dabr control bits */
319
+ ptrace_set_debugreg(child_pid, 0);
320
+ return 0;
321
+}
244322
245
- /* use PPC_PTRACE_SETHWDEBUG breakpoint */
246
- if (!(dbginfo->features & PPC_DEBUG_FEATURE_DATA_BP_RANGE))
247
- return; /* not supported */
248
- wh = set_hwbreakpoint_addr((void *)data, 0);
323
+static void get_ppc_hw_breakpoint(struct ppc_hw_breakpoint *info, int type,
324
+ unsigned long addr, int len)
325
+{
326
+ info->version = 1;
327
+ info->trigger_type = type;
328
+ info->condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
329
+ info->addr = (__u64)addr;
330
+ info->addr2 = (__u64)addr + len;
331
+ info->condition_value = 0;
332
+ if (!len)
333
+ info->addr_mode = PPC_BREAKPOINT_MODE_EXACT;
334
+ else
335
+ info->addr_mode = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE;
336
+}
337
+
338
+static void test_sethwdebug_exact(pid_t child_pid)
339
+{
340
+ struct ppc_hw_breakpoint info;
341
+ unsigned long wp_addr = (unsigned long)&glvar;
342
+ char *name = "PPC_PTRACE_SETHWDEBUG, MODE_EXACT";
343
+ int len = 1; /* hardcoded in kernel */
344
+ int wh;
345
+
346
+ /* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, WO test */
347
+ get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_WRITE, wp_addr, 0);
348
+ wh = ptrace_sethwdebug(child_pid, &info);
249349 ptrace(PTRACE_CONT, child_pid, NULL, 0);
250
- sprintf(buf, "Test %s watchpoint with len: %d ", mode_str, len);
251
- check_success(buf);
252
- /* Unregister hw brkpoint */
253
- del_hwbreakpoint_addr(wh);
350
+ check_success(child_pid, name, "WO", wp_addr, len);
351
+ ptrace_delhwdebug(child_pid, wh);
254352
255
- /* try a wider range */
256
- range = 8;
257
- if (dawr)
258
- range = 512 - ((int)data & (DAWR_LENGTH_MAX - 1));
259
- wh = set_hwbreakpoint_addr((void *)data, range);
353
+ /* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, RO test */
354
+ get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_READ, wp_addr, 0);
355
+ wh = ptrace_sethwdebug(child_pid, &info);
260356 ptrace(PTRACE_CONT, child_pid, NULL, 0);
261
- sprintf(buf, "Test %s watchpoint with len: %d ", mode_str, len);
262
- check_success(buf);
263
- /* Unregister hw brkpoint */
264
- del_hwbreakpoint_addr(wh);
357
+ check_success(child_pid, name, "RO", wp_addr, len);
358
+ ptrace_delhwdebug(child_pid, wh);
359
+
360
+ /* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, RW test */
361
+ get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_RW, wp_addr, 0);
362
+ wh = ptrace_sethwdebug(child_pid, &info);
363
+ ptrace(PTRACE_CONT, child_pid, NULL, 0);
364
+ check_success(child_pid, name, "RW", wp_addr, len);
365
+ ptrace_delhwdebug(child_pid, wh);
366
+}
367
+
368
+static void test_sethwdebug_exact_kernel_userspace(pid_t child_pid)
369
+{
370
+ struct ppc_hw_breakpoint info;
371
+ unsigned long wp_addr = (unsigned long)&cwd;
372
+ char *name = "PPC_PTRACE_SETHWDEBUG, MODE_EXACT";
373
+ int len = 1; /* hardcoded in kernel */
374
+ int wh;
375
+
376
+ /* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, Kernel Access Userspace test */
377
+ get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_WRITE, wp_addr, 0);
378
+ wh = ptrace_sethwdebug(child_pid, &info);
379
+ ptrace(PTRACE_CONT, child_pid, NULL, 0);
380
+ check_success(child_pid, name, "Kernel Access Userspace", wp_addr, len);
381
+ ptrace_delhwdebug(child_pid, wh);
382
+}
383
+
384
+static void test_sethwdebug_range_aligned(pid_t child_pid)
385
+{
386
+ struct ppc_hw_breakpoint info;
387
+ unsigned long wp_addr;
388
+ char *name = "PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW ALIGNED";
389
+ int len;
390
+ int wh;
391
+
392
+ /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW ALIGNED, WO test */
393
+ wp_addr = (unsigned long)&gstruct.a;
394
+ len = A_LEN;
395
+ get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_WRITE, wp_addr, len);
396
+ wh = ptrace_sethwdebug(child_pid, &info);
397
+ ptrace(PTRACE_CONT, child_pid, NULL, 0);
398
+ check_success(child_pid, name, "WO", wp_addr, len);
399
+ ptrace_delhwdebug(child_pid, wh);
400
+
401
+ /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW ALIGNED, RO test */
402
+ wp_addr = (unsigned long)&gstruct.a;
403
+ len = A_LEN;
404
+ get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_READ, wp_addr, len);
405
+ wh = ptrace_sethwdebug(child_pid, &info);
406
+ ptrace(PTRACE_CONT, child_pid, NULL, 0);
407
+ check_success(child_pid, name, "RO", wp_addr, len);
408
+ ptrace_delhwdebug(child_pid, wh);
409
+
410
+ /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW ALIGNED, RW test */
411
+ wp_addr = (unsigned long)&gstruct.a;
412
+ len = A_LEN;
413
+ get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_RW, wp_addr, len);
414
+ wh = ptrace_sethwdebug(child_pid, &info);
415
+ ptrace(PTRACE_CONT, child_pid, NULL, 0);
416
+ check_success(child_pid, name, "RW", wp_addr, len);
417
+ ptrace_delhwdebug(child_pid, wh);
418
+}
419
+
420
+static void test_sethwdebug_range_unaligned(pid_t child_pid)
421
+{
422
+ struct ppc_hw_breakpoint info;
423
+ unsigned long wp_addr;
424
+ char *name = "PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED";
425
+ int len;
426
+ int wh;
427
+
428
+ /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, WO test */
429
+ wp_addr = (unsigned long)&gstruct.b;
430
+ len = B_LEN;
431
+ get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_WRITE, wp_addr, len);
432
+ wh = ptrace_sethwdebug(child_pid, &info);
433
+ ptrace(PTRACE_CONT, child_pid, NULL, 0);
434
+ check_success(child_pid, name, "WO", wp_addr, len);
435
+ ptrace_delhwdebug(child_pid, wh);
436
+
437
+ /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, RO test */
438
+ wp_addr = (unsigned long)&gstruct.b;
439
+ len = B_LEN;
440
+ get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_READ, wp_addr, len);
441
+ wh = ptrace_sethwdebug(child_pid, &info);
442
+ ptrace(PTRACE_CONT, child_pid, NULL, 0);
443
+ check_success(child_pid, name, "RO", wp_addr, len);
444
+ ptrace_delhwdebug(child_pid, wh);
445
+
446
+ /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, RW test */
447
+ wp_addr = (unsigned long)&gstruct.b;
448
+ len = B_LEN;
449
+ get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_RW, wp_addr, len);
450
+ wh = ptrace_sethwdebug(child_pid, &info);
451
+ ptrace(PTRACE_CONT, child_pid, NULL, 0);
452
+ check_success(child_pid, name, "RW", wp_addr, len);
453
+ ptrace_delhwdebug(child_pid, wh);
454
+
455
+}
456
+
457
+static void test_sethwdebug_range_unaligned_dar(pid_t child_pid)
458
+{
459
+ struct ppc_hw_breakpoint info;
460
+ unsigned long wp_addr;
461
+ char *name = "PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, DAR OUTSIDE";
462
+ int len;
463
+ int wh;
464
+
465
+ /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, DAR OUTSIDE, RW test */
466
+ wp_addr = (unsigned long)&gstruct.b;
467
+ len = B_LEN;
468
+ get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_WRITE, wp_addr, len);
469
+ wh = ptrace_sethwdebug(child_pid, &info);
470
+ ptrace(PTRACE_CONT, child_pid, NULL, 0);
471
+ check_success(child_pid, name, "RW", wp_addr, len);
472
+ ptrace_delhwdebug(child_pid, wh);
473
+}
474
+
475
+static void test_sethwdebug_dawr_max_range(pid_t child_pid)
476
+{
477
+ struct ppc_hw_breakpoint info;
478
+ unsigned long wp_addr;
479
+ char *name = "PPC_PTRACE_SETHWDEBUG, DAWR_MAX_LEN";
480
+ int len;
481
+ int wh;
482
+
483
+ /* PPC_PTRACE_SETHWDEBUG, DAWR_MAX_LEN, RW test */
484
+ wp_addr = (unsigned long)big_var;
485
+ len = DAWR_MAX_LEN;
486
+ get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_RW, wp_addr, len);
487
+ wh = ptrace_sethwdebug(child_pid, &info);
488
+ ptrace(PTRACE_CONT, child_pid, NULL, 0);
489
+ check_success(child_pid, name, "RW", wp_addr, len);
490
+ ptrace_delhwdebug(child_pid, wh);
265491 }
266492
267493 /* Set the breakpoints and check the child successfully trigger them */
268
-static int launch_tests(bool dawr)
494
+static void
495
+run_tests(pid_t child_pid, struct ppc_debug_info *dbginfo, bool dawr)
269496 {
270
- char buf[1024];
271
- int len, i, status;
272
-
273
- struct ppc_debug_info dbginfo;
274
-
275
- i = ptrace(PPC_PTRACE_GETHWDBGINFO, child_pid, NULL, &dbginfo);
276
- if (i) {
277
- perror("Can't set breakpoint info\n");
278
- exit(-1);
497
+ test_set_debugreg(child_pid);
498
+ test_set_debugreg_kernel_userspace(child_pid);
499
+ test_sethwdebug_exact(child_pid);
500
+ test_sethwdebug_exact_kernel_userspace(child_pid);
501
+ if (dbginfo->features & PPC_DEBUG_FEATURE_DATA_BP_RANGE) {
502
+ test_sethwdebug_range_aligned(child_pid);
503
+ if (dawr || is_8xx) {
504
+ test_sethwdebug_range_unaligned(child_pid);
505
+ test_sethwdebug_range_unaligned_dar(child_pid);
506
+ test_sethwdebug_dawr_max_range(child_pid);
507
+ }
279508 }
280
- if (!(dbginfo.features & PPC_DEBUG_FEATURE_DATA_BP_RANGE))
281
- printf("WARNING: Kernel doesn't support PPC_PTRACE_SETHWDEBUG\n");
282
-
283
- /* Write watchpoint */
284
- for (len = 1; len <= sizeof(long); len <<= 1)
285
- launch_watchpoints(buf, BP_W, len, &dbginfo, dawr);
286
-
287
- /* Read-Write watchpoint */
288
- for (len = 1; len <= sizeof(long); len <<= 1)
289
- launch_watchpoints(buf, BP_RW, len, &dbginfo, dawr);
290
-
291
- ptrace(PTRACE_CONT, child_pid, NULL, 0);
292
-
293
- /*
294
- * Now we have unregistered the breakpoint, access by child
295
- * should not cause SIGTRAP.
296
- */
297
-
298
- wait(&status);
299
-
300
- if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) {
301
- printf("FAIL: Child process hit the breakpoint, which is not expected\n");
302
- ptrace(PTRACE_CONT, child_pid, NULL, 0);
303
- return TEST_FAIL;
304
- }
305
-
306
- if (WIFEXITED(status))
307
- printf("Child exited normally\n");
308
-
309
- return TEST_PASS;
310509 }
311510
312511 static int ptrace_hwbreak(void)
313512 {
314
- pid_t pid;
315
- int ret;
513
+ pid_t child_pid;
514
+ struct ppc_debug_info dbginfo;
316515 bool dawr;
317516
318
- pid = fork();
319
- if (!pid) {
320
- trigger_tests();
517
+ child_pid = fork();
518
+ if (!child_pid) {
519
+ test_workload();
321520 return 0;
322521 }
323522
324523 wait(NULL);
325524
326
- child_pid = pid;
525
+ get_dbginfo(child_pid, &dbginfo);
526
+ SKIP_IF(dbginfo.num_data_bps == 0);
327527
328
- get_dbginfo();
329
- SKIP_IF(!hwbreak_present());
330
- dawr = dawr_present();
528
+ dawr = dawr_present(&dbginfo);
529
+ run_tests(child_pid, &dbginfo, dawr);
331530
332
- ret = launch_tests(dawr);
333
-
531
+ /* Let the child exit first. */
532
+ ptrace(PTRACE_CONT, child_pid, NULL, 0);
334533 wait(NULL);
335534
336
- return ret;
535
+ /*
536
+ * Testcases exits immediately with -1 on any failure. If
537
+ * it has reached here, it means all tests were successful.
538
+ */
539
+ return TEST_PASS;
337540 }
338541
339542 int main(int argc, char **argv, char **envp)
340543 {
544
+ int pvr = 0;
545
+ asm __volatile__ ("mfspr %0,%1" : "=r"(pvr) : "i"(SPRN_PVR));
546
+ if (pvr == PVR_8xx)
547
+ is_8xx = true;
548
+
341549 return test_harness(ptrace_hwbreak, "ptrace-hwbreak");
342550 }