selftests/powerpc/ptrace: Declare test temporary variables as volatile
[platform/kernel/linux-starfive.git] / tools / testing / selftests / powerpc / ptrace / ptrace-hwbreak.c
1 // SPDX-License-Identifier: GPL-2.0+
2
3 /*
4  * Ptrace test for hw breakpoints
5  *
6  * Based on tools/testing/selftests/breakpoints/breakpoint_test.c
7  *
8  * This test forks and the parent then traces the child doing various
9  * types of ptrace enabled breakpoints
10  *
11  * Copyright (C) 2018 Michael Neuling, IBM Corporation.
12  */
13
14 #include <sys/ptrace.h>
15 #include <unistd.h>
16 #include <stddef.h>
17 #include <sys/user.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <signal.h>
21 #include <sys/types.h>
22 #include <sys/wait.h>
23 #include <sys/syscall.h>
24 #include <linux/limits.h>
25 #include "ptrace.h"
26 #include "reg.h"
27
28 #define SPRN_PVR        0x11F
29 #define PVR_8xx         0x00500000
30
31 bool is_8xx;
32
33 /*
34  * Use volatile on all global var so that compiler doesn't
35  * optimise their load/stores. Otherwise selftest can fail.
36  */
37 static volatile __u64 glvar;
38
39 #define DAWR_MAX_LEN 512
40 static volatile __u8 big_var[DAWR_MAX_LEN] __attribute__((aligned(512)));
41
42 #define A_LEN 6
43 #define B_LEN 6
44 struct gstruct {
45         __u8 a[A_LEN]; /* double word aligned */
46         __u8 b[B_LEN]; /* double word unaligned */
47 };
48 static volatile struct gstruct gstruct __attribute__((aligned(512)));
49
50 static volatile char cwd[PATH_MAX] __attribute__((aligned(8)));
51
52 static void get_dbginfo(pid_t child_pid, struct ppc_debug_info *dbginfo)
53 {
54         if (ptrace(PPC_PTRACE_GETHWDBGINFO, child_pid, NULL, dbginfo)) {
55                 perror("Can't get breakpoint info");
56                 exit(-1);
57         }
58 }
59
60 static bool dawr_present(struct ppc_debug_info *dbginfo)
61 {
62         return !!(dbginfo->features & PPC_DEBUG_FEATURE_DATA_BP_DAWR);
63 }
64
65 static void write_var(int len)
66 {
67         volatile __u8 *pcvar;
68         volatile __u16 *psvar;
69         volatile __u32 *pivar;
70         volatile __u64 *plvar;
71
72         switch (len) {
73         case 1:
74                 pcvar = (volatile __u8 *)&glvar;
75                 *pcvar = 0xff;
76                 break;
77         case 2:
78                 psvar = (volatile __u16 *)&glvar;
79                 *psvar = 0xffff;
80                 break;
81         case 4:
82                 pivar = (volatile __u32 *)&glvar;
83                 *pivar = 0xffffffff;
84                 break;
85         case 8:
86                 plvar = (volatile __u64 *)&glvar;
87                 *plvar = 0xffffffffffffffffLL;
88                 break;
89         }
90 }
91
92 static void read_var(int len)
93 {
94         __u8 cvar __attribute__((unused));
95         __u16 svar __attribute__((unused));
96         __u32 ivar __attribute__((unused));
97         __u64 lvar __attribute__((unused));
98
99         switch (len) {
100         case 1:
101                 cvar = (volatile __u8)glvar;
102                 break;
103         case 2:
104                 svar = (volatile __u16)glvar;
105                 break;
106         case 4:
107                 ivar = (volatile __u32)glvar;
108                 break;
109         case 8:
110                 lvar = (volatile __u64)glvar;
111                 break;
112         }
113 }
114
115 static void test_workload(void)
116 {
117         __u8 cvar __attribute__((unused));
118         __u32 ivar __attribute__((unused));
119         int len = 0;
120
121         if (ptrace(PTRACE_TRACEME, 0, NULL, 0)) {
122                 perror("Child can't be traced?");
123                 exit(-1);
124         }
125
126         /* Wake up father so that it sets up the first test */
127         kill(getpid(), SIGUSR1);
128
129         /* PTRACE_SET_DEBUGREG, WO test */
130         for (len = 1; len <= sizeof(glvar); len <<= 1)
131                 write_var(len);
132
133         /* PTRACE_SET_DEBUGREG, RO test */
134         for (len = 1; len <= sizeof(glvar); len <<= 1)
135                 read_var(len);
136
137         /* PTRACE_SET_DEBUGREG, RW test */
138         for (len = 1; len <= sizeof(glvar); len <<= 1) {
139                 if (rand() % 2)
140                         read_var(len);
141                 else
142                         write_var(len);
143         }
144
145         /* PTRACE_SET_DEBUGREG, Kernel Access Userspace test */
146         syscall(__NR_getcwd, &cwd, PATH_MAX);
147
148         /* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, WO test */
149         write_var(1);
150
151         /* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, RO test */
152         read_var(1);
153
154         /* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, RW test */
155         if (rand() % 2)
156                 write_var(1);
157         else
158                 read_var(1);
159
160         /* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, Kernel Access Userspace test */
161         syscall(__NR_getcwd, &cwd, PATH_MAX);
162
163         /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW ALIGNED, WO test */
164         gstruct.a[rand() % A_LEN] = 'a';
165
166         /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW ALIGNED, RO test */
167         cvar = gstruct.a[rand() % A_LEN];
168
169         /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW ALIGNED, RW test */
170         if (rand() % 2)
171                 gstruct.a[rand() % A_LEN] = 'a';
172         else
173                 cvar = gstruct.a[rand() % A_LEN];
174
175         /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, WO test */
176         gstruct.b[rand() % B_LEN] = 'b';
177
178         /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, RO test */
179         cvar = gstruct.b[rand() % B_LEN];
180
181         /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, RW test */
182         if (rand() % 2)
183                 gstruct.b[rand() % B_LEN] = 'b';
184         else
185                 cvar = gstruct.b[rand() % B_LEN];
186
187         /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, DAR OUTSIDE, RW test */
188         if (rand() % 2)
189                 *((int *)(gstruct.a + 4)) = 10;
190         else
191                 ivar = *((int *)(gstruct.a + 4));
192
193         /* PPC_PTRACE_SETHWDEBUG. DAWR_MAX_LEN. RW test */
194         if (rand() % 2)
195                 big_var[rand() % DAWR_MAX_LEN] = 'a';
196         else
197                 cvar = big_var[rand() % DAWR_MAX_LEN];
198
199         /* PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DW ALIGNED, WO test */
200         gstruct.a[rand() % A_LEN] = 'a';
201
202         /* PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DW UNALIGNED, RO test */
203         cvar = gstruct.b[rand() % B_LEN];
204
205         /* PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DAWR Overlap, WO test */
206         gstruct.a[rand() % A_LEN] = 'a';
207
208         /* PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DAWR Overlap, RO test */
209         cvar = gstruct.a[rand() % A_LEN];
210 }
211
212 static void check_success(pid_t child_pid, const char *name, const char *type,
213                           unsigned long saddr, int len)
214 {
215         int status;
216         siginfo_t siginfo;
217         unsigned long eaddr = (saddr + len - 1) | 0x7;
218
219         saddr &= ~0x7;
220
221         /* Wait for the child to SIGTRAP */
222         wait(&status);
223
224         ptrace(PTRACE_GETSIGINFO, child_pid, NULL, &siginfo);
225
226         if (!WIFSTOPPED(status) || WSTOPSIG(status) != SIGTRAP ||
227             (unsigned long)siginfo.si_addr < saddr ||
228             (unsigned long)siginfo.si_addr > eaddr) {
229                 printf("%s, %s, len: %d: Fail\n", name, type, len);
230                 exit(-1);
231         }
232
233         printf("%s, %s, len: %d: Ok\n", name, type, len);
234
235         if (!is_8xx) {
236                 /*
237                  * For ptrace registered watchpoint, signal is generated
238                  * before executing load/store. Singlestep the instruction
239                  * and then continue the test.
240                  */
241                 ptrace(PTRACE_SINGLESTEP, child_pid, NULL, 0);
242                 wait(NULL);
243         }
244 }
245
246 static void ptrace_set_debugreg(pid_t child_pid, unsigned long wp_addr)
247 {
248         if (ptrace(PTRACE_SET_DEBUGREG, child_pid, 0, wp_addr)) {
249                 perror("PTRACE_SET_DEBUGREG failed");
250                 exit(-1);
251         }
252 }
253
254 static int ptrace_sethwdebug(pid_t child_pid, struct ppc_hw_breakpoint *info)
255 {
256         int wh = ptrace(PPC_PTRACE_SETHWDEBUG, child_pid, 0, info);
257
258         if (wh <= 0) {
259                 perror("PPC_PTRACE_SETHWDEBUG failed");
260                 exit(-1);
261         }
262         return wh;
263 }
264
265 static void ptrace_delhwdebug(pid_t child_pid, int wh)
266 {
267         if (ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, wh) < 0) {
268                 perror("PPC_PTRACE_DELHWDEBUG failed");
269                 exit(-1);
270         }
271 }
272
273 #define DABR_READ_SHIFT         0
274 #define DABR_WRITE_SHIFT        1
275 #define DABR_TRANSLATION_SHIFT  2
276
277 static int test_set_debugreg(pid_t child_pid)
278 {
279         unsigned long wp_addr = (unsigned long)&glvar;
280         char *name = "PTRACE_SET_DEBUGREG";
281         int len;
282
283         /* PTRACE_SET_DEBUGREG, WO test*/
284         wp_addr &= ~0x7UL;
285         wp_addr |= (1UL << DABR_WRITE_SHIFT);
286         wp_addr |= (1UL << DABR_TRANSLATION_SHIFT);
287         for (len = 1; len <= sizeof(glvar); len <<= 1) {
288                 ptrace_set_debugreg(child_pid, wp_addr);
289                 ptrace(PTRACE_CONT, child_pid, NULL, 0);
290                 check_success(child_pid, name, "WO", wp_addr, len);
291         }
292
293         /* PTRACE_SET_DEBUGREG, RO test */
294         wp_addr &= ~0x7UL;
295         wp_addr |= (1UL << DABR_READ_SHIFT);
296         wp_addr |= (1UL << DABR_TRANSLATION_SHIFT);
297         for (len = 1; len <= sizeof(glvar); len <<= 1) {
298                 ptrace_set_debugreg(child_pid, wp_addr);
299                 ptrace(PTRACE_CONT, child_pid, NULL, 0);
300                 check_success(child_pid, name, "RO", wp_addr, len);
301         }
302
303         /* PTRACE_SET_DEBUGREG, RW test */
304         wp_addr &= ~0x7UL;
305         wp_addr |= (1Ul << DABR_READ_SHIFT);
306         wp_addr |= (1UL << DABR_WRITE_SHIFT);
307         wp_addr |= (1UL << DABR_TRANSLATION_SHIFT);
308         for (len = 1; len <= sizeof(glvar); len <<= 1) {
309                 ptrace_set_debugreg(child_pid, wp_addr);
310                 ptrace(PTRACE_CONT, child_pid, NULL, 0);
311                 check_success(child_pid, name, "RW", wp_addr, len);
312         }
313
314         ptrace_set_debugreg(child_pid, 0);
315         return 0;
316 }
317
318 static int test_set_debugreg_kernel_userspace(pid_t child_pid)
319 {
320         unsigned long wp_addr = (unsigned long)cwd;
321         char *name = "PTRACE_SET_DEBUGREG";
322
323         /* PTRACE_SET_DEBUGREG, Kernel Access Userspace test */
324         wp_addr &= ~0x7UL;
325         wp_addr |= (1Ul << DABR_READ_SHIFT);
326         wp_addr |= (1UL << DABR_WRITE_SHIFT);
327         wp_addr |= (1UL << DABR_TRANSLATION_SHIFT);
328         ptrace_set_debugreg(child_pid, wp_addr);
329         ptrace(PTRACE_CONT, child_pid, NULL, 0);
330         check_success(child_pid, name, "Kernel Access Userspace", wp_addr, 8);
331
332         ptrace_set_debugreg(child_pid, 0);
333         return 0;
334 }
335
336 static void get_ppc_hw_breakpoint(struct ppc_hw_breakpoint *info, int type,
337                                   unsigned long addr, int len)
338 {
339         info->version = 1;
340         info->trigger_type = type;
341         info->condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
342         info->addr = (__u64)addr;
343         info->addr2 = (__u64)addr + len;
344         info->condition_value = 0;
345         if (!len)
346                 info->addr_mode = PPC_BREAKPOINT_MODE_EXACT;
347         else
348                 info->addr_mode = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE;
349 }
350
351 static void test_sethwdebug_exact(pid_t child_pid)
352 {
353         struct ppc_hw_breakpoint info;
354         unsigned long wp_addr = (unsigned long)&glvar;
355         char *name = "PPC_PTRACE_SETHWDEBUG, MODE_EXACT";
356         int len = 1; /* hardcoded in kernel */
357         int wh;
358
359         /* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, WO test */
360         get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_WRITE, wp_addr, 0);
361         wh = ptrace_sethwdebug(child_pid, &info);
362         ptrace(PTRACE_CONT, child_pid, NULL, 0);
363         check_success(child_pid, name, "WO", wp_addr, len);
364         ptrace_delhwdebug(child_pid, wh);
365
366         /* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, RO test */
367         get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_READ, wp_addr, 0);
368         wh = ptrace_sethwdebug(child_pid, &info);
369         ptrace(PTRACE_CONT, child_pid, NULL, 0);
370         check_success(child_pid, name, "RO", wp_addr, len);
371         ptrace_delhwdebug(child_pid, wh);
372
373         /* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, RW test */
374         get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_RW, wp_addr, 0);
375         wh = ptrace_sethwdebug(child_pid, &info);
376         ptrace(PTRACE_CONT, child_pid, NULL, 0);
377         check_success(child_pid, name, "RW", wp_addr, len);
378         ptrace_delhwdebug(child_pid, wh);
379 }
380
381 static void test_sethwdebug_exact_kernel_userspace(pid_t child_pid)
382 {
383         struct ppc_hw_breakpoint info;
384         unsigned long wp_addr = (unsigned long)&cwd;
385         char *name = "PPC_PTRACE_SETHWDEBUG, MODE_EXACT";
386         int len = 1; /* hardcoded in kernel */
387         int wh;
388
389         /* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, Kernel Access Userspace test */
390         get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_WRITE, wp_addr, 0);
391         wh = ptrace_sethwdebug(child_pid, &info);
392         ptrace(PTRACE_CONT, child_pid, NULL, 0);
393         check_success(child_pid, name, "Kernel Access Userspace", wp_addr, len);
394         ptrace_delhwdebug(child_pid, wh);
395 }
396
397 static void test_sethwdebug_range_aligned(pid_t child_pid)
398 {
399         struct ppc_hw_breakpoint info;
400         unsigned long wp_addr;
401         char *name = "PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW ALIGNED";
402         int len;
403         int wh;
404
405         /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW ALIGNED, WO test */
406         wp_addr = (unsigned long)&gstruct.a;
407         len = A_LEN;
408         get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_WRITE, wp_addr, len);
409         wh = ptrace_sethwdebug(child_pid, &info);
410         ptrace(PTRACE_CONT, child_pid, NULL, 0);
411         check_success(child_pid, name, "WO", wp_addr, len);
412         ptrace_delhwdebug(child_pid, wh);
413
414         /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW ALIGNED, RO test */
415         wp_addr = (unsigned long)&gstruct.a;
416         len = A_LEN;
417         get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_READ, wp_addr, len);
418         wh = ptrace_sethwdebug(child_pid, &info);
419         ptrace(PTRACE_CONT, child_pid, NULL, 0);
420         check_success(child_pid, name, "RO", wp_addr, len);
421         ptrace_delhwdebug(child_pid, wh);
422
423         /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW ALIGNED, RW test */
424         wp_addr = (unsigned long)&gstruct.a;
425         len = A_LEN;
426         get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_RW, wp_addr, len);
427         wh = ptrace_sethwdebug(child_pid, &info);
428         ptrace(PTRACE_CONT, child_pid, NULL, 0);
429         check_success(child_pid, name, "RW", wp_addr, len);
430         ptrace_delhwdebug(child_pid, wh);
431 }
432
433 static void test_multi_sethwdebug_range(pid_t child_pid)
434 {
435         struct ppc_hw_breakpoint info1, info2;
436         unsigned long wp_addr1, wp_addr2;
437         char *name1 = "PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DW ALIGNED";
438         char *name2 = "PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DW UNALIGNED";
439         int len1, len2;
440         int wh1, wh2;
441
442         wp_addr1 = (unsigned long)&gstruct.a;
443         wp_addr2 = (unsigned long)&gstruct.b;
444         len1 = A_LEN;
445         len2 = B_LEN;
446         get_ppc_hw_breakpoint(&info1, PPC_BREAKPOINT_TRIGGER_WRITE, wp_addr1, len1);
447         get_ppc_hw_breakpoint(&info2, PPC_BREAKPOINT_TRIGGER_READ, wp_addr2, len2);
448
449         /* PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DW ALIGNED, WO test */
450         wh1 = ptrace_sethwdebug(child_pid, &info1);
451
452         /* PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DW UNALIGNED, RO test */
453         wh2 = ptrace_sethwdebug(child_pid, &info2);
454
455         ptrace(PTRACE_CONT, child_pid, NULL, 0);
456         check_success(child_pid, name1, "WO", wp_addr1, len1);
457
458         ptrace(PTRACE_CONT, child_pid, NULL, 0);
459         check_success(child_pid, name2, "RO", wp_addr2, len2);
460
461         ptrace_delhwdebug(child_pid, wh1);
462         ptrace_delhwdebug(child_pid, wh2);
463 }
464
465 static void test_multi_sethwdebug_range_dawr_overlap(pid_t child_pid)
466 {
467         struct ppc_hw_breakpoint info1, info2;
468         unsigned long wp_addr1, wp_addr2;
469         char *name = "PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DAWR Overlap";
470         int len1, len2;
471         int wh1, wh2;
472
473         wp_addr1 = (unsigned long)&gstruct.a;
474         wp_addr2 = (unsigned long)&gstruct.a;
475         len1 = A_LEN;
476         len2 = A_LEN;
477         get_ppc_hw_breakpoint(&info1, PPC_BREAKPOINT_TRIGGER_WRITE, wp_addr1, len1);
478         get_ppc_hw_breakpoint(&info2, PPC_BREAKPOINT_TRIGGER_READ, wp_addr2, len2);
479
480         /* PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DAWR Overlap, WO test */
481         wh1 = ptrace_sethwdebug(child_pid, &info1);
482
483         /* PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DAWR Overlap, RO test */
484         wh2 = ptrace_sethwdebug(child_pid, &info2);
485
486         ptrace(PTRACE_CONT, child_pid, NULL, 0);
487         check_success(child_pid, name, "WO", wp_addr1, len1);
488
489         ptrace(PTRACE_CONT, child_pid, NULL, 0);
490         check_success(child_pid, name, "RO", wp_addr2, len2);
491
492         ptrace_delhwdebug(child_pid, wh1);
493         ptrace_delhwdebug(child_pid, wh2);
494 }
495
496 static void test_sethwdebug_range_unaligned(pid_t child_pid)
497 {
498         struct ppc_hw_breakpoint info;
499         unsigned long wp_addr;
500         char *name = "PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED";
501         int len;
502         int wh;
503
504         /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, WO test */
505         wp_addr = (unsigned long)&gstruct.b;
506         len = B_LEN;
507         get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_WRITE, wp_addr, len);
508         wh = ptrace_sethwdebug(child_pid, &info);
509         ptrace(PTRACE_CONT, child_pid, NULL, 0);
510         check_success(child_pid, name, "WO", wp_addr, len);
511         ptrace_delhwdebug(child_pid, wh);
512
513         /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, RO test */
514         wp_addr = (unsigned long)&gstruct.b;
515         len = B_LEN;
516         get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_READ, wp_addr, len);
517         wh = ptrace_sethwdebug(child_pid, &info);
518         ptrace(PTRACE_CONT, child_pid, NULL, 0);
519         check_success(child_pid, name, "RO", wp_addr, len);
520         ptrace_delhwdebug(child_pid, wh);
521
522         /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, RW test */
523         wp_addr = (unsigned long)&gstruct.b;
524         len = B_LEN;
525         get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_RW, wp_addr, len);
526         wh = ptrace_sethwdebug(child_pid, &info);
527         ptrace(PTRACE_CONT, child_pid, NULL, 0);
528         check_success(child_pid, name, "RW", wp_addr, len);
529         ptrace_delhwdebug(child_pid, wh);
530
531 }
532
533 static void test_sethwdebug_range_unaligned_dar(pid_t child_pid)
534 {
535         struct ppc_hw_breakpoint info;
536         unsigned long wp_addr;
537         char *name = "PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, DAR OUTSIDE";
538         int len;
539         int wh;
540
541         /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, DAR OUTSIDE, RW test */
542         wp_addr = (unsigned long)&gstruct.b;
543         len = B_LEN;
544         get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_WRITE, wp_addr, len);
545         wh = ptrace_sethwdebug(child_pid, &info);
546         ptrace(PTRACE_CONT, child_pid, NULL, 0);
547         check_success(child_pid, name, "RW", wp_addr, len);
548         ptrace_delhwdebug(child_pid, wh);
549 }
550
551 static void test_sethwdebug_dawr_max_range(pid_t child_pid)
552 {
553         struct ppc_hw_breakpoint info;
554         unsigned long wp_addr;
555         char *name = "PPC_PTRACE_SETHWDEBUG, DAWR_MAX_LEN";
556         int len;
557         int wh;
558
559         /* PPC_PTRACE_SETHWDEBUG, DAWR_MAX_LEN, RW test */
560         wp_addr = (unsigned long)big_var;
561         len = DAWR_MAX_LEN;
562         get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_RW, wp_addr, len);
563         wh = ptrace_sethwdebug(child_pid, &info);
564         ptrace(PTRACE_CONT, child_pid, NULL, 0);
565         check_success(child_pid, name, "RW", wp_addr, len);
566         ptrace_delhwdebug(child_pid, wh);
567 }
568
569 /* Set the breakpoints and check the child successfully trigger them */
570 static void
571 run_tests(pid_t child_pid, struct ppc_debug_info *dbginfo, bool dawr)
572 {
573         test_set_debugreg(child_pid);
574         test_set_debugreg_kernel_userspace(child_pid);
575         test_sethwdebug_exact(child_pid);
576         test_sethwdebug_exact_kernel_userspace(child_pid);
577         if (dbginfo->features & PPC_DEBUG_FEATURE_DATA_BP_RANGE) {
578                 test_sethwdebug_range_aligned(child_pid);
579                 if (dawr || is_8xx) {
580                         test_sethwdebug_range_unaligned(child_pid);
581                         test_sethwdebug_range_unaligned_dar(child_pid);
582                         test_sethwdebug_dawr_max_range(child_pid);
583                         if (dbginfo->num_data_bps > 1) {
584                                 test_multi_sethwdebug_range(child_pid);
585                                 test_multi_sethwdebug_range_dawr_overlap(child_pid);
586                         }
587                 }
588         }
589 }
590
591 static int ptrace_hwbreak(void)
592 {
593         pid_t child_pid;
594         struct ppc_debug_info dbginfo;
595         bool dawr;
596
597         child_pid = fork();
598         if (!child_pid) {
599                 test_workload();
600                 return 0;
601         }
602
603         wait(NULL);
604
605         get_dbginfo(child_pid, &dbginfo);
606         SKIP_IF_MSG(dbginfo.num_data_bps == 0, "No data breakpoints present");
607
608         dawr = dawr_present(&dbginfo);
609         run_tests(child_pid, &dbginfo, dawr);
610
611         /* Let the child exit first. */
612         ptrace(PTRACE_CONT, child_pid, NULL, 0);
613         wait(NULL);
614
615         /*
616          * Testcases exits immediately with -1 on any failure. If
617          * it has reached here, it means all tests were successful.
618          */
619         return TEST_PASS;
620 }
621
622 int main(int argc, char **argv, char **envp)
623 {
624         is_8xx = mfspr(SPRN_PVR) == PVR_8xx;
625
626         return test_harness(ptrace_hwbreak, "ptrace-hwbreak");
627 }