source: mainline/uspace/lib/ofw/src/ofw.c

Last change on this file was 4d58bac, checked in by Jiri Svoboda <jiri@…>, 21 months ago

Library and utility for printing OpenFirmware device tree

  • Property mode set to 100644
File size: 7.1 KB
Line 
1/*
2 * Copyright (c) 2023 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup libofw
30 * @{
31 */
32/**
33 * @file OpenFirmware device tree access
34 */
35
36#include <assert.h>
37#include <errno.h>
38#include <ofw.h>
39#include <stdio.h>
40#include <stdlib.h>
41#include <str.h>
42#include <sysinfo.h>
43
44/** Convert OpenFirmware path to sysinfo path.
45 *
46 * @param ofwpath OpenFirmware path
47 * @param sipath place to store pointer to newly allocated sysinfo path
48 * @return EOK on success, ENOMEM if out of memory
49 */
50static errno_t ofw_path_to_sipath(const char *ofwpath, char **sipath)
51{
52 int rv;
53 size_t size;
54 size_t i;
55
56 if (str_cmp(ofwpath, "/") == 0)
57 ofwpath = "";
58
59 /* Append path to firmware.ofw */
60 rv = asprintf(sipath, "firmware.ofw%s", ofwpath);
61 if (rv < 0)
62 return ENOMEM;
63
64 /* Replace '/' with '.' */
65 size = str_size(*sipath);
66 for (i = 0; i < size; i++)
67 if ((*sipath)[i] == '/')
68 (*sipath)[i] = '.';
69
70 return EOK;
71}
72
73/** Initialize child iterator with first child entry.
74 *
75 * Initialize the child iterator and make it point to the first child
76 * of the specified OpenFirmware device node.
77 *
78 * @param it Child iterator to initialize
79 * @param ofwpath OpenFirmware path of the parent node
80 */
81errno_t ofw_child_it_first(ofw_child_it_t *it, const char *ofwpath)
82{
83 errno_t rc;
84 char *sipath = NULL;
85
86 it->ofwpath = NULL;
87 it->keys = NULL;
88 it->keys_sz = 0;
89 it->pos = 0;
90
91 rc = ofw_path_to_sipath(ofwpath, &sipath);
92 if (rc != EOK)
93 goto error;
94
95 if (str_cmp(ofwpath, "/") == 0) {
96 it->ofwpath = str_dup("");
97 } else {
98 it->ofwpath = str_dup(ofwpath);
99 }
100
101 if (it->ofwpath == NULL) {
102 rc = ENOMEM;
103 goto error;
104 }
105
106 it->keys = sysinfo_get_keys(sipath, &it->keys_sz);
107 if (it->keys == NULL) {
108 rc = ENOENT;
109 goto error;
110 }
111
112 return EOK;
113error:
114 if (sipath != NULL)
115 free(sipath);
116
117 if (it->ofwpath != NULL) {
118 free(it->ofwpath);
119 it->ofwpath = NULL;
120 }
121
122 return rc;
123}
124
125/** Move child iterator to the next child.
126 *
127 * @param it Child iterator
128 */
129void ofw_child_it_next(ofw_child_it_t *it)
130{
131 size_t adj;
132
133 assert(!ofw_child_it_end(it));
134
135 adj = str_nsize(it->keys + it->pos, it->keys_sz - it->pos) + 1;
136 assert(it->pos + adj <= it->keys_sz);
137 it->pos += adj;
138}
139
140/** Determine if there are no more child nodes.
141 *
142 * @param it Child iterator
143 * @return @c true iff iterator is beyond the last entry
144 */
145bool ofw_child_it_end(ofw_child_it_t *it)
146{
147 return it->pos >= it->keys_sz;
148}
149
150/** Get child name from iterator.
151 *
152 * @param it Child iterator
153 * @return Child name (valid until next operation on @a it
154 */
155const char *ofw_child_it_get_name(ofw_child_it_t *it)
156{
157 assert(!ofw_child_it_end(it));
158 return it->keys + it->pos;
159}
160
161/** Get child path from iterator.
162 *
163 * @param it Child iterator
164 * @param rpath Place to store pointer to allocated OpenFirmware path
165 * @return @c EOK on success or an error code
166 */
167errno_t ofw_child_it_get_path(ofw_child_it_t *it, char **rpath)
168{
169 const char *name;
170 int rv;
171
172 assert(!ofw_child_it_end(it));
173 name = ofw_child_it_get_name(it);
174
175 rv = asprintf(rpath, "%s/%s", it->ofwpath, name);
176 if (rv < 0)
177 return ENOMEM;
178
179 return EOK;
180}
181
182/** Finalize child iterator.
183 *
184 * This must be called after using a child iterator.
185 *
186 * @param it Child iterator
187 */
188void ofw_child_it_fini(ofw_child_it_t *it)
189{
190 free(it->ofwpath);
191 free(it->keys);
192 it->keys = NULL;
193 it->keys_sz = 0;
194}
195
196/** Initialize property iterator with property.
197 *
198 * Initialize the property iterator and make it point to the first property
199 * of the specified OpenFirmware device node.
200 *
201 * @param it Property iterator to initialize
202 * @param ofwpath OpenFirmware path of the node
203 */
204errno_t ofw_prop_it_first(ofw_prop_it_t *it, const char *ofwpath)
205{
206 errno_t rc;
207 char *sipath;
208
209 it->data = NULL;
210 it->data_sz = 0;
211 it->pos = 0;
212
213 rc = ofw_path_to_sipath(ofwpath, &sipath);
214 if (rc != EOK)
215 goto error;
216
217 it->data = sysinfo_get_data(sipath, &it->data_sz);
218 if (it->data == NULL) {
219 rc = ENOENT;
220 goto error;
221 }
222
223 return EOK;
224error:
225 if (sipath != NULL)
226 free(sipath);
227 return rc;
228}
229
230/** Move property iterator to the next property.
231 *
232 * @param it Child iterator
233 */
234void ofw_prop_it_next(ofw_prop_it_t *it)
235{
236 size_t cur_size;
237 size_t value_size;
238
239 cur_size = str_nsize(it->data + it->pos, it->data_sz - it->pos);
240 if (((char *) it->data)[it->pos + cur_size] != 0)
241 return;
242
243 it->pos += cur_size + 1;
244
245 /* Process value size */
246 memcpy(&value_size, it->data + it->pos, sizeof(value_size));
247
248 it->pos += sizeof(value_size);
249 if ((it->pos >= it->data_sz) || (it->pos + value_size > it->data_sz))
250 return;
251
252 it->pos += value_size;
253}
254
255/** Determine if there are no more properties.
256 *
257 * @param it Property iterator
258 * @return @c true iff iterator is beyond the last entry
259 */
260bool ofw_prop_it_end(ofw_prop_it_t *it)
261{
262 return it->pos >= it->data_sz;
263}
264
265/** Get property name from iterator.
266 *
267 * @param it Child iterator
268 * @return Property name (valid until next operation on @a it
269 */
270const char *ofw_prop_it_get_name(ofw_prop_it_t *it)
271{
272 assert(!ofw_prop_it_end(it));
273 return it->data + it->pos;
274}
275
276/** Get property data from iterator.
277 *
278 * @param it Property iterator
279 * @param rsize Place to store size of data
280 * @return Pointer to data
281 */
282const void *ofw_prop_it_get_data(ofw_prop_it_t *it, size_t *rsize)
283{
284 size_t cur_size;
285 size_t value_size;
286 size_t pos;
287
288 assert(!ofw_prop_it_end(it));
289 pos = it->pos;
290
291 cur_size = str_nsize(it->data + pos, it->data_sz - pos);
292 if (((char *) it->data)[pos + cur_size] != 0)
293 return NULL;
294
295 pos += cur_size + 1;
296
297 /* Process value size */
298 memcpy(&value_size, it->data + pos, sizeof(value_size));
299 pos += sizeof(value_size);
300
301 *rsize = value_size;
302 return it->data + pos;
303}
304
305/** Finalize property iterator.
306 *
307 * This must be called after using a child iterator.
308 *
309 * @param it Child iterator
310 */
311void ofw_prop_it_fini(ofw_prop_it_t *it)
312{
313 free(it->data);
314 it->data = NULL;
315 it->data_sz = 0;
316 it->pos = 0;
317}
318
319/** @}
320 */
Note: See TracBrowser for help on using the repository browser.