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 2007 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 prom_node_t *snp; 202 203 for (snp = np; snp != NULL; snp = snp->pn_sibling) { 204 if (snp->pn_nodeid == node) 205 return (snp); 206 207 if (snp->pn_child) 208 if ((nnp = find_node_work(snp->pn_child, node)) != NULL) 209 return (nnp); 210 } 211 212 return (NULL); 213 } 214 215 static prom_node_t * 216 find_node(pnode_t nodeid) 217 { 218 219 if (nodeid == OBP_NONODE) 220 return (promif_root); 221 222 if (promif_root == NULL) 223 return (NULL); 224 225 return (find_node_work(promif_root, nodeid)); 226 } 227 228 static int 229 getproplen(prom_node_t *pnp, char *name) 230 { 231 struct prom_prop *propp; 232 233 for (propp = pnp->pn_propp; propp != NULL; propp = propp->pp_next) 234 if (prom_strcmp(propp->pp_name, name) == 0) 235 return (propp->pp_len); 236 237 return (-1); 238 } 239 240 static void * 241 getprop(prom_node_t *np, char *name) 242 { 243 struct prom_prop *propp; 244 245 for (propp = np->pn_propp; propp != NULL; propp = propp->pp_next) 246 if (prom_strcmp(propp->pp_name, name) == 0) 247 return (propp->pp_val); 248 249 return (NULL); 250 } 251 252 static char * 253 nextprop(prom_node_t *pnp, char *name) 254 { 255 struct prom_prop *propp; 256 257 /* 258 * getting next of NULL or a null string returns the first prop name 259 */ 260 if (name == NULL || *name == '\0') 261 if (pnp->pn_propp) 262 return (pnp->pn_propp->pp_name); 263 264 for (propp = pnp->pn_propp; propp != NULL; propp = propp->pp_next) 265 if (prom_strcmp(propp->pp_name, name) == 0) 266 if (propp->pp_next) 267 return (propp->pp_next->pp_name); 268 269 return (NULL); 270 } 271 272 #ifndef _KMDB 273 274 int 275 promif_stree_setprop(pnode_t nodeid, char *name, void *value, int len) 276 { 277 prom_node_t *pnp; 278 struct prom_prop *prop; 279 280 pnp = find_node(nodeid); 281 if (pnp == NULL) { 282 prom_printf("find_node: no node?\n"); 283 return (-1); 284 } 285 286 /* 287 * If a property with this name exists, replace the existing 288 * value. 289 */ 290 for (prop = pnp->pn_propp; prop; prop = prop->pp_next) 291 if (prom_strcmp(prop->pp_name, name) == 0) { 292 kmem_free(prop->pp_val, prop->pp_len); 293 prop->pp_val = NULL; 294 if (len > 0) { 295 prop->pp_val = kmem_zalloc(len, KM_SLEEP); 296 bcopy(value, prop->pp_val, len); 297 } 298 prop->pp_len = len; 299 return (len); 300 } 301 302 return (-1); 303 } 304 305 /* 306 * Create a promif private copy of boot's device tree. 307 */ 308 void 309 promif_stree_init(void) 310 { 311 pnode_t node; 312 prom_node_t *pnp; 313 314 node = prom_rootnode(); 315 promif_root = pnp = create_node(OBP_NONODE, node); 316 317 create_peers(pnp, node); 318 create_children(pnp, node); 319 } 320 321 static void 322 create_children(prom_node_t *pnp, pnode_t parent) 323 { 324 prom_node_t *cnp; 325 pnode_t child; 326 327 _NOTE(CONSTCOND) 328 while (1) { 329 child = prom_childnode(parent); 330 if (child == 0) 331 break; 332 if (prom_getproplen(child, "name") <= 0) { 333 parent = child; 334 continue; 335 } 336 cnp = create_node(pnp, child); 337 pnp->pn_child = cnp; 338 create_peers(cnp, child); 339 pnp = cnp; 340 parent = child; 341 } 342 } 343 344 static void 345 create_peers(prom_node_t *np, pnode_t node) 346 { 347 prom_node_t *pnp; 348 pnode_t peer; 349 350 _NOTE(CONSTCOND) 351 while (1) { 352 peer = prom_nextnode(node); 353 if (peer == 0) 354 break; 355 if (prom_getproplen(peer, "name") <= 0) { 356 node = peer; 357 continue; 358 } 359 pnp = create_node(np->pn_parent, peer); 360 np->pn_sibling = pnp; 361 create_children(pnp, peer); 362 np = pnp; 363 node = peer; 364 } 365 } 366 367 static prom_node_t * 368 create_node(prom_node_t *parent, pnode_t node) 369 { 370 prom_node_t *pnp; 371 char prvname[OBP_MAXPROPNAME]; 372 char propname[OBP_MAXPROPNAME]; 373 int proplen; 374 void *propval; 375 376 pnp = kmem_zalloc(sizeof (prom_node_t), KM_SLEEP); 377 pnp->pn_nodeid = node; 378 pnp->pn_parent = parent; 379 380 prvname[0] = '\0'; 381 382 _NOTE(CONSTCOND) 383 while (1) { 384 (void) prom_nextprop(node, prvname, propname); 385 if (prom_strlen(propname) == 0) 386 break; 387 if ((proplen = prom_getproplen(node, propname)) == -1) 388 continue; 389 propval = NULL; 390 if (proplen != 0) { 391 propval = kmem_zalloc(proplen, KM_SLEEP); 392 (void) prom_getprop(node, propname, propval); 393 } 394 create_prop(pnp, propname, propval, proplen); 395 396 (void) prom_strcpy(prvname, propname); 397 } 398 399 return (pnp); 400 } 401 402 static void 403 create_prop(prom_node_t *pnp, char *name, void *val, int len) 404 { 405 struct prom_prop *prop; 406 struct prom_prop *newprop; 407 408 newprop = kmem_zalloc(sizeof (*newprop), KM_SLEEP); 409 newprop->pp_name = kmem_zalloc(prom_strlen(name) + 1, KM_SLEEP); 410 (void) prom_strcpy(newprop->pp_name, name); 411 newprop->pp_val = val; 412 newprop->pp_len = len; 413 414 if (pnp->pn_propp == NULL) { 415 pnp->pn_propp = newprop; 416 return; 417 } 418 419 /* move to the end of the prop list */ 420 for (prop = pnp->pn_propp; prop->pp_next != NULL; prop = prop->pp_next) 421 /* empty */; 422 423 /* append the new prop */ 424 prop->pp_next = newprop; 425 } 426 427 static void 428 promif_dump_tree(prom_node_t *pnp) 429 { 430 int i; 431 static int level = 0; 432 433 if (pnp == NULL) 434 return; 435 436 for (i = 0; i < level; i++) { 437 prom_printf(" "); 438 } 439 440 prom_printf("Node 0x%x (parent=0x%x, sibling=0x%x)\n", pnp->pn_nodeid, 441 (pnp->pn_parent) ? pnp->pn_parent->pn_nodeid : 0, 442 (pnp->pn_sibling) ? pnp->pn_sibling->pn_nodeid : 0); 443 444 if (pnp->pn_child != NULL) { 445 level++; 446 promif_dump_tree(pnp->pn_child); 447 level--; 448 } 449 450 if (pnp->pn_sibling != NULL) 451 promif_dump_tree(pnp->pn_sibling); 452 } 453 454 #endif 455