1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2019, Theobroma Systems Design und Consulting GmbH
4  */
5 
6 #include <common.h>
7 #include <command.h>
8 #include <errno.h>
9 #include <fdt_support.h>
10 #include <log.h>
11 #include <malloc.h>
12 #include <tee/optee.h>
13 
14 #include <linux/sizes.h>
15 
16 #include <test/ut.h>
17 #include <test/optee.h>
18 #include <test/suites.h>
19 
20 /* 4k ought to be enough for anybody */
21 #define FDT_COPY_SIZE	(4 * SZ_1K)
22 
23 extern u32 __dtb_test_optee_base_begin;
24 extern u32 __dtb_test_optee_optee_begin;
25 extern u32 __dtb_test_optee_no_optee_begin;
26 
27 static void *fdt;
28 static bool expect_success;
29 
optee_fdt_firmware(struct unit_test_state * uts)30 static int optee_fdt_firmware(struct unit_test_state *uts)
31 {
32 	const void *prop;
33 	int offs, len;
34 
35 	offs = fdt_path_offset(fdt, "/firmware/optee");
36 	ut_assert(expect_success ? offs >= 0 : offs < 0);
37 
38 	/* only continue if we have an optee node */
39 	if (offs < 0)
40 		return CMD_RET_SUCCESS;
41 
42 	prop = fdt_getprop(fdt, offs, "compatible", &len);
43 	ut_assertok(strncmp((const char *)prop, "linaro,optee-tz", len));
44 
45 	prop = fdt_getprop(fdt, offs, "method", &len);
46 	ut_assert(strncmp(prop, "hvc", 3) == 0 || strncmp(prop, "smc", 3) == 0);
47 
48 	return CMD_RET_SUCCESS;
49 }
50 OPTEE_TEST(optee_fdt_firmware, 0);
51 
optee_fdt_protected_memory(struct unit_test_state * uts)52 static int optee_fdt_protected_memory(struct unit_test_state *uts)
53 {
54 	int offs, subnode;
55 	bool found;
56 
57 	offs = fdt_path_offset(fdt, "/firmware/optee");
58 	ut_assert(expect_success ? offs >= 0 : offs < 0);
59 
60 	/* only continue if we have an optee node */
61 	if (offs < 0)
62 		return CMD_RET_SUCCESS;
63 
64 	/* optee inserts its memory regions as reserved-memory nodes */
65 	offs = fdt_subnode_offset(fdt, 0, "reserved-memory");
66 	ut_assert(offs >= 0);
67 
68 	subnode = fdt_first_subnode(fdt, offs);
69 	ut_assert(subnode);
70 
71 	found = 0;
72 	while (subnode >= 0) {
73 		const char *name = fdt_get_name(fdt, subnode, NULL);
74 		struct fdt_resource res;
75 
76 		ut_assert(name);
77 
78 		/* only handle optee reservations */
79 		if (strncmp(name, "optee", 5))
80 			continue;
81 
82 		found = true;
83 
84 		/* check if this subnode has a reg property */
85 		ut_assertok(fdt_get_resource(fdt, subnode, "reg", 0, &res));
86 		subnode = fdt_next_subnode(fdt, subnode);
87 	}
88 
89 	ut_assert(found);
90 
91 	return CMD_RET_SUCCESS;
92 }
93 OPTEE_TEST(optee_fdt_protected_memory, 0);
94 
do_ut_optee(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])95 int do_ut_optee(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
96 {
97 	struct unit_test *tests = UNIT_TEST_SUITE_START(optee_test);
98 	const int n_ents = UNIT_TEST_SUITE_COUNT(optee_test);
99 	struct unit_test_state *uts;
100 	void *fdt_optee = &__dtb_test_optee_optee_begin;
101 	void *fdt_no_optee = &__dtb_test_optee_no_optee_begin;
102 	void *fdt_base = &__dtb_test_optee_base_begin;
103 	int ret = -ENOMEM;
104 
105 	uts = calloc(1, sizeof(*uts));
106 	if (!uts)
107 		return -ENOMEM;
108 
109 	ut_assertok(fdt_check_header(fdt_base));
110 	ut_assertok(fdt_check_header(fdt_optee));
111 	ut_assertok(fdt_check_header(fdt_no_optee));
112 
113 	fdt = malloc(FDT_COPY_SIZE);
114 	if (!fdt)
115 		return ret;
116 
117 	/*
118 	 * Resize the FDT to 4k so that we have room to operate on
119 	 *
120 	 * (and relocate it since the memory might be mapped
121 	 * read-only)
122 	 */
123 	ut_assertok(fdt_open_into(fdt_base, fdt, FDT_COPY_SIZE));
124 
125 	/*
126 	 * (1) Try to copy optee nodes from empty dt.
127 	 * This should still run successfully.
128 	 */
129 	ut_assertok(optee_copy_fdt_nodes(fdt_no_optee, fdt));
130 
131 	expect_success = false;
132 	ret = cmd_ut_category("optee", "", tests, n_ents, argc, argv);
133 
134 	/* (2) Try to copy optee nodes from prefilled dt */
135 	ut_assertok(optee_copy_fdt_nodes(fdt_optee, fdt));
136 
137 	expect_success = true;
138 	ret = cmd_ut_category("optee", "", tests, n_ents, argc, argv);
139 
140 	/* (3) Try to copy OP-TEE nodes into a already filled DT */
141 	ut_assertok(fdt_open_into(fdt_optee, fdt, FDT_COPY_SIZE));
142 	ut_assertok(optee_copy_fdt_nodes(fdt_optee, fdt));
143 
144 	expect_success = true;
145 	ret = cmd_ut_category("optee", "", tests, n_ents, argc, argv);
146 
147 	free(fdt);
148 	return ret;
149 }
150