1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_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. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23/*
24    File:    UnpackPiData.c
25    Written by:    Jeffrey Robbin
26    Copyright:    � 1994, 1996 by Apple Computer, Inc., all rights reserved.
27
28    File:    GetSymbolFromPEF.c
29    Written by:    Jeffrey Robbin
30    Copyright:    � 1994, 1996 by Apple Computer, Inc., all rights reserved.
31*/
32
33#include <CoreFoundation/CoreFoundation.h>
34#include <IOKit/IOKitLib.h>
35#include <stdlib.h>
36#include <err.h>
37#include <sys/file.h>
38#include <nlist.h>
39#include <stdio.h>
40#include <unistd.h>
41#include <sys/param.h>
42#include <sys/stat.h>
43#include <sys/errno.h>
44
45#include <mach/mach.h>
46#include <mach/mach_error.h>
47#include <mach/mach_host.h>
48
49#include "GetSymbolFromPEF.h"
50#include <IOKit/graphics/IOGraphicsLib.h>
51#include "IOGraphicsLibPrivate.h"
52#include "IOGraphicsLibInternal.h"
53
54enum
55{
56    kIOPEFparamErr                = 1001,
57    kIOPEFmemFullErr              = 1002,
58    kIOPEFcfragFragmentFormatErr  = 1003,
59    kIOPEFcfragNoSectionErr       = 1004,
60    kIOPEFcfragNoSymbolErr        = 1005,
61    kIOPEFcfragFragmentCorruptErr = 1006
62};
63
64/*******************************************************************************
65*
66*******************************************************************************/
67static unsigned char PEFGetNextByte(
68    unsigned char ** rawBuffer,
69    int * rawBufferRemaining)
70{
71    *rawBufferRemaining = *rawBufferRemaining - 1;
72    return *(*rawBuffer)++;
73}
74
75
76/*******************************************************************************
77*
78*******************************************************************************/
79static uint32_t PEFGetCount(
80    unsigned char ** rawBuffer,
81    int * rawBufferRemaining)
82{
83    register unsigned char b;
84    register uint32_t value = 0UL;
85
86    /* Scan the count value. All required bytes MUST be present... */
87
88    b = PEFGetNextByte(rawBuffer, rawBufferRemaining);
89    if (!IS_LAST_PICNT_BYTE(b)) {           // if 1st byte is not that last...
90        value = CONCAT_PICNT(value, b);     // ...init value using 1st byte
91
92        b = PEFGetNextByte(rawBuffer, rawBufferRemaining);
93        if (!IS_LAST_PICNT_BYTE(b)) {       // if 2nd byte is not the last...
94            value = CONCAT_PICNT(value, b); // ...add in 2nd byte
95
96            b = PEFGetNextByte(rawBuffer, rawBufferRemaining);
97            if (!IS_LAST_PICNT_BYTE(b)) {       // if 3rd byte is not the last...
98                value = CONCAT_PICNT(value, b); // ...add in 3rd byte
99
100                b = PEFGetNextByte(rawBuffer, rawBufferRemaining);
101                if (!IS_LAST_PICNT_BYTE(b)) {       // if 4th is not the last...
102                    value = CONCAT_PICNT(value, b); // ...add in 4th byte
103
104                    // 5th byte is definitly last!
105                    b = PEFGetNextByte(rawBuffer, rawBufferRemaining);
106                }
107            }
108        }
109    }
110
111    value = CONCAT_PICNT(value, b); /* add in "last" byte (whichever one) */
112
113    return value;
114}
115
116
117
118/*******************************************************************************
119* UnpackPiData expands a compressed section into memory.
120*******************************************************************************/
121static OSErr UnpackPiData(
122    LogicalAddress   thePEFPtr,
123    SectionHeaderPtr sectionHeaderPtr,
124    LogicalAddress * theData)
125{
126    int             cntX, cnt, rpt, dcnt, delta;
127    unsigned char    op, b;
128    unsigned char *  unpackBuffer;
129    unsigned char *  originalUnpackBuffer;
130    unsigned char *  endUnpackBuffer;
131    unsigned char *  oldRawBuffer;
132    int             oldRawBufferRemaining;
133    unsigned char *  rawBuffer;
134    int             rawBufferRemaining;
135
136    // Verify incoming section is packed.
137    if (sectionHeaderPtr->regionKind != kPIDataSection) {
138        return kIOPEFparamErr;
139    }
140
141    // Allocate memory to unpack into
142    originalUnpackBuffer = (unsigned char*)NewPtrSys(sectionHeaderPtr->initSize);
143    if (originalUnpackBuffer == nil) {
144        return kIOPEFmemFullErr;
145    }
146
147    unpackBuffer = originalUnpackBuffer;
148    endUnpackBuffer = unpackBuffer + sectionHeaderPtr->initSize;
149    rawBuffer = (unsigned char*)((uintptr_t)thePEFPtr +
150        sectionHeaderPtr->containerOffset);
151    rawBufferRemaining = sectionHeaderPtr->rawSize;
152
153
154   /* Expand the pidata instructions.  EOF will terminate processing
155    * through the setjmp on pidData_jmpbuf above...
156    */
157    while (rawBufferRemaining > 0) {
158
159       /*****
160        * The first byte of each instruction contains the opcode and a count.
161        * If the countis 0, the count starts in the next byte...
162        */
163
164       /* Pick up the opcode and first count operand...
165        */
166        b = PEFGetNextByte(&rawBuffer, &rawBufferRemaining);
167
168        op  = PIOP(b);
169        cnt = PICNT(b);
170
171        if (cnt == 0) {
172            cnt = PEFGetCount(&rawBuffer, &rawBufferRemaining);
173        }
174
175       /* Unpack the data as a function of the opcode...
176        */
177        switch (op) {
178          case kZero:  // zero out cnt bytes...
179            if (unpackBuffer + cnt > endUnpackBuffer) {
180                goto Error;
181            }
182            memset(unpackBuffer, 0, cnt);
183            unpackBuffer += cnt;
184            break;
185
186          case kBlock: // copy cnt bytes...
187            if (unpackBuffer + cnt > endUnpackBuffer) {
188                goto Error;
189            }
190            while (--cnt >= 0) {
191                *unpackBuffer++ = PEFGetNextByte(&rawBuffer, &rawBufferRemaining);
192            }
193            break;
194
195          case kRepeat: // copy cnt bytes rpt times...
196            rpt = PEFGetCount(&rawBuffer, &rawBufferRemaining) + 1;
197
198            if (cnt == 1) {
199                if (unpackBuffer + rpt > endUnpackBuffer) {
200                    goto Error;
201                }
202                b = PEFGetNextByte(&rawBuffer, &rawBufferRemaining);
203                memset(unpackBuffer, b, rpt);
204                unpackBuffer += rpt;
205            } else {
206                oldRawBufferRemaining    = rawBufferRemaining;
207                oldRawBuffer            = rawBuffer;
208                while (--rpt >= 0) {
209                    if (unpackBuffer + cnt > endUnpackBuffer) {
210                        goto Error;
211                    }
212                    rawBufferRemaining    = oldRawBufferRemaining;
213                    rawBuffer            = oldRawBuffer;
214                    cntX = cnt;
215                    while (--cntX >= 0) {
216                        *unpackBuffer++ = PEFGetNextByte(&rawBuffer,
217                            &rawBufferRemaining);
218                    }
219                }
220            }
221            break;
222
223          case kRepeatZero: //copy cnt 0's and dcnt bytes rpt times
224            dcnt = PEFGetCount(&rawBuffer, &rawBufferRemaining); // ...then copy cnt more 0's
225            rpt = PEFGetCount(&rawBuffer, &rawBufferRemaining);
226
227            goto rptPart1; // jump into loop to copy 0's first...
228
229            while (--rpt >= 0) {
230                if (unpackBuffer + dcnt > endUnpackBuffer) {
231                    goto Error;
232                }
233                cntX = dcnt; // cnt repeating parts follow each other
234                while (--cntX >= 0) {
235                    *unpackBuffer++ = PEFGetNextByte(&rawBuffer,
236                        &rawBufferRemaining);
237                }
238
239rptPart1: // non-repeating part is always 0's...
240                if (unpackBuffer + cnt > endUnpackBuffer) {
241                    goto Error;
242                }
243                memset(unpackBuffer, 0, cnt);
244                unpackBuffer += cnt;
245            }
246            break;
247
248          case kRepeatBlock: // copy cnt repeating bytes and dcnt
249            dcnt = PEFGetCount(&rawBuffer, &rawBufferRemaining);                    /* non-repating bytes rcnt times...            */
250            rpt = PEFGetCount(&rawBuffer, &rawBufferRemaining);                    /* ...then copy cnt repeating bytes            */
251
252            oldRawBufferRemaining    = rawBufferRemaining;
253            oldRawBuffer            = rawBuffer;
254            delta                    = 0;  /*  the repeating part and each non-rep    */
255
256            goto rptPart2;  /* jump into loop to copy rptng part 1st */
257
258            while (--rpt >= 0) {
259                if (unpackBuffer + dcnt > endUnpackBuffer) {
260                    goto Error;
261                }
262
263                rawBuffer            = oldRawBuffer + cnt + delta;
264                rawBufferRemaining    = oldRawBufferRemaining - (cnt + delta);
265                cntX = dcnt;
266                while (--cntX >= 0) {
267                    *unpackBuffer++ = PEFGetNextByte(&rawBuffer,
268                        &rawBufferRemaining);
269                }
270                delta += dcnt;
271
272rptPart2:
273                if (unpackBuffer + cnt > endUnpackBuffer) {
274                    goto Error;
275                }
276                rawBuffer            = oldRawBuffer;
277                rawBufferRemaining    = oldRawBufferRemaining;
278                cntX = cnt;
279                while (--cntX >= 0) {
280                    *unpackBuffer++ = PEFGetNextByte(&rawBuffer,
281                        &rawBufferRemaining);
282                }
283            }
284
285            rawBuffer            = oldRawBuffer + cnt + delta;
286            rawBufferRemaining    = oldRawBufferRemaining - (cnt + delta);
287            break;
288
289            default:
290              goto Error;
291              break;
292        } /* switch */
293    } /* for */
294
295    *theData = originalUnpackBuffer;
296
297    return noErr;
298
299Error:
300    if (unpackBuffer)
301        DisposePtr((Ptr)originalUnpackBuffer);
302
303    *theData = nil;
304
305    return kIOPEFparamErr;
306}
307
308
309/*******************************************************************************
310* GetSymbolFromPEF will extract from a PEF container the data associated
311* with a given symbol name.  It requires that the PEF file have been previously
312* loaded into memory.
313*******************************************************************************/
314static OSStatus GetSymbolFromPEF(
315    char *inSymbolName,
316    const LogicalAddress thePEFPtr,
317    LogicalAddress theSymbolPtr,
318    ByteCount theSymbolSize)
319{
320    StringPtr           theSymbolName = (StringPtr) inSymbolName;
321    ContainerHeaderPtr  containerHeaderPtr;  // Pointer to the Container Header
322    SectionHeaderPtr    loaderSectionPtr = 0; // Ptr to Loader Section Header
323    SectionHeaderPtr    exportSectionPtr;    // Ptr to Section Header with symbol
324    short               currentSection;
325    Boolean             foundSection;
326    Boolean             foundSymbol;
327    int                numExportSymbols;
328    LoaderHeaderPtr     loaderHeaderPtr;
329    ExportSymbolEntryPtr       exportSymbolEntryPtr;
330    LoaderExportChainEntryPtr  exportChainEntryPtr;
331    StringPtr           exportSymbolName;
332    LogicalAddress      expandedDataPtr;
333    unsigned char *     sourceDataPtr;
334    unsigned char *     destDataPtr;
335
336    containerHeaderPtr = (ContainerHeaderPtr)thePEFPtr;
337
338    // Does the magic cookie match?
339    if (containerHeaderPtr->magicCookie != 'Joy!') {
340        return kIOPEFcfragFragmentFormatErr;
341    }
342    // Is this a known PEF container format?
343    if (containerHeaderPtr->containerID != 'peff') {
344        return kIOPEFcfragFragmentFormatErr;
345    }
346
347    // Validate parameters
348    if (theSymbolPtr == nil) {
349        return kIOPEFparamErr;
350    }
351
352    // Find the loader section.
353    foundSection = false;
354    for (currentSection = 0;
355         currentSection < containerHeaderPtr->nbrOfSections;
356         currentSection++) {
357
358        loaderSectionPtr = (SectionHeaderPtr)((uintptr_t)containerHeaderPtr +
359            sizeof(ContainerHeader) +
360            (sizeof(SectionHeader) * currentSection));
361
362        if (loaderSectionPtr->regionKind == kLoaderSection) {
363            foundSection = true;
364            break;
365        }
366    }
367
368    if (foundSection == false) {
369        return kIOPEFcfragNoSectionErr;
370    }
371
372    // Get the number of export symbols.
373    loaderHeaderPtr = (LoaderHeaderPtr)((uintptr_t)thePEFPtr +
374        loaderSectionPtr->containerOffset);
375    numExportSymbols = loaderHeaderPtr->nbrExportSyms;
376
377    // Start at the first exported symbol.
378    exportSymbolEntryPtr = (ExportSymbolEntryPtr)((uintptr_t)loaderHeaderPtr +
379        loaderHeaderPtr->slotTblOffset +
380        (sizeof(LoaderHashSlotEntry) * (1<<loaderHeaderPtr->hashSlotTblSz)) +
381        (sizeof(LoaderExportChainEntry) * numExportSymbols));
382
383    exportChainEntryPtr = (LoaderExportChainEntryPtr)
384        ((uintptr_t)loaderHeaderPtr +
385        loaderHeaderPtr->slotTblOffset +
386        (sizeof(LoaderHashSlotEntry) * (1<<loaderHeaderPtr->hashSlotTblSz)));
387
388    foundSymbol = false;
389    while (numExportSymbols-- > 0) {
390        exportSymbolName = (StringPtr)((uintptr_t)loaderHeaderPtr +
391             loaderHeaderPtr->strTblOffset +
392             (exportSymbolEntryPtr->class_and_name & 0x00FFFFFF));
393
394        if (SymbolCompare(theSymbolName, exportSymbolName,
395                exportChainEntryPtr->_h._h_h._nameLength)) {
396
397            foundSymbol = true;
398            break;
399        }
400        exportSymbolEntryPtr = (ExportSymbolEntryPtr)
401            (((intptr_t) exportSymbolEntryPtr) + 10);
402        exportChainEntryPtr++;
403    }
404
405    if (foundSymbol == false) {
406        return kIOPEFcfragNoSymbolErr;
407    }
408
409    // Found the symbol, so... let's go get the data!
410    exportSectionPtr = (SectionHeaderPtr)((uintptr_t)containerHeaderPtr +
411        sizeof(ContainerHeader) +
412        (sizeof(SectionHeader) * exportSymbolEntryPtr->sectionNumber));
413
414    expandedDataPtr = nil;
415
416    switch (exportSectionPtr -> regionKind) {
417      case kPIDataSection:
418        // Expand the data!  (Not yet... :)
419        if (UnpackPiData(thePEFPtr, exportSectionPtr, &expandedDataPtr) != noErr) {
420            return kIOPEFcfragFragmentCorruptErr;
421        }
422
423        sourceDataPtr = (unsigned char*)((uintptr_t)expandedDataPtr +
424            exportSymbolEntryPtr->address);
425        break;
426
427      default:
428        sourceDataPtr = (unsigned char*)((uintptr_t)thePEFPtr +
429            exportSectionPtr->containerOffset +
430            exportSymbolEntryPtr->address);
431        break;
432    }
433
434
435    // Copy the data!
436    destDataPtr = (unsigned char*)theSymbolPtr;
437
438    while (theSymbolSize-- > 0) {
439        *destDataPtr++ = *sourceDataPtr++;
440    }
441
442    // Cleanup any expanded data
443
444    if (expandedDataPtr != nil) {
445        DisposePtr((Ptr)expandedDataPtr);
446    }
447
448    return noErr;
449}
450
451
452/*******************************************************************************
453*
454*******************************************************************************/
455static IOByteCount GetPEFLen(LogicalAddress thePEFPtr)
456{
457    ContainerHeaderPtr containerHeaderPtr; // Pointer to the Container Header
458    SectionHeaderPtr sections;
459    short currentSection;
460    int  lastOffset = 0;
461    int  len = 0;
462
463    containerHeaderPtr = (ContainerHeaderPtr)thePEFPtr;
464
465    // Does the magic cookie match?
466    if (containerHeaderPtr->magicCookie != 'Joy!') {
467        return 0;
468    }
469
470    // Is this a known PEF container format?
471    if (containerHeaderPtr->containerID != 'peff') {
472        return 0;
473    }
474
475    // Find the loader section.
476    sections = (SectionHeaderPtr) (containerHeaderPtr + 1);
477    for (currentSection = 0;
478         currentSection < containerHeaderPtr->nbrOfSections;
479         currentSection++) {
480
481        if (sections[currentSection].containerOffset > lastOffset) {
482            lastOffset = sections[currentSection].containerOffset;
483            len = sections[currentSection].rawSize;
484        }
485    }
486
487    return lastOffset + len;
488}
489
490/*******************************************************************************
491* theExportSymbol is NOT null-terminated, so use theExportSymbolLength.
492*******************************************************************************/
493static Boolean SymbolCompare(
494    StringPtr theLookedForSymbol,
495    StringPtr theExportSymbol,
496    uint32_t theExportSymbolLength)
497{
498    unsigned char * p1 = (unsigned char*)theLookedForSymbol;
499    unsigned char * p2 = (unsigned char*)theExportSymbol;
500
501    // Same length?
502    // (skip over p string len byte)
503    if (theExportSymbolLength != *p1++) {
504        return false;
505    }
506
507    while (theExportSymbolLength-- != 0) {
508        if (*p1++ != *p2++) {
509            return false;
510        }
511    }
512
513    return true;
514}
515
516
517/*******************************************************************************
518*
519*******************************************************************************/
520// The Driver Description
521enum {
522    kInitialDriverDescriptor    = 0,
523    kVersionOneDriverDescriptor    = 1,
524    kTheDescriptionSignature    = 'mtej',
525};
526
527struct DriverType {
528    unsigned char nameInfoStr[32]; // Driver Name/Info String
529    uint32_t    version;         // Driver Version Number - really NumVersion
530};
531typedef struct DriverType DriverType;
532
533struct DriverDescription {
534    uint32_t driverDescSignature; // Signature field of this structure
535    uint32_t driverDescVersion;   // Version of this data structure
536    DriverType    driverType;          // Type of Driver
537    // other data follows...
538};
539typedef struct DriverDescription DriverDescription;
540
541/*******************************************************************************
542*
543*******************************************************************************/
544static void ExaminePEF(
545    mach_port_t masterPort,
546    char * pef,
547    IOByteCount pefLen,
548    CFDictionaryRef allMatching)
549{
550    char                   descripName[] = "\pTheDriverDescription";
551    int                   err;
552    DriverDescription      descrip;
553    char                   matchName[40];
554    uint32_t          newVersion;
555    uint32_t          curVersion;
556    IOReturn               kr;
557    io_iterator_t          iter;
558    io_service_t           service;
559    io_string_t            path;
560    CFStringRef            ndrvPropName = CFSTR("driver,AAPL,MacOS,PowerPC");
561    CFDataRef              ndrv;
562    CFStringRef            matchKey;
563    CFTypeRef              value = 0;
564    CFDictionaryRef        matching = 0;
565    CFMutableDictionaryRef dict;
566
567    err = GetSymbolFromPEF(descripName, pef, &descrip, sizeof(descrip));
568    if (err != 0) {
569        printf("\nGetSymbolFromPEF returns %d\n",err);
570        return;
571    }
572    if ((descrip.driverDescSignature != kTheDescriptionSignature) ||
573       (descrip.driverDescVersion != kInitialDriverDescriptor)) {
574
575        return;
576    }
577
578    strncpy(matchName, (char *) descrip.driverType.nameInfoStr + 1,
579        descrip.driverType.nameInfoStr[0]);
580    matchName[descrip.driverType.nameInfoStr[0]] = 0;
581
582    matchKey = CFStringCreateWithCString( kCFAllocatorDefault, matchName,
583                                            kCFStringEncodingMacRoman );
584    if (!matchKey)
585        return;
586
587    if (allMatching)
588    {
589        value = CFDictionaryGetValue(allMatching, matchKey);
590        if (value)
591        {
592            if (value && (CFDictionaryGetTypeID() == CFGetTypeID(value)))
593                matching = CFRetain(value);
594            else if (value && (CFStringGetTypeID() == CFGetTypeID(value)))
595            {
596                CFRelease(matchKey);
597                matchKey = CFRetain(value);
598            }
599        }
600    }
601
602    if (!matching)
603    {
604        CFStringRef nameMatchKey = CFSTR(kIONameMatchKey);
605        matching = CFDictionaryCreate( kCFAllocatorDefault,
606                                        (const void **) &nameMatchKey, (const void **) &matchKey, 1,
607                                        &kCFTypeDictionaryKeyCallBacks,
608                                        &kCFTypeDictionaryValueCallBacks );
609    }
610    CFRelease(matchKey);
611    if (!matching)
612        return;
613
614    kr = IOServiceGetMatchingServices(masterPort, matching, &iter);
615    if (kIOReturnSuccess != kr)
616        return;
617
618    newVersion = descrip.driverType.version;
619    if ((newVersion & 0xffff) == 0x8000) {
620        // final stage, release rev
621        newVersion |= 0xff;
622    }
623
624    for ( ; (service = IOIteratorNext(iter)); IOObjectRelease(service))
625    {
626        kr = IORegistryEntryGetPath(service, kIOServicePlane, path);
627        if (kIOReturnSuccess == kr)
628            printf("Name %s matches %s, ", matchName, path);
629
630        ndrv = (CFDataRef) IORegistryEntryCreateCFProperty(service, ndrvPropName,
631            kCFAllocatorDefault, kNilOptions);
632
633        if (ndrv)
634        {
635            DriverDescription   _curDesc;
636            DriverDescription * curDesc;
637
638            curDesc = (DriverDescription *) CFDataGetBytePtr(ndrv);
639            err = noErr;
640
641            if ((sizeof(DriverDescription) > (size_t) CFDataGetLength(ndrv))
642             || (curDesc->driverDescSignature != kTheDescriptionSignature))
643            {
644                curDesc = &_curDesc;
645                err = GetSymbolFromPEF(descripName,
646                    (const LogicalAddress)CFDataGetBytePtr(ndrv),
647                    curDesc, sizeof(DriverDescription));
648            }
649            if (err != noErr)
650                printf("GetSymbolFromPEF returns %d\n",err);
651            else
652            {
653                if ((curDesc->driverDescSignature == kTheDescriptionSignature) &&
654                    (curDesc->driverDescVersion == kInitialDriverDescriptor))
655                {
656                    curVersion = curDesc->driverType.version;
657                    printf("new version %08x, current version %08x\n",
658                        newVersion, curVersion);
659
660                    if ((curVersion & 0xffff) == 0x8000) {
661                        // final stage, release rev
662                        curVersion |= 0xff;
663                    }
664                    if (newVersion <= curVersion) {
665                        pefLen = 0;
666                    }
667                }
668            }
669            CFRelease(ndrv);
670        }
671
672        if (pefLen == 0)
673            continue;
674
675        ndrv = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault,
676                           (UInt8 *) pef, pefLen, kCFAllocatorNull);
677        if (ndrv == 0)
678            continue;
679
680        printf("Installing ndrv (");
681        dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
682            &kCFTypeDictionaryKeyCallBacks,
683            &kCFTypeDictionaryValueCallBacks);
684
685        if (dict)
686        {
687            io_service_t child = MACH_PORT_NULL;
688            io_iterator_t iter;
689
690            CFDictionarySetValue(dict, ndrvPropName, ndrv);
691
692            kr = IORegistryEntryGetChildIterator(service, kIOServicePlane, &iter);
693            if (kr == kIOReturnSuccess)
694            {
695                kr = kIOReturnNotFound;
696                for( ;
697                    (child = IOIteratorNext(iter));
698                    IOObjectRelease(child)) {
699
700                    if (IOObjectConformsTo(child, "IOFramebuffer"))
701                        break;
702                }
703                IOObjectRelease(iter);
704            }
705            if (child)
706            {
707                kr = IORegistryEntrySetCFProperties(child, dict);
708                IOObjectRelease(child);
709            }
710            CFRelease(dict);
711        }
712        else
713            kr = kIOReturnNoMemory;
714
715        CFRelease(ndrv);
716        printf("%08x)\n", kr);
717    }
718    IOObjectRelease(iter);
719
720    return;
721}
722
723/*******************************************************************************
724*
725*******************************************************************************/
726
727static int PEFExamineFile(mach_port_t masterPort, CFURLRef file, CFDictionaryRef props)
728{
729    vm_offset_t     pefBytes;
730    vm_size_t       pefFileLen;
731    char *          pef;
732    IOByteCount     pefLen, pos = 0;
733    int             err;
734    CFDictionaryRef fileMatch;
735    CFDictionaryRef matching = 0;
736    Boolean         matches = true;
737    char            cFile[MAXPATHLEN];
738
739    do
740    {
741        if (!props)
742            continue;
743
744        fileMatch = CFDictionaryGetValue(props, CFSTR("IONDRVFileMatching"));
745        if (fileMatch && (CFDictionaryGetTypeID() != CFGetTypeID(fileMatch)))
746            fileMatch = 0;
747
748        if (fileMatch)
749        {
750            io_service_t service;
751
752            CFRetain(fileMatch);
753            service = IOServiceGetMatchingService(masterPort, fileMatch);
754            matches = (MACH_PORT_NULL != service);
755            if (matches)
756                IOObjectRelease(service);
757            continue;
758        }
759
760        matching = CFDictionaryGetValue(props, CFSTR("IONDRVMatching"));
761        if (matching && (CFDictionaryGetTypeID() != CFGetTypeID(matching)))
762            matching = 0;
763
764    }
765    while (false);
766
767    if (!matches)
768        return (kIOReturnSuccess);
769
770    if (CFURLGetFileSystemRepresentation(file, TRUE, (UInt8 *) cFile, MAXPATHLEN))
771        err = readFile(cFile, &pefBytes, &pefFileLen);
772    else
773        err = kIOReturnIOError;
774
775    if (kIOReturnSuccess != err)
776        return (err);
777
778    pef = (char *) pefBytes;
779    while ((pos < pefFileLen) && (pefLen = GetPEFLen(pef)))
780    {
781        ExaminePEF(masterPort, pef, pefLen, matching);
782        pefLen = (pefLen + 15) & ~15;
783        pef += pefLen;
784        pos += pefLen;
785    }
786
787    if (pefBytes)
788        vm_deallocate(mach_task_self(), pefBytes, pefFileLen);
789
790    return (0);
791}
792
793static void _PEFExamineFile(mach_port_t masterPort, CFURLRef ndrvURL, CFDictionaryRef plist)
794{
795    if (PEFExamineFile(masterPort, ndrvURL, plist))
796    {
797        char buf[PATH_MAX];
798        char * ndrv_path;
799        if(CFURLGetFileSystemRepresentation(ndrvURL, true /*resolve*/,
800                (UInt8*)buf, PATH_MAX)) {
801            ndrv_path = buf;
802        } else {
803            ndrv_path = "(unknown)";
804        }
805
806        printf("error processing NDRV \"%s\"", ndrv_path);
807    }
808}
809
810static void PEFExamineBundle( mach_port_t masterPort __unused, CFBundleRef bdl )
811{
812    CFURLRef        ndrvURL;
813    CFDictionaryRef plist;
814
815    plist = CFBundleGetInfoDictionary(bdl);
816    if (!plist)
817        return;
818    ndrvURL = CFBundleCopyExecutableURL(bdl);
819    if (!ndrvURL)
820        return;
821
822    _PEFExamineFile(kIOMasterPortDefault, ndrvURL, plist);
823
824    CFRelease(ndrvURL);
825}
826
827void IOLoadPEFsFromURL( CFURLRef ndrvDirURL, io_service_t service __unused )
828{
829    CFIndex     ndrvCount, n;
830    CFArrayRef  ndrvDirContents = NULL; // must release
831    SInt32      error;
832
833    ndrvDirContents = (CFArrayRef) CFURLCreatePropertyFromResource(
834        kCFAllocatorDefault, ndrvDirURL, kCFURLFileDirectoryContents,
835        &error);
836
837    ndrvCount = ndrvDirContents ? CFArrayGetCount(ndrvDirContents) : 0;
838
839    for (n = 0; n < ndrvCount; n++)
840    {
841        CFURLRef        ndrvURL = NULL;  // don't release
842        CFNumberRef     num;
843        CFBundleRef     bdl;
844        CFStringRef     ext;
845        SInt32          mode;
846        Boolean         skip;
847
848        ndrvURL = (CFURLRef)CFArrayGetValueAtIndex(ndrvDirContents, n);
849
850        bdl = CFBundleCreate(kCFAllocatorDefault, ndrvURL);
851        if (bdl)
852        {
853            PEFExamineBundle(kIOMasterPortDefault, bdl);
854            CFRelease(bdl);
855            continue;
856        }
857
858        ext = CFURLCopyPathExtension(ndrvURL);
859        if (ext)
860        {
861            skip = CFEqual(ext, CFSTR(".plist"));
862            CFRelease(ext);
863            if (skip)
864                continue;
865        }
866
867        num = (CFNumberRef) CFURLCreatePropertyFromResource(
868            kCFAllocatorDefault, ndrvURL, kCFURLFilePOSIXMode, &error);
869        if (!num)
870            continue;
871        CFNumberGetValue(num, kCFNumberSInt32Type, (SInt32 *) &mode);
872        CFRelease(num);
873        if ((mode & S_IFMT) == S_IFREG)
874            _PEFExamineFile(kIOMasterPortDefault, ndrvURL, NULL);
875    }
876
877    if (ndrvDirContents)
878        CFRelease(ndrvDirContents);
879}
880
881