1/* The common simulator framework for GDB, the GNU Debugger. 2 3 Copyright 2002-2023 Free Software Foundation, Inc. 4 5 Contributed by Andrew Cagney and Red Hat. 6 7 This file is part of GDB. 8 9 This program is free software; you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation; either version 3 of the License, or 12 (at your option) any later version. 13 14 This program is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 21 22/* This must come before any other includes. */ 23#include "defs.h" 24 25#include <ctype.h> 26#include <stdarg.h> 27#include <stdlib.h> 28#include <string.h> 29 30#include "hw-main.h" 31#include "hw-base.h" 32#include "hw-tree.h" 33 34#include "sim-io.h" 35#include "sim-assert.h" 36 37/* manipulate/lookup device names */ 38 39typedef struct _name_specifier 40{ 41 42 /* components in the full length name */ 43 char *path; 44 char *property; 45 char *value; 46 47 /* current device */ 48 char *family; 49 char *name; 50 char *unit; 51 char *args; 52 53 /* previous device */ 54 char *last_name; 55 char *last_family; 56 char *last_unit; 57 char *last_args; 58 59 /* work area */ 60 char buf[1024]; 61 62} name_specifier; 63 64 65 66/* Given a device specifier, break it up into its main components: 67 path (and if present) property name and property value. */ 68 69static int 70split_device_specifier (struct hw *current, 71 const char *device_specifier, 72 name_specifier *spec) 73{ 74 char *chp = NULL; 75 76 /* expand any leading alias if present */ 77 if (current != NULL 78 && *device_specifier != '\0' 79 && *device_specifier != '.' 80 && *device_specifier != '/') 81 { 82 struct hw *aliases = hw_tree_find_device (current, "/aliases"); 83 char alias[32]; 84 int len = 0; 85 while (device_specifier[len] != '\0' 86 && device_specifier[len] != '/' 87 && device_specifier[len] != ':' 88 && !isspace (device_specifier[len])) 89 { 90 alias[len] = device_specifier[len]; 91 len++; 92 if (len >= sizeof (alias)) 93 hw_abort (NULL, "split_device_specifier: buffer overflow"); 94 } 95 alias[len] = '\0'; 96 if (aliases != NULL 97 && hw_find_property (aliases, alias)) 98 { 99 strcpy (spec->buf, hw_find_string_property (aliases, alias)); 100 strcat (spec->buf, device_specifier + len); 101 } 102 else 103 { 104 strcpy (spec->buf, device_specifier); 105 } 106 } 107 else 108 { 109 strcpy (spec->buf, device_specifier); 110 } 111 112 /* check no overflow */ 113 if (strlen (spec->buf) >= sizeof (spec->buf)) 114 hw_abort (NULL, "split_device_specifier: buffer overflow\n"); 115 116 /* strip leading spaces */ 117 chp = spec->buf; 118 while (*chp != '\0' && isspace (*chp)) 119 chp++; 120 if (*chp == '\0') 121 return 0; 122 123 /* find the path and terminate it with null */ 124 spec->path = chp; 125 while (*chp != '\0' && !isspace (*chp)) 126 chp++; 127 if (*chp != '\0') 128 { 129 *chp = '\0'; 130 chp++; 131 } 132 133 /* and any value */ 134 while (*chp != '\0' && isspace (*chp)) 135 chp++; 136 spec->value = chp; 137 138 /* now go back and chop the property off of the path */ 139 if (spec->value[0] == '\0') 140 { 141 spec->property = NULL; /*not a property*/ 142 spec->value = NULL; 143 } 144 else if (spec->value[0] == '>' 145 || spec->value[0] == '<') 146 { 147 /* an interrupt spec */ 148 spec->property = NULL; 149 } 150 else 151 { 152 chp = strrchr (spec->path, '/'); 153 if (chp == NULL) 154 { 155 spec->property = spec->path; 156 spec->path = strchr (spec->property, '\0'); 157 } 158 else 159 { 160 *chp = '\0'; 161 spec->property = chp+1; 162 } 163 } 164 165 /* and mark the rest as invalid */ 166 spec->name = NULL; 167 spec->family = NULL; 168 spec->unit = NULL; 169 spec->args = NULL; 170 spec->last_name = NULL; 171 spec->last_family = NULL; 172 spec->last_unit = NULL; 173 spec->last_args = NULL; 174 175 return 1; 176} 177 178 179/* given a device specifier break it up into its main components - 180 path and property name - assuming that the last `device' is a 181 property name. */ 182 183static int 184split_property_specifier (struct hw *current, 185 const char *property_specifier, 186 name_specifier *spec) 187{ 188 if (split_device_specifier (current, property_specifier, spec)) 189 { 190 if (spec->property == NULL) 191 { 192 /* force the last name to be a property name */ 193 char *chp = strrchr (spec->path, '/'); 194 if (chp == NULL) 195 { 196 spec->property = spec->path; 197 spec->path = strrchr (spec->property, '\0');; 198 } 199 else 200 { 201 *chp = '\0'; 202 spec->property = chp + 1; 203 } 204 } 205 return 1; 206 } 207 else 208 return 0; 209} 210 211 212/* device the next device name and split it up, return 0 when no more 213 names to struct hw */ 214 215static int 216split_device_name (name_specifier *spec) 217{ 218 char *chp; 219 /* remember what came before */ 220 spec->last_name = spec->name; 221 spec->last_family = spec->family; 222 spec->last_unit = spec->unit; 223 spec->last_args = spec->args; 224 /* finished? */ 225 if (spec->path[0] == '\0') 226 { 227 spec->name = NULL; 228 spec->family = NULL; 229 spec->unit = NULL; 230 spec->args = NULL; 231 return 0; 232 } 233 /* break the current device spec from the path */ 234 spec->name = spec->path; 235 chp = strchr (spec->name, '/'); 236 if (chp == NULL) 237 spec->path = strchr (spec->name, '\0'); 238 else 239 { 240 spec->path = chp+1; 241 *chp = '\0'; 242 } 243 /* break out the base */ 244 if (spec->name[0] == '(') 245 { 246 chp = strchr (spec->name, ')'); 247 if (chp == NULL) 248 { 249 spec->family = spec->name; 250 } 251 else 252 { 253 *chp = '\0'; 254 spec->family = spec->name + 1; 255 spec->name = chp + 1; 256 } 257 } 258 else 259 { 260 spec->family = spec->name; 261 } 262 /* now break out the unit */ 263 chp = strchr (spec->name, '@'); 264 if (chp == NULL) 265 { 266 spec->unit = NULL; 267 chp = spec->name; 268 } 269 else 270 { 271 *chp = '\0'; 272 chp += 1; 273 spec->unit = chp; 274 } 275 /* finally any args */ 276 chp = strchr (chp, ':'); 277 if (chp == NULL) 278 spec->args = NULL; 279 else 280 { 281 *chp = '\0'; 282 spec->args = chp+1; 283 } 284 return 1; 285} 286 287 288/* device the value, returning the next non-space token */ 289 290static char * 291split_value (name_specifier *spec) 292{ 293 char *token; 294 if (spec->value == NULL) 295 return NULL; 296 /* skip leading white space */ 297 while (isspace (spec->value[0])) 298 spec->value++; 299 if (spec->value[0] == '\0') 300 { 301 spec->value = NULL; 302 return NULL; 303 } 304 token = spec->value; 305 /* find trailing space */ 306 while (spec->value[0] != '\0' && !isspace (spec->value[0])) 307 spec->value++; 308 /* chop this value out */ 309 if (spec->value[0] != '\0') 310 { 311 spec->value[0] = '\0'; 312 spec->value++; 313 } 314 return token; 315} 316 317 318 319/* traverse the path specified by spec starting at current */ 320 321static struct hw * 322split_find_device (struct hw *current, 323 name_specifier *spec) 324{ 325 /* strip off (and process) any leading ., .., ./ and / */ 326 while (1) 327 { 328 if (strncmp (spec->path, "/", strlen ("/")) == 0) 329 { 330 /* cd /... */ 331 while (current != NULL && hw_parent (current) != NULL) 332 current = hw_parent (current); 333 spec->path += strlen ("/"); 334 } 335 else if (strncmp (spec->path, "./", strlen ("./")) == 0) 336 { 337 /* cd ./... */ 338 spec->path += strlen ("./"); 339 } 340 else if (strncmp (spec->path, "../", strlen ("../")) == 0) 341 { 342 /* cd ../... */ 343 if (current != NULL && hw_parent (current) != NULL) 344 current = hw_parent (current); 345 spec->path += strlen ("../"); 346 } 347 else if (strcmp (spec->path, ".") == 0) 348 { 349 /* cd . */ 350 spec->path += strlen ("."); 351 } 352 else if (strcmp (spec->path, "..") == 0) 353 { 354 /* cd .. */ 355 if (current != NULL && hw_parent (current) != NULL) 356 current = hw_parent (current); 357 spec->path += strlen (".."); 358 } 359 else 360 break; 361 } 362 363 /* now go through the path proper */ 364 365 if (current == NULL) 366 { 367 split_device_name (spec); 368 return NULL; 369 } 370 371 while (split_device_name (spec)) 372 { 373 struct hw *child; 374 for (child = hw_child (current); 375 child != NULL; child = hw_sibling (child)) 376 { 377 if (strcmp (spec->name, hw_name (child)) == 0) 378 { 379 if (spec->unit == NULL) 380 break; 381 else 382 { 383 hw_unit phys; 384 hw_unit_decode (current, spec->unit, &phys); 385 if (memcmp (&phys, hw_unit_address (child), 386 sizeof (hw_unit)) == 0) 387 break; 388 } 389 } 390 } 391 if (child == NULL) 392 return current; /* search failed */ 393 current = child; 394 } 395 396 return current; 397} 398 399 400static struct hw * 401split_fill_path (struct hw *current, 402 const char *device_specifier, 403 name_specifier *spec) 404{ 405 /* break it up */ 406 if (!split_device_specifier (current, device_specifier, spec)) 407 hw_abort (current, "error parsing %s\n", device_specifier); 408 409 /* fill our tree with its contents */ 410 current = split_find_device (current, spec); 411 412 /* add any additional devices as needed */ 413 if (spec->name != NULL) 414 { 415 do 416 { 417 if (current != NULL && !hw_finished_p (current)) 418 hw_finish (current); 419 current = hw_create (NULL, 420 current, 421 spec->family, 422 spec->name, 423 spec->unit, 424 spec->args); 425 } 426 while (split_device_name (spec)); 427 } 428 429 return current; 430} 431 432 433/* <non-white-space> */ 434 435static const char * 436skip_token (const char *chp) 437{ 438 while (!isspace (*chp) && *chp != '\0') 439 chp++; 440 while (isspace (*chp) && *chp != '\0') 441 chp++; 442 return chp; 443} 444 445 446/* count the number of entries */ 447 448static int 449count_entries (struct hw *current, 450 const char *property_name, 451 const char *property_value, 452 int modulo) 453{ 454 const char *chp = property_value; 455 int nr_entries = 0; 456 while (*chp != '\0') 457 { 458 nr_entries += 1; 459 chp = skip_token (chp); 460 } 461 if ((nr_entries % modulo) != 0) 462 { 463 hw_abort (current, "incorrect number of entries for %s property %s, should be multiple of %d", 464 property_name, property_value, modulo); 465 } 466 return nr_entries / modulo; 467} 468 469 470 471/* parse: <address> ::= <token> ; device dependant */ 472 473static const char * 474parse_address (struct hw *current, 475 struct hw *bus, 476 const char *chp, 477 hw_unit *address) 478{ 479 if (hw_unit_decode (bus, chp, address) < 0) 480 hw_abort (current, "invalid unit address in %s", chp); 481 return skip_token (chp); 482} 483 484 485/* parse: <size> ::= <number> { "," <number> } ; */ 486 487static const char * 488parse_size (struct hw *current, 489 struct hw *bus, 490 const char *chp, 491 hw_unit *size) 492{ 493 int i; 494 int nr; 495 const char *curr = chp; 496 memset (size, 0, sizeof (*size)); 497 /* parse the numeric list */ 498 size->nr_cells = hw_unit_nr_size_cells (bus); 499 nr = 0; 500 while (1) 501 { 502 char *next; 503 size->cells[nr] = strtoul (curr, &next, 0); 504 if (curr == next) 505 hw_abort (current, "Problem parsing <size> %s", chp); 506 nr += 1; 507 if (next[0] != ',') 508 break; 509 if (nr == size->nr_cells) 510 hw_abort (current, "Too many values in <size> %s", chp); 511 curr = next + 1; 512 } 513 ASSERT (nr > 0 && nr <= size->nr_cells); 514 /* right align the numbers */ 515 for (i = 1; i <= size->nr_cells; i++) 516 { 517 if (i <= nr) 518 size->cells[size->nr_cells - i] = size->cells[nr - i]; 519 else 520 size->cells[size->nr_cells - i] = 0; 521 } 522 return skip_token (chp); 523} 524 525 526/* parse: <reg> ::= { <address> <size> } ; */ 527 528static void 529parse_reg_property (struct hw *current, 530 const char *property_name, 531 const char *property_value) 532{ 533 int nr_regs; 534 int reg_nr; 535 reg_property_spec *regs; 536 const char *chp; 537 538 /* determine the number of reg entries by counting tokens */ 539 nr_regs = count_entries (current, property_name, property_value, 2); 540 541 /* create working space */ 542 regs = zalloc (nr_regs * sizeof (*regs)); 543 544 /* fill it in */ 545 chp = property_value; 546 for (reg_nr = 0; reg_nr < nr_regs; reg_nr++) 547 { 548 chp = parse_address (current, hw_parent (current), 549 chp, ®s[reg_nr].address); 550 chp = parse_size (current, hw_parent (current), 551 chp, ®s[reg_nr].size); 552 } 553 554 /* create it */ 555 hw_add_reg_array_property (current, property_name, 556 regs, nr_regs); 557 558 free (regs); 559} 560 561 562/* { <child-address> <parent-address> <child-size> }* */ 563 564static void 565parse_ranges_property (struct hw *current, 566 const char *property_name, 567 const char *property_value) 568{ 569 int nr_ranges; 570 int range_nr; 571 range_property_spec *ranges; 572 const char *chp; 573 574 /* determine the number of ranges specified */ 575 nr_ranges = count_entries (current, property_name, property_value, 3); 576 577 /* create a property of that size */ 578 ranges = zalloc (nr_ranges * sizeof (*ranges)); 579 580 /* fill it in */ 581 chp = property_value; 582 for (range_nr = 0; range_nr < nr_ranges; range_nr++) 583 { 584 chp = parse_address (current, current, 585 chp, &ranges[range_nr].child_address); 586 chp = parse_address (current, hw_parent (current), 587 chp, &ranges[range_nr].parent_address); 588 chp = parse_size (current, current, 589 chp, &ranges[range_nr].size); 590 } 591 592 /* create it */ 593 hw_add_range_array_property (current, property_name, ranges, nr_ranges); 594 595 free (ranges); 596} 597 598 599/* <integer> ... */ 600 601static void 602parse_integer_property (struct hw *current, 603 const char *property_name, 604 const char *property_value) 605{ 606 int nr_entries; 607 unsigned_cell words[1024]; 608 /* integer or integer array? */ 609 nr_entries = 0; 610 while (1) 611 { 612 char *end; 613 words[nr_entries] = strtoul (property_value, &end, 0); 614 if (property_value == end) 615 break; 616 nr_entries += 1; 617 if (nr_entries * sizeof (words[0]) >= sizeof (words)) 618 hw_abort (current, "buffer overflow"); 619 property_value = end; 620 } 621 if (nr_entries == 0) 622 hw_abort (current, "error parsing integer property %s (%s)", 623 property_name, property_value); 624 else if (nr_entries == 1) 625 hw_add_integer_property (current, property_name, words[0]); 626 else 627 { 628 int i; 629 for (i = 0; i < nr_entries; i++) 630 { 631 H2BE (words[i]); 632 } 633 /* perhaps integer array property is better */ 634 hw_add_array_property (current, property_name, words, 635 sizeof (words[0]) * nr_entries); 636 } 637} 638 639 640/* <string> ... */ 641 642static void 643parse_string_property (struct hw *current, 644 const char *property_name, 645 const char *property_value) 646{ 647 char **strings; 648 const char *chp; 649 int nr_strings; 650 int approx_nr_strings; 651 652 /* get an estimate as to the number of strings by counting double 653 quotes */ 654 approx_nr_strings = 2; 655 for (chp = property_value; *chp; chp++) 656 { 657 if (*chp == '"') 658 approx_nr_strings++; 659 } 660 approx_nr_strings = (approx_nr_strings) / 2; 661 662 /* create a string buffer for that many (plus a null) */ 663 strings = (char**) zalloc ((approx_nr_strings + 1) * sizeof (char*)); 664 665 /* now find all the strings */ 666 chp = property_value; 667 nr_strings = 0; 668 while (1) 669 { 670 671 /* skip leading space */ 672 while (*chp != '\0' && isspace (*chp)) 673 chp += 1; 674 if (*chp == '\0') 675 break; 676 677 /* copy it in */ 678 if (*chp == '"') 679 { 680 /* a quoted string - watch for '\' et al. */ 681 /* estimate the size and allocate space for it */ 682 int pos; 683 chp++; 684 pos = 0; 685 while (chp[pos] != '\0' && chp[pos] != '"') 686 { 687 if (chp[pos] == '\\' && chp[pos+1] != '\0') 688 pos += 2; 689 else 690 pos += 1; 691 } 692 strings[nr_strings] = zalloc (pos + 1); 693 /* copy the string over */ 694 pos = 0; 695 while (*chp != '\0' && *chp != '"') 696 { 697 if (*chp == '\\' && *(chp+1) != '\0') 698 { 699 strings[nr_strings][pos] = *(chp+1); 700 chp += 2; 701 pos++; 702 } 703 else 704 { 705 strings[nr_strings][pos] = *chp; 706 chp += 1; 707 pos++; 708 } 709 } 710 if (*chp != '\0') 711 chp++; 712 strings[nr_strings][pos] = '\0'; 713 } 714 else 715 { 716 /* copy over a single unquoted token */ 717 int len = 0; 718 while (chp[len] != '\0' && !isspace (chp[len])) 719 len++; 720 strings[nr_strings] = zalloc (len + 1); 721 strncpy (strings[nr_strings], chp, len); 722 strings[nr_strings][len] = '\0'; 723 chp += len; 724 } 725 nr_strings++; 726 if (nr_strings > approx_nr_strings) 727 hw_abort (current, "String property %s badly formatted", 728 property_name); 729 } 730 ASSERT (strings[nr_strings] == NULL); /* from zalloc */ 731 732 /* install it */ 733 if (nr_strings == 0) 734 hw_add_string_property (current, property_name, ""); 735 else if (nr_strings == 1) 736 hw_add_string_property (current, property_name, strings[0]); 737 else 738 { 739 const char **specs = (const char**) strings; /* stop a bogus error */ 740 hw_add_string_array_property (current, property_name, 741 specs, nr_strings); 742 } 743 744 /* flush the created string */ 745 while (nr_strings > 0) 746 { 747 nr_strings--; 748 free (strings[nr_strings]); 749 } 750 free (strings); 751} 752 753 754/* <path-to-ihandle-device> */ 755 756#if NOT_YET 757static void 758parse_ihandle_property (struct hw *current, 759 const char *property, 760 const char *value) 761{ 762 ihandle_runtime_property_spec ihandle; 763 764 /* pass the full path */ 765 ihandle.full_path = value; 766 767 /* save this ready for the ihandle create */ 768 hw_add_ihandle_runtime_property (current, property, 769 &ihandle); 770} 771#endif 772 773 774struct hw * 775hw_tree_create (SIM_DESC sd, 776 const char *family) 777{ 778 return hw_create (sd, NULL, family, family, NULL, NULL); 779} 780 781void 782hw_tree_delete (struct hw *me) 783{ 784 /* Need to allow devices to disapear under our feet */ 785 while (hw_child (me) != NULL) 786 { 787 hw_tree_delete (hw_child (me)); 788 } 789 hw_delete (me); 790} 791 792 793struct hw * 794hw_tree_parse (struct hw *current, 795 const char *fmt, 796 ...) 797{ 798 va_list ap; 799 va_start (ap, fmt); 800 current = hw_tree_vparse (current, fmt, ap); 801 va_end (ap); 802 return current; 803} 804 805struct hw * 806hw_tree_vparse (struct hw *current, 807 const char *fmt, 808 va_list ap) 809{ 810 char device_specifier[1024]; 811 name_specifier spec; 812 813 /* format the path */ 814 vsprintf (device_specifier, fmt, ap); 815 if (strlen (device_specifier) >= sizeof (device_specifier)) 816 hw_abort (NULL, "device_tree_add_deviced: buffer overflow\n"); 817 818 /* construct the tree down to the final struct hw */ 819 current = split_fill_path (current, device_specifier, &spec); 820 821 /* is there an interrupt spec */ 822 if (spec.property == NULL 823 && spec.value != NULL) 824 { 825 char *op = split_value (&spec); 826 switch (op[0]) 827 { 828 case '>': 829 { 830 char *my_port_name = split_value (&spec); 831 int my_port; 832 char *dest_port_name = split_value (&spec); 833 int dest_port; 834 name_specifier dest_spec; 835 char *dest_hw_name = split_value (&spec); 836 struct hw *dest; 837 /* find my name */ 838 if (!hw_finished_p (current)) 839 hw_finish (current); 840 my_port = hw_port_decode (current, my_port_name, output_port); 841 /* find the dest device and port */ 842 dest = split_fill_path (current, dest_hw_name, &dest_spec); 843 if (!hw_finished_p (dest)) 844 hw_finish (dest); 845 dest_port = hw_port_decode (dest, dest_port_name, 846 input_port); 847 /* connect the two */ 848 hw_port_attach (current, 849 my_port, 850 dest, 851 dest_port, 852 permenant_object); 853 break; 854 } 855 default: 856 hw_abort (current, "unreconised interrupt spec %s\n", spec.value); 857 break; 858 } 859 } 860 861 /* is there a property */ 862 if (spec.property != NULL) 863 { 864 if (strcmp (spec.value, "true") == 0) 865 hw_add_boolean_property (current, spec.property, 1); 866 else if (strcmp (spec.value, "false") == 0) 867 hw_add_boolean_property (current, spec.property, 0); 868 else 869 { 870 const struct hw_property *property; 871 switch (spec.value[0]) 872 { 873#if NOT_YET 874 case '*': 875 { 876 parse_ihandle_property (current, spec.property, spec.value + 1); 877 break; 878 } 879#endif 880 case '[': 881 { 882 uint8_t words[1024]; 883 char *curr = spec.value + 1; 884 int nr_words = 0; 885 while (1) 886 { 887 char *next; 888 words[nr_words] = H2BE_1 (strtoul (curr, &next, 0)); 889 if (curr == next) 890 break; 891 curr = next; 892 nr_words += 1; 893 } 894 hw_add_array_property (current, spec.property, 895 words, sizeof (words[0]) * nr_words); 896 break; 897 } 898 case '"': 899 { 900 parse_string_property (current, spec.property, spec.value); 901 break; 902 } 903 case '!': 904 { 905 spec.value++; 906 property = hw_tree_find_property (current, spec.value); 907 if (property == NULL) 908 hw_abort (current, "property %s not found\n", spec.value); 909 hw_add_duplicate_property (current, 910 spec.property, 911 property); 912 break; 913 } 914 default: 915 { 916 if (strcmp (spec.property, "reg") == 0 917 || strcmp (spec.property, "assigned-addresses") == 0 918 || strcmp (spec.property, "alternate-reg") == 0) 919 { 920 parse_reg_property (current, spec.property, spec.value); 921 } 922 else if (strcmp (spec.property, "ranges") == 0) 923 { 924 parse_ranges_property (current, spec.property, spec.value); 925 } 926 else if (isdigit (spec.value[0]) 927 || (spec.value[0] == '-' && isdigit (spec.value[1])) 928 || (spec.value[0] == '+' && isdigit (spec.value[1]))) 929 { 930 parse_integer_property (current, spec.property, spec.value); 931 } 932 else 933 parse_string_property (current, spec.property, spec.value); 934 break; 935 } 936 } 937 } 938 } 939 return current; 940} 941 942 943static void 944finish_hw_tree (struct hw *me, 945 void *data) 946{ 947 if (!hw_finished_p (me)) 948 hw_finish (me); 949} 950 951void 952hw_tree_finish (struct hw *root) 953{ 954 hw_tree_traverse (root, finish_hw_tree, NULL, NULL); 955} 956 957 958 959void 960hw_tree_traverse (struct hw *root, 961 hw_tree_traverse_function *prefix, 962 hw_tree_traverse_function *postfix, 963 void *data) 964{ 965 struct hw *child; 966 if (prefix != NULL) 967 prefix (root, data); 968 for (child = hw_child (root); 969 child != NULL; 970 child = hw_sibling (child)) 971 { 972 hw_tree_traverse (child, prefix, postfix, data); 973 } 974 if (postfix != NULL) 975 postfix (root, data); 976} 977 978 979 980struct printer 981{ 982 hw_tree_print_callback *print; 983 void *file; 984}; 985 986static void 987print_address (struct hw *bus, 988 const hw_unit *phys, 989 struct printer *p) 990{ 991 char unit[32]; 992 hw_unit_encode (bus, phys, unit, sizeof (unit)); 993 p->print (p->file, " %s", unit); 994} 995 996static void 997print_size (struct hw *bus, 998 const hw_unit *size, 999 struct printer *p) 1000{ 1001 int i; 1002 for (i = 0; i < size->nr_cells; i++) 1003 if (size->cells[i] != 0) 1004 break; 1005 if (i < size->nr_cells) 1006 { 1007 p->print (p->file, " 0x%lx", (unsigned long) size->cells[i]); 1008 i++; 1009 for (; i < size->nr_cells; i++) 1010 p->print (p->file, ",0x%lx", (unsigned long) size->cells[i]); 1011 } 1012 else 1013 p->print (p->file, " 0"); 1014} 1015 1016static void 1017print_reg_property (struct hw *me, 1018 const struct hw_property *property, 1019 struct printer *p) 1020{ 1021 int reg_nr; 1022 reg_property_spec reg; 1023 for (reg_nr = 0; 1024 hw_find_reg_array_property (me, property->name, reg_nr, ®); 1025 reg_nr++) 1026 { 1027 print_address (hw_parent (me), ®.address, p); 1028 print_size (me, ®.size, p); 1029 } 1030} 1031 1032static void 1033print_ranges_property (struct hw *me, 1034 const struct hw_property *property, 1035 struct printer *p) 1036{ 1037 int range_nr; 1038 range_property_spec range; 1039 for (range_nr = 0; 1040 hw_find_range_array_property (me, property->name, range_nr, &range); 1041 range_nr++) 1042 { 1043 print_address (me, &range.child_address, p); 1044 print_address (hw_parent (me), &range.parent_address, p); 1045 print_size (me, &range.size, p); 1046 } 1047} 1048 1049static void 1050print_string (struct hw *me, 1051 const char *string, 1052 struct printer *p) 1053{ 1054 p->print (p->file, " \""); 1055 while (*string != '\0') 1056 { 1057 switch (*string) 1058 { 1059 case '"': 1060 p->print (p->file, "\\\""); 1061 break; 1062 case '\\': 1063 p->print (p->file, "\\\\"); 1064 break; 1065 default: 1066 p->print (p->file, "%c", *string); 1067 break; 1068 } 1069 string++; 1070 } 1071 p->print (p->file, "\""); 1072} 1073 1074static void 1075print_string_array_property (struct hw *me, 1076 const struct hw_property *property, 1077 struct printer *p) 1078{ 1079 int nr; 1080 string_property_spec string; 1081 for (nr = 0; 1082 hw_find_string_array_property (me, property->name, nr, &string); 1083 nr++) 1084 { 1085 print_string (me, string, p); 1086 } 1087} 1088 1089static void 1090print_properties (struct hw *me, 1091 struct printer *p) 1092{ 1093 const struct hw_property *property; 1094 for (property = hw_find_property (me, NULL); 1095 property != NULL; 1096 property = hw_next_property (property)) 1097 { 1098 if (hw_parent (me) == NULL) 1099 p->print (p->file, "/%s", property->name); 1100 else 1101 p->print (p->file, "%s/%s", hw_path (me), property->name); 1102 if (property->original != NULL) 1103 { 1104 p->print (p->file, " !"); 1105 p->print (p->file, "%s/%s", 1106 hw_path (property->original->owner), 1107 property->original->name); 1108 } 1109 else 1110 { 1111 switch (property->type) 1112 { 1113 case array_property: 1114 { 1115 if ((property->sizeof_array % sizeof (signed_cell)) == 0) 1116 { 1117 unsigned_cell *w = (unsigned_cell*) property->array; 1118 int cell_nr; 1119 for (cell_nr = 0; 1120 cell_nr < (property->sizeof_array / sizeof (unsigned_cell)); 1121 cell_nr++) 1122 { 1123 p->print (p->file, " 0x%lx", (unsigned long) BE2H_cell (w[cell_nr])); 1124 } 1125 } 1126 else 1127 { 1128 uint8_t *w = (uint8_t*)property->array; 1129 p->print (p->file, " ["); 1130 while ((char*)w - (char*)property->array < property->sizeof_array) 1131 { 1132 p->print (p->file, " 0x%2x", BE2H_1 (*w)); 1133 w++; 1134 } 1135 } 1136 break; 1137 } 1138 case boolean_property: 1139 { 1140 int b = hw_find_boolean_property (me, property->name); 1141 p->print (p->file, " %s", b ? "true" : "false"); 1142 break; 1143 } 1144#if NOT_YET 1145 case ihandle_property: 1146 { 1147 if (property->array != NULL) 1148 { 1149 device_instance *instance = hw_find_ihandle_property (me, property->name); 1150 p->print (p->file, " *%s", device_instance_path (instance)); 1151 } 1152 else 1153 { 1154 /* not yet initialized, ask the device for the path */ 1155 ihandle_runtime_property_spec spec; 1156 hw_find_ihandle_runtime_property (me, property->name, &spec); 1157 p->print (p->file, " *%s", spec.full_path); 1158 } 1159 break; 1160 } 1161#endif 1162 case integer_property: 1163 { 1164 unsigned_word w = hw_find_integer_property (me, property->name); 1165 p->print (p->file, " 0x%lx", (unsigned long)w); 1166 break; 1167 } 1168 case range_array_property: 1169 { 1170 print_ranges_property (me, property, p); 1171 break; 1172 } 1173 case reg_array_property: 1174 { 1175 print_reg_property (me, property, p); 1176 break; 1177 } 1178 case string_property: 1179 { 1180 const char *s = hw_find_string_property (me, property->name); 1181 print_string (me, s, p); 1182 break; 1183 } 1184 case string_array_property: 1185 { 1186 print_string_array_property (me, property, p); 1187 break; 1188 } 1189 } 1190 } 1191 p->print (p->file, "\n"); 1192 } 1193} 1194 1195static void 1196print_interrupts (struct hw *me, 1197 int my_port, 1198 struct hw *dest, 1199 int dest_port, 1200 void *data) 1201{ 1202 struct printer *p = data; 1203 char src[32]; 1204 char dst[32]; 1205 hw_port_encode (me, my_port, src, sizeof (src), output_port); 1206 hw_port_encode (dest, dest_port, dst, sizeof (dst), input_port); 1207 p->print (p->file, 1208 "%s > %s %s %s\n", 1209 hw_path (me), 1210 src, dst, 1211 hw_path (dest)); 1212} 1213 1214static void 1215print_device (struct hw *me, 1216 void *data) 1217{ 1218 struct printer *p = data; 1219 p->print (p->file, "%s\n", hw_path (me)); 1220 print_properties (me, p); 1221 hw_port_traverse (me, print_interrupts, data); 1222} 1223 1224void 1225hw_tree_print (struct hw *root, 1226 hw_tree_print_callback *print, 1227 void *file) 1228{ 1229 struct printer p; 1230 p.print = print; 1231 p.file = file; 1232 hw_tree_traverse (root, 1233 print_device, NULL, 1234 &p); 1235} 1236 1237 1238 1239#if NOT_YET 1240device_instance * 1241tree_instance (struct hw *root, 1242 const char *device_specifier) 1243{ 1244 /* find the device node */ 1245 struct hw *me; 1246 name_specifier spec; 1247 if (!split_device_specifier (root, device_specifier, &spec)) 1248 return NULL; 1249 me = split_find_device (root, &spec); 1250 if (spec.name != NULL) 1251 return NULL; 1252 /* create the instance */ 1253 return device_create_instance (me, device_specifier, spec.last_args); 1254} 1255#endif 1256 1257struct hw * 1258hw_tree_find_device (struct hw *root, 1259 const char *path_to_device) 1260{ 1261 struct hw *node; 1262 name_specifier spec; 1263 1264 /* parse the path */ 1265 split_device_specifier (root, path_to_device, &spec); 1266 if (spec.value != NULL) 1267 return NULL; /* something wierd */ 1268 1269 /* now find it */ 1270 node = split_find_device (root, &spec); 1271 if (spec.name != NULL) 1272 return NULL; /* not a leaf */ 1273 1274 return node; 1275} 1276 1277 1278const struct hw_property * 1279hw_tree_find_property (struct hw *root, 1280 const char *path_to_property) 1281{ 1282 name_specifier spec; 1283 if (!split_property_specifier (root, path_to_property, &spec)) 1284 hw_abort (root, "Invalid property path %s", path_to_property); 1285 root = split_find_device (root, &spec); 1286 if (spec.name != NULL) 1287 return NULL; /* not a leaf */ 1288 return hw_find_property (root, spec.property); 1289} 1290 1291int 1292hw_tree_find_boolean_property (struct hw *root, 1293 const char *path_to_property) 1294{ 1295 name_specifier spec; 1296 if (!split_property_specifier (root, path_to_property, &spec)) 1297 hw_abort (root, "Invalid property path %s", path_to_property); 1298 root = split_find_device (root, &spec); 1299 if (spec.name != NULL) 1300 hw_abort (root, "device \"%s\" not found (property \"%s\")", 1301 spec.name, path_to_property); 1302 return hw_find_boolean_property (root, spec.property); 1303} 1304 1305signed_cell 1306hw_tree_find_integer_property (struct hw *root, 1307 const char *path_to_property) 1308{ 1309 name_specifier spec; 1310 if (!split_property_specifier (root, path_to_property, &spec)) 1311 hw_abort (root, "Invalid property path %s", path_to_property); 1312 root = split_find_device (root, &spec); 1313 if (spec.name != NULL) 1314 hw_abort (root, "device \"%s\" not found (property \"%s\")", 1315 spec.name, path_to_property); 1316 return hw_find_integer_property (root, spec.property); 1317} 1318 1319#if NOT_YET 1320device_instance * 1321hw_tree_find_ihandle_property (struct hw *root, 1322 const char *path_to_property) 1323{ 1324 struct hw *root; 1325 name_specifier spec; 1326 if (!split_property_specifier (root, path_to_property, &spec)) 1327 hw_abort (root, "Invalid property path %s", path_to_property); 1328 root = split_find_device (root, &spec); 1329 if (spec.name != NULL) 1330 hw_abort (root, "device \"%s\" not found (property \"%s\")", 1331 spec.name, path_to_property); 1332 return hw_find_ihandle_property (root, spec.property); 1333} 1334#endif 1335 1336const char * 1337hw_tree_find_string_property (struct hw *root, 1338 const char *path_to_property) 1339{ 1340 name_specifier spec; 1341 if (!split_property_specifier (root, path_to_property, &spec)) 1342 hw_abort (root, "Invalid property path %s", path_to_property); 1343 root = split_find_device (root, &spec); 1344 if (spec.name != NULL) 1345 hw_abort (root, "device \"%s\" not found (property \"%s\")", 1346 spec.name, path_to_property); 1347 return hw_find_string_property (root, spec.property); 1348} 1349