source: mainline/boot/genarch/ofw_tree.c@ 0832b4d

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 0832b4d was 0832b4d, checked in by Jakub Jermar <jakub@…>, 17 years ago

OpenBIOS's nextprop is more sensitive than the OBP version.
Use two char arrays instead of one when determining the number of node's
properties.

—This line,
and those below, will be ignored—

M genarch/ofw_tree.c

  • Property mode set to 100644
File size: 7.0 KB
Line 
1/*
2 * Copyright (c) 2006 Jakub Jermar
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#include <ofw_tree.h>
30#include <ofw.h>
31#include <types.h>
32#include <string.h>
33#include <balloc.h>
34#include <asm.h>
35
36#define MAX_PATH_LEN 256
37
38static ofw_tree_node_t *ofw_tree_node_alloc(void)
39{
40 return balloc(sizeof(ofw_tree_node_t), sizeof(ofw_tree_node_t));
41}
42
43static ofw_tree_property_t *ofw_tree_properties_alloc(unsigned count)
44{
45 return balloc(count * sizeof(ofw_tree_property_t), sizeof(ofw_tree_property_t));
46}
47
48static void * ofw_tree_space_alloc(size_t size)
49{
50 char *addr;
51
52 /*
53 * What we do here is a nasty hack :-)
54 * Problem: string property values that are allocated via this
55 * function typically do not contain the trailing '\0'. This
56 * is very uncomfortable for kernel, which is supposed to deal
57 * with the properties.
58 * Solution: when allocating space via this function, we always
59 * allocate space for the extra '\0' character that we store
60 * behind the requested memory.
61 */
62 addr = balloc(size + 1, size);
63 if (addr)
64 addr[size] = '\0';
65 return addr;
66}
67
68/** Transfer information from one OpenFirmware node into its memory representation.
69 *
70 * Transfer entire information from the OpenFirmware device tree 'current' node to
71 * its memory representation in 'current_node'. This function recursively processes
72 * all node's children. Node's peers are processed iteratively in order to prevent
73 * stack from overflowing.
74 *
75 * @param current_node Pointer to uninitialized ofw_tree_node structure that will
76 * become the memory represenation of 'current'.
77 * @param parent_node Parent ofw_tree_node structure or NULL in case of root node.
78 * @param current OpenFirmware phandle to the current device tree node.
79 */
80static void ofw_tree_node_process(ofw_tree_node_t *current_node,
81 ofw_tree_node_t *parent_node, phandle current)
82{
83 static char path[MAX_PATH_LEN+1];
84 static char name[OFW_TREE_PROPERTY_MAX_NAMELEN];
85 static char name2[OFW_TREE_PROPERTY_MAX_NAMELEN];
86 phandle peer;
87 phandle child;
88 size_t len;
89 int i;
90
91 while (current_node) {
92 /*
93 * Initialize node.
94 */
95 current_node->parent = parent_node;
96 current_node->peer = NULL;
97 current_node->child = NULL;
98 current_node->node_handle = current;
99 current_node->properties = 0;
100 current_node->property = NULL;
101 current_node->device = NULL;
102
103 /*
104 * Get the disambigued name.
105 */
106 len = ofw_package_to_path(current, path, MAX_PATH_LEN);
107 if (len == -1)
108 return;
109
110 path[len] = '\0';
111 for (i = len - 1; i >= 0 && path[i] != '/'; i--)
112 ;
113 i++; /* do not include '/' */
114
115 len -= i;
116
117 /* add space for trailing '\0' */
118 current_node->da_name = ofw_tree_space_alloc(len + 1);
119 if (!current_node->da_name)
120 return;
121
122 memcpy(current_node->da_name, &path[i], len);
123 current_node->da_name[len] = '\0';
124
125 /*
126 * Recursively process the potential child node.
127 */
128 child = ofw_get_child_node(current);
129 if (child != 0 && child != -1) {
130 ofw_tree_node_t *child_node;
131
132 child_node = ofw_tree_node_alloc();
133 if (child_node) {
134 ofw_tree_node_process(child_node, current_node, child);
135 current_node->child = child_node;
136 }
137 }
138
139 /*
140 * Count properties.
141 */
142 name[0] = '\0';
143 while (ofw_next_property(current, name, name2) == 1) {
144 current_node->properties++;
145 memcpy(name, name2, OFW_TREE_PROPERTY_MAX_NAMELEN);
146 }
147
148 if (!current_node->properties)
149 return;
150
151 /*
152 * Copy properties.
153 */
154 current_node->property = ofw_tree_properties_alloc(current_node->properties);
155 if (!current_node->property)
156 return;
157
158 name[0] = '\0';
159 for (i = 0; ofw_next_property(current, name, name2) == 1; i++) {
160 size_t size;
161
162 if (i == current_node->properties)
163 break;
164
165 memcpy(name, name2, OFW_TREE_PROPERTY_MAX_NAMELEN);
166 memcpy(current_node->property[i].name, name,
167 OFW_TREE_PROPERTY_MAX_NAMELEN);
168 current_node->property[i].name[OFW_TREE_PROPERTY_MAX_NAMELEN] = '\0';
169
170 size = ofw_get_proplen(current, name);
171 current_node->property[i].size = size;
172 if (size) {
173 void *buf;
174
175 buf = ofw_tree_space_alloc(size);
176 if (current_node->property[i].value = buf) {
177 /*
178 * Copy property value to memory node.
179 */
180 (void) ofw_get_property(current, name, buf, size);
181 }
182 } else {
183 current_node->property[i].value = NULL;
184 }
185 }
186
187 current_node->properties = i; /* Just in case we ran out of memory. */
188
189 /*
190 * Iteratively process the next peer node.
191 * Note that recursion is a bad idea here.
192 * Due to the topology of the OpenFirmware device tree,
193 * the nesting of peer nodes could be to wide and the
194 * risk of overflowing the stack is too real.
195 */
196 peer = ofw_get_peer_node(current);
197 if (peer != 0 && peer != -1) {
198 ofw_tree_node_t *peer_node;
199
200 peer_node = ofw_tree_node_alloc();
201 if (peer_node) {
202 current_node->peer = peer_node;
203 current_node = peer_node;
204 current = peer;
205 /*
206 * Process the peer in next iteration.
207 */
208 continue;
209 }
210 }
211 /*
212 * No more peers on this level.
213 */
214 break;
215 }
216}
217
218/** Construct memory representation of OpenFirmware device tree.
219 *
220 * @return NULL on failure or pointer to the root node.
221 */
222ofw_tree_node_t *ofw_tree_build(void)
223{
224 ofw_tree_node_t *root;
225 phandle ssm_node;
226 ofw_tree_node_t *ssm;
227
228 root = ofw_tree_node_alloc();
229 if (root)
230 ofw_tree_node_process(root, NULL, ofw_root);
231
232 /*
233 * The firmware client interface does not automatically include the
234 * "ssm" node in the list of children of "/". A nasty yet working
235 * solution is to explicitly stick "ssm" to the OFW tree.
236 */
237 ssm_node = ofw_find_device("/ssm@0,0");
238 if (ssm_node != -1) {
239 ssm = ofw_tree_node_alloc();
240 if (ssm) {
241 ofw_tree_node_process(
242 ssm, root, ofw_find_device("/ssm@0,0"));
243 ssm->peer = root->child;
244 root->child = ssm;
245 }
246 }
247
248 return root;
249}
Note: See TracBrowser for help on using the repository browser.