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