1 /*
2 * Copyright (C) 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define TLOG_TAG "pacbench"
18
19 #include <arch/ops.h>
20 #include <inttypes.h>
21 #include <stdint.h>
22 #include <trusty_benchmark.h>
23 #include <uapi/err.h>
24
25 /* Runs over which to collect statistics */
26 #define RUNS 100u
27
28 /* Benchmark run duration */
29 #define LOOPS 1000000u
30 #define INSTRUCTIONS_PER_LOOP 16u
31
32 /* Extended loop count for faster functions */
33 #define EXTRA_LOOPS 10000000u
34
35 #define PACKBENCH_STR_REP2(s) s s
36 #define PACKBENCH_STR_REP4(s) PACKBENCH_STR_REP2(s) PACKBENCH_STR_REP2(s)
37 #define PACKBENCH_STR_REP8(s) PACKBENCH_STR_REP4(s) PACKBENCH_STR_REP4(s)
38 #define PACKBENCH_STR_REP16(s) PACKBENCH_STR_REP8(s) PACKBENCH_STR_REP8(s)
39
BENCH_SETUP(pac)40 BENCH_SETUP(pac) {
41 return NO_ERROR;
42 }
43
BENCH_TEARDOWN(pac)44 BENCH_TEARDOWN(pac) {}
45
46 #ifdef KERNEL_PAC_ENABLED
47 /*
48 * Test PACIA instruction.
49 * If PAC is supported and enabled in the kernel, this key should be valid and
50 * the instruction functional, though this benchmark does not test the
51 * instruction - see pactest instead.
52 */
BENCH_ALL_CPU(pac,pacia,RUNS)53 BENCH_ALL_CPU(pac, pacia, RUNS) {
54 uint64_t val = 0;
55
56 for (uint64_t i = 0; i < LOOPS; i++) {
57 __asm__ volatile(".arch_extension pauth\n\t" PACKBENCH_STR_REP16(
58 "PACIA %0, %1\n\t")
59 : "+r"(val)
60 : "r"(i));
61 }
62
63 return NO_ERROR;
64 }
65
BENCH_RESULT(pac,pacia,ps_per_pacia)66 BENCH_RESULT(pac, pacia, ps_per_pacia) {
67 return (bench_get_duration_ns() * 1000u) / (LOOPS * INSTRUCTIONS_PER_LOOP);
68 }
69
BENCH_RESULT(pac,pacia,us_total)70 BENCH_RESULT(pac, pacia, us_total) {
71 return bench_get_duration_ns() / 1000u;
72 }
73
BENCH_RESULT(pac,pacia,instructions)74 BENCH_RESULT(pac, pacia, instructions) {
75 return LOOPS * INSTRUCTIONS_PER_LOOP;
76 }
77
78 /*
79 * Test PACIA & AUTIA instruction.
80 * If PAC is supported and enabled in the kernel, this key should be valid and
81 * the instruction functional.
82 * Note we cannot test AUTIA alone since it may generate an exception if it
83 * fails.
84 */
BENCH_ALL_CPU(pac,pacautia,RUNS)85 BENCH_ALL_CPU(pac, pacautia, RUNS) {
86 uint64_t val = 0;
87
88 for (uint64_t i = 0; i < LOOPS; i++) {
89 __asm__ volatile(".arch_extension pauth\n\t" PACKBENCH_STR_REP16(
90 "PACIA %0, %1\n\tAUTIA %0, %1\n\t")
91 : "+r"(val)
92 : "r"(i));
93 }
94
95 return NO_ERROR;
96 }
97
BENCH_RESULT(pac,pacautia,ps_per_pacautia)98 BENCH_RESULT(pac, pacautia, ps_per_pacautia) {
99 return (bench_get_duration_ns() * 1000u) / (LOOPS * INSTRUCTIONS_PER_LOOP);
100 }
101
BENCH_RESULT(pac,pacautia,us_total)102 BENCH_RESULT(pac, pacautia, us_total) {
103 return bench_get_duration_ns() / 1000u;
104 }
105
BENCH_RESULT(pac,pacautia,instructions)106 BENCH_RESULT(pac, pacautia, instructions) {
107 return LOOPS * INSTRUCTIONS_PER_LOOP;
108 }
109
110 /*
111 * Test PACIB instruction.
112 * If PAC is supported and enabled in the kernel, this key should be valid and
113 * the instruction functional, though this benchmark does not test the
114 * instruction - see pactest instead.
115 */
BENCH_ALL_CPU(pac,pacib,RUNS)116 BENCH_ALL_CPU(pac, pacib, RUNS) {
117 uint64_t val = 0;
118
119 for (uint64_t i = 0; i < LOOPS; i++) {
120 __asm__ volatile(".arch_extension pauth\n\t" PACKBENCH_STR_REP16(
121 "PACIB %0, %1\n\t")
122 : "+r"(val)
123 : "r"(i));
124 }
125
126 return NO_ERROR;
127 }
128
BENCH_RESULT(pac,pacib,ps_per_pacib)129 BENCH_RESULT(pac, pacib, ps_per_pacib) {
130 return (bench_get_duration_ns() * 1000u) / (LOOPS * INSTRUCTIONS_PER_LOOP);
131 }
132
BENCH_RESULT(pac,pacib,us_total)133 BENCH_RESULT(pac, pacib, us_total) {
134 return bench_get_duration_ns() / 1000u;
135 }
136
BENCH_RESULT(pac,pacib,instructions)137 BENCH_RESULT(pac, pacib, instructions) {
138 return LOOPS * INSTRUCTIONS_PER_LOOP;
139 }
140
141 /*
142 * Test PACIAB & AUTIB instruction.
143 * Even if PAC is supported by the hardware, Trusty doesn't use or enable this
144 * key.
145 */
BENCH_ALL_CPU(pac,pacautib,RUNS)146 BENCH_ALL_CPU(pac, pacautib, RUNS) {
147 uint64_t val = 0;
148
149 for (uint64_t i = 0; i < LOOPS; i++) {
150 __asm__ volatile(".arch_extension pauth\n\t" PACKBENCH_STR_REP16(
151 "PACIB %0, %1\n\tAUTIB %0, %1\n\t")
152 : "+r"(val)
153 : "r"(i));
154 }
155
156 return NO_ERROR;
157 }
158
BENCH_RESULT(pac,pacautib,ps_per_pacautib)159 BENCH_RESULT(pac, pacautib, ps_per_pacautib) {
160 return (bench_get_duration_ns() * 1000u) / (LOOPS * INSTRUCTIONS_PER_LOOP);
161 }
162
BENCH_RESULT(pac,pacautib,us_total)163 BENCH_RESULT(pac, pacautib, us_total) {
164 return bench_get_duration_ns() / 1000u;
165 }
166
BENCH_RESULT(pac,pacautib,instructions)167 BENCH_RESULT(pac, pacautib, instructions) {
168 return LOOPS * INSTRUCTIONS_PER_LOOP;
169 }
170 #endif
171
172 /*
173 * Simple arithmetic instruction test.
174 */
BENCH_ALL_CPU(pac,add,RUNS)175 BENCH_ALL_CPU(pac, add, RUNS) {
176 uint64_t val = 0;
177
178 for (uint64_t i = 0; i < EXTRA_LOOPS; i++) {
179 __asm__ volatile(PACKBENCH_STR_REP16(PACBENCH_ADD_INSTR)
180 : "+r"(val)
181 : "r"(i));
182 }
183
184 return NO_ERROR;
185 }
186
BENCH_RESULT(pac,add,ps_per_add)187 BENCH_RESULT(pac, add, ps_per_add) {
188 return (bench_get_duration_ns() * 1000u) /
189 (EXTRA_LOOPS * INSTRUCTIONS_PER_LOOP);
190 }
191
BENCH_RESULT(pac,add,us_total)192 BENCH_RESULT(pac, add, us_total) {
193 return bench_get_duration_ns() / 1000u;
194 }
195
BENCH_RESULT(pac,add,instructions)196 BENCH_RESULT(pac, add, instructions) {
197 return EXTRA_LOOPS * INSTRUCTIONS_PER_LOOP;
198 }
199
200 /*
201 * NOP instruction test.
202 */
BENCH_ALL_CPU(pac,nop,RUNS)203 BENCH_ALL_CPU(pac, nop, RUNS) {
204 for (uint64_t i = 0; i < EXTRA_LOOPS; i++) {
205 __asm__ volatile(PACKBENCH_STR_REP16(PACBENCH_NOP_INSTR));
206 }
207
208 return NO_ERROR;
209 }
210
BENCH_RESULT(pac,nop,ps_per_nop)211 BENCH_RESULT(pac, nop, ps_per_nop) {
212 return (bench_get_duration_ns() * 1000u) /
213 (EXTRA_LOOPS * INSTRUCTIONS_PER_LOOP);
214 }
215
BENCH_RESULT(pac,nop,us_total)216 BENCH_RESULT(pac, nop, us_total) {
217 return bench_get_duration_ns() / 1000u;
218 }
219
BENCH_RESULT(pac,nop,instructions)220 BENCH_RESULT(pac, nop, instructions) {
221 return EXTRA_LOOPS * INSTRUCTIONS_PER_LOOP;
222 }
223
224 PORT_TEST(pac, "com.android.kernel.pacbench")
225