1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define TLOG_TAG "device_tree_user_test"
18 #define LOCAL_TRACE 0
19 
20 #include <endian.h>
21 #include <lib/shared/device_tree/device_tree.h>
22 #include <lib/unittest/unittest.h>
23 #include <string.h>
24 #include <trusty_unittest.h>
25 #include <uapi/err.h>
26 
27 #define TEST_NODE_COMPAT "google,test_node"
28 
29 typedef struct device_tree_ctxt {
30     struct device_tree_idevice_tree* tree;
31     /* The root test node is not necessarily the rot of the device tree */
32     struct device_tree_inode* root_node;
33 } DeviceTreeTest_t;
34 
TEST_F_SETUP(DeviceTreeTest)35 TEST_F_SETUP(DeviceTreeTest) {
36     struct device_tree_inode_iter* iter = NULL;
37 
38     _state->tree = NULL;
39     int rc = device_tree_get_service(&_state->tree);
40     ASSERT_EQ(rc, NO_ERROR);
41     ASSERT_NE(_state->tree, NULL);
42 
43     /* This is the compatible string of the root test node */
44     const char* root_compat = TEST_NODE_COMPAT;
45     rc = device_tree_idevice_tree_get_compatible_nodes(_state->tree,
46                                                        root_compat, &iter);
47     ASSERT_EQ(rc, NO_ERROR);
48     ASSERT_NE(iter, NULL);
49 
50     rc = device_tree_inode_iter_get_next_node(iter, &_state->root_node);
51     ASSERT_EQ(rc, NO_ERROR);
52     ASSERT_NE(_state->root_node, NULL);
53 
54     /*
55      * The test context stores the device tree interface and the root node so we
56      * shouldn't release those yet
57      */
58 test_abort:
59     if (iter) {
60         device_tree_inode_iter_release(&iter);
61     }
62 }
63 
TEST_F_TEARDOWN(DeviceTreeTest)64 TEST_F_TEARDOWN(DeviceTreeTest) {
65     /* Test setup ensures these aren't null */
66     device_tree_inode_release(&_state->root_node);
67     device_tree_idevice_tree_release(&_state->tree);
68 }
69 
TEST_F(DeviceTreeTest,get_prop)70 TEST_F(DeviceTreeTest, get_prop) {
71     /* Get a property */
72     struct device_tree_prop* prop = NULL;
73     int rc = device_tree_inode_get_prop(_state->root_node, "compatible", &prop);
74     ASSERT_EQ(rc, NO_ERROR);
75     ASSERT_NE(prop, NULL);
76 
77     /* Check that the property's name is correct */
78     const char* prop_name = NULL;
79     size_t len;
80     rc = device_tree_prop_get_name(prop, &prop_name, &len);
81     ASSERT_NE((char*)prop_name, NULL);
82     EXPECT_EQ(rc, NO_ERROR);
83     EXPECT_EQ(strcmp(prop_name, "compatible"), 0);
84     EXPECT_EQ(len, strlen("compatible"));
85 
86     /* Check that the property's value is correct */
87     char* prop_value = NULL;
88     rc = device_tree_prop_get_value(prop, (uint8_t**)&prop_value, &len);
89     ASSERT_NE(prop_value, NULL);
90     EXPECT_EQ(rc, NO_ERROR);
91     EXPECT_EQ(strcmp(prop_value, TEST_NODE_COMPAT), 0);
92     /* Add 1 since string property values include the null-terminator */
93     EXPECT_EQ(len, strlen(TEST_NODE_COMPAT) + 1);
94 
95 test_abort:
96     if (prop) {
97         device_tree_prop_release(&prop);
98     }
99 }
100 
TEST_F(DeviceTreeTest,get_node)101 TEST_F(DeviceTreeTest, get_node) {
102     struct device_tree_inode* node = NULL;
103     struct device_tree_prop* prop = NULL;
104 
105     /* Get a node */
106     int rc = device_tree_inode_get_subnode(_state->root_node, "chosen", &node);
107     ASSERT_EQ(rc, NO_ERROR);
108     ASSERT_NE(node, NULL);
109 
110     /* Get a property in the node */
111     rc = device_tree_inode_get_prop(node, "kaslr-seed", &prop);
112     ASSERT_EQ(rc, NO_ERROR);
113     ASSERT_NE(prop, NULL);
114 
115     /* Check the property's value */
116     uint8_t* prop_value = NULL;
117     size_t len;
118     uint8_t expected_value[] = {0xCA, 0xFE, 0xD0, 0x0D, 0x12, 0x34, 0x56, 0x78};
119     rc = device_tree_prop_get_value(prop, &prop_value, &len);
120     ASSERT_NE(prop_value, NULL);
121     EXPECT_EQ(rc, NO_ERROR);
122     EXPECT_EQ(memcmp(prop_value, &expected_value, 8), 0);
123     EXPECT_EQ(len, 8);
124 
125     /* Check the property's value using the u64 helper */
126     uint64_t prop_value_u64 = 0;
127     rc = device_tree_prop_get_u64(prop, &prop_value_u64);
128     EXPECT_EQ(rc, NO_ERROR);
129     EXPECT_EQ(prop_value_u64, 0xCAFED00D12345678);
130 
131     /* Check that we can't use the u32 helper for a u64 */
132     uint32_t prop_value_u32 = 0;
133     rc = device_tree_prop_get_u32(prop, &prop_value_u32);
134     EXPECT_EQ(rc, DT_ERROR_INVALID_ARGS);
135 
136 test_abort:
137     if (prop) {
138         device_tree_prop_release(&prop);
139     }
140     if (node) {
141         device_tree_inode_release(&node);
142     }
143 }
144 
TEST_F(DeviceTreeTest,iter_props)145 TEST_F(DeviceTreeTest, iter_props) {
146     struct device_tree_inode* node = NULL;
147     struct device_tree_iprop_iter* prop_iter = NULL;
148     struct device_tree_prop* prop = NULL;
149 
150     /* Get a node */
151     int rc = device_tree_inode_get_subnode(_state->root_node, "chosen", &node);
152     ASSERT_EQ(rc, NO_ERROR);
153     ASSERT_NE(node, NULL);
154 
155     /* Get an iterator over the node's properties */
156     rc = device_tree_inode_get_props(node, &prop_iter);
157     ASSERT_EQ(rc, NO_ERROR);
158     ASSERT_NE(prop_iter, NULL);
159 
160     /* Iterate over the properties */
161     const char* expected_prop_names[] = {"kaslr-seed", "bootargs", NULL};
162     int expected_rc[] = {NO_ERROR, NO_ERROR, DT_ERROR_PROP_NOT_FOUND};
163     for (size_t i = 0; i < countof(expected_prop_names); i++) {
164         /* Advance the property iterator */
165         rc = device_tree_iprop_iter_get_next_prop(prop_iter, &prop);
166         ASSERT_EQ(rc, expected_rc[i]);
167 
168         if (rc != NO_ERROR) {
169             /*
170              * prop is only non-null if there is a property, so no need to
171              * release here
172              */
173             continue;
174         }
175         /* If there was a property, check its name */
176         const char* prop_name = NULL;
177         size_t len;
178         ASSERT_NE(prop, NULL);
179         rc = device_tree_prop_get_name(prop, &prop_name, &len);
180         ASSERT_EQ(rc, NO_ERROR);
181         ASSERT_NE((char*)prop_name, NULL);
182         EXPECT_EQ(strcmp(prop_name, expected_prop_names[i]), 0);
183         EXPECT_EQ(len, strlen(expected_prop_names[i]));
184 
185         device_tree_prop_release(&prop);
186     }
187 
188 test_abort:
189     if (prop_iter) {
190         device_tree_iprop_iter_release(&prop_iter);
191     }
192     if (node) {
193         device_tree_inode_release(&node);
194     }
195     if (prop) {
196         device_tree_prop_release(&prop);
197     }
198 }
199 
TEST_F(DeviceTreeTest,iter_nodes)200 TEST_F(DeviceTreeTest, iter_nodes) {
201     struct device_tree_inode_iter* node_iter = NULL;
202     struct device_tree_inode* subnode = NULL;
203     struct device_tree_prop* subnode_prop = NULL;
204 
205     /* Get an iterator over the root node's subnodes */
206     int rc = device_tree_inode_get_subnodes(_state->root_node, &node_iter);
207     ASSERT_EQ(rc, NO_ERROR);
208     ASSERT_NE(node_iter, NULL);
209 
210     /* Iterate over the subnodes */
211     int expected_rc[] = {NO_ERROR, NO_ERROR, DT_ERROR_NODE_NOT_FOUND};
212     const char* subnode_names[] = {"chosen", "interrupt-controller@DEADBEEF",
213                                    NULL};
214     const char* subnode_props[] = {"kaslr-seed", "reg", NULL};
215     for (size_t i = 0; i < countof(subnode_names); i++) {
216         /* Advance the node iterator */
217         rc = device_tree_inode_iter_get_next_node(node_iter, &subnode);
218         ASSERT_EQ(rc, expected_rc[i]);
219 
220         if (rc != NO_ERROR) {
221             /*
222              * subnode_prop is only non-null if there is a property, so no need
223              * to release here
224              */
225             continue;
226         }
227         /* If there was a node, check its name */
228         ASSERT_NE(subnode, NULL);
229         const char* subnode_name = NULL;
230         rc = device_tree_inode_get_name(subnode, &subnode_name);
231         ASSERT_EQ(rc, NO_ERROR);
232         ASSERT_NE((char*)subnode_name, NULL);
233         EXPECT_EQ(strcmp(subnode_name, subnode_names[i]), 0);
234 
235         /* Check for a property that the node is expected to have */
236         rc = device_tree_inode_get_prop(subnode, subnode_props[i],
237                                         &subnode_prop);
238         ASSERT_EQ(rc, NO_ERROR);
239         ASSERT_NE(subnode_prop, NULL);
240 
241         /* Check the property's name */
242         const char* prop_name = NULL;
243         size_t len;
244         rc = device_tree_prop_get_name(subnode_prop, &prop_name, &len);
245         ASSERT_EQ(rc, NO_ERROR);
246         ASSERT_NE((char*)prop_name, NULL);
247         EXPECT_EQ(strcmp(prop_name, subnode_props[i]), 0);
248         EXPECT_EQ(len, strlen(subnode_props[i]));
249 
250         device_tree_prop_release(&subnode_prop);
251         device_tree_inode_release(&subnode);
252     }
253 
254 test_abort:
255     if (node_iter) {
256         device_tree_inode_iter_release(&node_iter);
257     }
258     if (subnode) {
259         device_tree_inode_release(&subnode);
260     }
261     if (subnode_prop) {
262         device_tree_prop_release(&subnode_prop);
263     }
264 }
265 
266 #if defined(TRUSTY_USERSPACE)
267 PORT_TEST(DeviceTreeTest, "com.android.trusty.device_tree.test")
268 #else
269 PORT_TEST(DeviceTreeTest, "com.android.kernel.device_tree.test")
270 #endif
271