cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ptrace-hwbreak.c (17598B)


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