#include <CoreFoundation/CoreFoundation.h> // (CFDictionary, ...)
#include <IOKit/IOCFSerialize.h> // (IOCFSerialize, ...)
#include <IOKit/IOKitLib.h> // (IOMasterPort, ...)
#include <IOKit/IOKitLibPrivate.h> // (IOServiceGetState, ...)
#include <sys/ioctl.h> // (TIOCGWINSZ, ...)
#include <term.h> // (tputs, ...)
#include <unistd.h> // (getopt, ...)
struct options
{
UInt32 bold:1; UInt32 format:1; UInt32 hex:1; UInt32 inheritance:1; UInt32 list:1; UInt32 root:1; UInt32 state:1; UInt32 tree:1;
char * class; UInt32 depth; char * key; char * name; char * plane; UInt32 width; };
struct context
{
io_registry_entry_t service;
UInt32 serviceDepth;
UInt64 stackOfBits;
struct options options;
};
static void assertion(int condition, char * message);
static void boldinit();
static void boldon();
static void boldoff();
static void printinit(int width);
static void print(const char * format, ...);
static void println(const char * format, ...);
static void cfshowinit(Boolean hex);
static void cfshow(CFTypeRef object);
static void cfarrayshow(CFArrayRef object);
static void cfbooleanshow(CFBooleanRef object);
static void cfdatashow(CFDataRef object);
static void cfdictionaryshow(CFDictionaryRef object);
static void cfnumbershow(CFNumberRef object);
static void cfsetshow(CFSetRef object);
static void cfstringshow(CFStringRef object);
static CFStringRef createInheritanceStringForIORegistryClassName(CFStringRef name);
static void printProp(CFStringRef key, CFTypeRef value, struct context * context);
static void printPhysAddr(CFTypeRef value, struct context * context);
static void printSlotNames(CFTypeRef value, struct context * context);
static void printPCIRanges(CFTypeRef value, struct context * context);
static void printInterruptMap(CFTypeRef value, struct context * context);
static void printInterrupts(CFTypeRef value, struct context * context);
static void printInterruptParent( CFTypeRef value, struct context * context );
static void printData(CFTypeRef value, struct context * context);
static Boolean compare( io_registry_entry_t service,
struct options options );
static void indent( Boolean isNode,
UInt32 serviceDepth,
UInt64 stackOfBits );
static void scan( io_registry_entry_t service,
Boolean serviceHasMoreSiblings,
UInt32 serviceDepth,
UInt64 stackOfBits,
struct options options );
static void search( io_registry_entry_t service,
UInt32 serviceDepth,
io_registry_entry_t stackOfObjects[],
struct options options );
static void show( io_registry_entry_t service,
UInt32 serviceDepth,
UInt64 stackOfBits,
struct options options );
static void showitem( const void * key,
const void * value,
void * parameter );
static void usage();
int main(int argc, char ** argv)
{
int argument = 0;
struct options options;
io_registry_entry_t service = 0; io_registry_entry_t stackOfObjects[64];
struct winsize winsize;
options.bold = FALSE;
options.format = FALSE;
options.hex = FALSE;
options.inheritance = FALSE;
options.list = FALSE;
options.root = FALSE;
options.state = TRUE;
options.tree = FALSE;
options.class = 0;
options.depth = UINT32_MAX;
options.key = 0;
options.name = 0;
options.plane = kIOServicePlane;
options.root = 0;
options.width = 0;
if (ioctl(fileno(stdout), TIOCGWINSZ, &winsize) == 0)
options.width = winsize.ws_col;
else if (ioctl(fileno(stdin), TIOCGWINSZ, &winsize) == 0)
options.width = winsize.ws_col;
while ( (argument = getopt(argc, argv, ":bc:d:fik:ln:p:rsStw:x")) != -1 )
{
switch (argument)
{
case 'b':
options.bold = TRUE;
break;
case 'c':
options.class = optarg;
break;
case 'd':
options.depth = atoi(optarg);
assertion(options.depth >= 0, "invalid depth");
if (options.depth == 0) options.depth = UINT32_MAX;
break;
case 'f':
options.format = TRUE;
break;
case 'i':
options.inheritance = TRUE;
break;
case 'k':
options.key = optarg;
break;
case 'l':
options.list = TRUE;
break;
case 'n':
options.name = optarg;
break;
case 'p':
options.plane = optarg;
break;
case 'r':
options.root = TRUE;
break;
case 's':
options.state = TRUE;
break;
case 'S':
options.state = FALSE;
break;
case 't':
options.tree = TRUE;
break;
case 'w':
options.width = atoi(optarg);
assertion(options.width >= 0, "invalid width");
break;
case 'x':
options.hex = TRUE;
break;
default:
usage();
break;
}
}
cfshowinit(options.hex);
printinit(options.width);
if (options.bold) boldinit();
service = IORegistryGetRootEntry(kIOMasterPortDefault);
assertion(service, "can't obtain I/O Kit's root service");
if (options.root)
{
search( service,
0,
stackOfObjects,
options );
}
else
{
scan( service,
FALSE,
0,
0,
options );
}
IOObjectRelease(service); service = 0;
exit(0);
}
static Boolean compare( io_registry_entry_t service,
struct options options )
{
CFStringRef key = 0; io_name_t location; Boolean match = FALSE;
io_name_t name; kern_return_t status = KERN_SUCCESS;
CFTypeRef value = 0;
if (options.class)
{
if (IOObjectConformsTo(service, options.class) == FALSE)
{
return FALSE;
}
match = TRUE;
}
if (options.key)
{
key = CFStringCreateWithCString( kCFAllocatorDefault,
options.key,
kCFStringEncodingUTF8 );
assertion(key != NULL, "can't create key");
value = IORegistryEntryCreateCFProperty( service,
key,
kCFAllocatorDefault,
kNilOptions );
CFRelease(key);
if (value == NULL)
{
return FALSE;
}
CFRelease(value);
match = TRUE;
}
if (options.name)
{
status = IORegistryEntryGetNameInPlane(service, options.plane, name);
assertion(status == KERN_SUCCESS, "can't obtain name");
if (strchr(options.name, '@'))
{
strcat(name, "@");
status = IORegistryEntryGetLocationInPlane(service, options.plane, location);
if (status == KERN_SUCCESS) strcat(name, location);
}
if (strcmp(options.name, name))
{
return FALSE;
}
match = TRUE;
}
return match;
}
static void search( io_registry_entry_t service,
UInt32 serviceDepth,
io_registry_entry_t stackOfObjects[],
struct options options )
{
io_registry_entry_t child = 0; io_registry_entry_t childUpNext = 0; io_iterator_t children = 0; UInt32 index = 0;
kern_return_t status = KERN_SUCCESS;
if (compare(service, options))
{
if (options.tree)
{
for (index = 0; index < serviceDepth; index++)
{
show(stackOfObjects[index], index, (2 << index), options);
}
options.depth += serviceDepth;
scan( service,
FALSE,
serviceDepth,
0,
options );
options.depth -= serviceDepth;
}
else
{
scan( service,
FALSE,
0,
0,
options );
}
println("");
}
else
{
stackOfObjects[serviceDepth] = service;
status = IORegistryEntryGetChildIterator(service, options.plane, &children);
assertion(status == KERN_SUCCESS, "can't obtain children");
childUpNext = IOIteratorNext(children);
while (childUpNext)
{
child = childUpNext;
childUpNext = IOIteratorNext(children);
search( child,
serviceDepth + 1,
stackOfObjects,
options );
IOObjectRelease(child); child = 0;
}
IOObjectRelease(children); children = 0;
}
}
static void scan( io_registry_entry_t service,
Boolean serviceHasMoreSiblings,
UInt32 serviceDepth,
UInt64 stackOfBits,
struct options options )
{
io_registry_entry_t child = 0; io_registry_entry_t childUpNext = 0; io_iterator_t children = 0; kern_return_t status = KERN_SUCCESS;
status = IORegistryEntryGetChildIterator(service, options.plane, &children);
assertion(status == KERN_SUCCESS, "can't obtain children");
childUpNext = IOIteratorNext(children);
if (serviceHasMoreSiblings)
stackOfBits |= (1 << serviceDepth);
else
stackOfBits &= ~(1 << serviceDepth);
if (options.depth > serviceDepth + 1)
{
if (childUpNext)
stackOfBits |= (2 << serviceDepth);
else
stackOfBits &= ~(2 << serviceDepth);
}
show(service, serviceDepth, stackOfBits, options);
if (options.depth > serviceDepth + 1)
{
while (childUpNext)
{
child = childUpNext;
childUpNext = IOIteratorNext(children);
scan( child,
(childUpNext) ? TRUE : FALSE,
serviceDepth + 1,
stackOfBits,
options );
IOObjectRelease(child); child = 0;
}
}
IOObjectRelease(children); children = 0;
}
static void show( io_registry_entry_t service,
UInt32 serviceDepth,
UInt64 stackOfBits,
struct options options )
{
io_name_t class; struct context context = { service, serviceDepth, stackOfBits, options };
uint32_t integer = 0;
UInt64 state = 0;
io_name_t location; io_name_t name; CFMutableDictionaryRef properties = 0; kern_return_t status = KERN_SUCCESS;
status = IORegistryEntryGetNameInPlane(service, options.plane, name);
assertion(status == KERN_SUCCESS, "can't obtain name");
indent(TRUE, serviceDepth, stackOfBits);
if (options.bold) boldon();
print("%s", name);
if (options.bold) boldoff();
status = IORegistryEntryGetLocationInPlane(service, options.plane, location);
if (status == KERN_SUCCESS) print("@%s", location);
print(" <class ");
if (options.inheritance)
{
CFStringRef classCFStr;
CFStringRef ancestryCFStr;
char * aCStr;
classCFStr = IOObjectCopyClass (service);
ancestryCFStr = createInheritanceStringForIORegistryClassName (classCFStr);
aCStr = (char *) CFStringGetCStringPtr (ancestryCFStr, kCFStringEncodingMacRoman);
if (NULL != aCStr)
{
print(aCStr);
}
CFRelease (classCFStr);
CFRelease (ancestryCFStr);
}
else
{
status = IOObjectGetClass(service, class);
assertion(status == KERN_SUCCESS, "can't obtain class name");
print("%s", class);
}
if (options.state)
{
if (IOObjectConformsTo(service, "IOService"))
{
status = IOServiceGetState(service, &state);
assertion(status == KERN_SUCCESS, "can't obtain state");
print( ", %sregistered, %smatched, %sactive",
state & kIOServiceRegisteredState ? "" : "!",
state & kIOServiceMatchedState ? "" : "!",
state & kIOServiceInactiveState ? "in" : "" );
status = IOServiceGetBusyState(service, &integer);
assertion(status == KERN_SUCCESS, "can't obtain busy state");
print(", busy %d", integer);
}
integer = IOObjectGetRetainCount(service);
assertion(integer >= 0, "can't obtain retain count");
print(", retain %d", integer);
}
println(">");
if (options.list || compare(service, options))
{
indent(FALSE, serviceDepth, stackOfBits);
println("{");
status = IORegistryEntryCreateCFProperties( service,
&properties,
kCFAllocatorDefault,
kNilOptions );
assertion(status == KERN_SUCCESS, "can't obtain properties");
assertion(CFGetTypeID(properties) == CFDictionaryGetTypeID(), NULL);
CFDictionaryApplyFunction(properties, showitem, &context);
indent(FALSE, serviceDepth, stackOfBits);
println("}");
indent(FALSE, serviceDepth, stackOfBits);
println("");
CFRelease(properties);
}
}
static void showitem(const void * key, const void * value, void * parameter)
{
struct context * context = parameter;
indent(FALSE, context->serviceDepth, context->stackOfBits);
print(" ");
cfshow(key);
print(" = ");
if (context->options.format)
{
printProp(key, value, context);
}
else
{
cfshow(value);
println("");
}
}
static void indent(Boolean isNode, UInt32 serviceDepth, UInt64 stackOfBits)
{
UInt32 index;
if (isNode)
{
for (index = 0; index < serviceDepth; index++)
print( (stackOfBits & (1 << index)) ? "| " : " " );
print("+-o ");
}
else {
for (index = 0; index <= serviceDepth + 1; index++)
print( (stackOfBits & (1 << index)) ? "| " : " " );
}
}
void usage()
{
fprintf( stderr,
"usage: ioreg [-bfilrsStx] [-c class] [-d depth] [-k key] [-n name] [-p plane] [-w width]\n"
"where options are:\n"
"\t-b show object name in bold\n"
"\t-c list properties of objects with the given class\n"
"\t-d limit tree to the given depth\n"
"\t-f enable smart formatting\n"
"\t-i show object inheritance\n"
"\t-k list properties of objects with the given key\n"
"\t-l list properties of all objects\n"
"\t-n list properties of objects with the given name\n"
"\t-p traverse registry over the given plane (IOService is default)\n"
"\t-r show subtrees rooted by the given criteria\n"
"\t-s show object state (eg. busy state, retain count)\n"
"\t-S don't show object state (eg. busy state, retain count)\n"
"\t-t show location of each substree\n"
"\t-w clip output to the given line width (0 is unlimited)\n"
"\t-x show data and numbers as hexadecimal\n"
);
exit(1);
}
static void assertion(int condition, char * message)
{
if (condition == 0)
{
fprintf(stderr, "ioreg: error: %s.\n", message);
exit(1);
}
}
static char * termcapstr_boldon = 0;
static char * termcapstr_boldoff = 0;
static int termcapstr_outc(int c)
{
return putchar(c);
}
static void boldinit()
{
char * term;
static char termcapbuf[64];
char * termcapbufptr = termcapbuf;
term = getenv("TERM");
if (term)
{
if (tgetent(NULL, term) > 0)
{
termcapstr_boldon = tgetstr("md", &termcapbufptr);
termcapstr_boldoff = tgetstr("me", &termcapbufptr);
assertion(termcapbufptr - termcapbuf <= sizeof(termcapbuf), NULL);
}
}
if (termcapstr_boldon == 0) termcapstr_boldon = "";
if (termcapstr_boldoff == 0) termcapstr_boldoff = "";
}
static void boldon()
{
tputs(termcapstr_boldon, 1, termcapstr_outc);
}
static void boldoff()
{
tputs(termcapstr_boldoff, 1, termcapstr_outc);
}
static char * printbuf = 0;
static int printbufclip = FALSE;
static int printbufleft = 0;
static int printbufsize = 0;
static void printinit(int width)
{
if (width)
{
printbuf = malloc(width);
printbufleft = width;
printbufsize = width;
assertion(printbuf != NULL, "can't allocate buffer");
}
}
static void printva(const char * format, va_list arguments)
{
if (printbufsize)
{
char * c;
int count = vsnprintf(printbuf, printbufleft, format, arguments);
while ( (c = strchr(printbuf, '\n')) ) *c = ' ';
printf("%s", printbuf);
if (count >= printbufleft)
{
count = printbufleft - 1;
printbufclip = TRUE;
}
printbufleft -= count; }
else
{
vprintf(format, arguments);
}
}
static void print(const char * format, ...)
{
va_list arguments;
va_start(arguments, format);
printva(format, arguments);
va_end(arguments);
}
static void println(const char * format, ...)
{
va_list arguments;
va_start(arguments, format);
printva(format, arguments);
va_end(arguments);
if (printbufclip) printf("$");
printf("\n");
printbufclip = FALSE;
printbufleft = printbufsize;
}
static Boolean cfshowhex;
static void cfshowinit(Boolean hex)
{
cfshowhex = hex;
}
static void cfshow(CFTypeRef object)
{
CFTypeID type = CFGetTypeID(object);
if ( type == CFArrayGetTypeID() ) cfarrayshow(object);
else if ( type == CFBooleanGetTypeID() ) cfbooleanshow(object);
else if ( type == CFDataGetTypeID() ) cfdatashow(object);
else if ( type == CFDictionaryGetTypeID() ) cfdictionaryshow(object);
else if ( type == CFNumberGetTypeID() ) cfnumbershow(object);
else if ( type == CFSetGetTypeID() ) cfsetshow(object);
else if ( type == CFStringGetTypeID() ) cfstringshow(object);
else print("<unknown object>");
}
static void cfarrayshowapplier(const void * value, void * parameter)
{
Boolean * first = (Boolean *) parameter;
if (*first)
*first = FALSE;
else
print(",");
cfshow(value);
}
static void cfarrayshow(CFArrayRef object)
{
Boolean first = TRUE;
CFRange range = { 0, CFArrayGetCount(object) };
print("(");
CFArrayApplyFunction(object, range, cfarrayshowapplier, &first);
print(")");
}
static void cfbooleanshow(CFBooleanRef object)
{
print(CFBooleanGetValue(object) ? "Yes" : "No");
}
static void cfdatashow(CFDataRef object)
{
UInt32 asciiNormalCount = 0;
UInt32 asciiSymbolCount = 0;
const UInt8 * bytes;
CFIndex index;
CFIndex length;
print("<");
length = CFDataGetLength(object);
bytes = CFDataGetBytePtr(object);
for (index = 0; index < length; index++) {
if (bytes[index] == 0) { #ifdef __ppc__
for (; index < length && bytes[index] == 0; index++) { }
#endif
break; }
else {
for (; index < length; index++)
{
if (isprint(bytes[index]))
asciiNormalCount++;
else if (bytes[index] >= 128 && bytes[index] <= 254)
asciiSymbolCount++;
else
break;
}
if (index < length && bytes[index] == 0) continue;
else break;
}
}
if ((asciiNormalCount >> 2) < asciiSymbolCount) index = 0;
else if (length == 1) index = 0;
else if (cfshowhex)
index = 0;
if (index >= length && asciiNormalCount) {
Boolean quoted = FALSE;
for (index = 0; index < length; index++)
{
if (bytes[index])
{
if (quoted == FALSE)
{
quoted = TRUE;
if (index)
print(",\"");
else
print("\"");
}
print("%c", bytes[index]);
}
else
{
if (quoted == TRUE)
{
quoted = FALSE;
print("\"");
}
else
break;
}
}
if (quoted == TRUE)
print("\"");
}
else {
for (index = 0; index < length; index++) print("%02x", bytes[index]);
}
print(">");
}
static void cfdictionaryshowapplier( const void * key,
const void * value,
void * parameter )
{
Boolean * first = (Boolean *) parameter;
if (*first)
*first = FALSE;
else
print(",");
cfshow(key);
print("=");
cfshow(value);
}
static void cfdictionaryshow(CFDictionaryRef object)
{
Boolean first = TRUE;
print("{");
CFDictionaryApplyFunction(object, cfdictionaryshowapplier, &first);
print("}");
}
static void cfnumbershow(CFNumberRef object)
{
long long number;
if (CFNumberGetValue(object, kCFNumberLongLongType, &number))
{
if (cfshowhex)
print("0x%qx", number);
else
print("%qu", number);
}
}
static void cfsetshowapplier(const void * value, void * parameter)
{
Boolean * first = (Boolean *) parameter;
if (*first)
*first = FALSE;
else
print(",");
cfshow(value);
}
static void cfsetshow(CFSetRef object)
{
Boolean first = TRUE;
print("[");
CFSetApplyFunction(object, cfsetshowapplier, &first);
print("]");
}
static void cfstringshow(CFStringRef object)
{
const char * c = CFStringGetCStringPtr(object, kCFStringEncodingMacRoman);
if (c)
print("\"%s\"", c);
else
{
CFIndex bufferSize = CFStringGetLength(object) + 1;
char * buffer = malloc(bufferSize);
if (buffer)
{
if ( CFStringGetCString(
object,
buffer,
bufferSize,
kCFStringEncodingMacRoman ) )
print("\"%s\"", buffer);
free(buffer);
}
}
}
static CFStringRef createInheritanceStringForIORegistryClassName(CFStringRef name)
{
CFStringRef curClassCFStr;
CFStringRef oldClassCFStr;
CFMutableStringRef outCFStr;
outCFStr = CFStringCreateMutable (NULL, 512);
CFStringInsert (outCFStr, 0, name);
curClassCFStr = CFStringCreateCopy (NULL, name);
for (;;)
{
oldClassCFStr = curClassCFStr;
curClassCFStr = IOObjectCopySuperclassForClass (curClassCFStr);
CFRelease (oldClassCFStr);
if (FALSE == CFEqual (curClassCFStr, CFSTR ("OSObject")))
{
CFStringInsert (outCFStr, 0, CFSTR (":"));
CFStringInsert (outCFStr, 0, curClassCFStr);
}
else
{
break;
}
}
return (CFStringRef) outCFStr;
}
static void printProp(CFStringRef key, CFTypeRef value, struct context * context)
{
kern_return_t status = KERN_SUCCESS;
Boolean valueShown = FALSE; io_registry_entry_t thisObj;
thisObj = context->service;
if (CFStringCompare(key, CFSTR("reg"), 0 ) == 0)
{
io_registry_entry_t parentObj; io_name_t parentName;
status = IORegistryEntryGetParentEntry( thisObj,
kIODeviceTreePlane,
&parentObj );
if (status == KERN_SUCCESS)
{
status = IORegistryEntryGetNameInPlane( parentObj,
kIODeviceTreePlane,
parentName );
assertion(status == KERN_SUCCESS, "could not get name of parent");
IOObjectRelease(parentObj);
if (strncmp(parentName, "pci", 3) == 0)
{
printPhysAddr(value, context);
valueShown = TRUE;
}
}
}
else if (CFStringCompare(key, CFSTR("assigned-addresses"), 0) == 0)
{
printPhysAddr(value, context);
valueShown = TRUE;
}
else if (CFStringCompare(key, CFSTR("slot-names"), 0) == 0)
{
printSlotNames(value, context);
valueShown = TRUE;
}
else if (CFStringCompare(key, CFSTR("ranges"), 0) == 0)
{
printPCIRanges(value, context);
valueShown = TRUE;
}
else if (CFStringCompare(key, CFSTR("interrupt-map"), 0) == 0)
{
printInterruptMap(value, context);
valueShown = TRUE;
}
else if ( CFStringCompare( key, CFSTR("interrupts"), 0) == 0 )
{
printInterrupts( value, context );
valueShown = TRUE;
}
else if ( CFStringCompare( key, CFSTR("interrupt-parent"), 0) == 0 )
{
printInterruptParent( value, context );
valueShown = TRUE;
}
if (valueShown == FALSE)
{
if (CFGetTypeID(value) == CFDataGetTypeID())
{
printData(value, context);
}
else
{
cfshow(value);
println("");
}
}
}
struct physAddrProperty {
UInt32 physHi;
UInt32 physMid;
UInt32 physLo;
UInt32 sizeHi;
UInt32 sizeLo;
};
#define kPhysAbsoluteMask 0x80000000
#define kPhysPrefetchMask 0x40000000
#define kPhysAliasMask 0x20000000
#define kPhysSpaceMask 0x03000000
#define kPhysSpaceShift 24
#define kPhysBusMask 0x00FF0000
#define kPhysBusShift 16
#define kPhysDeviceMask 0x0000F800
#define kPhysDeviceShift 11
#define kPhysFunctionMask 0x00000700
#define kPhysFunctionShift 8
#define kPhysRegisterMask 0x000000FF
#define kPhysRegisterShift 0
static SInt32
getRecursivePropValue( io_registry_entry_t thisRegEntry, CFStringRef propertyNameToLookFor )
{
SInt32 returnValue;
CFTypeRef ptr;
ptr = IORegistryEntrySearchCFProperty(thisRegEntry,
kIODeviceTreePlane,
propertyNameToLookFor,
kCFAllocatorDefault,
kIORegistryIterateParents | kIORegistryIterateRecursively);
assertion( ptr != NULL, "unable to get properties" );
returnValue = *(SInt32 *)CFDataGetBytePtr( (CFDataRef) ptr );
CFRelease( ptr );
return( returnValue );
}
static void printPhysAddr(CFTypeRef value, struct context * context)
{
CFIndex length; struct physAddrProperty *physAddr; UInt32 numPhysAddr, count, tmpCell;
UInt32 busNumber, deviceNumber,
functionNumber,
registerNumber;
const char *addressType,
*isPrefetch,
*isAlias,
*isAbsolute;
assertion(CFGetTypeID(value) == CFDataGetTypeID(), "invalid phys addr");
length = CFDataGetLength((CFDataRef)value);
if (length == 0)
{
println("<>");
return;
}
numPhysAddr = length / sizeof(struct physAddrProperty);
physAddr = (struct physAddrProperty *)CFDataGetBytePtr((CFDataRef)value);
println("");
for (count = 0; count < numPhysAddr; count++)
{
tmpCell = physAddr[count].physHi;
busNumber = (tmpCell & kPhysBusMask) >> kPhysBusShift;
deviceNumber = (tmpCell & kPhysDeviceMask) >> kPhysDeviceShift;
functionNumber = (tmpCell & kPhysFunctionMask) >> kPhysFunctionShift;
registerNumber = (tmpCell & kPhysRegisterMask) >> kPhysRegisterShift;
isAbsolute = ((tmpCell & kPhysAbsoluteMask) != 0) ? "abs" : "rel";
isPrefetch = ((tmpCell & kPhysPrefetchMask) != 0) ? ", prefetch" : "";
isAlias = ((tmpCell & kPhysAliasMask) != 0) ? ", alias" : "";
switch ((tmpCell & kPhysSpaceMask) >> kPhysSpaceShift)
{
case 0: addressType = "Config"; break;
case 1: addressType = "I/O"; break;
case 2: addressType = "Mem"; break;
case 3: addressType = "64-bit"; break;
default: addressType = "?"; break;
}
indent(FALSE, context->serviceDepth, context->stackOfBits);
println(" %02u: phys.hi: %08lx phys.mid: %08lx phys.lo: %08lx",
count,
physAddr[count].physHi,
physAddr[count].physMid,
physAddr[count].physLo );
indent(FALSE, context->serviceDepth, context->stackOfBits);
println(" size.hi: %08lx size.lo: %08lx",
physAddr[count].sizeHi,
physAddr[count].sizeLo );
indent(FALSE, context->serviceDepth, context->stackOfBits);
println(" bus: %u dev: %u func: %u reg: %u",
busNumber,
deviceNumber,
functionNumber,
registerNumber );
indent(FALSE, context->serviceDepth, context->stackOfBits);
println(" type: %s flags: %s%s%s",
addressType,
isAbsolute,
isPrefetch,
isAlias );
}
}
static void printSlotNames(CFTypeRef value, struct context * context)
{
CFIndex length;
char * bytePtr;
UInt32 count;
UInt32 * avail_slots;
assertion(CFGetTypeID(value) == CFDataGetTypeID(), "invalid phys addr");
length = CFDataGetLength((CFDataRef)value);
if (length == 0)
{
println("<>");
return;
}
avail_slots = (UInt32 *)CFDataGetBytePtr((CFDataRef)value);
bytePtr = (char *)avail_slots + sizeof(UInt32);
if (*avail_slots == 0)
{
println("<>");
return;
}
println("");
for (count = 0; count < 32; count++)
{
if ((*avail_slots & (1 << count)) != 0)
{
indent(FALSE, context->serviceDepth, context->stackOfBits);
println(" %02u: %s", count, bytePtr);
bytePtr += strlen(bytePtr) + 1; }
}
}
static void printPCIRanges(CFTypeRef value, struct context * context)
{
kern_return_t status = KERN_SUCCESS;
CFIndex length;
UInt32 *quadletPtr;
SInt32 parentACells, childACells, childSCells, elemSize;
io_registry_entry_t parentObj; int i,j,nRanges;
int counts[3];
const char *titles[] = {"-child--", "-parent-", "-size---"};
assertion(CFGetTypeID(value) == CFDataGetTypeID(), "invalid ranges");
length = CFDataGetLength((CFDataRef)value);
if (length == 0)
{
println("<>");
return;
}
quadletPtr = (UInt32 *)CFDataGetBytePtr((CFDataRef)value);
status = IORegistryEntryGetParentEntry( context->service, kIODeviceTreePlane, &parentObj );
assertion(status == KERN_SUCCESS, "unable to get device tree parent");
parentACells = getRecursivePropValue( parentObj, CFSTR( "#address-cells" ) );
IOObjectRelease( parentObj );
childACells = getRecursivePropValue( context->service, CFSTR( "#address-cells" ) );
childSCells = getRecursivePropValue( context->service, CFSTR( "#size-cells" ) );
elemSize = childACells + parentACells + childSCells;
println("");
indent(FALSE, context->serviceDepth, context->stackOfBits);
print(" ");
counts[0] = childACells;
counts[1] = parentACells;
counts[2] = childSCells;
for (j = 0; j < 3; j++)
{
print("%s", titles[j]); if (counts[j] > 1)
{
print("-");
for( i = 2; i <= counts[j]; i++)
{
if(i == counts[j])
print("-------- ");
else
print("---------");
}
}
else
print(" ");
}
println("");
nRanges = length/(elemSize * sizeof(UInt32));
for(j = 0; j < nRanges; j++)
{
indent(FALSE, context->serviceDepth, context->stackOfBits);
print(" ");
for(i = 0; i < elemSize; i++) print("%08x ", *quadletPtr++);
println("");
}
}
static void makepath(io_registry_entry_t target, io_string_t path)
{
kern_return_t status = KERN_SUCCESS;
status = IORegistryEntryGetPath(target, kIODeviceTreePlane, path);
assertion(status == KERN_SUCCESS, "unable to get path");
strcpy(path, strchr(path, ':') + 1);
}
static Boolean lookupPHandle(UInt32 phandle, io_registry_entry_t * device)
{
CFDictionaryRef props;
Boolean ret = FALSE; CFStringRef key = CFSTR(kIOPropertyMatchKey);
CFDictionaryRef value;
CFStringRef phandleKey = CFSTR("AAPL,phandle");
CFDataRef data;
data = CFDataCreate(NULL, (void *)&phandle, sizeof(UInt32));
props = CFDictionaryCreate( NULL,
(void *)&phandleKey,
(void *)&data,
1,
&kCFCopyStringDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks );
value = CFDictionaryCreate( NULL,
(void *)&key,
(void *)&props,
1,
&kCFCopyStringDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks );
*device = IOServiceGetMatchingService(kIOMasterPortDefault, value);
if (*device)
ret = TRUE;
CFRelease(props);
CFRelease(data);
return(ret);
}
static void printInterruptMap(CFTypeRef value, struct context * context)
{
io_registry_entry_t intParent;
io_string_t path;
SInt32 childCells, parentCells;
UInt32 *position, *end;
int length, count, index;
childCells = getRecursivePropValue( context->service, CFSTR("#address-cells" ) )
+ getRecursivePropValue( context->service, CFSTR("#interrupt-cells" ) );
position = (UInt32 *)CFDataGetBytePtr((CFDataRef)value);
length = CFDataGetLength((CFDataRef)value)/sizeof(UInt32);
end = position + length;
count = 0;
println("");
while (position < end)
{
indent(FALSE, context->serviceDepth, context->stackOfBits);
print(" %02d: ", count);
print(" child: ");
for (index = 0; index < childCells; index++) print("%08x ", *position++);
println("");
assertion( lookupPHandle(*position, &intParent), "error looking up phandle" );
parentCells = getRecursivePropValue( intParent, CFSTR( "#address-cells" ) )
+ getRecursivePropValue( intParent, CFSTR( "#interrupt-cells" ) );
*path = '\0';
makepath(intParent, path);
IOObjectRelease(intParent);
indent(FALSE, context->serviceDepth, context->stackOfBits);
println(" phandle: %08x (%s)", *position++, path);
indent(FALSE, context->serviceDepth, context->stackOfBits);
print(" parent: ");
for (index = 0; index < parentCells; index++) print("%08x ", *position++);
println("");
count++;
}
}
static void printInterrupts(CFTypeRef value, struct context * context)
{
UInt32 *position, *end;
int length, count, index;
position = (UInt32 *)CFDataGetBytePtr((CFDataRef)value);
length = CFDataGetLength((CFDataRef)value) / sizeof(UInt32);
end = position + length;
count = 0;
index = 0;
println("");
while (position < end)
{
indent(FALSE, context->serviceDepth, context->stackOfBits);
print(" %02d: ", index);
if ( count < (length-1) )
{
print("specifier: %08x (vector: %02lx) sense: %08x (", *position, (*position) & 0x000000FF, *(position+1) );
position ++;
count ++;
if ( (*position & 0x00000002 ) ) {
print( "HyperTransport vector: %04lx, ", (*position >> 16) & 0x0000FFFF );
}
println( "%s)", (*position & 1)? "level" : "edge" );
}
else
{
println("parent interrupt-map entry: %08x", *position );
}
position ++;
count ++;
index ++;
}
}
static void printInterruptParent( CFTypeRef value, struct context * context )
{
io_registry_entry_t parentRegEntry;
io_string_t path;
UInt32 * pHandleValue = (UInt32 *) CFDataGetBytePtr( (CFDataRef) value );
if ( lookupPHandle( *pHandleValue, &parentRegEntry ) )
{
*path = '\0';
makepath( parentRegEntry, path );
print( "<%08x>", *pHandleValue );
if ( *path != '\0' )
print( " (%s)", path );
println( "" );
IOObjectRelease( parentRegEntry );
}
}
static char ToAscii(UInt32 nibble)
{
nibble &= 0x0F;
if (nibble >= 0 && nibble <= 9)
return((char)nibble + '0');
else
return((char)nibble - 10 + 'A');
}
static void printData(CFTypeRef value, struct context * context)
{
UInt32 asciiNormalCount = 0;
UInt32 asciiSymbolCount = 0;
const UInt8 * bytes;
CFIndex index;
CFIndex length;
length = CFDataGetLength(value);
bytes = CFDataGetBytePtr(value);
for (index = 0; index < length; index++) {
if (bytes[index] == 0) { for (; index < length && bytes[index] == 0; index++) { }
break; }
else {
for (; index < length; index++)
{
if (isprint(bytes[index]))
asciiNormalCount++;
else if (bytes[index] >= 128 && bytes[index] <= 254)
asciiSymbolCount++;
else
break;
}
if (index < length && bytes[index] == 0) continue;
else break;
}
}
if ((asciiNormalCount >> 2) < asciiSymbolCount) index = 0;
else if (length == 1) index = 0;
else if (cfshowhex)
index = 0;
if (index >= length && asciiNormalCount) {
Boolean quoted = FALSE;
print("<");
for (index = 0; index < length; index++)
{
if (bytes[index])
{
if (quoted == FALSE)
{
quoted = TRUE;
if (index)
print(",\"");
else
print("\"");
}
print("%c", bytes[index]);
}
else
{
if (quoted == TRUE)
{
quoted = FALSE;
print("\"");
}
else
break;
}
}
if (quoted == TRUE)
print("\"");
print(">");
}
else if (length > 8) {
SInt8 work[ 256 ];
SInt8* p;
UInt32 i;
UInt32 offset;
UInt32 totalBytes;
UInt32 nBytesToDraw;
UInt32 bytesPerLine;
UInt8 c;
totalBytes = length;
bytesPerLine = (context->options.width - 20 - (2*context->serviceDepth))/4;
bytesPerLine = bytesPerLine > 32 ? 32 : bytesPerLine;
for ( offset = 0; offset < totalBytes; offset += bytesPerLine )
{
UInt32 offsetCopy;
UInt16 text;
println("");
if ( ( offset + bytesPerLine ) <= totalBytes )
nBytesToDraw = bytesPerLine;
else
nBytesToDraw = totalBytes - offset;
offsetCopy = offset;
work[ 8 ] = ':';
p = &work[ 7 ];
while ( offsetCopy != 0 )
{
*p-- = ToAscii( offsetCopy & 0x0F );
offsetCopy >>= 4;
}
while ( p >= work )
*p-- = '0';
p = &work[ 9 ];
for ( i = 0; i < nBytesToDraw; i++ )
{
c = bytes[ offset + i ];
*p++ = ' ';
*p++ = ToAscii( ( c & 0xF0 ) >> 4 );
*p++ = ToAscii( c & 0x0F );
}
for ( ; i < bytesPerLine; i++ )
{
text = ( ( ' ' << 8 ) | ' ' );
*( UInt16 * ) p = text;
p[ 2 ] = ' ';
p += 3;
}
*p++ = ' ';
for ( i = 0; i < nBytesToDraw; i++ )
{
c = bytes[ offset + i ];
if ( ( c < ' ' ) || ( c > '~' ) )
c = '.';
*p++ = c;
}
*p = 0;
indent(FALSE, context->serviceDepth, context->stackOfBits);
print(" %s", work);
}
} else
{
print("<");
for (index = 0; index < length; index++) print("%02x", bytes[index]);
print(">");
}
println("");
}