/* * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ /* File: UnpackPiData.c Written by: Jeffrey Robbin Copyright: © 1994, 1996 by Apple Computer, Inc., all rights reserved. File: GetSymbolFromPEF.c Written by: Jeffrey Robbin Copyright: © 1994, 1996 by Apple Computer, Inc., all rights reserved. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "GetSymbolFromPEF.h" #include #include "IOGraphicsLibPrivate.h" #include "IOGraphicsLibInternal.h" enum { kIOPEFparamErr = 1001, kIOPEFmemFullErr = 1002, kIOPEFcfragFragmentFormatErr = 1003, kIOPEFcfragNoSectionErr = 1004, kIOPEFcfragNoSymbolErr = 1005, kIOPEFcfragFragmentCorruptErr = 1006 }; /******************************************************************************* * *******************************************************************************/ static unsigned char PEFGetNextByte( unsigned char ** rawBuffer, int * rawBufferRemaining) { *rawBufferRemaining = *rawBufferRemaining - 1; return *(*rawBuffer)++; } /******************************************************************************* * *******************************************************************************/ static uint32_t PEFGetCount( unsigned char ** rawBuffer, int * rawBufferRemaining) { register unsigned char b; register uint32_t value = 0UL; /* Scan the count value. All required bytes MUST be present... */ b = PEFGetNextByte(rawBuffer, rawBufferRemaining); if (!IS_LAST_PICNT_BYTE(b)) { // if 1st byte is not that last... value = CONCAT_PICNT(value, b); // ...init value using 1st byte b = PEFGetNextByte(rawBuffer, rawBufferRemaining); if (!IS_LAST_PICNT_BYTE(b)) { // if 2nd byte is not the last... value = CONCAT_PICNT(value, b); // ...add in 2nd byte b = PEFGetNextByte(rawBuffer, rawBufferRemaining); if (!IS_LAST_PICNT_BYTE(b)) { // if 3rd byte is not the last... value = CONCAT_PICNT(value, b); // ...add in 3rd byte b = PEFGetNextByte(rawBuffer, rawBufferRemaining); if (!IS_LAST_PICNT_BYTE(b)) { // if 4th is not the last... value = CONCAT_PICNT(value, b); // ...add in 4th byte // 5th byte is definitly last! b = PEFGetNextByte(rawBuffer, rawBufferRemaining); } } } } value = CONCAT_PICNT(value, b); /* add in "last" byte (whichever one) */ return value; } /******************************************************************************* * UnpackPiData expands a compressed section into memory. *******************************************************************************/ static OSErr UnpackPiData( LogicalAddress thePEFPtr, SectionHeaderPtr sectionHeaderPtr, LogicalAddress * theData) { int cntX, cnt, rpt, dcnt, delta; unsigned char op, b; unsigned char * unpackBuffer; unsigned char * originalUnpackBuffer; unsigned char * endUnpackBuffer; unsigned char * oldRawBuffer; int oldRawBufferRemaining; unsigned char * rawBuffer; int rawBufferRemaining; // Verify incoming section is packed. if (sectionHeaderPtr->regionKind != kPIDataSection) { return kIOPEFparamErr; } // Allocate memory to unpack into originalUnpackBuffer = (unsigned char*)NewPtrSys(sectionHeaderPtr->initSize); if (originalUnpackBuffer == nil) { return kIOPEFmemFullErr; } unpackBuffer = originalUnpackBuffer; endUnpackBuffer = unpackBuffer + sectionHeaderPtr->initSize; rawBuffer = (unsigned char*)((uintptr_t)thePEFPtr + sectionHeaderPtr->containerOffset); rawBufferRemaining = sectionHeaderPtr->rawSize; /* Expand the pidata instructions. EOF will terminate processing * through the setjmp on pidData_jmpbuf above... */ while (rawBufferRemaining > 0) { /***** * The first byte of each instruction contains the opcode and a count. * If the countis 0, the count starts in the next byte... */ /* Pick up the opcode and first count operand... */ b = PEFGetNextByte(&rawBuffer, &rawBufferRemaining); op = PIOP(b); cnt = PICNT(b); if (cnt == 0) { cnt = PEFGetCount(&rawBuffer, &rawBufferRemaining); } /* Unpack the data as a function of the opcode... */ switch (op) { case kZero: // zero out cnt bytes... if (unpackBuffer + cnt > endUnpackBuffer) { goto Error; } memset(unpackBuffer, 0, cnt); unpackBuffer += cnt; break; case kBlock: // copy cnt bytes... if (unpackBuffer + cnt > endUnpackBuffer) { goto Error; } while (--cnt >= 0) { *unpackBuffer++ = PEFGetNextByte(&rawBuffer, &rawBufferRemaining); } break; case kRepeat: // copy cnt bytes rpt times... rpt = PEFGetCount(&rawBuffer, &rawBufferRemaining) + 1; if (cnt == 1) { if (unpackBuffer + rpt > endUnpackBuffer) { goto Error; } b = PEFGetNextByte(&rawBuffer, &rawBufferRemaining); memset(unpackBuffer, b, rpt); unpackBuffer += rpt; } else { oldRawBufferRemaining = rawBufferRemaining; oldRawBuffer = rawBuffer; while (--rpt >= 0) { if (unpackBuffer + cnt > endUnpackBuffer) { goto Error; } rawBufferRemaining = oldRawBufferRemaining; rawBuffer = oldRawBuffer; cntX = cnt; while (--cntX >= 0) { *unpackBuffer++ = PEFGetNextByte(&rawBuffer, &rawBufferRemaining); } } } break; case kRepeatZero: //copy cnt 0's and dcnt bytes rpt times dcnt = PEFGetCount(&rawBuffer, &rawBufferRemaining); // ...then copy cnt more 0's rpt = PEFGetCount(&rawBuffer, &rawBufferRemaining); goto rptPart1; // jump into loop to copy 0's first... while (--rpt >= 0) { if (unpackBuffer + dcnt > endUnpackBuffer) { goto Error; } cntX = dcnt; // cnt repeating parts follow each other while (--cntX >= 0) { *unpackBuffer++ = PEFGetNextByte(&rawBuffer, &rawBufferRemaining); } rptPart1: // non-repeating part is always 0's... if (unpackBuffer + cnt > endUnpackBuffer) { goto Error; } memset(unpackBuffer, 0, cnt); unpackBuffer += cnt; } break; case kRepeatBlock: // copy cnt repeating bytes and dcnt dcnt = PEFGetCount(&rawBuffer, &rawBufferRemaining); /* non-repating bytes rcnt times... */ rpt = PEFGetCount(&rawBuffer, &rawBufferRemaining); /* ...then copy cnt repeating bytes */ oldRawBufferRemaining = rawBufferRemaining; oldRawBuffer = rawBuffer; delta = 0; /* the repeating part and each non-rep */ goto rptPart2; /* jump into loop to copy rptng part 1st */ while (--rpt >= 0) { if (unpackBuffer + dcnt > endUnpackBuffer) { goto Error; } rawBuffer = oldRawBuffer + cnt + delta; rawBufferRemaining = oldRawBufferRemaining - (cnt + delta); cntX = dcnt; while (--cntX >= 0) { *unpackBuffer++ = PEFGetNextByte(&rawBuffer, &rawBufferRemaining); } delta += dcnt; rptPart2: if (unpackBuffer + cnt > endUnpackBuffer) { goto Error; } rawBuffer = oldRawBuffer; rawBufferRemaining = oldRawBufferRemaining; cntX = cnt; while (--cntX >= 0) { *unpackBuffer++ = PEFGetNextByte(&rawBuffer, &rawBufferRemaining); } } rawBuffer = oldRawBuffer + cnt + delta; rawBufferRemaining = oldRawBufferRemaining - (cnt + delta); break; default: goto Error; break; } /* switch */ } /* for */ *theData = originalUnpackBuffer; return noErr; Error: if (unpackBuffer) DisposePtr((Ptr)originalUnpackBuffer); *theData = nil; return kIOPEFparamErr; } /******************************************************************************* * GetSymbolFromPEF will extract from a PEF container the data associated * with a given symbol name. It requires that the PEF file have been previously * loaded into memory. *******************************************************************************/ static OSStatus GetSymbolFromPEF( char *inSymbolName, const LogicalAddress thePEFPtr, LogicalAddress theSymbolPtr, ByteCount theSymbolSize) { StringPtr theSymbolName = (StringPtr) inSymbolName; ContainerHeaderPtr containerHeaderPtr; // Pointer to the Container Header SectionHeaderPtr loaderSectionPtr = 0; // Ptr to Loader Section Header SectionHeaderPtr exportSectionPtr; // Ptr to Section Header with symbol short currentSection; Boolean foundSection; Boolean foundSymbol; int numExportSymbols; LoaderHeaderPtr loaderHeaderPtr; ExportSymbolEntryPtr exportSymbolEntryPtr; LoaderExportChainEntryPtr exportChainEntryPtr; StringPtr exportSymbolName; LogicalAddress expandedDataPtr; unsigned char * sourceDataPtr; unsigned char * destDataPtr; containerHeaderPtr = (ContainerHeaderPtr)thePEFPtr; // Does the magic cookie match? if (containerHeaderPtr->magicCookie != 'Joy!') { return kIOPEFcfragFragmentFormatErr; } // Is this a known PEF container format? if (containerHeaderPtr->containerID != 'peff') { return kIOPEFcfragFragmentFormatErr; } // Validate parameters if (theSymbolPtr == nil) { return kIOPEFparamErr; } // Find the loader section. foundSection = false; for (currentSection = 0; currentSection < containerHeaderPtr->nbrOfSections; currentSection++) { loaderSectionPtr = (SectionHeaderPtr)((uintptr_t)containerHeaderPtr + sizeof(ContainerHeader) + (sizeof(SectionHeader) * currentSection)); if (loaderSectionPtr->regionKind == kLoaderSection) { foundSection = true; break; } } if (foundSection == false) { return kIOPEFcfragNoSectionErr; } // Get the number of export symbols. loaderHeaderPtr = (LoaderHeaderPtr)((uintptr_t)thePEFPtr + loaderSectionPtr->containerOffset); numExportSymbols = loaderHeaderPtr->nbrExportSyms; // Start at the first exported symbol. exportSymbolEntryPtr = (ExportSymbolEntryPtr)((uintptr_t)loaderHeaderPtr + loaderHeaderPtr->slotTblOffset + (sizeof(LoaderHashSlotEntry) * (1<hashSlotTblSz)) + (sizeof(LoaderExportChainEntry) * numExportSymbols)); exportChainEntryPtr = (LoaderExportChainEntryPtr) ((uintptr_t)loaderHeaderPtr + loaderHeaderPtr->slotTblOffset + (sizeof(LoaderHashSlotEntry) * (1<hashSlotTblSz))); foundSymbol = false; while (numExportSymbols-- > 0) { exportSymbolName = (StringPtr)((uintptr_t)loaderHeaderPtr + loaderHeaderPtr->strTblOffset + (exportSymbolEntryPtr->class_and_name & 0x00FFFFFF)); if (SymbolCompare(theSymbolName, exportSymbolName, exportChainEntryPtr->_h._h_h._nameLength)) { foundSymbol = true; break; } exportSymbolEntryPtr = (ExportSymbolEntryPtr) (((intptr_t) exportSymbolEntryPtr) + 10); exportChainEntryPtr++; } if (foundSymbol == false) { return kIOPEFcfragNoSymbolErr; } // Found the symbol, so... let's go get the data! exportSectionPtr = (SectionHeaderPtr)((uintptr_t)containerHeaderPtr + sizeof(ContainerHeader) + (sizeof(SectionHeader) * exportSymbolEntryPtr->sectionNumber)); expandedDataPtr = nil; switch (exportSectionPtr -> regionKind) { case kPIDataSection: // Expand the data! (Not yet... :) if (UnpackPiData(thePEFPtr, exportSectionPtr, &expandedDataPtr) != noErr) { return kIOPEFcfragFragmentCorruptErr; } sourceDataPtr = (unsigned char*)((uintptr_t)expandedDataPtr + exportSymbolEntryPtr->address); break; default: sourceDataPtr = (unsigned char*)((uintptr_t)thePEFPtr + exportSectionPtr->containerOffset + exportSymbolEntryPtr->address); break; } // Copy the data! destDataPtr = (unsigned char*)theSymbolPtr; while (theSymbolSize-- > 0) { *destDataPtr++ = *sourceDataPtr++; } // Cleanup any expanded data if (expandedDataPtr != nil) { DisposePtr((Ptr)expandedDataPtr); } return noErr; } /******************************************************************************* * *******************************************************************************/ static IOByteCount GetPEFLen(LogicalAddress thePEFPtr) { ContainerHeaderPtr containerHeaderPtr; // Pointer to the Container Header SectionHeaderPtr sections; short currentSection; int lastOffset = 0; int len = 0; containerHeaderPtr = (ContainerHeaderPtr)thePEFPtr; // Does the magic cookie match? if (containerHeaderPtr->magicCookie != 'Joy!') { return 0; } // Is this a known PEF container format? if (containerHeaderPtr->containerID != 'peff') { return 0; } // Find the loader section. sections = (SectionHeaderPtr) (containerHeaderPtr + 1); for (currentSection = 0; currentSection < containerHeaderPtr->nbrOfSections; currentSection++) { if (sections[currentSection].containerOffset > lastOffset) { lastOffset = sections[currentSection].containerOffset; len = sections[currentSection].rawSize; } } return lastOffset + len; } /******************************************************************************* * theExportSymbol is NOT null-terminated, so use theExportSymbolLength. *******************************************************************************/ static Boolean SymbolCompare( StringPtr theLookedForSymbol, StringPtr theExportSymbol, uint32_t theExportSymbolLength) { unsigned char * p1 = (unsigned char*)theLookedForSymbol; unsigned char * p2 = (unsigned char*)theExportSymbol; // Same length? // (skip over p string len byte) if (theExportSymbolLength != *p1++) { return false; } while (theExportSymbolLength-- != 0) { if (*p1++ != *p2++) { return false; } } return true; } /******************************************************************************* * *******************************************************************************/ // The Driver Description enum { kInitialDriverDescriptor = 0, kVersionOneDriverDescriptor = 1, kTheDescriptionSignature = 'mtej', }; struct DriverType { unsigned char nameInfoStr[32]; // Driver Name/Info String uint32_t version; // Driver Version Number - really NumVersion }; typedef struct DriverType DriverType; struct DriverDescription { uint32_t driverDescSignature; // Signature field of this structure uint32_t driverDescVersion; // Version of this data structure DriverType driverType; // Type of Driver // other data follows... }; typedef struct DriverDescription DriverDescription; /******************************************************************************* * *******************************************************************************/ static void ExaminePEF( mach_port_t masterPort, char * pef, IOByteCount pefLen, CFDictionaryRef allMatching) { char descripName[] = "\pTheDriverDescription"; int err; DriverDescription descrip; char matchName[40]; uint32_t newVersion; uint32_t curVersion; IOReturn kr; io_iterator_t iter; io_service_t service; io_string_t path; CFStringRef ndrvPropName = CFSTR("driver,AAPL,MacOS,PowerPC"); CFDataRef ndrv; CFStringRef matchKey; CFTypeRef value = 0; CFDictionaryRef matching = 0; CFMutableDictionaryRef dict; err = GetSymbolFromPEF(descripName, pef, &descrip, sizeof(descrip)); if (err != 0) { printf("\nGetSymbolFromPEF returns %d\n",err); return; } if ((descrip.driverDescSignature != kTheDescriptionSignature) || (descrip.driverDescVersion != kInitialDriverDescriptor)) { return; } strncpy(matchName, (char *) descrip.driverType.nameInfoStr + 1, descrip.driverType.nameInfoStr[0]); matchName[descrip.driverType.nameInfoStr[0]] = 0; matchKey = CFStringCreateWithCString( kCFAllocatorDefault, matchName, kCFStringEncodingMacRoman ); if (!matchKey) return; if (allMatching) { value = CFDictionaryGetValue(allMatching, matchKey); if (value) { if (value && (CFDictionaryGetTypeID() == CFGetTypeID(value))) matching = CFRetain(value); else if (value && (CFStringGetTypeID() == CFGetTypeID(value))) { CFRelease(matchKey); matchKey = CFRetain(value); } } } if (!matching) { CFStringRef nameMatchKey = CFSTR(kIONameMatchKey); matching = CFDictionaryCreate( kCFAllocatorDefault, (const void **) &nameMatchKey, (const void **) &matchKey, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks ); } CFRelease(matchKey); if (!matching) return; kr = IOServiceGetMatchingServices(masterPort, matching, &iter); if (kIOReturnSuccess != kr) return; newVersion = descrip.driverType.version; if ((newVersion & 0xffff) == 0x8000) { // final stage, release rev newVersion |= 0xff; } for ( ; (service = IOIteratorNext(iter)); IOObjectRelease(service)) { kr = IORegistryEntryGetPath(service, kIOServicePlane, path); if (kIOReturnSuccess == kr) printf("Name %s matches %s, ", matchName, path); ndrv = (CFDataRef) IORegistryEntryCreateCFProperty(service, ndrvPropName, kCFAllocatorDefault, kNilOptions); if (ndrv) { DriverDescription _curDesc; DriverDescription * curDesc; curDesc = (DriverDescription *) CFDataGetBytePtr(ndrv); err = noErr; if ((sizeof(DriverDescription) > (size_t) CFDataGetLength(ndrv)) || (curDesc->driverDescSignature != kTheDescriptionSignature)) { curDesc = &_curDesc; err = GetSymbolFromPEF(descripName, (const LogicalAddress)CFDataGetBytePtr(ndrv), curDesc, sizeof(DriverDescription)); } if (err != noErr) printf("GetSymbolFromPEF returns %d\n",err); else { if ((curDesc->driverDescSignature == kTheDescriptionSignature) && (curDesc->driverDescVersion == kInitialDriverDescriptor)) { curVersion = curDesc->driverType.version; printf("new version %08x, current version %08x\n", newVersion, curVersion); if ((curVersion & 0xffff) == 0x8000) { // final stage, release rev curVersion |= 0xff; } if (newVersion <= curVersion) { pefLen = 0; } } } CFRelease(ndrv); } if (pefLen == 0) continue; ndrv = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (UInt8 *) pef, pefLen, kCFAllocatorNull); if (ndrv == 0) continue; printf("Installing ndrv ("); dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); if (dict) { io_service_t child = MACH_PORT_NULL; io_iterator_t iter; CFDictionarySetValue(dict, ndrvPropName, ndrv); kr = IORegistryEntryGetChildIterator(service, kIOServicePlane, &iter); if (kr == kIOReturnSuccess) { kr = kIOReturnNotFound; for( ; (child = IOIteratorNext(iter)); IOObjectRelease(child)) { if (IOObjectConformsTo(child, "IOFramebuffer")) break; } IOObjectRelease(iter); } if (child) { kr = IORegistryEntrySetCFProperties(child, dict); IOObjectRelease(child); } CFRelease(dict); } else kr = kIOReturnNoMemory; CFRelease(ndrv); printf("%08x)\n", kr); } IOObjectRelease(iter); return; } /******************************************************************************* * *******************************************************************************/ static int PEFExamineFile(mach_port_t masterPort, CFURLRef file, CFDictionaryRef props) { vm_offset_t pefBytes; vm_size_t pefFileLen; char * pef; IOByteCount pefLen, pos = 0; int err; CFDictionaryRef fileMatch; CFDictionaryRef matching = 0; Boolean matches = true; char cFile[MAXPATHLEN]; do { if (!props) continue; fileMatch = CFDictionaryGetValue(props, CFSTR("IONDRVFileMatching")); if (fileMatch && (CFDictionaryGetTypeID() != CFGetTypeID(fileMatch))) fileMatch = 0; if (fileMatch) { io_service_t service; CFRetain(fileMatch); service = IOServiceGetMatchingService(masterPort, fileMatch); matches = (MACH_PORT_NULL != service); if (matches) IOObjectRelease(service); continue; } matching = CFDictionaryGetValue(props, CFSTR("IONDRVMatching")); if (matching && (CFDictionaryGetTypeID() != CFGetTypeID(matching))) matching = 0; } while (false); if (!matches) return (kIOReturnSuccess); if (CFURLGetFileSystemRepresentation(file, TRUE, (UInt8 *) cFile, MAXPATHLEN)) err = readFile(cFile, &pefBytes, &pefFileLen); else err = kIOReturnIOError; if (kIOReturnSuccess != err) return (err); pef = (char *) pefBytes; while ((pos < pefFileLen) && (pefLen = GetPEFLen(pef))) { ExaminePEF(masterPort, pef, pefLen, matching); pefLen = (pefLen + 15) & ~15; pef += pefLen; pos += pefLen; } if (pefBytes) vm_deallocate(mach_task_self(), pefBytes, pefFileLen); return (0); } static void _PEFExamineFile(mach_port_t masterPort, CFURLRef ndrvURL, CFDictionaryRef plist) { if (PEFExamineFile(masterPort, ndrvURL, plist)) { char buf[PATH_MAX]; char * ndrv_path; if(CFURLGetFileSystemRepresentation(ndrvURL, true /*resolve*/, (UInt8*)buf, PATH_MAX)) { ndrv_path = buf; } else { ndrv_path = "(unknown)"; } printf("error processing NDRV \"%s\"", ndrv_path); } } static void PEFExamineBundle( mach_port_t masterPort __unused, CFBundleRef bdl ) { CFURLRef ndrvURL; CFDictionaryRef plist; plist = CFBundleGetInfoDictionary(bdl); if (!plist) return; ndrvURL = CFBundleCopyExecutableURL(bdl); if (!ndrvURL) return; _PEFExamineFile(kIOMasterPortDefault, ndrvURL, plist); CFRelease(ndrvURL); } void IOLoadPEFsFromURL( CFURLRef ndrvDirURL, io_service_t service __unused ) { CFIndex ndrvCount, n; CFArrayRef ndrvDirContents = NULL; // must release SInt32 error; ndrvDirContents = (CFArrayRef) CFURLCreatePropertyFromResource( kCFAllocatorDefault, ndrvDirURL, kCFURLFileDirectoryContents, &error); ndrvCount = ndrvDirContents ? CFArrayGetCount(ndrvDirContents) : 0; for (n = 0; n < ndrvCount; n++) { CFURLRef ndrvURL = NULL; // don't release CFNumberRef num; CFBundleRef bdl; CFStringRef ext; SInt32 mode; Boolean skip; ndrvURL = (CFURLRef)CFArrayGetValueAtIndex(ndrvDirContents, n); bdl = CFBundleCreate(kCFAllocatorDefault, ndrvURL); if (bdl) { PEFExamineBundle(kIOMasterPortDefault, bdl); CFRelease(bdl); continue; } ext = CFURLCopyPathExtension(ndrvURL); if (ext) { skip = CFEqual(ext, CFSTR(".plist")); CFRelease(ext); if (skip) continue; } num = (CFNumberRef) CFURLCreatePropertyFromResource( kCFAllocatorDefault, ndrvURL, kCFURLFilePOSIXMode, &error); if (!num) continue; CFNumberGetValue(num, kCFNumberSInt32Type, (SInt32 *) &mode); CFRelease(num); if ((mode & S_IFMT) == S_IFREG) _PEFExamineFile(kIOMasterPortDefault, ndrvURL, NULL); } if (ndrvDirContents) CFRelease(ndrvDirContents); }