• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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