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) + 3UL) & ~(3UL)) 48#define next_prop(x) ((DeviceTreeNodeProperty *) (((uintptr_t)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 size_t length = 0; 131 char *origbp = bp; 132 133 while (*cp != 0) { 134 if (*cp == kDTPathNameSeparator) { 135 cp++; 136 break; 137 } 138 if (++length > kDTMaxEntryNameLength) { 139 *origbp = '\0'; 140 return cp; 141 } 142 *bp++ = *cp++; 143 } 144 *bp = 0; 145 return cp; 146} 147 148static RealDTEntry 149FindChild(RealDTEntry cur, char *buf) 150{ 151 RealDTEntry child; 152 unsigned long index; 153 char * str; 154 unsigned int dummy; 155 156 if (cur->nChildren == 0) { 157 return NULL; 158 } 159 index = 1; 160 child = GetFirstChild(cur); 161 while (1) { 162 if (DTGetProperty(child, "name", (void **)&str, &dummy) != kSuccess) { 163 break; 164 } 165 if (strcmp(str, buf) == 0) { 166 return child; 167 } 168 if (index >= cur->nChildren) { 169 break; 170 } 171 child = GetNextChild(child); 172 index++; 173 } 174 return NULL; 175} 176 177 178/* 179 * External Routines 180 */ 181void 182DTInit(void *base) 183{ 184 DTRootNode = (RealDTEntry) base; 185 DTInitialized = (DTRootNode != 0); 186} 187 188int 189DTEntryIsEqual(const DTEntry ref1, const DTEntry ref2) 190{ 191 /* equality of pointers */ 192 return (ref1 == ref2); 193} 194 195static char *startingP; // needed for find_entry 196int find_entry(const char *propName, const char *propValue, DTEntry *entryH); 197 198int DTFindEntry(const char *propName, const char *propValue, DTEntry *entryH) 199{ 200 if (!DTInitialized) { 201 return kError; 202 } 203 204 startingP = (char *)DTRootNode; 205 return(find_entry(propName, propValue, entryH)); 206} 207 208int find_entry(const char *propName, const char *propValue, DTEntry *entryH) 209{ 210 DeviceTreeNode *nodeP = (DeviceTreeNode *) (void *) startingP; 211 unsigned int k; 212 213 if (nodeP->nProperties == 0) return(kError); // End of the list of nodes 214 startingP = (char *) (nodeP + 1); 215 216 // Search current entry 217 for (k = 0; k < nodeP->nProperties; ++k) { 218 DeviceTreeNodeProperty *propP = (DeviceTreeNodeProperty *) (void *) startingP; 219 220 startingP += sizeof (*propP) + ((propP->length + 3) & -4); 221 222 if (strcmp (propP->name, propName) == 0) { 223 if (propValue == NULL || strcmp( (char *)(propP + 1), propValue) == 0) 224 { 225 *entryH = (DTEntry)nodeP; 226 return(kSuccess); 227 } 228 } 229 } 230 231 // Search child nodes 232 for (k = 0; k < nodeP->nChildren; ++k) 233 { 234 if (find_entry(propName, propValue, entryH) == kSuccess) 235 return(kSuccess); 236 } 237 return(kError); 238} 239 240int 241DTLookupEntry(const DTEntry searchPoint, const char *pathName, DTEntry *foundEntry) 242{ 243 DTEntryNameBuf buf; 244 RealDTEntry cur; 245 const char * cp; 246 247 if (!DTInitialized) { 248 return kError; 249 } 250 if (searchPoint == NULL) { 251 cur = DTRootNode; 252 } else { 253 cur = searchPoint; 254 } 255 cp = pathName; 256 if (*cp == kDTPathNameSeparator) { 257 cp++; 258 if (*cp == 0) { 259 *foundEntry = cur; 260 return kSuccess; 261 } 262 } 263 do { 264 cp = GetNextComponent(cp, buf); 265 266 /* Check for done */ 267 if (*buf == 0) { 268 if (*cp == 0) { 269 *foundEntry = cur; 270 return kSuccess; 271 } 272 break; 273 } 274 275 cur = FindChild(cur, buf); 276 277 } while (cur != NULL); 278 279 return kError; 280} 281 282int 283DTCreateEntryIterator(const DTEntry startEntry, DTEntryIterator *iterator) 284{ 285 RealDTEntryIterator iter; 286 287 if (!DTInitialized) { 288 return kError; 289 } 290 291 iter = (RealDTEntryIterator) kalloc(sizeof(struct OpaqueDTEntryIterator)); 292 if (startEntry != NULL) { 293 iter->outerScope = (RealDTEntry) startEntry; 294 iter->currentScope = (RealDTEntry) startEntry; 295 } else { 296 iter->outerScope = DTRootNode; 297 iter->currentScope = DTRootNode; 298 } 299 iter->currentEntry = NULL; 300 iter->savedScope = NULL; 301 iter->currentIndex = 0; 302 303 *iterator = iter; 304 return kSuccess; 305} 306 307int 308DTDisposeEntryIterator(DTEntryIterator iterator) 309{ 310 RealDTEntryIterator iter = iterator; 311 DTSavedScopePtr scope; 312 313 while ((scope = iter->savedScope) != NULL) { 314 iter->savedScope = scope->nextScope; 315 kfree(scope, sizeof(struct DTSavedScope)); 316 } 317 kfree(iterator, sizeof(struct OpaqueDTEntryIterator)); 318 return kSuccess; 319} 320 321int 322DTEnterEntry(DTEntryIterator iterator, DTEntry childEntry) 323{ 324 RealDTEntryIterator iter = iterator; 325 DTSavedScopePtr newScope; 326 327 if (childEntry == NULL) { 328 return kError; 329 } 330 newScope = (DTSavedScopePtr) kalloc(sizeof(struct DTSavedScope)); 331 newScope->nextScope = iter->savedScope; 332 newScope->scope = iter->currentScope; 333 newScope->entry = iter->currentEntry; 334 newScope->index = iter->currentIndex; 335 336 iter->currentScope = childEntry; 337 iter->currentEntry = NULL; 338 iter->savedScope = newScope; 339 iter->currentIndex = 0; 340 341 return kSuccess; 342} 343 344int 345DTExitEntry(DTEntryIterator iterator, DTEntry *currentPosition) 346{ 347 RealDTEntryIterator iter = iterator; 348 DTSavedScopePtr newScope; 349 350 newScope = iter->savedScope; 351 if (newScope == NULL) { 352 return kError; 353 } 354 iter->savedScope = newScope->nextScope; 355 iter->currentScope = newScope->scope; 356 iter->currentEntry = newScope->entry; 357 iter->currentIndex = newScope->index; 358 *currentPosition = iter->currentEntry; 359 360 kfree(newScope, sizeof(struct DTSavedScope)); 361 362 return kSuccess; 363} 364 365int 366DTIterateEntries(DTEntryIterator iterator, DTEntry *nextEntry) 367{ 368 RealDTEntryIterator iter = iterator; 369 370 if (iter->currentIndex >= iter->currentScope->nChildren) { 371 *nextEntry = NULL; 372 return kIterationDone; 373 } else { 374 iter->currentIndex++; 375 if (iter->currentIndex == 1) { 376 iter->currentEntry = GetFirstChild(iter->currentScope); 377 } else { 378 iter->currentEntry = GetNextChild(iter->currentEntry); 379 } 380 *nextEntry = iter->currentEntry; 381 return kSuccess; 382 } 383} 384 385int 386DTRestartEntryIteration(DTEntryIterator iterator) 387{ 388 RealDTEntryIterator iter = iterator; 389#if 0 390 // This commented out code allows a second argument (outer) 391 // which (if true) causes restarting at the outer scope 392 // rather than the current scope. 393 DTSavedScopePtr scope; 394 395 if (outer) { 396 while ((scope = iter->savedScope) != NULL) { 397 iter->savedScope = scope->nextScope; 398 kfree((vm_offset_t) scope, sizeof(struct DTSavedScope)); 399 } 400 iter->currentScope = iter->outerScope; 401 } 402#endif 403 iter->currentEntry = NULL; 404 iter->currentIndex = 0; 405 return kSuccess; 406} 407 408int 409DTGetProperty(const DTEntry entry, const char *propertyName, void **propertyValue, unsigned int *propertySize) 410{ 411 DeviceTreeNodeProperty *prop; 412 unsigned int k; 413 414 if (entry == NULL || entry->nProperties == 0) { 415 return kError; 416 } else { 417 prop = (DeviceTreeNodeProperty *) (entry + 1); 418 for (k = 0; k < entry->nProperties; k++) { 419 if (strcmp(prop->name, propertyName) == 0) { 420 *propertyValue = (void *) (((uintptr_t)prop) 421 + sizeof(DeviceTreeNodeProperty)); 422 *propertySize = prop->length; 423 return kSuccess; 424 } 425 prop = next_prop(prop); 426 } 427 } 428 return kError; 429} 430 431int 432DTCreatePropertyIterator(const DTEntry entry, DTPropertyIterator *iterator) 433{ 434 RealDTPropertyIterator iter; 435 436 iter = (RealDTPropertyIterator) kalloc(sizeof(struct OpaqueDTPropertyIterator)); 437 iter->entry = entry; 438 iter->currentProperty = NULL; 439 iter->currentIndex = 0; 440 441 *iterator = iter; 442 return kSuccess; 443} 444 445int 446DTDisposePropertyIterator(DTPropertyIterator iterator) 447{ 448 kfree(iterator, sizeof(struct OpaqueDTPropertyIterator)); 449 return kSuccess; 450} 451 452int 453DTIterateProperties(DTPropertyIterator iterator, char **foundProperty) 454{ 455 RealDTPropertyIterator iter = iterator; 456 457 if (iter->currentIndex >= iter->entry->nProperties) { 458 *foundProperty = NULL; 459 return kIterationDone; 460 } else { 461 iter->currentIndex++; 462 if (iter->currentIndex == 1) { 463 iter->currentProperty = (DeviceTreeNodeProperty *) (iter->entry + 1); 464 } else { 465 iter->currentProperty = next_prop(iter->currentProperty); 466 } 467 *foundProperty = iter->currentProperty->name; 468 return kSuccess; 469 } 470} 471 472int 473DTRestartPropertyIteration(DTPropertyIterator iterator) 474{ 475 RealDTPropertyIterator iter = iterator; 476 477 iter->currentProperty = NULL; 478 iter->currentIndex = 0; 479 return kSuccess; 480} 481 482