14e98e3e1Schristos /* The common simulator framework for GDB, the GNU Debugger. 24e98e3e1Schristos 3*88241920Schristos Copyright 2002-2024 Free Software Foundation, Inc. 44e98e3e1Schristos 54e98e3e1Schristos Contributed by Andrew Cagney and Red Hat. 64e98e3e1Schristos 74e98e3e1Schristos This file is part of GDB. 84e98e3e1Schristos 94e98e3e1Schristos This program is free software; you can redistribute it and/or modify 104e98e3e1Schristos it under the terms of the GNU General Public License as published by 114e98e3e1Schristos the Free Software Foundation; either version 3 of the License, or 124e98e3e1Schristos (at your option) any later version. 134e98e3e1Schristos 144e98e3e1Schristos This program is distributed in the hope that it will be useful, 154e98e3e1Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of 164e98e3e1Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 174e98e3e1Schristos GNU General Public License for more details. 184e98e3e1Schristos 194e98e3e1Schristos You should have received a copy of the GNU General Public License 204e98e3e1Schristos along with this program. If not, see <http://www.gnu.org/licenses/>. */ 214e98e3e1Schristos 224b169a6bSchristos /* This must come before any other includes. */ 234b169a6bSchristos #include "defs.h" 244b169a6bSchristos 254b169a6bSchristos #include <ctype.h> 264b169a6bSchristos #include <stdarg.h> 274b169a6bSchristos #include <stdlib.h> 284b169a6bSchristos #include <string.h> 294e98e3e1Schristos 304e98e3e1Schristos #include "hw-main.h" 314e98e3e1Schristos #include "hw-base.h" 324e98e3e1Schristos #include "hw-tree.h" 334e98e3e1Schristos 344e98e3e1Schristos #include "sim-io.h" 354e98e3e1Schristos #include "sim-assert.h" 364e98e3e1Schristos 374e98e3e1Schristos /* manipulate/lookup device names */ 384e98e3e1Schristos 394e98e3e1Schristos typedef struct _name_specifier 404e98e3e1Schristos { 414e98e3e1Schristos 424e98e3e1Schristos /* components in the full length name */ 434e98e3e1Schristos char *path; 444e98e3e1Schristos char *property; 454e98e3e1Schristos char *value; 464e98e3e1Schristos 474e98e3e1Schristos /* current device */ 484e98e3e1Schristos char *family; 494e98e3e1Schristos char *name; 504e98e3e1Schristos char *unit; 514e98e3e1Schristos char *args; 524e98e3e1Schristos 534e98e3e1Schristos /* previous device */ 544e98e3e1Schristos char *last_name; 554e98e3e1Schristos char *last_family; 564e98e3e1Schristos char *last_unit; 574e98e3e1Schristos char *last_args; 584e98e3e1Schristos 594e98e3e1Schristos /* work area */ 604e98e3e1Schristos char buf[1024]; 614e98e3e1Schristos 624e98e3e1Schristos } name_specifier; 634e98e3e1Schristos 644e98e3e1Schristos 654e98e3e1Schristos 664e98e3e1Schristos /* Given a device specifier, break it up into its main components: 674e98e3e1Schristos path (and if present) property name and property value. */ 684e98e3e1Schristos 694e98e3e1Schristos static int 704e98e3e1Schristos split_device_specifier (struct hw *current, 714e98e3e1Schristos const char *device_specifier, 724e98e3e1Schristos name_specifier *spec) 734e98e3e1Schristos { 744e98e3e1Schristos char *chp = NULL; 754e98e3e1Schristos 764e98e3e1Schristos /* expand any leading alias if present */ 774e98e3e1Schristos if (current != NULL 784e98e3e1Schristos && *device_specifier != '\0' 794e98e3e1Schristos && *device_specifier != '.' 804e98e3e1Schristos && *device_specifier != '/') 814e98e3e1Schristos { 824e98e3e1Schristos struct hw *aliases = hw_tree_find_device (current, "/aliases"); 834e98e3e1Schristos char alias[32]; 844e98e3e1Schristos int len = 0; 854e98e3e1Schristos while (device_specifier[len] != '\0' 864e98e3e1Schristos && device_specifier[len] != '/' 874e98e3e1Schristos && device_specifier[len] != ':' 884e98e3e1Schristos && !isspace (device_specifier[len])) 894e98e3e1Schristos { 904e98e3e1Schristos alias[len] = device_specifier[len]; 914e98e3e1Schristos len++; 924e98e3e1Schristos if (len >= sizeof (alias)) 934e98e3e1Schristos hw_abort (NULL, "split_device_specifier: buffer overflow"); 944e98e3e1Schristos } 954e98e3e1Schristos alias[len] = '\0'; 964e98e3e1Schristos if (aliases != NULL 974e98e3e1Schristos && hw_find_property (aliases, alias)) 984e98e3e1Schristos { 994e98e3e1Schristos strcpy (spec->buf, hw_find_string_property (aliases, alias)); 1004e98e3e1Schristos strcat (spec->buf, device_specifier + len); 1014e98e3e1Schristos } 1024e98e3e1Schristos else 1034e98e3e1Schristos { 1044e98e3e1Schristos strcpy (spec->buf, device_specifier); 1054e98e3e1Schristos } 1064e98e3e1Schristos } 1074e98e3e1Schristos else 1084e98e3e1Schristos { 1094e98e3e1Schristos strcpy (spec->buf, device_specifier); 1104e98e3e1Schristos } 1114e98e3e1Schristos 1124e98e3e1Schristos /* check no overflow */ 1134e98e3e1Schristos if (strlen (spec->buf) >= sizeof (spec->buf)) 1144e98e3e1Schristos hw_abort (NULL, "split_device_specifier: buffer overflow\n"); 1154e98e3e1Schristos 1164e98e3e1Schristos /* strip leading spaces */ 1174e98e3e1Schristos chp = spec->buf; 1184e98e3e1Schristos while (*chp != '\0' && isspace (*chp)) 1194e98e3e1Schristos chp++; 1204e98e3e1Schristos if (*chp == '\0') 1214e98e3e1Schristos return 0; 1224e98e3e1Schristos 1234e98e3e1Schristos /* find the path and terminate it with null */ 1244e98e3e1Schristos spec->path = chp; 1254e98e3e1Schristos while (*chp != '\0' && !isspace (*chp)) 1264e98e3e1Schristos chp++; 1274e98e3e1Schristos if (*chp != '\0') 1284e98e3e1Schristos { 1294e98e3e1Schristos *chp = '\0'; 1304e98e3e1Schristos chp++; 1314e98e3e1Schristos } 1324e98e3e1Schristos 1334e98e3e1Schristos /* and any value */ 1344e98e3e1Schristos while (*chp != '\0' && isspace (*chp)) 1354e98e3e1Schristos chp++; 1364e98e3e1Schristos spec->value = chp; 1374e98e3e1Schristos 1384e98e3e1Schristos /* now go back and chop the property off of the path */ 1394e98e3e1Schristos if (spec->value[0] == '\0') 1404e98e3e1Schristos { 1414e98e3e1Schristos spec->property = NULL; /*not a property*/ 1424e98e3e1Schristos spec->value = NULL; 1434e98e3e1Schristos } 1444e98e3e1Schristos else if (spec->value[0] == '>' 1454e98e3e1Schristos || spec->value[0] == '<') 1464e98e3e1Schristos { 1474e98e3e1Schristos /* an interrupt spec */ 1484e98e3e1Schristos spec->property = NULL; 1494e98e3e1Schristos } 1504e98e3e1Schristos else 1514e98e3e1Schristos { 1524e98e3e1Schristos chp = strrchr (spec->path, '/'); 1534e98e3e1Schristos if (chp == NULL) 1544e98e3e1Schristos { 1554e98e3e1Schristos spec->property = spec->path; 1564e98e3e1Schristos spec->path = strchr (spec->property, '\0'); 1574e98e3e1Schristos } 1584e98e3e1Schristos else 1594e98e3e1Schristos { 1604e98e3e1Schristos *chp = '\0'; 1614e98e3e1Schristos spec->property = chp+1; 1624e98e3e1Schristos } 1634e98e3e1Schristos } 1644e98e3e1Schristos 1654e98e3e1Schristos /* and mark the rest as invalid */ 1664e98e3e1Schristos spec->name = NULL; 1674e98e3e1Schristos spec->family = NULL; 1684e98e3e1Schristos spec->unit = NULL; 1694e98e3e1Schristos spec->args = NULL; 1704e98e3e1Schristos spec->last_name = NULL; 1714e98e3e1Schristos spec->last_family = NULL; 1724e98e3e1Schristos spec->last_unit = NULL; 1734e98e3e1Schristos spec->last_args = NULL; 1744e98e3e1Schristos 1754e98e3e1Schristos return 1; 1764e98e3e1Schristos } 1774e98e3e1Schristos 1784e98e3e1Schristos 1794e98e3e1Schristos /* given a device specifier break it up into its main components - 1804e98e3e1Schristos path and property name - assuming that the last `device' is a 1814e98e3e1Schristos property name. */ 1824e98e3e1Schristos 1834e98e3e1Schristos static int 1844e98e3e1Schristos split_property_specifier (struct hw *current, 1854e98e3e1Schristos const char *property_specifier, 1864e98e3e1Schristos name_specifier *spec) 1874e98e3e1Schristos { 1884e98e3e1Schristos if (split_device_specifier (current, property_specifier, spec)) 1894e98e3e1Schristos { 1904e98e3e1Schristos if (spec->property == NULL) 1914e98e3e1Schristos { 1924e98e3e1Schristos /* force the last name to be a property name */ 1934e98e3e1Schristos char *chp = strrchr (spec->path, '/'); 1944e98e3e1Schristos if (chp == NULL) 1954e98e3e1Schristos { 1964e98e3e1Schristos spec->property = spec->path; 1974e98e3e1Schristos spec->path = strrchr (spec->property, '\0');; 1984e98e3e1Schristos } 1994e98e3e1Schristos else 2004e98e3e1Schristos { 2014e98e3e1Schristos *chp = '\0'; 2024e98e3e1Schristos spec->property = chp + 1; 2034e98e3e1Schristos } 2044e98e3e1Schristos } 2054e98e3e1Schristos return 1; 2064e98e3e1Schristos } 2074e98e3e1Schristos else 2084e98e3e1Schristos return 0; 2094e98e3e1Schristos } 2104e98e3e1Schristos 2114e98e3e1Schristos 2124e98e3e1Schristos /* device the next device name and split it up, return 0 when no more 2134e98e3e1Schristos names to struct hw */ 2144e98e3e1Schristos 2154e98e3e1Schristos static int 2164e98e3e1Schristos split_device_name (name_specifier *spec) 2174e98e3e1Schristos { 2184e98e3e1Schristos char *chp; 2194e98e3e1Schristos /* remember what came before */ 2204e98e3e1Schristos spec->last_name = spec->name; 2214e98e3e1Schristos spec->last_family = spec->family; 2224e98e3e1Schristos spec->last_unit = spec->unit; 2234e98e3e1Schristos spec->last_args = spec->args; 2244e98e3e1Schristos /* finished? */ 2254e98e3e1Schristos if (spec->path[0] == '\0') 2264e98e3e1Schristos { 2274e98e3e1Schristos spec->name = NULL; 2284e98e3e1Schristos spec->family = NULL; 2294e98e3e1Schristos spec->unit = NULL; 2304e98e3e1Schristos spec->args = NULL; 2314e98e3e1Schristos return 0; 2324e98e3e1Schristos } 2334e98e3e1Schristos /* break the current device spec from the path */ 2344e98e3e1Schristos spec->name = spec->path; 2354e98e3e1Schristos chp = strchr (spec->name, '/'); 2364e98e3e1Schristos if (chp == NULL) 2374e98e3e1Schristos spec->path = strchr (spec->name, '\0'); 2384e98e3e1Schristos else 2394e98e3e1Schristos { 2404e98e3e1Schristos spec->path = chp+1; 2414e98e3e1Schristos *chp = '\0'; 2424e98e3e1Schristos } 2434e98e3e1Schristos /* break out the base */ 2444e98e3e1Schristos if (spec->name[0] == '(') 2454e98e3e1Schristos { 2464e98e3e1Schristos chp = strchr (spec->name, ')'); 2474e98e3e1Schristos if (chp == NULL) 2484e98e3e1Schristos { 2494e98e3e1Schristos spec->family = spec->name; 2504e98e3e1Schristos } 2514e98e3e1Schristos else 2524e98e3e1Schristos { 2534e98e3e1Schristos *chp = '\0'; 2544e98e3e1Schristos spec->family = spec->name + 1; 2554e98e3e1Schristos spec->name = chp + 1; 2564e98e3e1Schristos } 2574e98e3e1Schristos } 2584e98e3e1Schristos else 2594e98e3e1Schristos { 2604e98e3e1Schristos spec->family = spec->name; 2614e98e3e1Schristos } 2624e98e3e1Schristos /* now break out the unit */ 2634e98e3e1Schristos chp = strchr (spec->name, '@'); 2644e98e3e1Schristos if (chp == NULL) 2654e98e3e1Schristos { 2664e98e3e1Schristos spec->unit = NULL; 2674e98e3e1Schristos chp = spec->name; 2684e98e3e1Schristos } 2694e98e3e1Schristos else 2704e98e3e1Schristos { 2714e98e3e1Schristos *chp = '\0'; 2724e98e3e1Schristos chp += 1; 2734e98e3e1Schristos spec->unit = chp; 2744e98e3e1Schristos } 2754e98e3e1Schristos /* finally any args */ 2764e98e3e1Schristos chp = strchr (chp, ':'); 2774e98e3e1Schristos if (chp == NULL) 2784e98e3e1Schristos spec->args = NULL; 2794e98e3e1Schristos else 2804e98e3e1Schristos { 2814e98e3e1Schristos *chp = '\0'; 2824e98e3e1Schristos spec->args = chp+1; 2834e98e3e1Schristos } 2844e98e3e1Schristos return 1; 2854e98e3e1Schristos } 2864e98e3e1Schristos 2874e98e3e1Schristos 2884e98e3e1Schristos /* device the value, returning the next non-space token */ 2894e98e3e1Schristos 2904e98e3e1Schristos static char * 2914e98e3e1Schristos split_value (name_specifier *spec) 2924e98e3e1Schristos { 2934e98e3e1Schristos char *token; 2944e98e3e1Schristos if (spec->value == NULL) 2954e98e3e1Schristos return NULL; 2964e98e3e1Schristos /* skip leading white space */ 2974e98e3e1Schristos while (isspace (spec->value[0])) 2984e98e3e1Schristos spec->value++; 2994e98e3e1Schristos if (spec->value[0] == '\0') 3004e98e3e1Schristos { 3014e98e3e1Schristos spec->value = NULL; 3024e98e3e1Schristos return NULL; 3034e98e3e1Schristos } 3044e98e3e1Schristos token = spec->value; 3054e98e3e1Schristos /* find trailing space */ 3064e98e3e1Schristos while (spec->value[0] != '\0' && !isspace (spec->value[0])) 3074e98e3e1Schristos spec->value++; 3084e98e3e1Schristos /* chop this value out */ 3094e98e3e1Schristos if (spec->value[0] != '\0') 3104e98e3e1Schristos { 3114e98e3e1Schristos spec->value[0] = '\0'; 3124e98e3e1Schristos spec->value++; 3134e98e3e1Schristos } 3144e98e3e1Schristos return token; 3154e98e3e1Schristos } 3164e98e3e1Schristos 3174e98e3e1Schristos 3184e98e3e1Schristos 3194e98e3e1Schristos /* traverse the path specified by spec starting at current */ 3204e98e3e1Schristos 3214e98e3e1Schristos static struct hw * 3224e98e3e1Schristos split_find_device (struct hw *current, 3234e98e3e1Schristos name_specifier *spec) 3244e98e3e1Schristos { 3254e98e3e1Schristos /* strip off (and process) any leading ., .., ./ and / */ 3264e98e3e1Schristos while (1) 3274e98e3e1Schristos { 3284e98e3e1Schristos if (strncmp (spec->path, "/", strlen ("/")) == 0) 3294e98e3e1Schristos { 3304e98e3e1Schristos /* cd /... */ 3314e98e3e1Schristos while (current != NULL && hw_parent (current) != NULL) 3324e98e3e1Schristos current = hw_parent (current); 3334e98e3e1Schristos spec->path += strlen ("/"); 3344e98e3e1Schristos } 3354e98e3e1Schristos else if (strncmp (spec->path, "./", strlen ("./")) == 0) 3364e98e3e1Schristos { 3374e98e3e1Schristos /* cd ./... */ 3384e98e3e1Schristos spec->path += strlen ("./"); 3394e98e3e1Schristos } 3404e98e3e1Schristos else if (strncmp (spec->path, "../", strlen ("../")) == 0) 3414e98e3e1Schristos { 3424e98e3e1Schristos /* cd ../... */ 3434e98e3e1Schristos if (current != NULL && hw_parent (current) != NULL) 3444e98e3e1Schristos current = hw_parent (current); 3454e98e3e1Schristos spec->path += strlen ("../"); 3464e98e3e1Schristos } 3474e98e3e1Schristos else if (strcmp (spec->path, ".") == 0) 3484e98e3e1Schristos { 3494e98e3e1Schristos /* cd . */ 3504e98e3e1Schristos spec->path += strlen ("."); 3514e98e3e1Schristos } 3524e98e3e1Schristos else if (strcmp (spec->path, "..") == 0) 3534e98e3e1Schristos { 3544e98e3e1Schristos /* cd .. */ 3554e98e3e1Schristos if (current != NULL && hw_parent (current) != NULL) 3564e98e3e1Schristos current = hw_parent (current); 3574e98e3e1Schristos spec->path += strlen (".."); 3584e98e3e1Schristos } 3594e98e3e1Schristos else 3604e98e3e1Schristos break; 3614e98e3e1Schristos } 3624e98e3e1Schristos 3634e98e3e1Schristos /* now go through the path proper */ 3644e98e3e1Schristos 3654e98e3e1Schristos if (current == NULL) 3664e98e3e1Schristos { 3674e98e3e1Schristos split_device_name (spec); 3684e98e3e1Schristos return NULL; 3694e98e3e1Schristos } 3704e98e3e1Schristos 3714e98e3e1Schristos while (split_device_name (spec)) 3724e98e3e1Schristos { 3734e98e3e1Schristos struct hw *child; 3744e98e3e1Schristos for (child = hw_child (current); 3754e98e3e1Schristos child != NULL; child = hw_sibling (child)) 3764e98e3e1Schristos { 3774e98e3e1Schristos if (strcmp (spec->name, hw_name (child)) == 0) 3784e98e3e1Schristos { 3794e98e3e1Schristos if (spec->unit == NULL) 3804e98e3e1Schristos break; 3814e98e3e1Schristos else 3824e98e3e1Schristos { 3834e98e3e1Schristos hw_unit phys; 3844e98e3e1Schristos hw_unit_decode (current, spec->unit, &phys); 3854e98e3e1Schristos if (memcmp (&phys, hw_unit_address (child), 3864e98e3e1Schristos sizeof (hw_unit)) == 0) 3874e98e3e1Schristos break; 3884e98e3e1Schristos } 3894e98e3e1Schristos } 3904e98e3e1Schristos } 3914e98e3e1Schristos if (child == NULL) 3924e98e3e1Schristos return current; /* search failed */ 3934e98e3e1Schristos current = child; 3944e98e3e1Schristos } 3954e98e3e1Schristos 3964e98e3e1Schristos return current; 3974e98e3e1Schristos } 3984e98e3e1Schristos 3994e98e3e1Schristos 4004e98e3e1Schristos static struct hw * 4014e98e3e1Schristos split_fill_path (struct hw *current, 4024e98e3e1Schristos const char *device_specifier, 4034e98e3e1Schristos name_specifier *spec) 4044e98e3e1Schristos { 4054e98e3e1Schristos /* break it up */ 4064e98e3e1Schristos if (!split_device_specifier (current, device_specifier, spec)) 4074e98e3e1Schristos hw_abort (current, "error parsing %s\n", device_specifier); 4084e98e3e1Schristos 4094e98e3e1Schristos /* fill our tree with its contents */ 4104e98e3e1Schristos current = split_find_device (current, spec); 4114e98e3e1Schristos 4124e98e3e1Schristos /* add any additional devices as needed */ 4134e98e3e1Schristos if (spec->name != NULL) 4144e98e3e1Schristos { 4154e98e3e1Schristos do 4164e98e3e1Schristos { 4174e98e3e1Schristos if (current != NULL && !hw_finished_p (current)) 4184e98e3e1Schristos hw_finish (current); 4194e98e3e1Schristos current = hw_create (NULL, 4204e98e3e1Schristos current, 4214e98e3e1Schristos spec->family, 4224e98e3e1Schristos spec->name, 4234e98e3e1Schristos spec->unit, 4244e98e3e1Schristos spec->args); 4254e98e3e1Schristos } 4264e98e3e1Schristos while (split_device_name (spec)); 4274e98e3e1Schristos } 4284e98e3e1Schristos 4294e98e3e1Schristos return current; 4304e98e3e1Schristos } 4314e98e3e1Schristos 4324e98e3e1Schristos 4334e98e3e1Schristos /* <non-white-space> */ 4344e98e3e1Schristos 4354e98e3e1Schristos static const char * 4364e98e3e1Schristos skip_token (const char *chp) 4374e98e3e1Schristos { 4384e98e3e1Schristos while (!isspace (*chp) && *chp != '\0') 4394e98e3e1Schristos chp++; 4404e98e3e1Schristos while (isspace (*chp) && *chp != '\0') 4414e98e3e1Schristos chp++; 4424e98e3e1Schristos return chp; 4434e98e3e1Schristos } 4444e98e3e1Schristos 4454e98e3e1Schristos 4464e98e3e1Schristos /* count the number of entries */ 4474e98e3e1Schristos 4484e98e3e1Schristos static int 4494e98e3e1Schristos count_entries (struct hw *current, 4504e98e3e1Schristos const char *property_name, 4514e98e3e1Schristos const char *property_value, 4524e98e3e1Schristos int modulo) 4534e98e3e1Schristos { 4544e98e3e1Schristos const char *chp = property_value; 4554e98e3e1Schristos int nr_entries = 0; 4564e98e3e1Schristos while (*chp != '\0') 4574e98e3e1Schristos { 4584e98e3e1Schristos nr_entries += 1; 4594e98e3e1Schristos chp = skip_token (chp); 4604e98e3e1Schristos } 4614e98e3e1Schristos if ((nr_entries % modulo) != 0) 4624e98e3e1Schristos { 4634e98e3e1Schristos hw_abort (current, "incorrect number of entries for %s property %s, should be multiple of %d", 4644e98e3e1Schristos property_name, property_value, modulo); 4654e98e3e1Schristos } 4664e98e3e1Schristos return nr_entries / modulo; 4674e98e3e1Schristos } 4684e98e3e1Schristos 4694e98e3e1Schristos 4704e98e3e1Schristos 4714e98e3e1Schristos /* parse: <address> ::= <token> ; device dependant */ 4724e98e3e1Schristos 4734e98e3e1Schristos static const char * 4744e98e3e1Schristos parse_address (struct hw *current, 4754e98e3e1Schristos struct hw *bus, 4764e98e3e1Schristos const char *chp, 4774e98e3e1Schristos hw_unit *address) 4784e98e3e1Schristos { 4794e98e3e1Schristos if (hw_unit_decode (bus, chp, address) < 0) 4804e98e3e1Schristos hw_abort (current, "invalid unit address in %s", chp); 4814e98e3e1Schristos return skip_token (chp); 4824e98e3e1Schristos } 4834e98e3e1Schristos 4844e98e3e1Schristos 4854e98e3e1Schristos /* parse: <size> ::= <number> { "," <number> } ; */ 4864e98e3e1Schristos 4874e98e3e1Schristos static const char * 4884e98e3e1Schristos parse_size (struct hw *current, 4894e98e3e1Schristos struct hw *bus, 4904e98e3e1Schristos const char *chp, 4914e98e3e1Schristos hw_unit *size) 4924e98e3e1Schristos { 4934e98e3e1Schristos int i; 4944e98e3e1Schristos int nr; 4954e98e3e1Schristos const char *curr = chp; 4964e98e3e1Schristos memset (size, 0, sizeof (*size)); 4974e98e3e1Schristos /* parse the numeric list */ 4984e98e3e1Schristos size->nr_cells = hw_unit_nr_size_cells (bus); 4994e98e3e1Schristos nr = 0; 5004e98e3e1Schristos while (1) 5014e98e3e1Schristos { 5024e98e3e1Schristos char *next; 5034e98e3e1Schristos size->cells[nr] = strtoul (curr, &next, 0); 5044e98e3e1Schristos if (curr == next) 5054e98e3e1Schristos hw_abort (current, "Problem parsing <size> %s", chp); 5064e98e3e1Schristos nr += 1; 5074e98e3e1Schristos if (next[0] != ',') 5084e98e3e1Schristos break; 5094e98e3e1Schristos if (nr == size->nr_cells) 5104e98e3e1Schristos hw_abort (current, "Too many values in <size> %s", chp); 5114e98e3e1Schristos curr = next + 1; 5124e98e3e1Schristos } 5134e98e3e1Schristos ASSERT (nr > 0 && nr <= size->nr_cells); 5144e98e3e1Schristos /* right align the numbers */ 5154e98e3e1Schristos for (i = 1; i <= size->nr_cells; i++) 5164e98e3e1Schristos { 5174e98e3e1Schristos if (i <= nr) 5184e98e3e1Schristos size->cells[size->nr_cells - i] = size->cells[nr - i]; 5194e98e3e1Schristos else 5204e98e3e1Schristos size->cells[size->nr_cells - i] = 0; 5214e98e3e1Schristos } 5224e98e3e1Schristos return skip_token (chp); 5234e98e3e1Schristos } 5244e98e3e1Schristos 5254e98e3e1Schristos 5264e98e3e1Schristos /* parse: <reg> ::= { <address> <size> } ; */ 5274e98e3e1Schristos 5284e98e3e1Schristos static void 5294e98e3e1Schristos parse_reg_property (struct hw *current, 5304e98e3e1Schristos const char *property_name, 5314e98e3e1Schristos const char *property_value) 5324e98e3e1Schristos { 5334e98e3e1Schristos int nr_regs; 5344e98e3e1Schristos int reg_nr; 5354e98e3e1Schristos reg_property_spec *regs; 5364e98e3e1Schristos const char *chp; 5374e98e3e1Schristos 5384e98e3e1Schristos /* determine the number of reg entries by counting tokens */ 5394e98e3e1Schristos nr_regs = count_entries (current, property_name, property_value, 2); 5404e98e3e1Schristos 5414e98e3e1Schristos /* create working space */ 5424e98e3e1Schristos regs = zalloc (nr_regs * sizeof (*regs)); 5434e98e3e1Schristos 5444e98e3e1Schristos /* fill it in */ 5454e98e3e1Schristos chp = property_value; 5464e98e3e1Schristos for (reg_nr = 0; reg_nr < nr_regs; reg_nr++) 5474e98e3e1Schristos { 5484e98e3e1Schristos chp = parse_address (current, hw_parent (current), 5494e98e3e1Schristos chp, ®s[reg_nr].address); 5504e98e3e1Schristos chp = parse_size (current, hw_parent (current), 5514e98e3e1Schristos chp, ®s[reg_nr].size); 5524e98e3e1Schristos } 5534e98e3e1Schristos 5544e98e3e1Schristos /* create it */ 5554e98e3e1Schristos hw_add_reg_array_property (current, property_name, 5564e98e3e1Schristos regs, nr_regs); 5574e98e3e1Schristos 5584e98e3e1Schristos free (regs); 5594e98e3e1Schristos } 5604e98e3e1Schristos 5614e98e3e1Schristos 5624e98e3e1Schristos /* { <child-address> <parent-address> <child-size> }* */ 5634e98e3e1Schristos 5644e98e3e1Schristos static void 5654e98e3e1Schristos parse_ranges_property (struct hw *current, 5664e98e3e1Schristos const char *property_name, 5674e98e3e1Schristos const char *property_value) 5684e98e3e1Schristos { 5694e98e3e1Schristos int nr_ranges; 5704e98e3e1Schristos int range_nr; 5714e98e3e1Schristos range_property_spec *ranges; 5724e98e3e1Schristos const char *chp; 5734e98e3e1Schristos 5744e98e3e1Schristos /* determine the number of ranges specified */ 5754e98e3e1Schristos nr_ranges = count_entries (current, property_name, property_value, 3); 5764e98e3e1Schristos 5774e98e3e1Schristos /* create a property of that size */ 5784e98e3e1Schristos ranges = zalloc (nr_ranges * sizeof (*ranges)); 5794e98e3e1Schristos 5804e98e3e1Schristos /* fill it in */ 5814e98e3e1Schristos chp = property_value; 5824e98e3e1Schristos for (range_nr = 0; range_nr < nr_ranges; range_nr++) 5834e98e3e1Schristos { 5844e98e3e1Schristos chp = parse_address (current, current, 5854e98e3e1Schristos chp, &ranges[range_nr].child_address); 5864e98e3e1Schristos chp = parse_address (current, hw_parent (current), 5874e98e3e1Schristos chp, &ranges[range_nr].parent_address); 5884e98e3e1Schristos chp = parse_size (current, current, 5894e98e3e1Schristos chp, &ranges[range_nr].size); 5904e98e3e1Schristos } 5914e98e3e1Schristos 5924e98e3e1Schristos /* create it */ 5934e98e3e1Schristos hw_add_range_array_property (current, property_name, ranges, nr_ranges); 5944e98e3e1Schristos 5954e98e3e1Schristos free (ranges); 5964e98e3e1Schristos } 5974e98e3e1Schristos 5984e98e3e1Schristos 5994e98e3e1Schristos /* <integer> ... */ 6004e98e3e1Schristos 6014e98e3e1Schristos static void 6024e98e3e1Schristos parse_integer_property (struct hw *current, 6034e98e3e1Schristos const char *property_name, 6044e98e3e1Schristos const char *property_value) 6054e98e3e1Schristos { 6064e98e3e1Schristos int nr_entries; 6074e98e3e1Schristos unsigned_cell words[1024]; 6084e98e3e1Schristos /* integer or integer array? */ 6094e98e3e1Schristos nr_entries = 0; 6104e98e3e1Schristos while (1) 6114e98e3e1Schristos { 6124e98e3e1Schristos char *end; 6134e98e3e1Schristos words[nr_entries] = strtoul (property_value, &end, 0); 6144e98e3e1Schristos if (property_value == end) 6154e98e3e1Schristos break; 6164e98e3e1Schristos nr_entries += 1; 6174e98e3e1Schristos if (nr_entries * sizeof (words[0]) >= sizeof (words)) 6184e98e3e1Schristos hw_abort (current, "buffer overflow"); 6194e98e3e1Schristos property_value = end; 6204e98e3e1Schristos } 6214e98e3e1Schristos if (nr_entries == 0) 6224e98e3e1Schristos hw_abort (current, "error parsing integer property %s (%s)", 6234e98e3e1Schristos property_name, property_value); 6244e98e3e1Schristos else if (nr_entries == 1) 6254e98e3e1Schristos hw_add_integer_property (current, property_name, words[0]); 6264e98e3e1Schristos else 6274e98e3e1Schristos { 6284e98e3e1Schristos int i; 6294e98e3e1Schristos for (i = 0; i < nr_entries; i++) 6304e98e3e1Schristos { 6314e98e3e1Schristos H2BE (words[i]); 6324e98e3e1Schristos } 6334e98e3e1Schristos /* perhaps integer array property is better */ 6344e98e3e1Schristos hw_add_array_property (current, property_name, words, 6354e98e3e1Schristos sizeof (words[0]) * nr_entries); 6364e98e3e1Schristos } 6374e98e3e1Schristos } 6384e98e3e1Schristos 6394e98e3e1Schristos 6404e98e3e1Schristos /* <string> ... */ 6414e98e3e1Schristos 6424e98e3e1Schristos static void 6434e98e3e1Schristos parse_string_property (struct hw *current, 6444e98e3e1Schristos const char *property_name, 6454e98e3e1Schristos const char *property_value) 6464e98e3e1Schristos { 6474e98e3e1Schristos char **strings; 6484e98e3e1Schristos const char *chp; 6494e98e3e1Schristos int nr_strings; 6504e98e3e1Schristos int approx_nr_strings; 6514e98e3e1Schristos 6524e98e3e1Schristos /* get an estimate as to the number of strings by counting double 6534e98e3e1Schristos quotes */ 6544e98e3e1Schristos approx_nr_strings = 2; 6554e98e3e1Schristos for (chp = property_value; *chp; chp++) 6564e98e3e1Schristos { 6574e98e3e1Schristos if (*chp == '"') 6584e98e3e1Schristos approx_nr_strings++; 6594e98e3e1Schristos } 6604e98e3e1Schristos approx_nr_strings = (approx_nr_strings) / 2; 6614e98e3e1Schristos 6624e98e3e1Schristos /* create a string buffer for that many (plus a null) */ 6634e98e3e1Schristos strings = (char**) zalloc ((approx_nr_strings + 1) * sizeof (char*)); 6644e98e3e1Schristos 6654e98e3e1Schristos /* now find all the strings */ 6664e98e3e1Schristos chp = property_value; 6674e98e3e1Schristos nr_strings = 0; 6684e98e3e1Schristos while (1) 6694e98e3e1Schristos { 6704e98e3e1Schristos 6714e98e3e1Schristos /* skip leading space */ 6724e98e3e1Schristos while (*chp != '\0' && isspace (*chp)) 6734e98e3e1Schristos chp += 1; 6744e98e3e1Schristos if (*chp == '\0') 6754e98e3e1Schristos break; 6764e98e3e1Schristos 6774e98e3e1Schristos /* copy it in */ 6784e98e3e1Schristos if (*chp == '"') 6794e98e3e1Schristos { 6804e98e3e1Schristos /* a quoted string - watch for '\' et al. */ 6814e98e3e1Schristos /* estimate the size and allocate space for it */ 6824e98e3e1Schristos int pos; 6834e98e3e1Schristos chp++; 6844e98e3e1Schristos pos = 0; 6854e98e3e1Schristos while (chp[pos] != '\0' && chp[pos] != '"') 6864e98e3e1Schristos { 6874e98e3e1Schristos if (chp[pos] == '\\' && chp[pos+1] != '\0') 6884e98e3e1Schristos pos += 2; 6894e98e3e1Schristos else 6904e98e3e1Schristos pos += 1; 6914e98e3e1Schristos } 6924e98e3e1Schristos strings[nr_strings] = zalloc (pos + 1); 6934e98e3e1Schristos /* copy the string over */ 6944e98e3e1Schristos pos = 0; 6954e98e3e1Schristos while (*chp != '\0' && *chp != '"') 6964e98e3e1Schristos { 6974e98e3e1Schristos if (*chp == '\\' && *(chp+1) != '\0') 6984e98e3e1Schristos { 6994e98e3e1Schristos strings[nr_strings][pos] = *(chp+1); 7004e98e3e1Schristos chp += 2; 7014e98e3e1Schristos pos++; 7024e98e3e1Schristos } 7034e98e3e1Schristos else 7044e98e3e1Schristos { 7054e98e3e1Schristos strings[nr_strings][pos] = *chp; 7064e98e3e1Schristos chp += 1; 7074e98e3e1Schristos pos++; 7084e98e3e1Schristos } 7094e98e3e1Schristos } 7104e98e3e1Schristos if (*chp != '\0') 7114e98e3e1Schristos chp++; 7124e98e3e1Schristos strings[nr_strings][pos] = '\0'; 7134e98e3e1Schristos } 7144e98e3e1Schristos else 7154e98e3e1Schristos { 7164e98e3e1Schristos /* copy over a single unquoted token */ 7174e98e3e1Schristos int len = 0; 7184e98e3e1Schristos while (chp[len] != '\0' && !isspace (chp[len])) 7194e98e3e1Schristos len++; 7204e98e3e1Schristos strings[nr_strings] = zalloc (len + 1); 7214e98e3e1Schristos strncpy (strings[nr_strings], chp, len); 7224e98e3e1Schristos strings[nr_strings][len] = '\0'; 7234e98e3e1Schristos chp += len; 7244e98e3e1Schristos } 7254e98e3e1Schristos nr_strings++; 7264e98e3e1Schristos if (nr_strings > approx_nr_strings) 7274e98e3e1Schristos hw_abort (current, "String property %s badly formatted", 7284e98e3e1Schristos property_name); 7294e98e3e1Schristos } 7304e98e3e1Schristos ASSERT (strings[nr_strings] == NULL); /* from zalloc */ 7314e98e3e1Schristos 7324e98e3e1Schristos /* install it */ 7334e98e3e1Schristos if (nr_strings == 0) 7344e98e3e1Schristos hw_add_string_property (current, property_name, ""); 7354e98e3e1Schristos else if (nr_strings == 1) 7364e98e3e1Schristos hw_add_string_property (current, property_name, strings[0]); 7374e98e3e1Schristos else 7384e98e3e1Schristos { 7394e98e3e1Schristos const char **specs = (const char**) strings; /* stop a bogus error */ 7404e98e3e1Schristos hw_add_string_array_property (current, property_name, 7414e98e3e1Schristos specs, nr_strings); 7424e98e3e1Schristos } 7434e98e3e1Schristos 7444e98e3e1Schristos /* flush the created string */ 7454e98e3e1Schristos while (nr_strings > 0) 7464e98e3e1Schristos { 7474e98e3e1Schristos nr_strings--; 7484e98e3e1Schristos free (strings[nr_strings]); 7494e98e3e1Schristos } 7504e98e3e1Schristos free (strings); 7514e98e3e1Schristos } 7524e98e3e1Schristos 7534e98e3e1Schristos 7544e98e3e1Schristos /* <path-to-ihandle-device> */ 7554e98e3e1Schristos 7564e98e3e1Schristos #if NOT_YET 7574e98e3e1Schristos static void 7584e98e3e1Schristos parse_ihandle_property (struct hw *current, 7594e98e3e1Schristos const char *property, 7604e98e3e1Schristos const char *value) 7614e98e3e1Schristos { 7624e98e3e1Schristos ihandle_runtime_property_spec ihandle; 7634e98e3e1Schristos 7644e98e3e1Schristos /* pass the full path */ 7654e98e3e1Schristos ihandle.full_path = value; 7664e98e3e1Schristos 7674e98e3e1Schristos /* save this ready for the ihandle create */ 7684e98e3e1Schristos hw_add_ihandle_runtime_property (current, property, 7694e98e3e1Schristos &ihandle); 7704e98e3e1Schristos } 7714e98e3e1Schristos #endif 7724e98e3e1Schristos 7734e98e3e1Schristos 7744e98e3e1Schristos struct hw * 7754e98e3e1Schristos hw_tree_create (SIM_DESC sd, 7764e98e3e1Schristos const char *family) 7774e98e3e1Schristos { 7784e98e3e1Schristos return hw_create (sd, NULL, family, family, NULL, NULL); 7794e98e3e1Schristos } 7804e98e3e1Schristos 7814e98e3e1Schristos void 7824e98e3e1Schristos hw_tree_delete (struct hw *me) 7834e98e3e1Schristos { 7844e98e3e1Schristos /* Need to allow devices to disapear under our feet */ 7854e98e3e1Schristos while (hw_child (me) != NULL) 7864e98e3e1Schristos { 7874e98e3e1Schristos hw_tree_delete (hw_child (me)); 7884e98e3e1Schristos } 7894e98e3e1Schristos hw_delete (me); 7904e98e3e1Schristos } 7914e98e3e1Schristos 7924e98e3e1Schristos 7934e98e3e1Schristos struct hw * 7944e98e3e1Schristos hw_tree_parse (struct hw *current, 7954e98e3e1Schristos const char *fmt, 7964e98e3e1Schristos ...) 7974e98e3e1Schristos { 7984e98e3e1Schristos va_list ap; 7994e98e3e1Schristos va_start (ap, fmt); 8004e98e3e1Schristos current = hw_tree_vparse (current, fmt, ap); 8014e98e3e1Schristos va_end (ap); 8024e98e3e1Schristos return current; 8034e98e3e1Schristos } 8044e98e3e1Schristos 8054e98e3e1Schristos struct hw * 8064e98e3e1Schristos hw_tree_vparse (struct hw *current, 8074e98e3e1Schristos const char *fmt, 8084e98e3e1Schristos va_list ap) 8094e98e3e1Schristos { 8104e98e3e1Schristos char device_specifier[1024]; 8114e98e3e1Schristos name_specifier spec; 8124e98e3e1Schristos 8134e98e3e1Schristos /* format the path */ 8144e98e3e1Schristos vsprintf (device_specifier, fmt, ap); 8154e98e3e1Schristos if (strlen (device_specifier) >= sizeof (device_specifier)) 8164e98e3e1Schristos hw_abort (NULL, "device_tree_add_deviced: buffer overflow\n"); 8174e98e3e1Schristos 8184e98e3e1Schristos /* construct the tree down to the final struct hw */ 8194e98e3e1Schristos current = split_fill_path (current, device_specifier, &spec); 8204e98e3e1Schristos 8214e98e3e1Schristos /* is there an interrupt spec */ 8224e98e3e1Schristos if (spec.property == NULL 8234e98e3e1Schristos && spec.value != NULL) 8244e98e3e1Schristos { 8254e98e3e1Schristos char *op = split_value (&spec); 8264e98e3e1Schristos switch (op[0]) 8274e98e3e1Schristos { 8284e98e3e1Schristos case '>': 8294e98e3e1Schristos { 8304e98e3e1Schristos char *my_port_name = split_value (&spec); 8314e98e3e1Schristos int my_port; 8324e98e3e1Schristos char *dest_port_name = split_value (&spec); 8334e98e3e1Schristos int dest_port; 8344e98e3e1Schristos name_specifier dest_spec; 8354e98e3e1Schristos char *dest_hw_name = split_value (&spec); 8364e98e3e1Schristos struct hw *dest; 8374e98e3e1Schristos /* find my name */ 8384e98e3e1Schristos if (!hw_finished_p (current)) 8394e98e3e1Schristos hw_finish (current); 8404e98e3e1Schristos my_port = hw_port_decode (current, my_port_name, output_port); 8414e98e3e1Schristos /* find the dest device and port */ 8424e98e3e1Schristos dest = split_fill_path (current, dest_hw_name, &dest_spec); 8434e98e3e1Schristos if (!hw_finished_p (dest)) 8444e98e3e1Schristos hw_finish (dest); 8454e98e3e1Schristos dest_port = hw_port_decode (dest, dest_port_name, 8464e98e3e1Schristos input_port); 8474e98e3e1Schristos /* connect the two */ 8484e98e3e1Schristos hw_port_attach (current, 8494e98e3e1Schristos my_port, 8504e98e3e1Schristos dest, 8514e98e3e1Schristos dest_port, 852*88241920Schristos permanent_object); 8534e98e3e1Schristos break; 8544e98e3e1Schristos } 8554e98e3e1Schristos default: 8564e98e3e1Schristos hw_abort (current, "unreconised interrupt spec %s\n", spec.value); 8574e98e3e1Schristos break; 8584e98e3e1Schristos } 8594e98e3e1Schristos } 8604e98e3e1Schristos 8614e98e3e1Schristos /* is there a property */ 8624e98e3e1Schristos if (spec.property != NULL) 8634e98e3e1Schristos { 8644e98e3e1Schristos if (strcmp (spec.value, "true") == 0) 8654e98e3e1Schristos hw_add_boolean_property (current, spec.property, 1); 8664e98e3e1Schristos else if (strcmp (spec.value, "false") == 0) 8674e98e3e1Schristos hw_add_boolean_property (current, spec.property, 0); 8684e98e3e1Schristos else 8694e98e3e1Schristos { 8704e98e3e1Schristos const struct hw_property *property; 8714e98e3e1Schristos switch (spec.value[0]) 8724e98e3e1Schristos { 8734e98e3e1Schristos #if NOT_YET 8744e98e3e1Schristos case '*': 8754e98e3e1Schristos { 8764e98e3e1Schristos parse_ihandle_property (current, spec.property, spec.value + 1); 8774e98e3e1Schristos break; 8784e98e3e1Schristos } 8794e98e3e1Schristos #endif 8804e98e3e1Schristos case '[': 8814e98e3e1Schristos { 8824b169a6bSchristos uint8_t words[1024]; 8834e98e3e1Schristos char *curr = spec.value + 1; 8844e98e3e1Schristos int nr_words = 0; 8854e98e3e1Schristos while (1) 8864e98e3e1Schristos { 8874e98e3e1Schristos char *next; 8884e98e3e1Schristos words[nr_words] = H2BE_1 (strtoul (curr, &next, 0)); 8894e98e3e1Schristos if (curr == next) 8904e98e3e1Schristos break; 8914e98e3e1Schristos curr = next; 8924e98e3e1Schristos nr_words += 1; 8934e98e3e1Schristos } 8944e98e3e1Schristos hw_add_array_property (current, spec.property, 8954e98e3e1Schristos words, sizeof (words[0]) * nr_words); 8964e98e3e1Schristos break; 8974e98e3e1Schristos } 8984e98e3e1Schristos case '"': 8994e98e3e1Schristos { 9004e98e3e1Schristos parse_string_property (current, spec.property, spec.value); 9014e98e3e1Schristos break; 9024e98e3e1Schristos } 9034e98e3e1Schristos case '!': 9044e98e3e1Schristos { 9054e98e3e1Schristos spec.value++; 9064e98e3e1Schristos property = hw_tree_find_property (current, spec.value); 9074e98e3e1Schristos if (property == NULL) 9084e98e3e1Schristos hw_abort (current, "property %s not found\n", spec.value); 9094e98e3e1Schristos hw_add_duplicate_property (current, 9104e98e3e1Schristos spec.property, 9114e98e3e1Schristos property); 9124e98e3e1Schristos break; 9134e98e3e1Schristos } 9144e98e3e1Schristos default: 9154e98e3e1Schristos { 9164e98e3e1Schristos if (strcmp (spec.property, "reg") == 0 9174e98e3e1Schristos || strcmp (spec.property, "assigned-addresses") == 0 9184e98e3e1Schristos || strcmp (spec.property, "alternate-reg") == 0) 9194e98e3e1Schristos { 9204e98e3e1Schristos parse_reg_property (current, spec.property, spec.value); 9214e98e3e1Schristos } 9224e98e3e1Schristos else if (strcmp (spec.property, "ranges") == 0) 9234e98e3e1Schristos { 9244e98e3e1Schristos parse_ranges_property (current, spec.property, spec.value); 9254e98e3e1Schristos } 9264e98e3e1Schristos else if (isdigit (spec.value[0]) 9274e98e3e1Schristos || (spec.value[0] == '-' && isdigit (spec.value[1])) 9284e98e3e1Schristos || (spec.value[0] == '+' && isdigit (spec.value[1]))) 9294e98e3e1Schristos { 9304e98e3e1Schristos parse_integer_property (current, spec.property, spec.value); 9314e98e3e1Schristos } 9324e98e3e1Schristos else 9334e98e3e1Schristos parse_string_property (current, spec.property, spec.value); 9344e98e3e1Schristos break; 9354e98e3e1Schristos } 9364e98e3e1Schristos } 9374e98e3e1Schristos } 9384e98e3e1Schristos } 9394e98e3e1Schristos return current; 9404e98e3e1Schristos } 9414e98e3e1Schristos 9424e98e3e1Schristos 9434e98e3e1Schristos static void 9444e98e3e1Schristos finish_hw_tree (struct hw *me, 9454e98e3e1Schristos void *data) 9464e98e3e1Schristos { 9474e98e3e1Schristos if (!hw_finished_p (me)) 9484e98e3e1Schristos hw_finish (me); 9494e98e3e1Schristos } 9504e98e3e1Schristos 9514e98e3e1Schristos void 9524e98e3e1Schristos hw_tree_finish (struct hw *root) 9534e98e3e1Schristos { 9544e98e3e1Schristos hw_tree_traverse (root, finish_hw_tree, NULL, NULL); 9554e98e3e1Schristos } 9564e98e3e1Schristos 9574e98e3e1Schristos 9584e98e3e1Schristos 9594e98e3e1Schristos void 9604e98e3e1Schristos hw_tree_traverse (struct hw *root, 9614e98e3e1Schristos hw_tree_traverse_function *prefix, 9624e98e3e1Schristos hw_tree_traverse_function *postfix, 9634e98e3e1Schristos void *data) 9644e98e3e1Schristos { 9654e98e3e1Schristos struct hw *child; 9664e98e3e1Schristos if (prefix != NULL) 9674e98e3e1Schristos prefix (root, data); 9684e98e3e1Schristos for (child = hw_child (root); 9694e98e3e1Schristos child != NULL; 9704e98e3e1Schristos child = hw_sibling (child)) 9714e98e3e1Schristos { 9724e98e3e1Schristos hw_tree_traverse (child, prefix, postfix, data); 9734e98e3e1Schristos } 9744e98e3e1Schristos if (postfix != NULL) 9754e98e3e1Schristos postfix (root, data); 9764e98e3e1Schristos } 9774e98e3e1Schristos 9784e98e3e1Schristos 9794e98e3e1Schristos 9804e98e3e1Schristos struct printer 9814e98e3e1Schristos { 9824e98e3e1Schristos hw_tree_print_callback *print; 9834e98e3e1Schristos void *file; 9844e98e3e1Schristos }; 9854e98e3e1Schristos 9864e98e3e1Schristos static void 9874e98e3e1Schristos print_address (struct hw *bus, 9884e98e3e1Schristos const hw_unit *phys, 9894e98e3e1Schristos struct printer *p) 9904e98e3e1Schristos { 9914e98e3e1Schristos char unit[32]; 9924e98e3e1Schristos hw_unit_encode (bus, phys, unit, sizeof (unit)); 9934e98e3e1Schristos p->print (p->file, " %s", unit); 9944e98e3e1Schristos } 9954e98e3e1Schristos 9964e98e3e1Schristos static void 9974e98e3e1Schristos print_size (struct hw *bus, 9984e98e3e1Schristos const hw_unit *size, 9994e98e3e1Schristos struct printer *p) 10004e98e3e1Schristos { 10014e98e3e1Schristos int i; 10024e98e3e1Schristos for (i = 0; i < size->nr_cells; i++) 10034e98e3e1Schristos if (size->cells[i] != 0) 10044e98e3e1Schristos break; 10054e98e3e1Schristos if (i < size->nr_cells) 10064e98e3e1Schristos { 10074e98e3e1Schristos p->print (p->file, " 0x%lx", (unsigned long) size->cells[i]); 10084e98e3e1Schristos i++; 10094e98e3e1Schristos for (; i < size->nr_cells; i++) 10104e98e3e1Schristos p->print (p->file, ",0x%lx", (unsigned long) size->cells[i]); 10114e98e3e1Schristos } 10124e98e3e1Schristos else 10134e98e3e1Schristos p->print (p->file, " 0"); 10144e98e3e1Schristos } 10154e98e3e1Schristos 10164e98e3e1Schristos static void 10174e98e3e1Schristos print_reg_property (struct hw *me, 10184e98e3e1Schristos const struct hw_property *property, 10194e98e3e1Schristos struct printer *p) 10204e98e3e1Schristos { 10214e98e3e1Schristos int reg_nr; 10224e98e3e1Schristos reg_property_spec reg; 10234e98e3e1Schristos for (reg_nr = 0; 10244e98e3e1Schristos hw_find_reg_array_property (me, property->name, reg_nr, ®); 10254e98e3e1Schristos reg_nr++) 10264e98e3e1Schristos { 10274e98e3e1Schristos print_address (hw_parent (me), ®.address, p); 10284e98e3e1Schristos print_size (me, ®.size, p); 10294e98e3e1Schristos } 10304e98e3e1Schristos } 10314e98e3e1Schristos 10324e98e3e1Schristos static void 10334e98e3e1Schristos print_ranges_property (struct hw *me, 10344e98e3e1Schristos const struct hw_property *property, 10354e98e3e1Schristos struct printer *p) 10364e98e3e1Schristos { 10374e98e3e1Schristos int range_nr; 10384e98e3e1Schristos range_property_spec range; 10394e98e3e1Schristos for (range_nr = 0; 10404e98e3e1Schristos hw_find_range_array_property (me, property->name, range_nr, &range); 10414e98e3e1Schristos range_nr++) 10424e98e3e1Schristos { 10434e98e3e1Schristos print_address (me, &range.child_address, p); 10444e98e3e1Schristos print_address (hw_parent (me), &range.parent_address, p); 10454e98e3e1Schristos print_size (me, &range.size, p); 10464e98e3e1Schristos } 10474e98e3e1Schristos } 10484e98e3e1Schristos 10494e98e3e1Schristos static void 10504e98e3e1Schristos print_string (struct hw *me, 10514e98e3e1Schristos const char *string, 10524e98e3e1Schristos struct printer *p) 10534e98e3e1Schristos { 10544e98e3e1Schristos p->print (p->file, " \""); 10554e98e3e1Schristos while (*string != '\0') 10564e98e3e1Schristos { 10574e98e3e1Schristos switch (*string) 10584e98e3e1Schristos { 10594e98e3e1Schristos case '"': 10604e98e3e1Schristos p->print (p->file, "\\\""); 10614e98e3e1Schristos break; 10624e98e3e1Schristos case '\\': 10634e98e3e1Schristos p->print (p->file, "\\\\"); 10644e98e3e1Schristos break; 10654e98e3e1Schristos default: 10664e98e3e1Schristos p->print (p->file, "%c", *string); 10674e98e3e1Schristos break; 10684e98e3e1Schristos } 10694e98e3e1Schristos string++; 10704e98e3e1Schristos } 10714e98e3e1Schristos p->print (p->file, "\""); 10724e98e3e1Schristos } 10734e98e3e1Schristos 10744e98e3e1Schristos static void 10754e98e3e1Schristos print_string_array_property (struct hw *me, 10764e98e3e1Schristos const struct hw_property *property, 10774e98e3e1Schristos struct printer *p) 10784e98e3e1Schristos { 10794e98e3e1Schristos int nr; 10804e98e3e1Schristos string_property_spec string; 10814e98e3e1Schristos for (nr = 0; 10824e98e3e1Schristos hw_find_string_array_property (me, property->name, nr, &string); 10834e98e3e1Schristos nr++) 10844e98e3e1Schristos { 10854e98e3e1Schristos print_string (me, string, p); 10864e98e3e1Schristos } 10874e98e3e1Schristos } 10884e98e3e1Schristos 10894e98e3e1Schristos static void 10904e98e3e1Schristos print_properties (struct hw *me, 10914e98e3e1Schristos struct printer *p) 10924e98e3e1Schristos { 10934e98e3e1Schristos const struct hw_property *property; 10944e98e3e1Schristos for (property = hw_find_property (me, NULL); 10954e98e3e1Schristos property != NULL; 10964e98e3e1Schristos property = hw_next_property (property)) 10974e98e3e1Schristos { 10984e98e3e1Schristos if (hw_parent (me) == NULL) 10994e98e3e1Schristos p->print (p->file, "/%s", property->name); 11004e98e3e1Schristos else 11014e98e3e1Schristos p->print (p->file, "%s/%s", hw_path (me), property->name); 11024e98e3e1Schristos if (property->original != NULL) 11034e98e3e1Schristos { 11044e98e3e1Schristos p->print (p->file, " !"); 11054e98e3e1Schristos p->print (p->file, "%s/%s", 11064e98e3e1Schristos hw_path (property->original->owner), 11074e98e3e1Schristos property->original->name); 11084e98e3e1Schristos } 11094e98e3e1Schristos else 11104e98e3e1Schristos { 11114e98e3e1Schristos switch (property->type) 11124e98e3e1Schristos { 11134e98e3e1Schristos case array_property: 11144e98e3e1Schristos { 11154e98e3e1Schristos if ((property->sizeof_array % sizeof (signed_cell)) == 0) 11164e98e3e1Schristos { 11174e98e3e1Schristos unsigned_cell *w = (unsigned_cell*) property->array; 11184e98e3e1Schristos int cell_nr; 11194e98e3e1Schristos for (cell_nr = 0; 11204e98e3e1Schristos cell_nr < (property->sizeof_array / sizeof (unsigned_cell)); 11214e98e3e1Schristos cell_nr++) 11224e98e3e1Schristos { 11234e98e3e1Schristos p->print (p->file, " 0x%lx", (unsigned long) BE2H_cell (w[cell_nr])); 11244e98e3e1Schristos } 11254e98e3e1Schristos } 11264e98e3e1Schristos else 11274e98e3e1Schristos { 11284b169a6bSchristos uint8_t *w = (uint8_t*)property->array; 11294e98e3e1Schristos p->print (p->file, " ["); 11304e98e3e1Schristos while ((char*)w - (char*)property->array < property->sizeof_array) 11314e98e3e1Schristos { 11324e98e3e1Schristos p->print (p->file, " 0x%2x", BE2H_1 (*w)); 11334e98e3e1Schristos w++; 11344e98e3e1Schristos } 11354e98e3e1Schristos } 11364e98e3e1Schristos break; 11374e98e3e1Schristos } 11384e98e3e1Schristos case boolean_property: 11394e98e3e1Schristos { 11404e98e3e1Schristos int b = hw_find_boolean_property (me, property->name); 11414e98e3e1Schristos p->print (p->file, " %s", b ? "true" : "false"); 11424e98e3e1Schristos break; 11434e98e3e1Schristos } 11444e98e3e1Schristos #if NOT_YET 11454e98e3e1Schristos case ihandle_property: 11464e98e3e1Schristos { 11474e98e3e1Schristos if (property->array != NULL) 11484e98e3e1Schristos { 11494e98e3e1Schristos device_instance *instance = hw_find_ihandle_property (me, property->name); 11504e98e3e1Schristos p->print (p->file, " *%s", device_instance_path (instance)); 11514e98e3e1Schristos } 11524e98e3e1Schristos else 11534e98e3e1Schristos { 11544e98e3e1Schristos /* not yet initialized, ask the device for the path */ 11554e98e3e1Schristos ihandle_runtime_property_spec spec; 11564e98e3e1Schristos hw_find_ihandle_runtime_property (me, property->name, &spec); 11574e98e3e1Schristos p->print (p->file, " *%s", spec.full_path); 11584e98e3e1Schristos } 11594e98e3e1Schristos break; 11604e98e3e1Schristos } 11614e98e3e1Schristos #endif 11624e98e3e1Schristos case integer_property: 11634e98e3e1Schristos { 11644e98e3e1Schristos unsigned_word w = hw_find_integer_property (me, property->name); 11654e98e3e1Schristos p->print (p->file, " 0x%lx", (unsigned long)w); 11664e98e3e1Schristos break; 11674e98e3e1Schristos } 11684e98e3e1Schristos case range_array_property: 11694e98e3e1Schristos { 11704e98e3e1Schristos print_ranges_property (me, property, p); 11714e98e3e1Schristos break; 11724e98e3e1Schristos } 11734e98e3e1Schristos case reg_array_property: 11744e98e3e1Schristos { 11754e98e3e1Schristos print_reg_property (me, property, p); 11764e98e3e1Schristos break; 11774e98e3e1Schristos } 11784e98e3e1Schristos case string_property: 11794e98e3e1Schristos { 11804e98e3e1Schristos const char *s = hw_find_string_property (me, property->name); 11814e98e3e1Schristos print_string (me, s, p); 11824e98e3e1Schristos break; 11834e98e3e1Schristos } 11844e98e3e1Schristos case string_array_property: 11854e98e3e1Schristos { 11864e98e3e1Schristos print_string_array_property (me, property, p); 11874e98e3e1Schristos break; 11884e98e3e1Schristos } 11894e98e3e1Schristos } 11904e98e3e1Schristos } 11914e98e3e1Schristos p->print (p->file, "\n"); 11924e98e3e1Schristos } 11934e98e3e1Schristos } 11944e98e3e1Schristos 11954e98e3e1Schristos static void 11964e98e3e1Schristos print_interrupts (struct hw *me, 11974e98e3e1Schristos int my_port, 11984e98e3e1Schristos struct hw *dest, 11994e98e3e1Schristos int dest_port, 12004e98e3e1Schristos void *data) 12014e98e3e1Schristos { 12024e98e3e1Schristos struct printer *p = data; 12034e98e3e1Schristos char src[32]; 12044e98e3e1Schristos char dst[32]; 12054e98e3e1Schristos hw_port_encode (me, my_port, src, sizeof (src), output_port); 12064e98e3e1Schristos hw_port_encode (dest, dest_port, dst, sizeof (dst), input_port); 12074e98e3e1Schristos p->print (p->file, 12084e98e3e1Schristos "%s > %s %s %s\n", 12094e98e3e1Schristos hw_path (me), 12104e98e3e1Schristos src, dst, 12114e98e3e1Schristos hw_path (dest)); 12124e98e3e1Schristos } 12134e98e3e1Schristos 12144e98e3e1Schristos static void 12154e98e3e1Schristos print_device (struct hw *me, 12164e98e3e1Schristos void *data) 12174e98e3e1Schristos { 12184e98e3e1Schristos struct printer *p = data; 12194e98e3e1Schristos p->print (p->file, "%s\n", hw_path (me)); 12204e98e3e1Schristos print_properties (me, p); 12214e98e3e1Schristos hw_port_traverse (me, print_interrupts, data); 12224e98e3e1Schristos } 12234e98e3e1Schristos 12244e98e3e1Schristos void 12254e98e3e1Schristos hw_tree_print (struct hw *root, 12264e98e3e1Schristos hw_tree_print_callback *print, 12274e98e3e1Schristos void *file) 12284e98e3e1Schristos { 12294e98e3e1Schristos struct printer p; 12304e98e3e1Schristos p.print = print; 12314e98e3e1Schristos p.file = file; 12324e98e3e1Schristos hw_tree_traverse (root, 12334e98e3e1Schristos print_device, NULL, 12344e98e3e1Schristos &p); 12354e98e3e1Schristos } 12364e98e3e1Schristos 12374e98e3e1Schristos 12384e98e3e1Schristos 12394e98e3e1Schristos #if NOT_YET 12404e98e3e1Schristos device_instance * 12414e98e3e1Schristos tree_instance (struct hw *root, 12424e98e3e1Schristos const char *device_specifier) 12434e98e3e1Schristos { 12444e98e3e1Schristos /* find the device node */ 12454e98e3e1Schristos struct hw *me; 12464e98e3e1Schristos name_specifier spec; 12474e98e3e1Schristos if (!split_device_specifier (root, device_specifier, &spec)) 12484e98e3e1Schristos return NULL; 12494e98e3e1Schristos me = split_find_device (root, &spec); 12504e98e3e1Schristos if (spec.name != NULL) 12514e98e3e1Schristos return NULL; 12524e98e3e1Schristos /* create the instance */ 12534e98e3e1Schristos return device_create_instance (me, device_specifier, spec.last_args); 12544e98e3e1Schristos } 12554e98e3e1Schristos #endif 12564e98e3e1Schristos 12574e98e3e1Schristos struct hw * 12584e98e3e1Schristos hw_tree_find_device (struct hw *root, 12594e98e3e1Schristos const char *path_to_device) 12604e98e3e1Schristos { 12614e98e3e1Schristos struct hw *node; 12624e98e3e1Schristos name_specifier spec; 12634e98e3e1Schristos 12644e98e3e1Schristos /* parse the path */ 12654e98e3e1Schristos split_device_specifier (root, path_to_device, &spec); 12664e98e3e1Schristos if (spec.value != NULL) 12674e98e3e1Schristos return NULL; /* something wierd */ 12684e98e3e1Schristos 12694e98e3e1Schristos /* now find it */ 12704e98e3e1Schristos node = split_find_device (root, &spec); 12714e98e3e1Schristos if (spec.name != NULL) 12724e98e3e1Schristos return NULL; /* not a leaf */ 12734e98e3e1Schristos 12744e98e3e1Schristos return node; 12754e98e3e1Schristos } 12764e98e3e1Schristos 12774e98e3e1Schristos 12784e98e3e1Schristos const struct hw_property * 12794e98e3e1Schristos hw_tree_find_property (struct hw *root, 12804e98e3e1Schristos const char *path_to_property) 12814e98e3e1Schristos { 12824e98e3e1Schristos name_specifier spec; 12834e98e3e1Schristos if (!split_property_specifier (root, path_to_property, &spec)) 12844e98e3e1Schristos hw_abort (root, "Invalid property path %s", path_to_property); 12854e98e3e1Schristos root = split_find_device (root, &spec); 12864e98e3e1Schristos if (spec.name != NULL) 12874e98e3e1Schristos return NULL; /* not a leaf */ 12884e98e3e1Schristos return hw_find_property (root, spec.property); 12894e98e3e1Schristos } 12904e98e3e1Schristos 12914e98e3e1Schristos int 12924e98e3e1Schristos hw_tree_find_boolean_property (struct hw *root, 12934e98e3e1Schristos const char *path_to_property) 12944e98e3e1Schristos { 12954e98e3e1Schristos name_specifier spec; 12964e98e3e1Schristos if (!split_property_specifier (root, path_to_property, &spec)) 12974e98e3e1Schristos hw_abort (root, "Invalid property path %s", path_to_property); 12984e98e3e1Schristos root = split_find_device (root, &spec); 12994e98e3e1Schristos if (spec.name != NULL) 13004e98e3e1Schristos hw_abort (root, "device \"%s\" not found (property \"%s\")", 13014e98e3e1Schristos spec.name, path_to_property); 13024e98e3e1Schristos return hw_find_boolean_property (root, spec.property); 13034e98e3e1Schristos } 13044e98e3e1Schristos 13054e98e3e1Schristos signed_cell 13064e98e3e1Schristos hw_tree_find_integer_property (struct hw *root, 13074e98e3e1Schristos const char *path_to_property) 13084e98e3e1Schristos { 13094e98e3e1Schristos name_specifier spec; 13104e98e3e1Schristos if (!split_property_specifier (root, path_to_property, &spec)) 13114e98e3e1Schristos hw_abort (root, "Invalid property path %s", path_to_property); 13124e98e3e1Schristos root = split_find_device (root, &spec); 13134e98e3e1Schristos if (spec.name != NULL) 13144e98e3e1Schristos hw_abort (root, "device \"%s\" not found (property \"%s\")", 13154e98e3e1Schristos spec.name, path_to_property); 13164e98e3e1Schristos return hw_find_integer_property (root, spec.property); 13174e98e3e1Schristos } 13184e98e3e1Schristos 13194e98e3e1Schristos #if NOT_YET 13204e98e3e1Schristos device_instance * 13214e98e3e1Schristos hw_tree_find_ihandle_property (struct hw *root, 13224e98e3e1Schristos const char *path_to_property) 13234e98e3e1Schristos { 13244e98e3e1Schristos struct hw *root; 13254e98e3e1Schristos name_specifier spec; 13264e98e3e1Schristos if (!split_property_specifier (root, path_to_property, &spec)) 13274e98e3e1Schristos hw_abort (root, "Invalid property path %s", path_to_property); 13284e98e3e1Schristos root = split_find_device (root, &spec); 13294e98e3e1Schristos if (spec.name != NULL) 13304e98e3e1Schristos hw_abort (root, "device \"%s\" not found (property \"%s\")", 13314e98e3e1Schristos spec.name, path_to_property); 13324e98e3e1Schristos return hw_find_ihandle_property (root, spec.property); 13334e98e3e1Schristos } 13344e98e3e1Schristos #endif 13354e98e3e1Schristos 13364e98e3e1Schristos const char * 13374e98e3e1Schristos hw_tree_find_string_property (struct hw *root, 13384e98e3e1Schristos const char *path_to_property) 13394e98e3e1Schristos { 13404e98e3e1Schristos name_specifier spec; 13414e98e3e1Schristos if (!split_property_specifier (root, path_to_property, &spec)) 13424e98e3e1Schristos hw_abort (root, "Invalid property path %s", path_to_property); 13434e98e3e1Schristos root = split_find_device (root, &spec); 13444e98e3e1Schristos if (spec.name != NULL) 13454e98e3e1Schristos hw_abort (root, "device \"%s\" not found (property \"%s\")", 13464e98e3e1Schristos spec.name, path_to_property); 13474e98e3e1Schristos return hw_find_string_property (root, spec.property); 13484e98e3e1Schristos } 1349