1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Copyright (c) 2015, Linaro Limited
4 * All rights reserved.
5 */
6
7 #include <tee_api.h>
8 #include <storage_benchmark.h>
9 #include <ta_storage_benchmark.h>
10 #include <tee_internal_api_extensions.h>
11
12 #define DEFAULT_CHUNK_SIZE (1 << 10)
13 #define DEFAULT_DATA_SIZE (1024)
14
15 #define SCRAMBLE(x) ((x & 0xff) ^ 0xaa)
16
17 #define ASSERT_PARAM_TYPE(pt_in, pt_expect) \
18 do { \
19 if ((pt_in) != (pt_expect)) \
20 return TEE_ERROR_BAD_PARAMETERS; \
21 } while (0)
22
23 static uint8_t filename[] = "BenchmarkTestFile";
24
fill_buffer(uint8_t * buf,size_t size)25 static void fill_buffer(uint8_t *buf, size_t size)
26 {
27 size_t i = 0;
28
29 if (!buf)
30 return;
31
32 for (i = 0; i < size; i++)
33 buf[i] = SCRAMBLE(i);
34 }
35
verify_buffer(uint8_t * buf,size_t size)36 static TEE_Result verify_buffer(uint8_t *buf, size_t size)
37 {
38 size_t i = 0;
39
40 if (!buf)
41 return TEE_ERROR_BAD_PARAMETERS;
42
43 for (i = 0; i < size; i++) {
44 uint8_t expect_data = SCRAMBLE(i);
45
46 if (expect_data != buf[i]) {
47 return TEE_ERROR_CORRUPT_OBJECT;
48 }
49 }
50
51 return TEE_SUCCESS;
52 }
53
tee_time_to_ms(TEE_Time t)54 static inline uint32_t tee_time_to_ms(TEE_Time t)
55 {
56 return t.seconds * 1000 + t.millis;
57 }
58
get_delta_time_in_ms(TEE_Time start,TEE_Time stop)59 static inline uint32_t get_delta_time_in_ms(TEE_Time start, TEE_Time stop)
60 {
61 return tee_time_to_ms(stop) - tee_time_to_ms(start);
62 }
63
prepare_test_file(size_t data_size,uint8_t * chunk_buf,size_t chunk_size)64 static TEE_Result prepare_test_file(size_t data_size, uint8_t *chunk_buf,
65 size_t chunk_size)
66 {
67 size_t remain_bytes = data_size;
68 TEE_Result res = TEE_SUCCESS;
69 TEE_ObjectHandle object = TEE_HANDLE_NULL;
70
71 res = TEE_CreatePersistentObject(TEE_STORAGE_PRIVATE,
72 filename, sizeof(filename),
73 TEE_DATA_FLAG_ACCESS_READ |
74 TEE_DATA_FLAG_ACCESS_WRITE |
75 TEE_DATA_FLAG_ACCESS_WRITE_META |
76 TEE_DATA_FLAG_OVERWRITE,
77 NULL, NULL, 0, &object);
78 if (res != TEE_SUCCESS) {
79 EMSG("Failed to create persistent object, res=0x%08x",
80 res);
81 goto exit;
82 }
83
84 while (remain_bytes) {
85 size_t write_size = 0;
86
87 if (remain_bytes < chunk_size)
88 write_size = remain_bytes;
89 else
90 write_size = chunk_size;
91 res = TEE_WriteObjectData(object, chunk_buf, write_size);
92 if (res != TEE_SUCCESS) {
93 EMSG("Failed to write data, res=0x%08x", res);
94 goto exit_close_object;
95 }
96 remain_bytes -= write_size;
97 }
98 exit_close_object:
99 TEE_CloseObject(object);
100 exit:
101 return res;
102 }
103
test_write(TEE_ObjectHandle object,size_t data_size,uint8_t * chunk_buf,size_t chunk_size,uint32_t * spent_time_in_ms)104 static TEE_Result test_write(TEE_ObjectHandle object, size_t data_size,
105 uint8_t *chunk_buf, size_t chunk_size,
106 uint32_t *spent_time_in_ms)
107 {
108 TEE_Time start_time = { };
109 TEE_Time stop_time = { };
110 size_t remain_bytes = data_size;
111 TEE_Result res = TEE_SUCCESS;
112
113 TEE_GetSystemTime(&start_time);
114
115 while (remain_bytes) {
116 size_t write_size = 0;
117
118 DMSG("Write data, remain bytes: %zu", remain_bytes);
119 if (chunk_size > remain_bytes)
120 write_size = remain_bytes;
121 else
122 write_size = chunk_size;
123 res = TEE_WriteObjectData(object, chunk_buf, write_size);
124 if (res != TEE_SUCCESS) {
125 EMSG("Failed to write data, res=0x%08x", res);
126 goto exit;
127 }
128 remain_bytes -= write_size;
129 }
130
131 TEE_GetSystemTime(&stop_time);
132
133 *spent_time_in_ms = get_delta_time_in_ms(start_time, stop_time);
134
135 IMSG("start: %u.%u(s), stop: %u.%u(s), delta: %u(ms)",
136 start_time.seconds, start_time.millis,
137 stop_time.seconds, stop_time.millis,
138 *spent_time_in_ms);
139
140 exit:
141 return res;
142 }
143
test_read(TEE_ObjectHandle object,size_t data_size,uint8_t * chunk_buf,size_t chunk_size,uint32_t * spent_time_in_ms)144 static TEE_Result test_read(TEE_ObjectHandle object, size_t data_size,
145 uint8_t *chunk_buf, size_t chunk_size,
146 uint32_t *spent_time_in_ms)
147 {
148 TEE_Time start_time = { };
149 TEE_Time stop_time = { };
150 size_t remain_bytes = data_size;
151 TEE_Result res = TEE_SUCCESS;
152 uint32_t read_bytes = 0;
153
154 TEE_GetSystemTime(&start_time);
155
156 while (remain_bytes) {
157 size_t read_size = 0;
158
159 DMSG("Read data, remain bytes: %zu", remain_bytes);
160 if (remain_bytes < chunk_size)
161 read_size = remain_bytes;
162 else
163 read_size = chunk_size;
164 res = TEE_ReadObjectData(object, chunk_buf, read_size,
165 &read_bytes);
166 if (res != TEE_SUCCESS) {
167 EMSG("Failed to read data, res=0x%08x", res);
168 goto exit;
169 }
170
171 remain_bytes -= read_size;
172 }
173
174 TEE_GetSystemTime(&stop_time);
175
176 *spent_time_in_ms = get_delta_time_in_ms(start_time, stop_time);
177
178 IMSG("start: %u.%u(s), stop: %u.%u(s), delta: %u(ms)",
179 start_time.seconds, start_time.millis,
180 stop_time.seconds, stop_time.millis,
181 *spent_time_in_ms);
182
183 exit:
184 return res;
185 }
186
test_rewrite(TEE_ObjectHandle object,size_t data_size,uint8_t * chunk_buf,size_t chunk_size,uint32_t * spent_time_in_ms)187 static TEE_Result test_rewrite(TEE_ObjectHandle object, size_t data_size,
188 uint8_t *chunk_buf, size_t chunk_size,
189 uint32_t *spent_time_in_ms)
190 {
191 TEE_Time start_time = { };
192 TEE_Time stop_time = { };
193 size_t remain_bytes = data_size;
194 TEE_Result res = TEE_SUCCESS;
195 uint32_t read_bytes = 0;
196
197 TEE_GetSystemTime(&start_time);
198
199 while (remain_bytes) {
200 size_t write_size = 0;
201 int32_t negative_chunk_size = 0;
202
203 if (remain_bytes < chunk_size)
204 write_size = remain_bytes;
205 else
206 write_size = chunk_size;
207 negative_chunk_size = -(int32_t)write_size;
208
209 /* Read a chunk */
210 res = TEE_ReadObjectData(object, chunk_buf, write_size,
211 &read_bytes);
212 if (res != TEE_SUCCESS) {
213 EMSG("Failed to read data, res=0x%08x", res);
214 goto exit;
215 }
216
217 if (read_bytes != write_size) {
218 EMSG("Partial data read, bytes=%u", read_bytes);
219 res = TEE_ERROR_CORRUPT_OBJECT;
220 goto exit;
221 }
222
223 /* Seek to the position before read */
224 res = TEE_SeekObjectData(object, negative_chunk_size,
225 TEE_DATA_SEEK_CUR);
226 if (res != TEE_SUCCESS) {
227 EMSG("Failed to seek to previous offset");
228 goto exit;
229 }
230
231 /* Write a chunk*/
232 res = TEE_WriteObjectData(object, chunk_buf, write_size);
233 if (res != TEE_SUCCESS) {
234 EMSG("Failed to write data, res=0x%08x", res);
235 goto exit;
236 }
237
238 remain_bytes -= write_size;
239 }
240
241 TEE_GetSystemTime(&stop_time);
242
243 *spent_time_in_ms = get_delta_time_in_ms(start_time, stop_time);
244
245 IMSG("start: %u.%u(s), stop: %u.%u(s), delta: %u(ms)",
246 start_time.seconds, start_time.millis,
247 stop_time.seconds, stop_time.millis,
248 *spent_time_in_ms);
249
250 exit:
251 return res;
252 }
253
verify_file_data(TEE_ObjectHandle object,size_t data_size,uint8_t * chunk_buf,size_t chunk_size)254 static TEE_Result verify_file_data(TEE_ObjectHandle object, size_t data_size,
255 uint8_t *chunk_buf, size_t chunk_size)
256 {
257 TEE_Result res = TEE_ERROR_GENERIC;
258 size_t tmp_data_size = data_size;
259
260 res = TEE_SeekObjectData(object, 0, TEE_DATA_SEEK_SET);
261 if (res != TEE_SUCCESS) {
262 EMSG("Failed to seek to offset 0");
263 goto exit;
264 }
265
266 TEE_MemFill(chunk_buf, 0, chunk_size);
267
268 tmp_data_size = data_size;
269 while (tmp_data_size > 0) {
270 uint32_t read_bytes = 0;
271
272 res = TEE_ReadObjectData(object, chunk_buf, chunk_size,
273 &read_bytes);
274 if (res != TEE_SUCCESS) {
275 EMSG("Failed to read data, res=0x%08x", res);
276 goto exit;
277 }
278
279 if (read_bytes != chunk_size) {
280 EMSG("Data size not match");
281 res = TEE_ERROR_CORRUPT_OBJECT;
282 goto exit;
283 }
284
285 res = verify_buffer(chunk_buf, chunk_size);
286 if (res != TEE_SUCCESS) {
287 EMSG("Verify data failed, res=0x%08x", res);
288 goto exit;
289 }
290
291 tmp_data_size -= chunk_size;
292 }
293
294 exit:
295 return res;
296 }
297
ta_stroage_benchmark_chunk_access_test(uint32_t nCommandID,uint32_t param_types,TEE_Param params[4])298 static TEE_Result ta_stroage_benchmark_chunk_access_test(uint32_t nCommandID,
299 uint32_t param_types, TEE_Param params[4])
300 {
301 TEE_Result res = TEE_ERROR_GENERIC;
302 size_t data_size = 0;
303 size_t chunk_size = 0;
304 TEE_ObjectHandle object = TEE_HANDLE_NULL;
305 uint8_t *chunk_buf = NULL;
306 uint32_t *spent_time_in_ms = ¶ms[2].value.a;
307 bool do_verify = false;
308
309 ASSERT_PARAM_TYPE(param_types, TEE_PARAM_TYPES(
310 TEE_PARAM_TYPE_VALUE_INPUT,
311 TEE_PARAM_TYPE_VALUE_INPUT,
312 TEE_PARAM_TYPE_VALUE_OUTPUT,
313 TEE_PARAM_TYPE_NONE));
314
315 data_size = params[0].value.a;
316 chunk_size = params[0].value.b;
317 do_verify = params[1].value.a;
318
319 if (data_size == 0)
320 data_size = DEFAULT_DATA_SIZE;
321
322 if (chunk_size == 0)
323 chunk_size = DEFAULT_CHUNK_SIZE;
324
325 IMSG("command id: %u, test data size: %zd, chunk size: %zd\n",
326 nCommandID, data_size, chunk_size);
327
328 chunk_buf = TEE_Malloc(chunk_size, TEE_MALLOC_FILL_ZERO);
329 if (!chunk_buf) {
330 EMSG("Failed to allocate memory");
331 res = TEE_ERROR_OUT_OF_MEMORY;
332 goto exit;
333 }
334
335 fill_buffer(chunk_buf, chunk_size);
336 res = prepare_test_file(data_size, chunk_buf, chunk_size);
337 if (res != TEE_SUCCESS) {
338 EMSG("Failed to create test file, res=0x%08x",
339 res);
340 goto exit_free_chunk_buf;
341 }
342
343 res = TEE_OpenPersistentObject(TEE_STORAGE_PRIVATE,
344 filename, sizeof(filename),
345 TEE_DATA_FLAG_ACCESS_READ |
346 TEE_DATA_FLAG_ACCESS_WRITE |
347 TEE_DATA_FLAG_ACCESS_WRITE_META,
348 &object);
349 if (res != TEE_SUCCESS) {
350 EMSG("Failed to open persistent object, res=0x%08x",
351 res);
352 goto exit_remove_object;
353 }
354
355 switch (nCommandID) {
356 case TA_STORAGE_BENCHMARK_CMD_TEST_READ:
357 res = test_read(object, data_size, chunk_buf,
358 chunk_size, spent_time_in_ms);
359 break;
360
361 case TA_STORAGE_BENCHMARK_CMD_TEST_WRITE:
362 res = test_write(object, data_size, chunk_buf,
363 chunk_size, spent_time_in_ms);
364 break;
365
366 case TA_STORAGE_BENCHMARK_CMD_TEST_REWRITE:
367 res = test_rewrite(object, data_size, chunk_buf,
368 chunk_size, spent_time_in_ms);
369 break;
370
371 default:
372 res = TEE_ERROR_BAD_PARAMETERS;
373 }
374
375 if (res != TEE_SUCCESS)
376 goto exit_remove_object;
377
378 if (do_verify)
379 res = verify_file_data(object, data_size,
380 chunk_buf, chunk_size);
381
382
383 exit_remove_object:
384 TEE_CloseAndDeletePersistentObject1(object);
385 exit_free_chunk_buf:
386 TEE_Free(chunk_buf);
387 exit:
388
389 return res;
390 }
391
ta_storage_benchmark_cmd_handler(uint32_t nCommandID,uint32_t param_types,TEE_Param params[4])392 TEE_Result ta_storage_benchmark_cmd_handler(uint32_t nCommandID,
393 uint32_t param_types, TEE_Param params[4])
394 {
395 TEE_Result res = TEE_ERROR_GENERIC;
396
397 switch (nCommandID) {
398 case TA_STORAGE_BENCHMARK_CMD_TEST_READ:
399 case TA_STORAGE_BENCHMARK_CMD_TEST_WRITE:
400 case TA_STORAGE_BENCHMARK_CMD_TEST_REWRITE:
401 res = ta_stroage_benchmark_chunk_access_test(nCommandID,
402 param_types, params);
403 break;
404
405 default:
406 res = TEE_ERROR_BAD_PARAMETERS;
407 }
408
409 return res;
410 }
411
412