blob: f5b614bf592b80f50d9ed289bfa84cfc0a49c634 [file] [log] [blame]
Mark Dykese7810b52020-06-03 15:46:55 -05001/*
mardyk0182389fb2023-09-25 16:34:56 -05002 * Copyright (c) 2023, Arm Limited. All rights reserved.
Mark Dykese7810b52020-06-03 15:46:55 -05003 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <arch_helpers.h>
8#include <debug.h>
9#include <drivers/arm/private_timer.h>
10#include <events.h>
11#include "fifo3d.h"
12#include <libfdt.h>
13
Mark Dykese7810b52020-06-03 15:46:55 -050014#include <tftf_lib.h>
Mark Dykese7810b52020-06-03 15:46:55 -050015
16extern char _binary___dtb_start[];
mardyk0182389fb2023-09-25 16:34:56 -050017extern void runtestfunction(char *funcstr);
Mark Dykese7810b52020-06-03 15:46:55 -050018
19struct memmod tmod __aligned(65536) __section("smcfuzz");
20
21/*
22 * switch to use either standard C malloc or custom SMC malloc
23 */
24
25#define FIRST_NODE_DEVTREE_OFFSET (8)
26
27#ifdef SMC_FUZZ_TMALLOC
28#define GENMALLOC(x) malloc((x))
29#define GENFREE(x) free((x))
30#else
31#define GENMALLOC(x) smcmalloc((x), mmod)
32#define GENFREE(x) smcfree((x), mmod)
33#endif
34
35/*
36 * Device tree parameter struct
37 */
38
39struct fdt_header_sf {
40 unsigned int magic;
41 unsigned int totalsize;
42 unsigned int off_dt_struct;
43 unsigned int off_dt_strings;
44 unsigned int off_mem_rsvmap;
45 unsigned int version;
46 unsigned int last_comp_version;
47 unsigned int boot_cpuid_phys;
48 unsigned int size_dt_strings;
49 unsigned int size_dt_struct;
50};
51
52/*
53 * Structure to read the fields of the device tree
54 */
55struct propval {
56 unsigned int len;
57 unsigned int nameoff;
58};
59
60/*
61 * Converting from big endian to little endian to read values
62 * of device tree
63 */
64unsigned int lendconv(unsigned int val)
65{
66 unsigned int res;
67
68 res = val << 24;
69 res |= ((val << 8) & 0xFF0000U);
70 res |= ((val >> 8) & 0xFF00U);
71 res |= ((val >> 24) & 0xFFU);
72 return res;
73}
74
75/*
76 * Function to read strings from device tree
77 */
78void pullstringdt(void **dtb,
79 void *dtb_beg,
80 unsigned int offset,
81 char *cset)
82{
83 int fistr;
84 int cntchr;
85 char rval;
86
87 if (offset != 0U) {
88 *dtb = dtb_beg + offset;
89 }
90 fistr = 0;
91
92 cntchr = 0;
93 while (fistr == 0) {
94 rval = *((char *)*dtb);
95 *dtb += sizeof(char);
96 cset[cntchr] = rval;
97 if (cset[cntchr] == 0) {
98 fistr = 1;
99 }
100 cntchr++;
101 }
102
103 if ((cntchr % 4) != 0) {
104 for (unsigned int i = 0U; (int)i < (4 - (cntchr % 4)); i++) {
105 *dtb += sizeof(char);
106 }
107 }
108}
109
110/*
111 * Structure for Node information extracted from device tree
112 */
113struct rand_smc_node {
114 int *biases; // Biases of the individual nodes
115 int *biasarray; // Array of biases across all nodes
116 char **snames; // String that is unique to the SMC call called in test
117 struct rand_smc_node *treenodes; // Selection of nodes that are farther down in the tree
118 // that reference further rand_smc_node objects
119 int *norcall; // Specifies whether a particular node is a leaf node or tree node
120 int entries; // Number of nodes in object
121 int biasent; // Number that gives the total number of entries in biasarray
122 // based on all biases of the nodes
123 char **nname; // Array of node names
124};
125
126
127/*
128 * Create bias tree from given device tree description
129 */
130
131struct rand_smc_node *createsmctree(int *casz,
132 struct memmod *mmod)
133{
134 void *dtb;
135 void *dtb_pn;
136 void *dtb_beg;
137 struct fdt_header fhd;
138 unsigned int rval;
139 struct propval pv;
140 char cset[MAX_NAME_CHARS];
141 char nodename[MAX_NAME_CHARS];
142 int dtdone;
143 struct fifo3d f3d;
144 int leafnode = 0;
145 unsigned int fnode = 0U;
146 unsigned int bias_count = 0U;
147 unsigned int bintnode = 0U;
148 unsigned int treenodetrack = 0U;
149 struct fdt_header *fhdptr;
150 struct rand_smc_node *ndarray = NULL;
151 int cntndarray;
152 struct rand_smc_node nrnode;
153 struct rand_smc_node *tndarray;
154
155 f3d.col = 0;
156 f3d.curr_col = 0;
157
158 /*
159 * Read device tree header and check for valid type
160 */
161
162 fhdptr = (struct fdt_header *)_binary___dtb_start;
163
164 if (fdt_check_header((void *)fhdptr) != 0) {
165 printf("ERROR, not device tree compliant\n");
166 }
167 fhd = *fhdptr;
168 cntndarray = 0;
169 nrnode.entries = 0;
170
171 /*
172 * Create pointers to device tree data
173 */
174 dtb = _binary___dtb_start;
175 dtb_pn = _binary___dtb_start;
176
177 dtb_beg = dtb;
178 fhd = *((struct fdt_header *)dtb);
179 dtb += (fdt32_to_cpu(fhd.off_dt_struct) + FIRST_NODE_DEVTREE_OFFSET);
180 dtdone = 0;
181
182 /*
183 * Reading device tree file
184 */
185 while (dtdone == 0) {
186 rval = *((unsigned int *)dtb);
187 dtb += sizeof(unsigned int);
188
189 /*
190 * Reading node name from device tree and pushing it into the raw data
191 * Table of possible values reading from device tree binary file:
192 * 1 New node found within current tree, possible leaf or tree variant
193 * 2 Node termination of current hiearchy.
194 * Could indicate end of tree or preparation for another branch
195 * 3 Leaf node indication where a bias with a function name should be
196 * found for the current node
197 * 9 End of device tree file and we end the read of the bias tree
198 */
199 if (fdt32_to_cpu(rval) == 1) {
200 pullstringdt(&dtb, dtb_beg, 0U, cset);
201 push_3dfifo_col(&f3d, cset, mmod);
202 strlcpy(nodename, cset, MAX_NAME_CHARS);
203
204 /*
205 * Error checking to make sure that bias is specified
206 */
207 if (fnode == 0U) {
208 fnode = 1U;
209 } else {
210 if (!((fnode == 1U) && (bias_count == 1U))) {
211 printf("ERROR: Did not find bias or multiple bias ");
212 printf("designations before %s %u %u\n",
213 cset, fnode, bias_count);
214 }
215 bias_count = 0U;
216 }
217 }
218
219 /*
220 * Reading node parameters of bias and function name
221 */
222 if (fdt32_to_cpu(rval) == 3) {
223 pv = *((struct propval *)dtb);
224 dtb += sizeof(struct propval);
225 pullstringdt(&dtb_pn, dtb_beg,
226 (fdt32_to_cpu(fhd.off_dt_strings) +
227 fdt32_to_cpu(pv.nameoff)), cset);
228 if (strcmp(cset, "bias") == 0) {
229 rval = *((unsigned int *)dtb);
230 dtb += sizeof(unsigned int);
231 push_3dfifo_bias(&f3d, fdt32_to_cpu(rval));
232 bias_count++;
233 if (bintnode == 1U) {
234 fnode = 0U;
235 bintnode = 0U;
236 bias_count = 0U;
237 }
238 }
239 if (strcmp(cset, "functionname") == 0) {
240 pullstringdt(&dtb, dtb_beg, 0, cset);
241 push_3dfifo_fname(&f3d, cset);
242 leafnode = 1;
243 if (bias_count == 0U) {
244 bintnode = 1U;
245 fnode = 1U;
246 } else {
247 bias_count = 0U;
248 fnode = 0U;
249 }
250 }
251 }
252
253 /*
254 * Node termination and evaluate whether the bias tree requires addition.
255 * The non tree nodes are added.
256 */
257 if (fdt32_to_cpu(rval) == 2) {
258 if ((fnode > 0U) || (bias_count > 0U)) {
259 printf("ERROR: early node termination... ");
260 printf("no bias or functionname field for leaf node, near %s %u\n",
261 nodename, fnode);
262 }
263 f3d.col--;
264 if (leafnode == 1) {
265 leafnode = 0;
266 } else {
267 /*
268 * Create bias tree in memory from raw data
269 */
270 tndarray =
271 GENMALLOC((cntndarray + 1) *
272 sizeof(struct rand_smc_node));
273 unsigned int treenodetrackmal = 0;
274 for (unsigned int j = 0U; (int)j < cntndarray; j++) {
275 tndarray[j].biases = GENMALLOC(ndarray[j].entries * sizeof(int));
276 tndarray[j].snames = GENMALLOC(ndarray[j].entries * sizeof(char *));
277 tndarray[j].norcall = GENMALLOC(ndarray[j].entries * sizeof(int));
278 tndarray[j].nname = GENMALLOC(ndarray[j].entries * sizeof(char *));
279 tndarray[j].treenodes = GENMALLOC(ndarray[j].entries * sizeof(struct rand_smc_node));
280 tndarray[j].entries = ndarray[j].entries;
281 for (unsigned int i = 0U; (int)i < ndarray[j].entries; i++) {
282 tndarray[j].snames[i] = GENMALLOC(1 * sizeof(char[MAX_NAME_CHARS]));
283 strlcpy(tndarray[j].snames[i], ndarray[j].snames[i], MAX_NAME_CHARS);
284 tndarray[j].nname[i] = GENMALLOC(1 * sizeof(char[MAX_NAME_CHARS]));
285 strlcpy(tndarray[j].nname[i], ndarray[j].nname[i], MAX_NAME_CHARS);
286 tndarray[j].biases[i] = ndarray[j].biases[i];
287 tndarray[j].norcall[i] = ndarray[j].norcall[i];
288 if (tndarray[j].norcall[i] == 1) {
289 tndarray[j].treenodes[i] = tndarray[treenodetrackmal];
290 treenodetrackmal++;
291 }
292 }
293 tndarray[j].biasent = ndarray[j].biasent;
294 tndarray[j].biasarray = GENMALLOC((tndarray[j].biasent) * sizeof(int));
295 for (unsigned int i = 0U; (int)i < ndarray[j].biasent; i++) {
296 tndarray[j].biasarray[i] = ndarray[j].biasarray[i];
297 }
298 }
299 tndarray[cntndarray].biases = GENMALLOC(f3d.row[f3d.col + 1] * sizeof(int));
300 tndarray[cntndarray].snames = GENMALLOC(f3d.row[f3d.col + 1] * sizeof(char *));
301 tndarray[cntndarray].norcall = GENMALLOC(f3d.row[f3d.col + 1] * sizeof(int));
302 tndarray[cntndarray].nname = GENMALLOC(f3d.row[f3d.col + 1] * sizeof(char *));
303 tndarray[cntndarray].treenodes = GENMALLOC(f3d.row[f3d.col + 1] * sizeof(struct rand_smc_node));
304 tndarray[cntndarray].entries = f3d.row[f3d.col + 1];
305
306 /*
307 * Populate bias tree with former values in tree
308 */
309 int cntbias = 0;
310 int bias_count = 0;
311 for (unsigned int j = 0U; (int)j < f3d.row[f3d.col + 1]; j++) {
312 tndarray[cntndarray].snames[j] = GENMALLOC(1 * sizeof(char[MAX_NAME_CHARS]));
313 strlcpy(tndarray[cntndarray].snames[j], f3d.fnamefifo[f3d.col + 1][j], MAX_NAME_CHARS);
314 tndarray[cntndarray].nname[j] = GENMALLOC(1 * sizeof(char[MAX_NAME_CHARS]));
315 strlcpy(tndarray[cntndarray].nname[j], f3d.nnfifo[f3d.col + 1][j], MAX_NAME_CHARS);
316 tndarray[cntndarray].biases[j] = f3d.biasfifo[f3d.col + 1][j];
317 cntbias += tndarray[cntndarray].biases[j];
318 if (strcmp(tndarray[cntndarray].snames[j], "none") != 0) {
319 strlcpy(tndarray[cntndarray].snames[j], f3d.fnamefifo[f3d.col + 1][j], MAX_NAME_CHARS);
320 tndarray[cntndarray].norcall[j] = 0;
321 tndarray[cntndarray].treenodes[j] = nrnode;
322 } else {
323 tndarray[cntndarray].norcall[j] = 1;
324 tndarray[cntndarray].treenodes[j] = tndarray[treenodetrack];
325 treenodetrack++;
326 }
327 }
328
329 tndarray[cntndarray].biasent = cntbias;
330 tndarray[cntndarray].biasarray = GENMALLOC((tndarray[cntndarray].biasent) * sizeof(int));
331 for (unsigned int j = 0U; j < tndarray[cntndarray].entries; j++) {
332 for (unsigned int i = 0U; i < tndarray[cntndarray].biases[j]; i++) {
333 tndarray[cntndarray].biasarray[bias_count] = j;
334 bias_count++;
335 }
336 }
337
338 /*
339 * Free memory of old bias tree
340 */
341 if (cntndarray > 0) {
342 for (unsigned int j = 0U; (int)j < cntndarray; j++) {
343 for (unsigned int i = 0U;
344 (int)i < ndarray[j].entries;
345 i++) {
346 GENFREE(ndarray[j].snames[i]);
347 GENFREE(ndarray[j].nname[i]);
348 }
349 GENFREE(ndarray[j].biases);
350 GENFREE(ndarray[j].norcall);
351 GENFREE(ndarray[j].biasarray);
352 GENFREE(ndarray[j].snames);
353 GENFREE(ndarray[j].nname);
354 GENFREE(ndarray[j].treenodes);
355 }
356 GENFREE(ndarray);
357 }
358
359 /*
360 * Move pointers to new bias tree to current tree
361 */
362 ndarray = tndarray;
363 cntndarray++;
364
365 /*
366 * Free raw data
367 */
368 for (unsigned int j = 0U; (int)j < f3d.row[f3d.col + 1]; j++) {
369 GENFREE(f3d.nnfifo[f3d.col + 1][j]);
370 GENFREE(f3d.fnamefifo[f3d.col + 1][j]);
371 }
372 GENFREE(f3d.nnfifo[f3d.col + 1]);
373 GENFREE(f3d.fnamefifo[f3d.col + 1]);
374 GENFREE(f3d.biasfifo[f3d.col + 1]);
375 f3d.curr_col -= 1;
376 }
377 }
378
379 /*
380 * Ending device tree file and freeing raw data
381 */
382 if (fdt32_to_cpu(rval) == 9) {
383 for (unsigned int i = 0U; (int)i < f3d.col; i++) {
384 for (unsigned int j = 0U; (int)j < f3d.row[i]; j++) {
385 GENFREE(f3d.nnfifo[i][j]);
386 GENFREE(f3d.fnamefifo[i][j]);
387 }
388 GENFREE(f3d.nnfifo[i]);
389 GENFREE(f3d.fnamefifo[i]);
390 GENFREE(f3d.biasfifo[i]);
391 }
392 GENFREE(f3d.nnfifo);
393 GENFREE(f3d.fnamefifo);
394 GENFREE(f3d.biasfifo);
395 GENFREE(f3d.row);
396 dtdone = 1;
397 }
398 }
399
400
401 *casz = cntndarray;
402 return ndarray;
403}
404
405/*
johpow01d5c79cc2021-06-23 16:10:22 -0500406 * Function executes a single SMC fuzz test instance with a supplied seed.
Mark Dykese7810b52020-06-03 15:46:55 -0500407 */
johpow01d5c79cc2021-06-23 16:10:22 -0500408test_result_t smc_fuzzing_instance(uint32_t seed)
Mark Dykese7810b52020-06-03 15:46:55 -0500409{
410 /*
411 * Setting up malloc block parameters
412 */
413 tmod.memptr = (void *)tmod.memory;
414 tmod.memptrend = (void *)tmod.memory;
415 tmod.maxmemblk = ((TOTALMEMORYSIZE / BLKSPACEDIV) / sizeof(struct memblk));
416 tmod.nmemblk = 1;
417 tmod.memptr->address = 0U;
418 tmod.memptr->size = TOTALMEMORYSIZE - (TOTALMEMORYSIZE / BLKSPACEDIV);
419 tmod.memptr->valid = 1;
420 tmod.mallocdeladd[0] = 0U;
421 tmod.precblock[0] = (void *)tmod.memory;
422 tmod.trailblock[0] = NULL;
423 tmod.cntdeladd = 0U;
424 tmod.ptrmemblkqueue = 0U;
425 tmod.mallocdeladd_queue_cnt = 0U;
426 tmod.checkadd = 1U;
427 tmod.checknumentries = 0U;
428 tmod.memerror = 0U;
429 struct memmod *mmod;
430 mmod = &tmod;
431 int cntndarray;
432 struct rand_smc_node *tlnode;
433
434 /*
435 * Creating SMC bias tree
436 */
437 struct rand_smc_node *ndarray = createsmctree(&cntndarray, &tmod);
438
439 if (tmod.memerror != 0) {
440 return TEST_RESULT_FAIL;
441 }
442
443 /*
johpow01d5c79cc2021-06-23 16:10:22 -0500444 * Initialize pseudo random number generator with supplied seed.
Mark Dykese7810b52020-06-03 15:46:55 -0500445 */
johpow01d5c79cc2021-06-23 16:10:22 -0500446 srand(seed);
Mark Dykese7810b52020-06-03 15:46:55 -0500447
448 /*
449 * Code to traverse the bias tree and select function based on the biaes within
450 *
451 * The algorithm starts with the first node to pull up the biasarray. The
452 * array is specified as a series of values that reflect the bias of the nodes
453 * in question. So for instance if there are three nodes with a bias of 2,5,7
454 * the biasarray would have the following constituency:
455 *
456 * 0,0,1,1,1,1,1,2,2,2,2,2,2,2.
457 *
458 * Mapping 0 as node 1, 1 as node 2, and 2 as node 3.
459 * The biasent variable contains the count of the size of the biasarray which
460 * provides the input for random selection. This is subsequently applied as an
461 * index to the biasarray. The selection pulls up the node and then is checked
462 * for whether it is a leaf or tree node using the norcall variable.
463 * If it is a leaf then the bias tree traversal ends with an SMC call.
464 * If it is a tree node then the process begins again with
465 * another loop to continue the process of selection until an eventual leaf
466 * node is found.
467 */
johpow01d5c79cc2021-06-23 16:10:22 -0500468 for (unsigned int i = 0U; i < SMC_FUZZ_CALLS_PER_INSTANCE; i++) {
Mark Dykese7810b52020-06-03 15:46:55 -0500469 tlnode = &ndarray[cntndarray - 1];
470 int nd = 0;
471 while (nd == 0) {
472 int nch = rand()%tlnode->biasent;
473 int selent = tlnode->biasarray[nch];
474 if (tlnode->norcall[selent] == 0) {
475 runtestfunction(tlnode->snames[selent]);
476 nd = 1;
477 } else {
478 tlnode = &tlnode->treenodes[selent];
479 }
480 }
481 }
482
483 /*
484 * End of test SMC selection and freeing of nodes
485 */
486 if (cntndarray > 0) {
487 for (unsigned int j = 0U; j < cntndarray; j++) {
488 for (unsigned int i = 0U; i < ndarray[j].entries; i++) {
489 GENFREE(ndarray[j].snames[i]);
490 GENFREE(ndarray[j].nname[i]);
491 }
492 GENFREE(ndarray[j].biases);
493 GENFREE(ndarray[j].norcall);
494 GENFREE(ndarray[j].biasarray);
495 GENFREE(ndarray[j].snames);
496 GENFREE(ndarray[j].nname);
497 GENFREE(ndarray[j].treenodes);
498 }
499 GENFREE(ndarray);
500 }
501
502 return TEST_RESULT_SUCCESS;
503}
johpow01d5c79cc2021-06-23 16:10:22 -0500504
505/*
506 * Top of SMC fuzzing module
507 */
508test_result_t smc_fuzzing_top(void)
509{
510 /* These SMC_FUZZ_x macros are supplied by the build system. */
511 test_result_t results[SMC_FUZZ_INSTANCE_COUNT];
512 uint32_t seeds[SMC_FUZZ_INSTANCE_COUNT] = {SMC_FUZZ_SEEDS};
513 test_result_t result = TEST_RESULT_SUCCESS;
514 unsigned int i;
515
516 /* Run each instance. */
517 for (i = 0U; i < SMC_FUZZ_INSTANCE_COUNT; i++) {
518 printf("Starting SMC fuzz test with seed 0x%x\n", seeds[i]);
519 results[i] = smc_fuzzing_instance(seeds[i]);
520 }
521
522 /* Report successes and failures. */
523 printf("SMC Fuzz Test Results Summary\n");
524 for (i = 0U; i < SMC_FUZZ_INSTANCE_COUNT; i++) {
525 /* Display instance number. */
526 printf(" Instance #%d\n", i);
527
528 /* Print test results. */
529 printf(" Result: ");
530 if (results[i] == TEST_RESULT_SUCCESS) {
531 printf("SUCCESS\n");
532 } else if (results[i] == TEST_RESULT_FAIL) {
533 printf("FAIL\n");
534 /* If we got a failure, update the result value. */
535 result = TEST_RESULT_FAIL;
536 } else if (results[i] == TEST_RESULT_SKIPPED) {
537 printf("SKIPPED\n");
538 }
539
540 /* Print seed used */
541 printf(" Seed: 0x%x\n", seeds[i]);
542 }
543
544 /*
545 * Print out the smc fuzzer parameters so this test can be replicated.
546 */
547 printf("SMC fuzz build parameters to recreate this test:\n");
548 printf(" SMC_FUZZ_INSTANCE_COUNT=%u\n",
549 SMC_FUZZ_INSTANCE_COUNT);
550 printf(" SMC_FUZZ_CALLS_PER_INSTANCE=%u\n",
551 SMC_FUZZ_CALLS_PER_INSTANCE);
552 printf(" SMC_FUZZ_SEEDS=0x%x", seeds[0]);
553 for (i = 1U; i < SMC_FUZZ_INSTANCE_COUNT; i++) {
554 printf(",0x%x", seeds[i]);
555 }
556 printf("\n");
557
558 return result;
559}