1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Copyright (c) 2017, Linaro Limited
4 */
5 #include <bench.h>
6 #include <compiler.h>
7 #include <kernel/misc.h>
8 #include <kernel/mutex.h>
9 #include <kernel/pseudo_ta.h>
10 #include <malloc.h>
11 #include <mm/core_memprot.h>
12 #include <mm/mobj.h>
13 #include <mm/tee_mm.h>
14 #include <mm/tee_pager.h>
15 #include <mm/vm.h>
16 #include <optee_rpc_cmd.h>
17 #include <pta_benchmark.h>
18 #include <stdio.h>
19 #include <string_ext.h>
20 #include <string.h>
21 #include <trace.h>
22
23 #define TA_NAME "benchmark.ta"
24 #define TA_PRINT_PREFIX "Benchmark: "
25
26 static struct tee_ts_global *bench_ts_global;
27 static size_t bench_ts_size;
28
29 static struct mutex bench_reg_mu = MUTEX_INITIALIZER;
30 static struct mobj *bench_mobj;
31
rpc_reg_global_buf(uint64_t type,paddr_t phta,size_t size)32 static TEE_Result rpc_reg_global_buf(uint64_t type, paddr_t phta, size_t size)
33 {
34 struct thread_param tpm = THREAD_PARAM_VALUE(IN, type, phta, size);
35
36 return thread_rpc_cmd(OPTEE_RPC_CMD_BENCH_REG, 1, &tpm);
37 }
38
alloc_benchmark_buffer(uint32_t type,TEE_Param p[TEE_NUM_PARAMS])39 static TEE_Result alloc_benchmark_buffer(uint32_t type,
40 TEE_Param p[TEE_NUM_PARAMS])
41 {
42 TEE_Result res;
43
44 if ((TEE_PARAM_TYPE_GET(type, 0) != TEE_PARAM_TYPE_VALUE_INOUT) ||
45 (TEE_PARAM_TYPE_GET(type, 1) != TEE_PARAM_TYPE_VALUE_INPUT) ||
46 (TEE_PARAM_TYPE_GET(type, 2) != TEE_PARAM_TYPE_NONE) ||
47 (TEE_PARAM_TYPE_GET(type, 3) != TEE_PARAM_TYPE_NONE)) {
48 return TEE_ERROR_BAD_PARAMETERS;
49 }
50
51 mutex_lock(&bench_reg_mu);
52
53 /* Check if we have already registered buffer */
54 if (bench_ts_global) {
55 EMSG(TA_PRINT_PREFIX
56 "timestamp buffer was already registered");
57 mutex_unlock(&bench_reg_mu);
58 return TEE_ERROR_BAD_STATE;
59 }
60
61 bench_ts_size = sizeof(struct tee_ts_global) +
62 p[1].value.a * sizeof(struct tee_ts_cpu_buf);
63 if (!bench_ts_size) {
64 EMSG(TA_PRINT_PREFIX
65 "invalid timestamp buffer size");
66 mutex_unlock(&bench_reg_mu);
67 return TEE_ERROR_BAD_STATE;
68 }
69
70 bench_mobj = thread_rpc_alloc_global_payload(bench_ts_size);
71 if (!bench_mobj) {
72 EMSG(TA_PRINT_PREFIX
73 "can't create mobj for timestamp buffer");
74 mutex_unlock(&bench_reg_mu);
75 return TEE_ERROR_OUT_OF_MEMORY;
76 }
77
78 bench_ts_global = (struct tee_ts_global *)mobj_get_va(bench_mobj, 0,
79 bench_ts_size);
80 if (!bench_ts_global) {
81 thread_rpc_free_global_payload(bench_mobj);
82 bench_mobj = NULL;
83
84 mutex_unlock(&bench_reg_mu);
85 return TEE_ERROR_BAD_STATE;
86 }
87
88 memset((void *)bench_ts_global, 0, bench_ts_size);
89 bench_ts_global->cores = p[1].value.a;
90
91 DMSG(TA_PRINT_PREFIX
92 "allocated timestamp buffer, addr = %p",
93 (void *)bench_ts_global);
94
95 mutex_unlock(&bench_reg_mu);
96
97 /* Send back to the optee linux kernel module */
98 res = rpc_reg_global_buf(OPTEE_MSG_RPC_CMD_BENCH_REG_NEW,
99 virt_to_phys((void *)bench_ts_global),
100 bench_ts_size);
101
102 p[0].value.a = virt_to_phys((void *)bench_ts_global);
103 p[0].value.b = bench_ts_size;
104
105 return res;
106 }
107
get_benchmark_memref(uint32_t type,TEE_Param p[TEE_NUM_PARAMS])108 static TEE_Result get_benchmark_memref(uint32_t type,
109 TEE_Param p[TEE_NUM_PARAMS])
110 {
111 if ((TEE_PARAM_TYPE_GET(type, 0) != TEE_PARAM_TYPE_VALUE_OUTPUT) ||
112 (TEE_PARAM_TYPE_GET(type, 1) != TEE_PARAM_TYPE_NONE) ||
113 (TEE_PARAM_TYPE_GET(type, 2) != TEE_PARAM_TYPE_NONE) ||
114 (TEE_PARAM_TYPE_GET(type, 3) != TEE_PARAM_TYPE_NONE)) {
115 return TEE_ERROR_BAD_PARAMETERS;
116 }
117
118 mutex_lock(&bench_reg_mu);
119
120 DMSG(TA_PRINT_PREFIX "Sending back timestamp buffer paddr = %p",
121 (void *)virt_to_phys((void *)bench_ts_global));
122
123 if (bench_ts_global) {
124 p[0].value.a = virt_to_phys((void *)bench_ts_global);
125 p[0].value.b = bench_ts_size;
126 } else {
127 p[0].value.a = 0;
128 p[0].value.b = 0;
129 }
130
131 mutex_unlock(&bench_reg_mu);
132
133 return TEE_SUCCESS;
134 }
135
unregister_benchmark(uint32_t type,TEE_Param p[TEE_NUM_PARAMS]__unused)136 static TEE_Result unregister_benchmark(uint32_t type,
137 TEE_Param p[TEE_NUM_PARAMS] __unused)
138 {
139 TEE_Result res;
140
141 if ((TEE_PARAM_TYPE_GET(type, 0) != TEE_PARAM_TYPE_NONE) ||
142 (TEE_PARAM_TYPE_GET(type, 1) != TEE_PARAM_TYPE_NONE) ||
143 (TEE_PARAM_TYPE_GET(type, 2) != TEE_PARAM_TYPE_NONE) ||
144 (TEE_PARAM_TYPE_GET(type, 3) != TEE_PARAM_TYPE_NONE)) {
145 return TEE_ERROR_BAD_PARAMETERS;
146 }
147 mutex_lock(&bench_reg_mu);
148
149 DMSG(TA_PRINT_PREFIX "Unregister benchmark ts buffer paddr = %p",
150 (void *)virt_to_phys((void *)bench_ts_global));
151 bench_ts_global = NULL;
152
153 mutex_unlock(&bench_reg_mu);
154
155 res = rpc_reg_global_buf(OPTEE_MSG_RPC_CMD_BENCH_REG_DEL, 0, 0);
156
157 thread_rpc_free_global_payload(bench_mobj);
158 bench_mobj = NULL;
159
160 return res;
161 }
162
invoke_command(void * session_ctx __unused,uint32_t cmd_id,uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS])163 static TEE_Result invoke_command(void *session_ctx __unused,
164 uint32_t cmd_id, uint32_t param_types,
165 TEE_Param params[TEE_NUM_PARAMS])
166 {
167 switch (cmd_id) {
168 case BENCHMARK_CMD_ALLOCATE_BUF:
169 return alloc_benchmark_buffer(param_types, params);
170 case BENCHMARK_CMD_GET_MEMREF:
171 return get_benchmark_memref(param_types, params);
172 case BENCHMARK_CMD_UNREGISTER:
173 return unregister_benchmark(param_types, params);
174 default:
175 break;
176 }
177
178 return TEE_ERROR_BAD_PARAMETERS;
179 }
180
181 pseudo_ta_register(.uuid = BENCHMARK_UUID, .name = TA_NAME,
182 .flags = PTA_DEFAULT_FLAGS,
183 .invoke_command_entry_point = invoke_command);
184
bm_timestamp(void)185 void bm_timestamp(void)
186 {
187 struct tee_ts_cpu_buf *cpu_buf;
188 struct tee_time_st ts_data;
189 uint64_t ts_i;
190 void *ret_addr;
191 uint32_t cur_cpu;
192 uint32_t exceptions;
193
194 if (!bench_ts_global)
195 return;
196
197 exceptions = thread_mask_exceptions(THREAD_EXCP_ALL);
198 cur_cpu = get_core_pos();
199
200 if (cur_cpu >= bench_ts_global->cores) {
201 thread_unmask_exceptions(exceptions);
202 return;
203 }
204
205 ret_addr = __builtin_return_address(0);
206
207 cpu_buf = &bench_ts_global->cpu_buf[cur_cpu];
208 ts_i = cpu_buf->head++;
209 ts_data.cnt = read_pmccntr() * TEE_BENCH_DIVIDER;
210 ts_data.addr = (uintptr_t)ret_addr;
211 ts_data.src = TEE_BENCH_CORE;
212 cpu_buf->stamps[ts_i & TEE_BENCH_MAX_MASK] = ts_data;
213
214 thread_unmask_exceptions(exceptions);
215 }
216