1*da650adaSThadeu Lima de Souza Cascardo // SPDX-License-Identifier: GPL-2.0+
2*da650adaSThadeu Lima de Souza Cascardo 
3*da650adaSThadeu Lima de Souza Cascardo /*
4*da650adaSThadeu Lima de Souza Cascardo  * Copyright 2018 IBM Corporation.
5*da650adaSThadeu Lima de Souza Cascardo  * Copyright 2020 Canonical Ltd.
6*da650adaSThadeu Lima de Souza Cascardo  */
7*da650adaSThadeu Lima de Souza Cascardo 
8*da650adaSThadeu Lima de Souza Cascardo #define __SANE_USERSPACE_TYPES__
9*da650adaSThadeu Lima de Souza Cascardo 
10*da650adaSThadeu Lima de Souza Cascardo #include <sys/types.h>
11*da650adaSThadeu Lima de Souza Cascardo #include <stdint.h>
12*da650adaSThadeu Lima de Souza Cascardo #include <malloc.h>
13*da650adaSThadeu Lima de Souza Cascardo #include <unistd.h>
14*da650adaSThadeu Lima de Souza Cascardo #include <signal.h>
15*da650adaSThadeu Lima de Souza Cascardo #include <stdlib.h>
16*da650adaSThadeu Lima de Souza Cascardo #include <string.h>
17*da650adaSThadeu Lima de Souza Cascardo #include <stdio.h>
18*da650adaSThadeu Lima de Souza Cascardo #include "utils.h"
19*da650adaSThadeu Lima de Souza Cascardo #include "flush_utils.h"
20*da650adaSThadeu Lima de Souza Cascardo 
21*da650adaSThadeu Lima de Souza Cascardo int uaccess_flush_test(void)
22*da650adaSThadeu Lima de Souza Cascardo {
23*da650adaSThadeu Lima de Souza Cascardo 	char *p;
24*da650adaSThadeu Lima de Souza Cascardo 	int repetitions = 10;
25*da650adaSThadeu Lima de Souza Cascardo 	int fd, passes = 0, iter, rc = 0;
26*da650adaSThadeu Lima de Souza Cascardo 	struct perf_event_read v;
27*da650adaSThadeu Lima de Souza Cascardo 	__u64 l1d_misses_total = 0;
28*da650adaSThadeu Lima de Souza Cascardo 	unsigned long iterations = 100000, zero_size = 24 * 1024;
29*da650adaSThadeu Lima de Souza Cascardo 	unsigned long l1d_misses_expected;
30*da650adaSThadeu Lima de Souza Cascardo 	int rfi_flush_orig;
31*da650adaSThadeu Lima de Souza Cascardo 	int entry_flush_orig;
32*da650adaSThadeu Lima de Souza Cascardo 	int uaccess_flush, uaccess_flush_orig;
33*da650adaSThadeu Lima de Souza Cascardo 
34*da650adaSThadeu Lima de Souza Cascardo 	SKIP_IF(geteuid() != 0);
35*da650adaSThadeu Lima de Souza Cascardo 
36*da650adaSThadeu Lima de Souza Cascardo 	// The PMU event we use only works on Power7 or later
37*da650adaSThadeu Lima de Souza Cascardo 	SKIP_IF(!have_hwcap(PPC_FEATURE_ARCH_2_06));
38*da650adaSThadeu Lima de Souza Cascardo 
39*da650adaSThadeu Lima de Souza Cascardo 	if (read_debugfs_file("powerpc/rfi_flush", &rfi_flush_orig) < 0) {
40*da650adaSThadeu Lima de Souza Cascardo 		perror("Unable to read powerpc/rfi_flush debugfs file");
41*da650adaSThadeu Lima de Souza Cascardo 		SKIP_IF(1);
42*da650adaSThadeu Lima de Souza Cascardo 	}
43*da650adaSThadeu Lima de Souza Cascardo 
44*da650adaSThadeu Lima de Souza Cascardo 	if (read_debugfs_file("powerpc/entry_flush", &entry_flush_orig) < 0) {
45*da650adaSThadeu Lima de Souza Cascardo 		perror("Unable to read powerpc/entry_flush debugfs file");
46*da650adaSThadeu Lima de Souza Cascardo 		SKIP_IF(1);
47*da650adaSThadeu Lima de Souza Cascardo 	}
48*da650adaSThadeu Lima de Souza Cascardo 
49*da650adaSThadeu Lima de Souza Cascardo 	if (read_debugfs_file("powerpc/uaccess_flush", &uaccess_flush_orig) < 0) {
50*da650adaSThadeu Lima de Souza Cascardo 		perror("Unable to read powerpc/entry_flush debugfs file");
51*da650adaSThadeu Lima de Souza Cascardo 		SKIP_IF(1);
52*da650adaSThadeu Lima de Souza Cascardo 	}
53*da650adaSThadeu Lima de Souza Cascardo 
54*da650adaSThadeu Lima de Souza Cascardo 	if (rfi_flush_orig != 0) {
55*da650adaSThadeu Lima de Souza Cascardo 		if (write_debugfs_file("powerpc/rfi_flush", 0) < 0) {
56*da650adaSThadeu Lima de Souza Cascardo 			perror("error writing to powerpc/rfi_flush debugfs file");
57*da650adaSThadeu Lima de Souza Cascardo 			FAIL_IF(1);
58*da650adaSThadeu Lima de Souza Cascardo 		}
59*da650adaSThadeu Lima de Souza Cascardo 	}
60*da650adaSThadeu Lima de Souza Cascardo 
61*da650adaSThadeu Lima de Souza Cascardo 	if (entry_flush_orig != 0) {
62*da650adaSThadeu Lima de Souza Cascardo 		if (write_debugfs_file("powerpc/entry_flush", 0) < 0) {
63*da650adaSThadeu Lima de Souza Cascardo 			perror("error writing to powerpc/entry_flush debugfs file");
64*da650adaSThadeu Lima de Souza Cascardo 			FAIL_IF(1);
65*da650adaSThadeu Lima de Souza Cascardo 		}
66*da650adaSThadeu Lima de Souza Cascardo 	}
67*da650adaSThadeu Lima de Souza Cascardo 
68*da650adaSThadeu Lima de Souza Cascardo 	uaccess_flush = uaccess_flush_orig;
69*da650adaSThadeu Lima de Souza Cascardo 
70*da650adaSThadeu Lima de Souza Cascardo 	fd = perf_event_open_counter(PERF_TYPE_HW_CACHE, PERF_L1D_READ_MISS_CONFIG, -1);
71*da650adaSThadeu Lima de Souza Cascardo 	FAIL_IF(fd < 0);
72*da650adaSThadeu Lima de Souza Cascardo 
73*da650adaSThadeu Lima de Souza Cascardo 	p = (char *)memalign(zero_size, CACHELINE_SIZE);
74*da650adaSThadeu Lima de Souza Cascardo 
75*da650adaSThadeu Lima de Souza Cascardo 	FAIL_IF(perf_event_enable(fd));
76*da650adaSThadeu Lima de Souza Cascardo 
77*da650adaSThadeu Lima de Souza Cascardo 	// disable L1 prefetching
78*da650adaSThadeu Lima de Souza Cascardo 	set_dscr(1);
79*da650adaSThadeu Lima de Souza Cascardo 
80*da650adaSThadeu Lima de Souza Cascardo 	iter = repetitions;
81*da650adaSThadeu Lima de Souza Cascardo 
82*da650adaSThadeu Lima de Souza Cascardo 	/*
83*da650adaSThadeu Lima de Souza Cascardo 	 * We expect to see l1d miss for each cacheline access when entry_flush
84*da650adaSThadeu Lima de Souza Cascardo 	 * is set. Allow a small variation on this.
85*da650adaSThadeu Lima de Souza Cascardo 	 */
86*da650adaSThadeu Lima de Souza Cascardo 	l1d_misses_expected = iterations * (zero_size / CACHELINE_SIZE - 2);
87*da650adaSThadeu Lima de Souza Cascardo 
88*da650adaSThadeu Lima de Souza Cascardo again:
89*da650adaSThadeu Lima de Souza Cascardo 	FAIL_IF(perf_event_reset(fd));
90*da650adaSThadeu Lima de Souza Cascardo 
91*da650adaSThadeu Lima de Souza Cascardo 	syscall_loop_uaccess(p, iterations, zero_size);
92*da650adaSThadeu Lima de Souza Cascardo 
93*da650adaSThadeu Lima de Souza Cascardo 	FAIL_IF(read(fd, &v, sizeof(v)) != sizeof(v));
94*da650adaSThadeu Lima de Souza Cascardo 
95*da650adaSThadeu Lima de Souza Cascardo 	if (uaccess_flush && v.l1d_misses >= l1d_misses_expected)
96*da650adaSThadeu Lima de Souza Cascardo 		passes++;
97*da650adaSThadeu Lima de Souza Cascardo 	else if (!uaccess_flush && v.l1d_misses < (l1d_misses_expected / 2))
98*da650adaSThadeu Lima de Souza Cascardo 		passes++;
99*da650adaSThadeu Lima de Souza Cascardo 
100*da650adaSThadeu Lima de Souza Cascardo 	l1d_misses_total += v.l1d_misses;
101*da650adaSThadeu Lima de Souza Cascardo 
102*da650adaSThadeu Lima de Souza Cascardo 	while (--iter)
103*da650adaSThadeu Lima de Souza Cascardo 		goto again;
104*da650adaSThadeu Lima de Souza Cascardo 
105*da650adaSThadeu Lima de Souza Cascardo 	if (passes < repetitions) {
106*da650adaSThadeu Lima de Souza Cascardo 		printf("FAIL (L1D misses with uaccess_flush=%d: %llu %c %lu) [%d/%d failures]\n",
107*da650adaSThadeu Lima de Souza Cascardo 		       uaccess_flush, l1d_misses_total, uaccess_flush ? '<' : '>',
108*da650adaSThadeu Lima de Souza Cascardo 		       uaccess_flush ? repetitions * l1d_misses_expected :
109*da650adaSThadeu Lima de Souza Cascardo 		       repetitions * l1d_misses_expected / 2,
110*da650adaSThadeu Lima de Souza Cascardo 		       repetitions - passes, repetitions);
111*da650adaSThadeu Lima de Souza Cascardo 		rc = 1;
112*da650adaSThadeu Lima de Souza Cascardo 	} else {
113*da650adaSThadeu Lima de Souza Cascardo 		printf("PASS (L1D misses with uaccess_flush=%d: %llu %c %lu) [%d/%d pass]\n",
114*da650adaSThadeu Lima de Souza Cascardo 		       uaccess_flush, l1d_misses_total, uaccess_flush ? '>' : '<',
115*da650adaSThadeu Lima de Souza Cascardo 		       uaccess_flush ? repetitions * l1d_misses_expected :
116*da650adaSThadeu Lima de Souza Cascardo 		       repetitions * l1d_misses_expected / 2,
117*da650adaSThadeu Lima de Souza Cascardo 		       passes, repetitions);
118*da650adaSThadeu Lima de Souza Cascardo 	}
119*da650adaSThadeu Lima de Souza Cascardo 
120*da650adaSThadeu Lima de Souza Cascardo 	if (uaccess_flush == uaccess_flush_orig) {
121*da650adaSThadeu Lima de Souza Cascardo 		uaccess_flush = !uaccess_flush_orig;
122*da650adaSThadeu Lima de Souza Cascardo 		if (write_debugfs_file("powerpc/uaccess_flush", uaccess_flush) < 0) {
123*da650adaSThadeu Lima de Souza Cascardo 			perror("error writing to powerpc/uaccess_flush debugfs file");
124*da650adaSThadeu Lima de Souza Cascardo 			return 1;
125*da650adaSThadeu Lima de Souza Cascardo 		}
126*da650adaSThadeu Lima de Souza Cascardo 		iter = repetitions;
127*da650adaSThadeu Lima de Souza Cascardo 		l1d_misses_total = 0;
128*da650adaSThadeu Lima de Souza Cascardo 		passes = 0;
129*da650adaSThadeu Lima de Souza Cascardo 		goto again;
130*da650adaSThadeu Lima de Souza Cascardo 	}
131*da650adaSThadeu Lima de Souza Cascardo 
132*da650adaSThadeu Lima de Souza Cascardo 	perf_event_disable(fd);
133*da650adaSThadeu Lima de Souza Cascardo 	close(fd);
134*da650adaSThadeu Lima de Souza Cascardo 
135*da650adaSThadeu Lima de Souza Cascardo 	set_dscr(0);
136*da650adaSThadeu Lima de Souza Cascardo 
137*da650adaSThadeu Lima de Souza Cascardo 	if (write_debugfs_file("powerpc/rfi_flush", rfi_flush_orig) < 0) {
138*da650adaSThadeu Lima de Souza Cascardo 		perror("unable to restore original value of powerpc/rfi_flush debugfs file");
139*da650adaSThadeu Lima de Souza Cascardo 		return 1;
140*da650adaSThadeu Lima de Souza Cascardo 	}
141*da650adaSThadeu Lima de Souza Cascardo 
142*da650adaSThadeu Lima de Souza Cascardo 	if (write_debugfs_file("powerpc/entry_flush", entry_flush_orig) < 0) {
143*da650adaSThadeu Lima de Souza Cascardo 		perror("unable to restore original value of powerpc/entry_flush debugfs file");
144*da650adaSThadeu Lima de Souza Cascardo 		return 1;
145*da650adaSThadeu Lima de Souza Cascardo 	}
146*da650adaSThadeu Lima de Souza Cascardo 
147*da650adaSThadeu Lima de Souza Cascardo 	if (write_debugfs_file("powerpc/uaccess_flush", uaccess_flush_orig) < 0) {
148*da650adaSThadeu Lima de Souza Cascardo 		perror("unable to restore original value of powerpc/uaccess_flush debugfs file");
149*da650adaSThadeu Lima de Souza Cascardo 		return 1;
150*da650adaSThadeu Lima de Souza Cascardo 	}
151*da650adaSThadeu Lima de Souza Cascardo 
152*da650adaSThadeu Lima de Souza Cascardo 	return rc;
153*da650adaSThadeu Lima de Souza Cascardo }
154*da650adaSThadeu Lima de Souza Cascardo 
155*da650adaSThadeu Lima de Souza Cascardo int main(int argc, char *argv[])
156*da650adaSThadeu Lima de Souza Cascardo {
157*da650adaSThadeu Lima de Souza Cascardo 	return test_harness(uaccess_flush_test, "uaccess_flush_test");
158*da650adaSThadeu Lima de Souza Cascardo }
159