// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * perf events self profiling example test case for hw breakpoints.
 *
 * This tests perf PERF_TYPE_BREAKPOINT parameters
 * 1) tests all variants of the break on read/write flags
 * 2) tests exclude_user == 0 and 1
 * 3) test array matches (if DAWR is supported))
 * 4) test different numbers of breakpoints matches
 *
 * Configure this breakpoint, then read and write the data a number of
 * times. Then check the output count from perf is as expected.
 *
 * Based on:
 *   http://ozlabs.org/~anton/junkcode/perf_events_example1.c
 *
 * Copyright (C) 2018 Michael Neuling, IBM Corporation.
 */

#include <unistd.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <elf.h>
#include <pthread.h>
#include <sys/syscall.h>
#include <linux/perf_event.h>
#include <linux/hw_breakpoint.h>
#include "utils.h"

#define MAX_LOOPS 10000

#define DAWR_LENGTH_MAX ((0x3f + 1) * 8)

static inline int sys_perf_event_open(struct perf_event_attr *attr, pid_t pid,
				      int cpu, int group_fd,
				      unsigned long flags)
{
	attr->size = sizeof(*attr);
	return syscall(__NR_perf_event_open, attr, pid, cpu, group_fd, flags);
}

static inline bool breakpoint_test(int len)
{
	struct perf_event_attr attr;
	int fd;

	/* setup counters */
	memset(&attr, 0, sizeof(attr));
	attr.disabled = 1;
	attr.type = PERF_TYPE_BREAKPOINT;
	attr.bp_type = HW_BREAKPOINT_R;
	/* bp_addr can point anywhere but needs to be aligned */
	attr.bp_addr = (__u64)(&attr) & 0xfffffffffffff800;
	attr.bp_len = len;
	fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
	if (fd < 0)
		return false;
	close(fd);
	return true;
}

static inline bool perf_breakpoint_supported(void)
{
	return breakpoint_test(4);
}

static inline bool dawr_supported(void)
{
	return breakpoint_test(DAWR_LENGTH_MAX);
}

static int runtestsingle(int readwriteflag, int exclude_user, int arraytest)
{
	int i,j;
	struct perf_event_attr attr;
	size_t res;
	unsigned long long breaks, needed;
	int readint;
	int readintarraybig[2*DAWR_LENGTH_MAX/sizeof(int)];
	int *readintalign;
	volatile int *ptr;
	int break_fd;
	int loop_num = MAX_LOOPS - (rand() % 100); /* provide some variability */
	volatile int *k;

	/* align to 0x400 boundary as required by DAWR */
	readintalign = (int *)(((unsigned long)readintarraybig + 0x7ff) &
			       0xfffffffffffff800);

	ptr = &readint;
	if (arraytest)
		ptr = &readintalign[0];

	/* setup counters */
	memset(&attr, 0, sizeof(attr));
	attr.disabled = 1;
	attr.type = PERF_TYPE_BREAKPOINT;
	attr.bp_type = readwriteflag;
	attr.bp_addr = (__u64)ptr;
	attr.bp_len = sizeof(int);
	if (arraytest)
		attr.bp_len = DAWR_LENGTH_MAX;
	attr.exclude_user = exclude_user;
	break_fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
	if (break_fd < 0) {
		perror("sys_perf_event_open");
		exit(1);
	}

	/* start counters */
	ioctl(break_fd, PERF_EVENT_IOC_ENABLE);

	/* Test a bunch of reads and writes */
	k = &readint;
	for (i = 0; i < loop_num; i++) {
		if (arraytest)
			k = &(readintalign[i % (DAWR_LENGTH_MAX/sizeof(int))]);

		j = *k;
		*k = j;
	}

	/* stop counters */
	ioctl(break_fd, PERF_EVENT_IOC_DISABLE);

	/* read and check counters */
	res = read(break_fd, &breaks, sizeof(unsigned long long));
	assert(res == sizeof(unsigned long long));
	/* we read and write each loop, so subtract the ones we are counting */
	needed = 0;
	if (readwriteflag & HW_BREAKPOINT_R)
		needed += loop_num;
	if (readwriteflag & HW_BREAKPOINT_W)
		needed += loop_num;
	needed = needed * (1 - exclude_user);
	printf("TESTED: addr:0x%lx brks:% 8lld loops:% 8i rw:%i !user:%i array:%i\n",
	       (unsigned long int)ptr, breaks, loop_num, readwriteflag, exclude_user, arraytest);
	if (breaks != needed) {
		printf("FAILED: 0x%lx brks:%lld needed:%lli %i %i %i\n\n",
		       (unsigned long int)ptr, breaks, needed, loop_num, readwriteflag, exclude_user);
		return 1;
	}
	close(break_fd);

	return 0;
}

