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_client_lib"
18
19 #include <binder/RpcSession.h>
20 #include <binder/RpcTransportTipcTrusty.h>
21 #include <endian.h>
22 #include <lib/shared/binder_discover/binder_discover.h>
23 #include <lib/shared/device_tree/device_tree.h>
24 #include <lib/shared/ibinder/macros.h>
25 #include <stdio.h>
26 #include <trusty_log.h>
27 #include <uapi/err.h>
28
29 #include <com/android/trusty/device_tree/IDeviceTree.h>
30
31 #define LOCAL_TRACE (0)
32
33 using android::IBinder;
34 using com::android::trusty::device_tree::IDeviceTree;
35 using com::android::trusty::device_tree::INode;
36 using com::android::trusty::device_tree::INodeIterator;
37 using com::android::trusty::device_tree::IPropIterator;
38 using com::android::trusty::device_tree::Property;
39
40 struct device_tree_idevice_tree {};
41 struct device_tree_iprop_iter {};
42 struct device_tree_inode_iter {};
43 struct device_tree_inode {};
44 struct device_tree_prop {};
45
46 IBINDER_DEFINE_IFACE(IDeviceTree, device_tree_idevice_tree);
47 IBINDER_DEFINE_IFACE(IPropIterator, device_tree_iprop_iter);
48 IBINDER_DEFINE_IFACE(INodeIterator, device_tree_inode_iter);
49 IBINDER_DEFINE_IFACE(INode, device_tree_inode);
50 IBINDER_DEFINE_PARCELABLE(Property, device_tree_prop);
51
device_tree_get_service(device_tree_idevice_tree ** tree)52 int device_tree_get_service(device_tree_idevice_tree** tree) {
53 assert(tree != nullptr);
54
55 android::sp<IBinder> cbinder;
56 const char* port =
57 #if defined(TRUSTY_USERSPACE)
58 IDeviceTree::PORT().c_str();
59 #else
60 IDeviceTree::KERNEL_PORT().c_str();
61 #endif
62 if (int rc = binder_discover_get_service(port, cbinder) != 0) {
63 return rc;
64 }
65 auto bdr = new (std::nothrow) device_tree_idevice_tree_container{
66 IDeviceTree::asInterface(cbinder), {}, 1};
67 if (bdr == nullptr) {
68 return DT_ERROR_NO_MEMORY;
69 }
70 *tree = &bdr->cbinder;
71
72 return android::OK;
73 }
74
from_binder_status(android::binder::Status status)75 static int from_binder_status(android::binder::Status status) {
76 if (status.serviceSpecificErrorCode() != 0) {
77 return status.serviceSpecificErrorCode();
78 }
79
80 // TODO: ensure no overlapping error codes
81 if (!status.isOk()) {
82 return -status.transactionError();
83 }
84
85 return android::OK;
86 }
87
device_tree_idevice_tree_get_compatible_nodes(struct device_tree_idevice_tree * self,const char * compat_str,struct device_tree_inode_iter ** iter)88 int device_tree_idevice_tree_get_compatible_nodes(
89 struct device_tree_idevice_tree* self,
90 const char* compat_str,
91 struct device_tree_inode_iter** iter) {
92 return device_tree_idevice_tree_get_compatible_nodes_from_list(
93 self, &compat_str, 1, iter);
94 }
95
device_tree_idevice_tree_get_compatible_nodes_from_list(struct device_tree_idevice_tree * self,const char ** compat_str_list,size_t num_str,struct device_tree_inode_iter ** iter)96 int device_tree_idevice_tree_get_compatible_nodes_from_list(
97 struct device_tree_idevice_tree* self,
98 const char** compat_str_list,
99 size_t num_str,
100 struct device_tree_inode_iter** iter) {
101 assert(self != nullptr);
102
103 std::vector<std::string> compat(compat_str_list, compat_str_list + num_str);
104 android::sp<INodeIterator> node_iter;
105
106 auto pidevice_tree = device_tree_idevice_tree_to_IDeviceTree(self);
107 auto rc = pidevice_tree->get_compatible_nodes_from_list(compat, &node_iter);
108
109 if (auto err = from_binder_status(rc); err != android::OK) {
110 return err;
111 }
112
113 auto pinode_iter_container = new (std::nothrow)
114 device_tree_inode_iter_container{node_iter, {}, 1};
115 if (pinode_iter_container == nullptr) {
116 return DT_ERROR_NO_MEMORY;
117 }
118 *iter = &pinode_iter_container->cbinder;
119
120 return android::OK;
121 }
122
device_tree_inode_iter_get_next_node(struct device_tree_inode_iter * iter,struct device_tree_inode ** node)123 int device_tree_inode_iter_get_next_node(struct device_tree_inode_iter* iter,
124 struct device_tree_inode** node) {
125 assert(iter != nullptr);
126 assert(node != nullptr);
127
128 android::sp<INode> node_ptr;
129 const auto pinode_iter = device_tree_inode_iter_to_INodeIterator(iter);
130 auto rc = pinode_iter->get_next_node(&node_ptr);
131
132 if (auto err = from_binder_status(rc); err != android::OK)
133 return err;
134
135 auto pinode_container =
136 new (std::nothrow) device_tree_inode_container{node_ptr, {}, 1};
137 if (pinode_container == nullptr) {
138 return DT_ERROR_NO_MEMORY;
139 }
140 *node = &pinode_container->cbinder;
141
142 return android::OK;
143 }
144
device_tree_inode_get_name(struct device_tree_inode * node,const char ** name)145 int device_tree_inode_get_name(struct device_tree_inode* node,
146 const char** name) {
147 assert(node != nullptr);
148 assert(name != nullptr);
149 auto pnode = device_tree_inode_to_INode(node);
150 std::string* node_name = new (std::nothrow) std::string();
151 if (node_name == nullptr) {
152 return DT_ERROR_NO_MEMORY;
153 }
154 auto rc = pnode->get_name(node_name);
155 if (auto err = from_binder_status(rc); err != android::OK)
156 return err;
157
158 *name = node_name->c_str();
159 return android::OK;
160 }
161
device_tree_inode_get_subnode(struct device_tree_inode * parent,const char * subnode_name,struct device_tree_inode ** subnode)162 int device_tree_inode_get_subnode(struct device_tree_inode* parent,
163 const char* subnode_name,
164 struct device_tree_inode** subnode) {
165 assert(parent != nullptr);
166 assert(subnode != nullptr);
167
168 android::sp<INode> node_ptr;
169 std::string node_name(subnode_name);
170
171 const auto pinode = device_tree_inode_to_INode(parent);
172 auto rc = pinode->get_subnode(node_name, &node_ptr);
173
174 if (auto err = from_binder_status(rc); err != android::OK)
175 return err;
176
177 auto pinode_container =
178 new (std::nothrow) device_tree_inode_container{node_ptr, {}, 1};
179 if (pinode_container == nullptr) {
180 return DT_ERROR_NO_MEMORY;
181 }
182 *subnode = &pinode_container->cbinder;
183
184 return android::OK;
185 }
186
device_tree_inode_get_subnodes(struct device_tree_inode * parent,struct device_tree_inode_iter ** iter)187 int device_tree_inode_get_subnodes(struct device_tree_inode* parent,
188 struct device_tree_inode_iter** iter) {
189 assert(parent != nullptr);
190 assert(iter != nullptr);
191
192 android::sp<INodeIterator> node_iter;
193
194 const auto pinode = device_tree_inode_to_INode(parent);
195 auto rc = pinode->get_subnodes(&node_iter);
196 if (auto err = from_binder_status(rc); err != android::OK)
197 return err;
198
199 auto pinode_iter_container = new (std::nothrow)
200 device_tree_inode_iter_container{node_iter, {}, 1};
201 if (pinode_iter_container == nullptr) {
202 return DT_ERROR_NO_MEMORY;
203 }
204 *iter = &pinode_iter_container->cbinder;
205
206 return android::OK;
207 }
208
device_tree_inode_get_prop(struct device_tree_inode * node,const char * name,struct device_tree_prop ** prop)209 int device_tree_inode_get_prop(struct device_tree_inode* node,
210 const char* name,
211 struct device_tree_prop** prop) {
212 assert(node != nullptr);
213 assert(name != nullptr);
214 assert(prop != nullptr);
215
216 std::string property_name(name);
217
218 auto property = new (std::nothrow) Property;
219 if (property == nullptr) {
220 return DT_ERROR_NO_MEMORY;
221 }
222 const auto pinode = device_tree_inode_to_INode(node);
223 auto rc = pinode->get_prop(property_name, property);
224
225 if (auto err = from_binder_status(rc); err != android::OK)
226 return err;
227
228 auto pproperty_container =
229 new (std::nothrow) device_tree_prop_container{property, {}, 1};
230 if (pproperty_container == nullptr) {
231 return DT_ERROR_NO_MEMORY;
232 }
233 *prop = &pproperty_container->cparcel;
234
235 return android::OK;
236 }
237
device_tree_inode_get_props(struct device_tree_inode * node,struct device_tree_iprop_iter ** prop)238 int device_tree_inode_get_props(struct device_tree_inode* node,
239 struct device_tree_iprop_iter** prop) {
240 assert(node != nullptr);
241 assert(prop != nullptr);
242
243 android::sp<IPropIterator> prop_iter;
244 const auto pinode = device_tree_inode_to_INode(node);
245 auto rc = pinode->get_props(&prop_iter);
246
247 if (auto err = from_binder_status(rc); err != android::OK)
248 return err;
249
250 auto piprop_iter_container = new (std::nothrow)
251 device_tree_iprop_iter_container{prop_iter, {}, 1};
252 if (piprop_iter_container == nullptr) {
253 return DT_ERROR_NO_MEMORY;
254 }
255 *prop = &piprop_iter_container->cbinder;
256
257 return android::OK;
258 }
259
device_tree_iprop_iter_get_next_prop(struct device_tree_iprop_iter * iter,struct device_tree_prop ** prop)260 int device_tree_iprop_iter_get_next_prop(struct device_tree_iprop_iter* iter,
261 struct device_tree_prop** prop) {
262 assert(iter != nullptr);
263 assert(prop != nullptr);
264
265 auto property = new (std::nothrow) Property;
266 if (property == nullptr) {
267 return DT_ERROR_NO_MEMORY;
268 }
269
270 const auto piprop_iter = device_tree_iprop_iter_to_IPropIterator(iter);
271 auto rc = piprop_iter->get_next_prop(property);
272
273 if (auto err = from_binder_status(rc); err != android::OK)
274 return err;
275
276 auto pproperty_container =
277 new (std::nothrow) device_tree_prop_container{property, {}, 1};
278 if (pproperty_container == nullptr) {
279 return DT_ERROR_NO_MEMORY;
280 }
281 *prop = &pproperty_container->cparcel;
282 return android::OK;
283 }
284
device_tree_prop_get_name(struct device_tree_prop * prop,const char ** name,size_t * name_len)285 int device_tree_prop_get_name(struct device_tree_prop* prop,
286 const char** name,
287 size_t* name_len) {
288 assert(prop != nullptr);
289 assert(name != nullptr);
290 assert(name_len != nullptr);
291
292 auto pprop = device_tree_prop_to_Property(prop);
293 *name = pprop->name.c_str();
294 *name_len = pprop->name.size();
295 return android::OK;
296 }
297
device_tree_prop_get_value(struct device_tree_prop * prop,uint8_t ** value,size_t * size)298 int device_tree_prop_get_value(struct device_tree_prop* prop,
299 uint8_t** value,
300 size_t* size) {
301 assert(prop != nullptr);
302 assert(value != nullptr);
303 assert(size != nullptr);
304
305 auto pprop = device_tree_prop_to_Property(prop);
306 *size = pprop->value.size();
307 *value = pprop->value.data();
308 return android::OK;
309 }
310
device_tree_prop_get_u32(struct device_tree_prop * prop,uint32_t * value)311 int device_tree_prop_get_u32(struct device_tree_prop* prop, uint32_t* value) {
312 assert(value != nullptr);
313 uint32_t* tmp_ptr = NULL;
314 size_t prop_size;
315 int rc = device_tree_prop_get_value(prop, (uint8_t**)&tmp_ptr, &prop_size);
316 if (rc != android::OK) {
317 return rc;
318 }
319 if (prop_size != sizeof(uint32_t)) {
320 TLOGI("Property is not a u32\n");
321 return DT_ERROR_INVALID_ARGS;
322 }
323 /* Convert from big-endian to little endian and write to output pointer */
324 *value = be32toh(*tmp_ptr);
325 return android::OK;
326 }
327
device_tree_prop_get_u64(struct device_tree_prop * prop,uint64_t * value)328 int device_tree_prop_get_u64(struct device_tree_prop* prop, uint64_t* value) {
329 assert(value != nullptr);
330 uint64_t* tmp_ptr = NULL;
331 size_t prop_size;
332 int rc = device_tree_prop_get_value(prop, (uint8_t**)&tmp_ptr, &prop_size);
333 if (rc != android::OK) {
334 return rc;
335 }
336 if (prop_size != sizeof(uint64_t)) {
337 TLOGI("Property is not a u64\n");
338 return DT_ERROR_INVALID_ARGS;
339 }
340 /* Convert from big-endian to little endian and write to output pointer */
341 *value = be64toh(*tmp_ptr);
342 return android::OK;
343 }
344