1 /*
2 * Copyright (c) 2017, Linaro Limited
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE.
26 */
27 #include <err.h>
28 #include <fcntl.h>
29 #include <math.h>
30 #include <pthread.h>
31 #include <sched.h>
32 #include <stdbool.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <sys/mman.h>
37 #include <sys/stat.h>
38 #include <tee_bench.h>
39 #include <tee_client_api.h>
40 #include <unistd.h>
41
42 #include "teec_benchmark.h"
43
44 struct tee_ts_global *bench_ts_global;
45 static const TEEC_UUID pta_benchmark_uuid = PTA_BENCHMARK_UUID;
46
47 static TEEC_Context bench_ctx;
48 static TEEC_Session bench_sess;
49
50 static pthread_mutex_t teec_bench_mu = PTHREAD_MUTEX_INITIALIZER;
51
52 /* Cycle counter */
read_ccounter(void)53 static inline uint64_t read_ccounter(void)
54 {
55 uint64_t ccounter = 0;
56 #ifdef __aarch64__
57 asm volatile("mrs %0, PMCCNTR_EL0" : "=r"(ccounter));
58 #else
59 asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r"(ccounter));
60 #endif
61 return ccounter * TEE_BENCH_DIVIDER;
62 }
63
benchmark_pta_open(void)64 static TEEC_Result benchmark_pta_open(void)
65 {
66 TEEC_Result res = TEEC_ERROR_GENERIC;
67 uint32_t ret_orig = 0;
68
69 res = TEEC_InitializeContext(NULL, &bench_ctx);
70 if (res != TEEC_SUCCESS)
71 return res;
72
73 res = TEEC_OpenSession(&bench_ctx, &bench_sess,
74 &pta_benchmark_uuid,
75 TEEC_LOGIN_PUBLIC, NULL, NULL, &ret_orig);
76 if (res != TEEC_SUCCESS) {
77 TEEC_FinalizeContext(&bench_ctx);
78 return res;
79 }
80
81 return res;
82 }
83
benchmark_pta_close(void)84 static void benchmark_pta_close(void)
85 {
86 TEEC_CloseSession(&bench_sess);
87 TEEC_FinalizeContext(&bench_ctx);
88 }
89
benchmark_get_bench_buf_paddr(uint64_t * paddr_ts_buf,uint64_t * size)90 static TEEC_Result benchmark_get_bench_buf_paddr(uint64_t *paddr_ts_buf,
91 uint64_t *size)
92 {
93 TEEC_Result res = TEEC_ERROR_GENERIC;
94 uint32_t ret_orig = 0;
95 TEEC_Operation op;
96
97 memset(&op, 0, sizeof(op));
98
99 res = benchmark_pta_open();
100 if (res != TEEC_SUCCESS)
101 return res;
102
103 op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_OUTPUT, TEEC_NONE,
104 TEEC_NONE, TEEC_NONE);
105
106 res = TEEC_InvokeCommand(&bench_sess, BENCHMARK_CMD_GET_MEMREF,
107 &op, &ret_orig);
108 if (res != TEEC_SUCCESS)
109 return res;
110
111 *paddr_ts_buf = op.params[0].value.a;
112 *size = op.params[0].value.b;
113
114 benchmark_pta_close();
115
116 return res;
117 }
118
mmap_paddr(intptr_t paddr,uint64_t size)119 static void *mmap_paddr(intptr_t paddr, uint64_t size)
120 {
121 int devmem = 0;
122 off_t offset = 0;
123 off_t page_addr = 0;
124 intptr_t *hw_addr = NULL;
125
126 devmem = open("/dev/mem", O_RDWR);
127 if (!devmem)
128 return NULL;
129
130 offset = (off_t)paddr % getpagesize();
131 page_addr = (off_t)(paddr - offset);
132
133 hw_addr = (intptr_t *)mmap(0, size, PROT_READ|PROT_WRITE,
134 MAP_SHARED, devmem, page_addr);
135 if (hw_addr == MAP_FAILED) {
136 close(devmem);
137 return NULL;
138 }
139
140 close(devmem);
141 return (hw_addr + offset);
142 }
143
144 /* check if we are in benchmark mode */
benchmark_check_mode(void)145 static bool benchmark_check_mode(void)
146 {
147 uint64_t ts_buf_raw = 0;
148 uint64_t ts_buf_size = 0;
149 bool res = true;
150
151 if (!bench_ts_global) {
152 /* receive buffer from Benchmark PTA and register it */
153 benchmark_get_bench_buf_paddr(&ts_buf_raw, &ts_buf_size);
154 if (ts_buf_raw && ts_buf_size) {
155 bench_ts_global = mmap_paddr(ts_buf_raw, ts_buf_size);
156 res = (bench_ts_global) ? true : false;
157 } else {
158 res = false;
159 }
160 }
161
162 return res;
163 }
164
165 /* Adding timestamp to buffer */
bm_timestamp(void)166 void bm_timestamp(void)
167 {
168 struct tee_ts_cpu_buf *cpu_buf = NULL;
169 uint64_t ts_i = 0;
170 void *ret_addr = NULL;
171 uint32_t cur_cpu = 0;
172 int ret = 0;
173 cpu_set_t cpu_set_old;
174 cpu_set_t cpu_set_tmp;
175 struct tee_time_st ts_data;
176
177 memset(&cpu_set_old, 0, sizeof(cpu_set_old));
178 memset(&cpu_set_tmp, 0, sizeof(cpu_set_tmp));
179 memset(&ts_data, 0, sizeof(ts_data));
180
181 if (pthread_mutex_trylock(&teec_bench_mu))
182 return;
183
184 if (!benchmark_check_mode())
185 goto error;
186
187 CPU_ZERO(&cpu_set_old);
188 ret = sched_getaffinity(0, sizeof(cpu_set_old), &cpu_set_old);
189 if (ret)
190 goto error;
191
192 /* stick to the same core while putting timestamp */
193 cur_cpu = sched_getcpu();
194 CPU_ZERO(&cpu_set_tmp);
195 CPU_SET(cur_cpu, &cpu_set_tmp);
196 ret = sched_setaffinity(0, sizeof(cpu_set_tmp), &cpu_set_tmp);
197 if (ret)
198 goto error;
199
200 /* fill timestamp data */
201 if (cur_cpu >= bench_ts_global->cores) {
202 ret = sched_setaffinity(0, sizeof(cpu_set_old), &cpu_set_old);
203 goto error;
204 }
205
206 ret_addr = __builtin_return_address(0);
207
208 cpu_buf = &bench_ts_global->cpu_buf[cur_cpu];
209 ts_i = __sync_fetch_and_add(&cpu_buf->head, 1);
210 ts_data.cnt = read_ccounter();
211 ts_data.addr = (uintptr_t)ret_addr;
212 ts_data.src = TEE_BENCH_CLIENT;
213 cpu_buf->stamps[ts_i & TEE_BENCH_MAX_MASK] = ts_data;
214
215 /* set back affinity mask */
216 sched_setaffinity(0, sizeof(cpu_set_old), &cpu_set_old);
217
218 error:
219 pthread_mutex_unlock(&teec_bench_mu);
220 }
221
222