static int runtest_dar_outside(void)
{
	void *target;
	volatile __u16 temp16;
	volatile __u64 temp64;
	struct perf_event_attr attr;
	int break_fd;
	unsigned long long breaks;
	int fail = 0;
	size_t res;

	target = malloc(8);
	if (!target) {
		perror("malloc failed");
		exit(EXIT_FAILURE);
	}

	/* setup counters */
	memset(&attr, 0, sizeof(attr));
	attr.disabled = 1;
	attr.type = PERF_TYPE_BREAKPOINT;
	attr.exclude_kernel = 1;
	attr.exclude_hv = 1;
	attr.exclude_guest = 1;
	attr.bp_type = HW_BREAKPOINT_RW;
	/* watch middle half of target array */
	attr.bp_addr = (__u64)(target + 2);
	attr.bp_len = 4;
	break_fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
	if (break_fd < 0) {
		free(target);
		perror("sys_perf_event_open");
		exit(EXIT_FAILURE);
	}

	/* Shouldn't hit. */
	ioctl(break_fd, PERF_EVENT_IOC_RESET);
	ioctl(break_fd, PERF_EVENT_IOC_ENABLE);
	temp16 = *((__u16 *)target);
	*((__u16 *)target) = temp16;
	ioctl(break_fd, PERF_EVENT_IOC_DISABLE);
	res = read(break_fd, &breaks, sizeof(unsigned long long));
	assert(res == sizeof(unsigned long long));
	if (breaks == 0) {
		printf("TESTED: No overlap\n");
	} else {
		printf("FAILED: No overlap: %lld != 0\n", breaks);
		fail = 1;
	}

	/* Hit */
	ioctl(break_fd, PERF_EVENT_IOC_RESET);
	ioctl(break_fd, PERF_EVENT_IOC_ENABLE);
	temp16 = *((__u16 *)(target + 1));
	*((__u16 *)(target + 1)) = temp16;
	ioctl(break_fd, PERF_EVENT_IOC_DISABLE);
	res = read(break_fd, &breaks, sizeof(unsigned long long));
	assert(res == sizeof(unsigned long long));
	if (breaks == 2) {
		printf("TESTED: Partial overlap\n");
	} else {
		printf("FAILED: Partial overlap: %lld != 2\n", breaks);
		fail = 1;
	}

	/* Hit */
	ioctl(break_fd, PERF_EVENT_IOC_RESET);
	ioctl(break_fd, PERF_EVENT_IOC_ENABLE);
	temp16 = *((__u16 *)(target + 5));
	*((__u16 *)(target + 5)) = temp16;
	ioctl(break_fd, PERF_EVENT_IOC_DISABLE);
	res = read(break_fd, &breaks, sizeof(unsigned long long));
	assert(res == sizeof(unsigned long long));
	if (breaks == 2) {
		printf("TESTED: Partial overlap\n");
	} else {
		printf("FAILED: Partial overlap: %lld != 2\n", breaks);
		fail = 1;
	}

	/* Shouldn't Hit */
	ioctl(break_fd, PERF_EVENT_IOC_RESET);
	ioctl(break_fd, PERF_EVENT_IOC_ENABLE);
	temp16 = *((__u16 *)(target + 6));
	*((__u16 *)(target + 6)) = temp16;
	ioctl(break_fd, PERF_EVENT_IOC_DISABLE);
	res = read(break_fd, &breaks, sizeof(unsigned long long));
	assert(res == sizeof(unsigned long long));
	if (breaks == 0) {
		printf("TESTED: No overlap\n");
	} else {
		printf("FAILED: No overlap: %lld != 0\n", breaks);
		fail = 1;
	}

	/* Hit */
	ioctl(break_fd, PERF_EVENT_IOC_RESET);
	ioctl(break_fd, PERF_EVENT_IOC_ENABLE);
	temp64 = *((__u64 *)target);
	*((__u64 *)target) = temp64;
	ioctl(break_fd, PERF_EVENT_IOC_DISABLE);
	res = read(break_fd, &breaks, sizeof(unsigned long long));
	assert(res == sizeof(unsigned long long));
	if (breaks == 2) {
		printf("TESTED: Full overlap\n");
	} else {
		printf("FAILED: Full overlap: %lld != 2\n", breaks);
		fail = 1;
	}

	free(target);
	close(break_fd);
	return fail;
}

static int runtest(void)
{
	int rwflag;
	int exclude_user;
	int ret;

	/*
	 * perf defines rwflag as two bits read and write and at least
	 * one must be set.  So range 1-3.
	 */
	for (rwflag = 1 ; rwflag < 4; rwflag++) {
		for (exclude_user = 0 ; exclude_user < 2; exclude_user++) {
			ret = runtestsingle(rwflag, exclude_user, 0);
			if (ret)
				return ret;

			/* if we have the dawr, we can do an array test */
			if (!dawr_supported())
				continue;
			ret = runtestsingle(rwflag, exclude_user, 1);
			if (ret)
				return ret;
		}
	}

	ret = runtest_dar_outside();
	return ret;
}


static int perf_hwbreak(void)
{
	srand ( time(NULL) );

	SKIP_IF(!perf_breakpoint_supported());

	return runtest();
}

int main(int argc, char *argv[], char **envp)
{
	return test_harness(perf_hwbreak, "perf_hwbreak");
}
