1/* 2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28/* 29 * @OSF_FREE_COPYRIGHT@ 30 */ 31 32#include <pexpert/protos.h> 33#include <pexpert/boot.h> 34#include <pexpert/device_tree.h> 35 36#include <mach/mach_types.h> 37#include <mach/machine/vm_types.h> 38#include <kern/kern_types.h> 39#include <kern/kalloc.h> 40 41#include <sys/types.h> 42 43#ifndef NULL 44#define NULL ((void *) 0) 45#endif 46 47#define round_long(x) (((x) + 3) & -4) 48#define next_prop(x) ((DeviceTreeNodeProperty *) (((int)x) + sizeof(DeviceTreeNodeProperty) + round_long(x->length))) 49 50/* Entry*/ 51typedef DeviceTreeNode *RealDTEntry; 52 53typedef struct DTSavedScope { 54 struct DTSavedScope * nextScope; 55 RealDTEntry scope; 56 RealDTEntry entry; 57 unsigned long index; 58} *DTSavedScopePtr; 59 60/* Entry Iterator*/ 61typedef struct OpaqueDTEntryIterator { 62 RealDTEntry outerScope; 63 RealDTEntry currentScope; 64 RealDTEntry currentEntry; 65 DTSavedScopePtr savedScope; 66 unsigned long currentIndex; 67} *RealDTEntryIterator; 68 69/* Property Iterator*/ 70typedef struct OpaqueDTPropertyIterator { 71 RealDTEntry entry; 72 DeviceTreeNodeProperty *currentProperty; 73 unsigned long currentIndex; 74} *RealDTPropertyIterator; 75 76static int DTInitialized; 77static RealDTEntry DTRootNode; 78 79/* 80 * Support Routines 81 */ 82static RealDTEntry 83skipProperties(RealDTEntry entry) 84{ 85 DeviceTreeNodeProperty *prop; 86 unsigned int k; 87 88 if (entry == NULL || entry->nProperties == 0) { 89 return NULL; 90 } else { 91 prop = (DeviceTreeNodeProperty *) (entry + 1); 92 for (k = 0; k < entry->nProperties; k++) { 93 prop = next_prop(prop); 94 } 95 } 96 return ((RealDTEntry) prop); 97} 98 99static RealDTEntry 100skipTree(RealDTEntry root) 101{ 102 RealDTEntry entry; 103 unsigned int k; 104 105 entry = skipProperties(root); 106 if (entry == NULL) { 107 return NULL; 108 } 109 for (k = 0; k < root->nChildren; k++) { 110 entry = skipTree(entry); 111 } 112 return entry; 113} 114 115static RealDTEntry 116GetFirstChild(RealDTEntry parent) 117{ 118 return skipProperties(parent); 119} 120 121static RealDTEntry 122GetNextChild(RealDTEntry sibling) 123{ 124 return skipTree(sibling); 125} 126 127static const char * 128GetNextComponent(const char *cp, char *bp) 129{ 130 while (*cp != 0) { 131 if (*cp == kDTPathNameSeparator) { 132 cp++; 133 break; 134 } 135 *bp++ = *cp++; 136 } 137 *bp = 0; 138 return cp; 139} 140 141static RealDTEntry 142FindChild(RealDTEntry cur, char *buf) 143{ 144 RealDTEntry child; 145 unsigned long index; 146 char * str; 147 unsigned int dummy; 148 149 if (cur->nChildren == 0) { 150 return NULL; 151 } 152 index = 1; 153 child = GetFirstChild(cur); 154 while (1) { 155 if (DTGetProperty(child, "name", (void **)&str, &dummy) != kSuccess) { 156 break; 157 } 158 if (strcmp(str, buf) == 0) { 159 return child; 160 } 161 if (index >= cur->nChildren) { 162 break; 163 } 164 child = GetNextChild(child); 165 index++; 166 } 167 return NULL; 168} 169 170 171/* 172 * External Routines 173 */ 174void 175DTInit(void *base) 176{ 177 DTRootNode = (RealDTEntry) base; 178 DTInitialized = (DTRootNode != 0); 179} 180 181int 182DTEntryIsEqual(const DTEntry ref1, const DTEntry ref2) 183{ 184 /* equality of pointers */ 185 return (ref1 == ref2); 186} 187 188static char *startingP; // needed for find_entry 189int find_entry(const char *propName, const char *propValue, DTEntry *entryH); 190 191int DTFindEntry(const char *propName, const char *propValue, DTEntry *entryH) 192{ 193 if (!DTInitialized) { 194 return kError; 195 } 196 197 startingP = (char *)DTRootNode; 198 return(find_entry(propName, propValue, entryH)); 199} 200 201int find_entry(const char *propName, const char *propValue, DTEntry *entryH) 202{ 203 DeviceTreeNode *nodeP = (DeviceTreeNode *) startingP; 204 unsigned int k; 205 206 if (nodeP->nProperties == 0) return(kError); // End of the list of nodes 207 startingP = (char *) (nodeP + 1); 208 209 // Search current entry 210 for (k = 0; k < nodeP->nProperties; ++k) { 211 DeviceTreeNodeProperty *propP = (DeviceTreeNodeProperty *) startingP; 212 213 startingP += sizeof (*propP) + ((propP->length + 3) & -4); 214 215 if (strcmp (propP->name, propName) == 0) { 216 if (propValue == NULL || strcmp( (char *)(propP + 1), propValue) == 0) 217 { 218 *entryH = (DTEntry)nodeP; 219 return(kSuccess); 220 } 221 } 222 } 223 224 // Search child nodes 225 for (k = 0; k < nodeP->nChildren; ++k) 226 { 227 if (find_entry(propName, propValue, entryH) == kSuccess) 228 return(kSuccess); 229 } 230 return(kError); 231} 232 233int 234DTLookupEntry(const DTEntry searchPoint, const char *pathName, DTEntry *foundEntry) 235{ 236 DTEntryNameBuf buf; 237 RealDTEntry cur; 238 const char * cp; 239 240 if (!DTInitialized) { 241 return kError; 242 } 243 if (searchPoint == NULL) { 244 cur = DTRootNode; 245 } else { 246 cur = searchPoint; 247 } 248 cp = pathName; 249 if (*cp == kDTPathNameSeparator) { 250 cp++; 251 if (*cp == 0) { 252 *foundEntry = cur; 253 return kSuccess; 254 } 255 } 256 do { 257 cp = GetNextComponent(cp, buf); 258 259 /* Check for done */ 260 if (*buf == 0) { 261 if (*cp == 0) { 262 *foundEntry = cur; 263 return kSuccess; 264 } 265 break; 266 } 267 268 cur = FindChild(cur, buf); 269 270 } while (cur != NULL); 271 272 return kError; 273} 274 275int 276DTCreateEntryIterator(const DTEntry startEntry, DTEntryIterator *iterator) 277{ 278 RealDTEntryIterator iter; 279 280 if (!DTInitialized) { 281 return kError; 282 } 283 284 iter = (RealDTEntryIterator) kalloc(sizeof(struct OpaqueDTEntryIterator)); 285 if (startEntry != NULL) { 286 iter->outerScope = (RealDTEntry) startEntry; 287 iter->currentScope = (RealDTEntry) startEntry; 288 } else { 289 iter->outerScope = DTRootNode; 290 iter->currentScope = DTRootNode; 291 } 292 iter->currentEntry = NULL; 293 iter->savedScope = NULL; 294 iter->currentIndex = 0; 295 296 *iterator = iter; 297 return kSuccess; 298} 299 300int 301DTDisposeEntryIterator(DTEntryIterator iterator) 302{ 303 RealDTEntryIterator iter = iterator; 304 DTSavedScopePtr scope; 305 306 while ((scope = iter->savedScope) != NULL) { 307 iter->savedScope = scope->nextScope; 308 kfree(scope, sizeof(struct DTSavedScope)); 309 } 310 kfree(iterator, sizeof(struct OpaqueDTEntryIterator)); 311 return kSuccess; 312} 313 314int 315DTEnterEntry(DTEntryIterator iterator, DTEntry childEntry) 316{ 317 RealDTEntryIterator iter = iterator; 318 DTSavedScopePtr newScope; 319 320 if (childEntry == NULL) { 321 return kError; 322 } 323 newScope = (DTSavedScopePtr) kalloc(sizeof(struct DTSavedScope)); 324 newScope->nextScope = iter->savedScope; 325 newScope->scope = iter->currentScope; 326 newScope->entry = iter->currentEntry; 327 newScope->index = iter->currentIndex; 328 329 iter->currentScope = childEntry; 330 iter->currentEntry = NULL; 331 iter->savedScope = newScope; 332 iter->currentIndex = 0; 333 334 return kSuccess; 335} 336 337int 338DTExitEntry(DTEntryIterator iterator, DTEntry *currentPosition) 339{ 340 RealDTEntryIterator iter = iterator; 341 DTSavedScopePtr newScope; 342 343 newScope = iter->savedScope; 344 if (newScope == NULL) { 345 return kError; 346 } 347 iter->savedScope = newScope->nextScope; 348 iter->currentScope = newScope->scope; 349 iter->currentEntry = newScope->entry; 350 iter->currentIndex = newScope->index; 351 *currentPosition = iter->currentEntry; 352 353 kfree(newScope, sizeof(struct DTSavedScope)); 354 355 return kSuccess; 356} 357 358int 359DTIterateEntries(DTEntryIterator iterator, DTEntry *nextEntry) 360{ 361 RealDTEntryIterator iter = iterator; 362 363 if (iter->currentIndex >= iter->currentScope->nChildren) { 364 *nextEntry = NULL; 365 return kIterationDone; 366 } else { 367 iter->currentIndex++; 368 if (iter->currentIndex == 1) { 369 iter->currentEntry = GetFirstChild(iter->currentScope); 370 } else { 371 iter->currentEntry = GetNextChild(iter->currentEntry); 372 } 373 *nextEntry = iter->currentEntry; 374 return kSuccess; 375 } 376} 377 378int 379DTRestartEntryIteration(DTEntryIterator iterator) 380{ 381 RealDTEntryIterator iter = iterator; 382#if 0 383 // This commented out code allows a second argument (outer) 384 // which (if true) causes restarting at the outer scope 385 // rather than the current scope. 386 DTSavedScopePtr scope; 387 388 if (outer) { 389 while ((scope = iter->savedScope) != NULL) { 390 iter->savedScope = scope->nextScope; 391 kfree((vm_offset_t) scope, sizeof(struct DTSavedScope)); 392 } 393 iter->currentScope = iter->outerScope; 394 } 395#endif 396 iter->currentEntry = NULL; 397 iter->currentIndex = 0; 398 return kSuccess; 399} 400 401int 402DTGetProperty(const DTEntry entry, const char *propertyName, void **propertyValue, unsigned int *propertySize) 403{ 404 DeviceTreeNodeProperty *prop; 405 unsigned int k; 406 407 if (entry == NULL || entry->nProperties == 0) { 408 return kError; 409 } else { 410 prop = (DeviceTreeNodeProperty *) (entry + 1); 411 for (k = 0; k < entry->nProperties; k++) { 412 if (strcmp(prop->name, propertyName) == 0) { 413 *propertyValue = (void *) (((int)prop) 414 + sizeof(DeviceTreeNodeProperty)); 415 *propertySize = prop->length; 416 return kSuccess; 417 } 418 prop = next_prop(prop); 419 } 420 } 421 return kError; 422} 423 424int 425DTCreatePropertyIterator(const DTEntry entry, DTPropertyIterator *iterator) 426{ 427 RealDTPropertyIterator iter; 428 429 iter = (RealDTPropertyIterator) kalloc(sizeof(struct OpaqueDTPropertyIterator)); 430 iter->entry = entry; 431 iter->currentProperty = NULL; 432 iter->currentIndex = 0; 433 434 *iterator = iter; 435 return kSuccess; 436} 437 438int 439DTDisposePropertyIterator(DTPropertyIterator iterator) 440{ 441 kfree(iterator, sizeof(struct OpaqueDTPropertyIterator)); 442 return kSuccess; 443} 444 445int 446DTIterateProperties(DTPropertyIterator iterator, char **foundProperty) 447{ 448 RealDTPropertyIterator iter = iterator; 449 450 if (iter->currentIndex >= iter->entry->nProperties) { 451 *foundProperty = NULL; 452 return kIterationDone; 453 } else { 454 iter->currentIndex++; 455 if (iter->currentIndex == 1) { 456 iter->currentProperty = (DeviceTreeNodeProperty *) (iter->entry + 1); 457 } else { 458 iter->currentProperty = next_prop(iter->currentProperty); 459 } 460 *foundProperty = iter->currentProperty->name; 461 return kSuccess; 462 } 463} 464 465int 466DTRestartPropertyIteration(DTPropertyIterator iterator) 467{ 468 RealDTPropertyIterator iter = iterator; 469 470 iter->currentProperty = NULL; 471 iter->currentIndex = 0; 472 return kSuccess; 473} 474 475