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