Update to new config scheme
[deliverable/binutils-gdb.git] / sim / ppc / device_tree.c
CommitLineData
cb7a6892
MM
1/* This file is part of the program psim.
2
3 Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19 */
20
21
22#ifndef _DEVICE_TREE_C_
23#define _DEVICE_TREE_C_
24
25#ifndef STATIC_INLINE_DEVICE_TREE
26#define STATIC_INLINE_DEVICE_TREE STATIC_INLINE
27#endif
28
29#include <string.h>
30
31#include "basics.h"
32#include "device_tree.h"
33#include "devices.h"
34
35#include "bfd.h"
36
37enum { clayton_memory_size = 0x100000 };
38
39/* insert the address into the device_nodes sorted list of addresses */
40INLINE_DEVICE_TREE void
41device_node_add_address(device_node *node,
42 unsigned_word lower_bound,
43 unsigned size,
44 device_access access,
45 void *init)
46{
47 unsigned_word upper_bound = lower_bound + size;
48 device_address *new_address;
49 device_address **current_address;
50
51 /* find the insertion point */
52 current_address = &node->addresses;
53 while (*current_address != NULL
54 && (*current_address)->upper_bound >= upper_bound) {
55 current_address = &(*current_address)->next_address;
56 }
57
58 /* insert */
59 new_address = ZALLOC(device_address);
60 new_address->lower_bound = lower_bound;
61 new_address->upper_bound = lower_bound + size;
62 new_address->size = size;
63 new_address->access = access;
64 new_address->init = init;
65 new_address->next_address = *current_address;
66 *current_address = new_address;
67}
68
69
70/* create a new device tree optionally making it a child of the parent
71 node */
72
73INLINE_DEVICE_TREE device_node *
74device_node_create(device_node *parent,
75 char *name,
76 device_type type,
77 device_callbacks *callbacks,
78 void *data)
79{
80 device_node *new_node;
81 new_node = ZALLOC(device_node);
82 new_node->parent = parent;
83 new_node->name = name;
84 new_node->type = type;
85 new_node->callbacks = callbacks;
86 new_node->data = data;
87 if (parent != NULL) {
88 new_node->sibling = parent->children;
89 parent->children = new_node;
90 }
91 return new_node;
92}
93
94
95/* Binary file:
96
97 The specified file is a binary, assume VEA is required, construct a
98 fake device tree based on the addresses of the text / data segments
99 requested by the binary */
100
101
102/* Update the fake device tree so that memory is allocated for this
103 section */
104STATIC_INLINE_DEVICE_TREE void
105update_memory_node_for_section(bfd *abfd,
106 asection *the_section,
107 PTR obj)
108{
109 unsigned_word section_vma;
110 unsigned_word section_size;
111 device_access section_access;
112 void *section_init;
113 device_node *memory = (device_node*)obj;
114
115 /* skip the section if no memory to allocate */
116 if (! (bfd_get_section_flags(abfd, the_section) & SEC_ALLOC))
117 return;
118
119 /* check/ignore any sections of size zero */
120 section_size = bfd_get_section_size_before_reloc(the_section);
121 if (section_size == 0)
122 return;
123
124 /* find where it is to go */
125 section_vma = bfd_get_section_vma(abfd, the_section);
126
127 TRACE(trace_device_tree,
128 ("name=%-7s, vma=0x%.8x, size=%6d, flags=%3x(%s%s%s%s )\n",
129 bfd_get_section_name(abfd, the_section),
130 section_vma, section_size,
131 bfd_get_section_flags(abfd, the_section),
132 bfd_get_section_flags(abfd, the_section) & SEC_LOAD ? " LOAD" : "",
133 bfd_get_section_flags(abfd, the_section) & SEC_CODE ? " CODE" : "",
134 bfd_get_section_flags(abfd, the_section) & SEC_DATA ? " DATA" : "",
135 bfd_get_section_flags(abfd, the_section) & SEC_ALLOC ? " ALLOC" : "",
136 bfd_get_section_flags(abfd, the_section) & SEC_READONLY ? " READONLY" : ""
137 ));
138
139 if (bfd_get_section_flags(abfd, the_section) & SEC_LOAD) {
140 section_init = zalloc(section_size);
141 if (!bfd_get_section_contents(abfd,
142 the_section,
143 section_init, 0,
144 section_size)) {
145 bfd_perror("core:load_section()");
146 error("load of data failed");
147 return;
148 }
149 }
150 else {
151 section_init = NULL;
152 }
153
154 /* determine the devices access */
155 if (bfd_get_section_flags(abfd, the_section) & SEC_CODE)
156 section_access = (device_is_readable | device_is_executable);
157 else if (bfd_get_section_flags(abfd, the_section) & SEC_READONLY)
158 section_access = device_is_readable;
159 else
160 section_access = (device_is_readable | device_is_writeable);
161
162 /* find our memory and add this section to its list of addresses */
163 device_node_add_address(memory,
164 section_vma,
165 section_size,
166 section_access,
167 section_init);
168}
169
170
171/* construct the device tree from the executable */
172
173STATIC_INLINE_DEVICE_TREE device_node *
174create_option_device_node(device_node *root,
175 bfd *image)
176{
177 device_node *option_node;
178
179 /* the option node and than its members */
180 option_node = device_node_create(root, "options", options_device,
181 NULL, NULL);
182
183 /* which endian are we ? */
184 device_node_create(option_node,
185 "little-endian?",
186 boolean_type_device,
187 NULL,
188 (void*)(image->xvec->byteorder_big_p ? 0 : -1));
189
190 /* what is the initial entry point */
191 device_node_create(option_node,
192 "program-counter",
193 integer_type_device,
194 NULL,
195 (void*)(bfd_get_start_address(image)));
196
197 /* address of top of boot stack */
198 TRACE(trace_tbd, ("create_optioin_device_node() - TBD - NT/OpenBoot?\n"));
199 device_node_create(option_node,
200 "stack-pointer",
201 integer_type_device,
202 NULL,
203 (void*)(bfd_get_start_address(image) == 0
204 ? clayton_memory_size /* OEA */
205 : (image->xvec->flavour == bfd_target_elf_flavour
206 ? 0xe0000000 /* elf */
207 : 0x20000000 /* xcoff */)));
208
209 /* execution environment */
210 device_node_create(option_node,
211 "vea?",
212 boolean_type_device,
213 NULL,
214 (void*)(bfd_get_start_address(image) == 0
215 ? 0
216 : -1));
217
218 /* what type of binary */
219 TRACE(trace_tbd, ("create_optioin_device_node() - TBD - NT/OpenBoot?\n"));
220 device_node_create(option_node,
221 "elf?",
222 boolean_type_device,
223 NULL,
224 (void*)(image->xvec->flavour == bfd_target_elf_flavour
225 ? -1 /* elf binary */
226 : 0 /* probably aix binary */));
227
228 /* must all memory transfers be naturally aligned? */
229 device_node_create(option_node,
230 "aligned?",
231 boolean_type_device,
232 NULL,
233 (void*)((WITH_ALIGNMENT == NONSTRICT_ALIGNMENT
234 || image->xvec->byteorder_big_p
235 || bfd_get_start_address(image) != 0)
236 ? 0
237 : -1));
238
239
240 return option_node;
241}
242
243
244/* clatyon is a simple machine that does not require interrupts or any
245 thing else */
246
247STATIC_INLINE_DEVICE_TREE device_node *
248create_clayton_device_tree(bfd *image)
249{
250 device_node *root;
251 device_node *io_node;
252 device_node *data_node;
253 device_node *memory_node;
254
255 /* the root */
256 root = ZALLOC(device_node);
257
258 /* memory - clayton has 2mb of RAM at location 0 */
259 memory_node = device_node_create(root,
260 "memory",
261 memory_device,
262 NULL,
263 NULL);
264 device_node_add_address(memory_node, 0x0, clayton_memory_size,
265 (device_is_readable
266 | device_is_writeable
267 | device_is_executable),
268 NULL);
269
270 /* io address space */
271 io_node = device_node_create(root, "io", bus_device, NULL, NULL);
272
273 /* and IO devices */
274 find_device_descriptor("console")
275 ->creator(io_node, "console@0x400000,0");
276 find_device_descriptor("halt")
277 ->creator(io_node, "halt@0x500000,0");
278 find_device_descriptor("icu")
279 ->creator(io_node, "icu@0x600000,0");
280
281 /* data to load */
282 data_node = device_node_create(root, "image", data_device, NULL, NULL);
283 bfd_map_over_sections(image,
284 update_memory_node_for_section,
285 (PTR)data_node);
286
287 /* options */
288 create_option_device_node(root, image);
289
290 return root;
291}
292
293
294/* user mode executable build up a device tree that reflects this */
295
296STATIC_INLINE_DEVICE_TREE device_node *
297create_vea_device_tree(bfd *image)
298{
299 device_node *root;
300 device_node *memory_node;
301 device_node *option_node;
302
303 /* the root */
304 root = ZALLOC(device_node);
305
306 /* memory */
307 memory_node = device_node_create(root, "memory", memory_device,
308 NULL, NULL);
309 bfd_map_over_sections(image,
310 update_memory_node_for_section,
311 (PTR)memory_node);
312 /* options - only endian so far */
313 option_node = create_option_device_node(root, image);
314
315 return root;
316}
317
318
319/* create a device tree from the specified file */
320INLINE_DEVICE_TREE device_node *
321device_tree_create(const char *file_name)
322{
323 bfd *image;
324 device_node *tree;
325
326 bfd_init(); /* could be redundant but ... */
327
328 /* open the file */
329 image = bfd_openr(file_name, NULL);
330 if (image == NULL) {
331 bfd_perror("open failed:");
332 error("nothing loaded\n");
333 return NULL;
334 }
335
336 /* check it is valid */
337 if (!bfd_check_format(image, bfd_object)) {
338 printf_filtered("create_device_tree() - FIXME - should check more bfd bits\n");
339 printf_filtered("create_device_tree() - %s not an executable, assume device file\n", file_name);
340 bfd_close(image);
341 image = NULL;
342 }
343
344 /* depending on what was found about the file, load it */
345 if (image != NULL) {
346 if (bfd_get_start_address(image) == 0) {
347 TRACE(trace_device_tree, ("create_device_tree() - clayton image\n"));
348 tree = create_clayton_device_tree(image);
349 }
350 else if (bfd_get_start_address(image) > 0) {
351 TRACE(trace_device_tree, ("create_device_tree() - vea image\n"));
352 tree = create_vea_device_tree(image);
353 }
354 bfd_close(image);
355 }
356 else {
357 error("TBD - create_device_tree() text file defining device tree\n");
358 tree = NULL;
359 }
360
361 return tree;
362}
363
364
365/* traverse a device tree applying prefix/postfix functions to it */
366
367INLINE_DEVICE_TREE void
368device_tree_traverse(device_node *root,
369 device_tree_traverse_function *prefix,
370 device_tree_traverse_function *postfix,
371 void *data)
372{
373 device_node *child;
374 if (prefix != NULL)
375 prefix(root, data);
376 for (child = root->children; child != NULL; child = child->sibling) {
377 device_tree_traverse(child, prefix, postfix, data);
378 }
379 if (postfix != NULL)
380 postfix(root, data);
381}
382
383
384/* query the device tree */
385
386INLINE_DEVICE_TREE device_node *
387device_tree_find_node(device_node *root,
388 const char *path)
389{
390 char *chp;
391 int name_len;
392 device_node *child;
393
394 /* strip off any leading `/', `../' or `./' */
395 while (1) {
396 if (strncmp(path, "/", strlen("/")) == 0) {
397 while (root->parent != NULL)
398 root = root->parent;
399 path += strlen("/");
400 }
401 else if (strncmp(path, "./", strlen("./")) == 0) {
402 root = root;
403 path += strlen("./");
404 }
405 else if (strncmp(path, "../", strlen("../")) == 0) {
406 if (root->parent != NULL)
407 root = root->parent;
408 path += strlen("../");
409 }
410 else {
411 break;
412 }
413 }
414
415 /* find the qualified (with @) and unqualified names in the path */
416 chp = strchr(path, '/');
417 name_len = (chp == NULL
418 ? strlen(path)
419 : chp - path);
420
421 /* search through children for a match */
422 for (child = root->children;
423 child != NULL;
424 child = child->sibling) {
425 if (strncmp(path, child->name, name_len) == 0
426 && (strlen(child->name) == name_len
427 || strchr(child->name, '@') == child->name + name_len)) {
428 if (path[name_len] == '\0')
429 return child;
430 else
431 return device_tree_find_node(child, path + name_len + 1);
432 }
433 }
434 return NULL;
435}
436
437INLINE_DEVICE_TREE device_node *device_tree_find_next_node
438(device_node *root,
439 const char *path,
440 device_node *last);
441
442INLINE_DEVICE_TREE signed_word
443device_tree_find_int(device_node *root,
444 const char *path)
445{
446 device_node *int_node = device_tree_find_node(root, path);
447 if (int_node == NULL) {
448 error("device_tree_find_int() - node %s does not exist\n", path);
449 return 0;
450 }
451 else if (int_node->type != integer_type_device) {
452 error("device_tree_find_int() - node %s is not an int\n", path);
453 return 0;
454 }
455 else {
456 return (signed_word)(int_node->data);
457 }
458}
459
460
461INLINE_DEVICE_TREE const char *device_tree_find_string
462(device_node *root,
463 const char *path);
464
465INLINE_DEVICE_TREE int
466device_tree_find_boolean(device_node *root,
467 const char *path)
468{
469 device_node *int_node = device_tree_find_node(root, path);
470 if (int_node == NULL) {
471 error("device_tree_find_boolean() - node %s does not exist\n", path);
472 return 0;
473 }
474 else if (int_node->type != boolean_type_device) {
475 error("device_tree_find_boolean() - node %s is not a boolean\n", path);
476 return 0;
477 }
478 else {
479 return (signed_word)(int_node->data);
480 }
481}
482
483
484INLINE_DEVICE_TREE void *device_tree_find_bytes
485(device_node *root,
486 const char *path);
487
488/* dump out a device node and addresses */
489
490INLINE_DEVICE_TREE void
491device_tree_dump(device_node *device,
492 void *ignore_data_argument)
493{
494 printf_filtered("(device_node@0x%x\n", device);
495 printf_filtered(" (parent 0x%x)\n", device->parent);
496 printf_filtered(" (children 0x%x)\n", device->children);
497 printf_filtered(" (sibling 0x%x)\n", device->sibling);
498 printf_filtered(" (name %s)\n", device->name ? device->name : "(null)");
499 printf_filtered(" (type %d)\n", device->type);
500 printf_filtered(" (handlers 0x%x)\n", device->callbacks);
501 printf_filtered(" (addresses %d)\n", device->addresses);
502 printf_filtered(" (data %d)\n", device->data);
503 printf_filtered(")\n");
504}
505
506#endif /* _DEVICE_TREE_C_ */
This page took 0.041669 seconds and 4 git commands to generate.