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