1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/promif_impl.h> 30 #include <sys/kmem.h> 31 #include <sys/machsystm.h> 32 33 /* 34 * A property attached to a node in the kernel's 35 * shadow copy of the PROM device tree. 36 */ 37 typedef struct prom_prop { 38 struct prom_prop *pp_next; 39 char *pp_name; 40 int pp_len; 41 void *pp_val; 42 } prom_prop_t; 43 44 /* 45 * A node in the kernel's shadow copy of the PROM 46 * device tree. 47 */ 48 typedef struct prom_node { 49 pnode_t pn_nodeid; 50 struct prom_prop *pn_propp; 51 struct prom_node *pn_parent; 52 struct prom_node *pn_child; 53 struct prom_node *pn_sibling; 54 } prom_node_t; 55 56 static prom_node_t *promif_root; 57 58 static prom_node_t *find_node(pnode_t nodeid); 59 static prom_node_t *find_node_work(prom_node_t *np, pnode_t node); 60 static int getproplen(prom_node_t *pnp, char *name); 61 static void *getprop(prom_node_t *pnp, char *name); 62 static char *nextprop(prom_node_t *pnp, char *name); 63 64 #ifndef _KMDB 65 static void create_prop(prom_node_t *pnp, char *name, void *val, int len); 66 static prom_node_t *create_node(prom_node_t *parent, pnode_t node); 67 static void create_peers(prom_node_t *pnp, pnode_t node); 68 static void create_children(prom_node_t *pnp, pnode_t parent); 69 #endif 70 71 /* 72 * Hooks for kmdb for accessing the PROM shadow tree. The driver portion 73 * of kmdb will retrieve the root of the tree and pass it down to the 74 * debugger portion of kmdb. As the kmdb debugger is standalone, it has 75 * its own promif_root pointer that it will be set to the value passed by 76 * the driver so that kmdb points to the shadow tree maintained by the kernel. 77 * So the "get" function is in the kernel while the "set" function is in kmdb. 78 */ 79 #ifdef _KMDB 80 void 81 promif_stree_setroot(void *root) 82 { 83 promif_root = (prom_node_t *)root; 84 } 85 #else 86 void * 87 promif_stree_getroot(void) 88 { 89 return (promif_root); 90 } 91 #endif 92 93 /* 94 * Interfaces used internally by promif functions. 95 * These hide all accesses to the shadow tree. 96 */ 97 98 pnode_t 99 promif_stree_parentnode(pnode_t nodeid) 100 { 101 prom_node_t *pnp; 102 103 pnp = find_node(nodeid); 104 if (pnp && pnp->pn_parent) { 105 return (pnp->pn_parent->pn_nodeid); 106 } 107 108 return (OBP_NONODE); 109 } 110 111 pnode_t 112 promif_stree_childnode(pnode_t nodeid) 113 { 114 prom_node_t *pnp; 115 116 pnp = find_node(nodeid); 117 if (pnp && pnp->pn_child) 118 return (pnp->pn_child->pn_nodeid); 119 120 return (OBP_NONODE); 121 } 122 123 pnode_t 124 promif_stree_nextnode(pnode_t nodeid) 125 { 126 prom_node_t *pnp; 127 128 /* 129 * Note: next(0) returns the root node 130 */ 131 pnp = find_node(nodeid); 132 if (pnp && (nodeid == OBP_NONODE)) 133 return (pnp->pn_nodeid); 134 if (pnp && pnp->pn_sibling) 135 return (pnp->pn_sibling->pn_nodeid); 136 137 return (OBP_NONODE); 138 } 139 140 int 141 promif_stree_getproplen(pnode_t nodeid, char *name) 142 { 143 prom_node_t *pnp; 144 145 pnp = find_node(nodeid); 146 if (pnp == NULL) 147 return (-1); 148 149 return (getproplen(pnp, name)); 150 } 151 152 int 153 promif_stree_getprop(pnode_t nodeid, char *name, void *value) 154 { 155 prom_node_t *pnp; 156 void *prop; 157 int len; 158 159 pnp = find_node(nodeid); 160 if (pnp == NULL) { 161 prom_printf("find_node: no node?\n"); 162 return (-1); 163 } 164 165 len = getproplen(pnp, name); 166 if (len > 0) { 167 prop = getprop(pnp, name); 168 bcopy(prop, value, len); 169 } else { 170 prom_printf("find_node: getproplen: %d\n", len); 171 } 172 173 return (len); 174 } 175 176 char * 177 promif_stree_nextprop(pnode_t nodeid, char *name, char *next) 178 { 179 prom_node_t *pnp; 180 char *propname; 181 182 next[0] = '\0'; 183 184 pnp = find_node(nodeid); 185 if (pnp == NULL) 186 return (NULL); 187 188 propname = nextprop(pnp, name); 189 if (propname == NULL) 190 return (next); 191 192 (void) prom_strcpy(next, propname); 193 194 return (next); 195 } 196 197 static prom_node_t * 198 find_node_work(prom_node_t *np, pnode_t node) 199 { 200 prom_node_t *nnp; 201 202 if (np->pn_nodeid == node) 203 return (np); 204 205 if (np->pn_child) 206 if ((nnp = find_node_work(np->pn_child, node)) != NULL) 207 return (nnp); 208 209 if (np->pn_sibling) 210 if ((nnp = find_node_work(np->pn_sibling, node)) != NULL) 211 return (nnp); 212 213 return (NULL); 214 } 215 216 static prom_node_t * 217 find_node(pnode_t nodeid) 218 { 219 220 if (nodeid == OBP_NONODE) 221 return (promif_root); 222 223 if (promif_root == NULL) 224 return (NULL); 225 226 return (find_node_work(promif_root, nodeid)); 227 } 228 229 static int 230 getproplen(prom_node_t *pnp, char *name) 231 { 232 struct prom_prop *propp; 233 234 for (propp = pnp->pn_propp; propp != NULL; propp = propp->pp_next) 235 if (prom_strcmp(propp->pp_name, name) == 0) 236 return (propp->pp_len); 237 238 return (-1); 239 } 240 241 static void * 242 getprop(prom_node_t *np, char *name) 243 { 244 struct prom_prop *propp; 245 246 for (propp = np->pn_propp; propp != NULL; propp = propp->pp_next) 247 if (prom_strcmp(propp->pp_name, name) == 0) 248 return (propp->pp_val); 249 250 return (NULL); 251 } 252 253 static char * 254 nextprop(prom_node_t *pnp, char *name) 255 { 256 struct prom_prop *propp; 257 258 /* 259 * getting next of NULL or a null string returns the first prop name 260 */ 261 if (name == NULL || *name == '\0') 262 if (pnp->pn_propp) 263 return (pnp->pn_propp->pp_name); 264 265 for (propp = pnp->pn_propp; propp != NULL; propp = propp->pp_next) 266 if (prom_strcmp(propp->pp_name, name) == 0) 267 if (propp->pp_next) 268 return (propp->pp_next->pp_name); 269 270 return (NULL); 271 } 272 273 #ifndef _KMDB 274 275 int 276 promif_stree_setprop(pnode_t nodeid, char *name, void *value, int len) 277 { 278 prom_node_t *pnp; 279 struct prom_prop *prop; 280 281 pnp = find_node(nodeid); 282 if (pnp == NULL) { 283 prom_printf("find_node: no node?\n"); 284 return (-1); 285 } 286 287 /* 288 * If a property with this name exists, replace the existing 289 * value. 290 */ 291 for (prop = pnp->pn_propp; prop; prop = prop->pp_next) 292 if (prom_strcmp(prop->pp_name, name) == 0) { 293 kmem_free(prop->pp_val, prop->pp_len); 294 prop->pp_val = NULL; 295 if (len > 0) { 296 prop->pp_val = kmem_zalloc(len, KM_SLEEP); 297 bcopy(value, prop->pp_val, len); 298 } 299 prop->pp_len = len; 300 return (len); 301 } 302 303 return (-1); 304 } 305 306 /* 307 * Create a promif private copy of boot's device tree. 308 */ 309 void 310 promif_stree_init(void) 311 { 312 pnode_t node; 313 prom_node_t *pnp; 314 315 node = prom_rootnode(); 316 promif_root = pnp = create_node(OBP_NONODE, node); 317 318 create_peers(pnp, node); 319 create_children(pnp, node); 320 } 321 322 static void 323 create_children(prom_node_t *pnp, pnode_t parent) 324 { 325 prom_node_t *cnp; 326 pnode_t child; 327 328 _NOTE(CONSTCOND) 329 while (1) { 330 child = prom_childnode(parent); 331 if (child == 0) 332 break; 333 if (prom_getproplen(child, "name") <= 0) { 334 parent = child; 335 continue; 336 } 337 cnp = create_node(pnp, child); 338 pnp->pn_child = cnp; 339 create_peers(cnp, child); 340 pnp = cnp; 341 parent = child; 342 } 343 } 344 345 static void 346 create_peers(prom_node_t *np, pnode_t node) 347 { 348 prom_node_t *pnp; 349 pnode_t peer; 350 351 _NOTE(CONSTCOND) 352 while (1) { 353 peer = prom_nextnode(node); 354 if (peer == 0) 355 break; 356 if (prom_getproplen(peer, "name") <= 0) { 357 node = peer; 358 continue; 359 } 360 pnp = create_node(np->pn_parent, peer); 361 np->pn_sibling = pnp; 362 create_children(pnp, peer); 363 np = pnp; 364 node = peer; 365 } 366 } 367 368 static prom_node_t * 369 create_node(prom_node_t *parent, pnode_t node) 370 { 371 prom_node_t *pnp; 372 char prvname[OBP_MAXPROPNAME]; 373 char propname[OBP_MAXPROPNAME]; 374 int proplen; 375 void *propval; 376 377 pnp = kmem_zalloc(sizeof (prom_node_t), KM_SLEEP); 378 pnp->pn_nodeid = node; 379 pnp->pn_parent = parent; 380 381 prvname[0] = '\0'; 382 383 _NOTE(CONSTCOND) 384 while (1) { 385 (void) prom_nextprop(node, prvname, propname); 386 if (prom_strlen(propname) == 0) 387 break; 388 if ((proplen = prom_getproplen(node, propname)) == -1) 389 continue; 390 propval = NULL; 391 if (proplen != 0) { 392 propval = kmem_zalloc(proplen, KM_SLEEP); 393 (void) prom_getprop(node, propname, propval); 394 } 395 create_prop(pnp, propname, propval, proplen); 396 397 (void) prom_strcpy(prvname, propname); 398 } 399 400 return (pnp); 401 } 402 403 static void 404 create_prop(prom_node_t *pnp, char *name, void *val, int len) 405 { 406 struct prom_prop *prop; 407 struct prom_prop *newprop; 408 409 newprop = kmem_zalloc(sizeof (*newprop), KM_SLEEP); 410 newprop->pp_name = kmem_zalloc(prom_strlen(name) + 1, KM_SLEEP); 411 (void) prom_strcpy(newprop->pp_name, name); 412 newprop->pp_val = val; 413 newprop->pp_len = len; 414 415 if (pnp->pn_propp == NULL) { 416 pnp->pn_propp = newprop; 417 return; 418 } 419 420 /* move to the end of the prop list */ 421 for (prop = pnp->pn_propp; prop->pp_next != NULL; prop = prop->pp_next) 422 /* empty */; 423 424 /* append the new prop */ 425 prop->pp_next = newprop; 426 } 427 428 static void 429 promif_dump_tree(prom_node_t *pnp) 430 { 431 int i; 432 static int level = 0; 433 434 if (pnp == NULL) 435 return; 436 437 for (i = 0; i < level; i++) { 438 prom_printf(" "); 439 } 440 441 prom_printf("Node 0x%x (parent=0x%x, sibling=0x%x)\n", pnp->pn_nodeid, 442 (pnp->pn_parent) ? pnp->pn_parent->pn_nodeid : 0, 443 (pnp->pn_sibling) ? pnp->pn_sibling->pn_nodeid : 0); 444 445 if (pnp->pn_child != NULL) { 446 level++; 447 promif_dump_tree(pnp->pn_child); 448 level--; 449 } 450 451 if (pnp->pn_sibling != NULL) 452 promif_dump_tree(pnp->pn_sibling); 453 } 454 455 #endif 456