/* * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * The contents of this file constitute Original Code as defined in and * are subject to the Apple Public Source License Version 1.1 (the * "License"). You may not use this file except in compliance with the * License. Please obtain a copy of the License at * http://www.apple.com/publicsource and read it before using this file. * * This 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 OR NON-INFRINGEMENT. Please see the * License for the specific language governing rights and limitations * under the License. * * @APPLE_LICENSE_HEADER_END@ */ #if __ppc__ #include #include #include "IOPEFLibraries.h" #include "IOPEFLoader.h" #include "IOPEFInternals.h" #define LOG if(0) IOLog #define INFO if(0) IOLog struct SectionVars { LogicalAddress address; ByteCount allocSize; ByteCount unpackedLength; Boolean isPacked; }; typedef struct SectionVars SectionVars; struct InstanceVars { BytePtr pef; // container in memory CFContHandlerRef cRef; CFContHandlerProcs * cProcs; ItemCount numSections; SectionVars * sections; IONDRVUndefinedSymbolHandler undefinedHandler; void * undefHandlerSelf; }; typedef struct InstanceVars InstanceVars; static OSStatus LocationToAddress( InstanceVars * inst, CFContLogicalLocation * location, LogicalAddress * address ); static OSStatus SatisfyImports( InstanceVars * inst ); static OSStatus Instantiate( InstanceVars * inst ); #define PCFM_BlockCopy(src,dst,len) memcpy(dst,src,len) #define PCFM_BlockClear(dst,len) memset(dst,0,len) #define PCFM_MakeExecutable(addr,len) flush_dcache((vm_offset_t)addr, len, 0); \ invalidate_icache((vm_offset_t)addr, len, 0) extern OSStatus CallTVector( void * p1, void * p2, void * p3, void * p4, void * p5, void * p6, LogicalAddress entry ); // ¤ // =========================================================================================== // CFContHashName () // ================= CFContStringHash CFContHashName ( BytePtr nameText, ByteCount nameLength ) { BytePtr currChar = nameText; SInt32 hashValue = 0; // ! Signed to match old published PEF algorithm. ByteCount length = 0; ByteCount limit; CFContStringHash result; #define PseudoRotate(x) ( ( (x) << 1 ) - ( (x) >> (16) ) ) for (limit = nameLength; limit > 0; limit -= 1) { if (*currChar == NULL) break; hashValue = (PseudoRotate ( hashValue )) ^ *currChar; currChar += 1; length += 1; } result = (length << 16) | ((UInt16) ((hashValue ^ (hashValue >> 16)) & 0xFFFF)); return result; } // CFContHashName () // =========================================================================================== LogicalAddress PCodeAllocateMem( ByteCount size ); void PCodeReleaseMem( LogicalAddress address ); extern void *kern_os_malloc(size_t size); extern void kern_os_free(void * addr); LogicalAddress PCodeAllocateMem( ByteCount size ) { return ((LogicalAddress) kern_os_malloc((size_t) size)); } void PCodeReleaseMem( LogicalAddress address ) { kern_os_free( (void *) address ); } // =========================================================================================== OSStatus PCodeOpen( LogicalAddress container, ByteCount containerSize, PCodeInstance * instance, UInt32 * createDate ) { OSStatus err; InstanceVars * inst; inst = PCodeAllocateMem( sizeof( InstanceVars)); *instance = inst; inst->pef = (BytePtr) container; // procID, name, err = PEF_OpenContainer( container, container, containerSize, 0 /*options*/, PCodeAllocateMem, PCodeReleaseMem, &inst->cRef, &inst->cProcs, createDate ); if (err) LOG( "PEF_OpenContainer = %ld\n", err ); return (err); } OSStatus PCodeInstantiate( PCodeInstance instance, IONDRVUndefinedSymbolHandler handler, void * self ) { OSStatus err; InstanceVars * inst = instance; CFContLogicalLocation initLocation; LogicalAddress tv; CFragInitBlock initInfo; inst->undefinedHandler = handler; inst->undefHandlerSelf = self; do { err = Instantiate( inst ); if (err) continue; // call INIT err = PEF_GetAnonymousSymbolLocations( inst->cRef, NULL, &initLocation, NULL ); if (err) continue; err = LocationToAddress( inst, &initLocation, &tv ); if (err || (tv == NULL)) continue; bzero( &initInfo, sizeof( initInfo)); err = CallTVector( &initInfo, 0, 0, 0, 0, 0, tv ); } while (false); return (err); } OSStatus PCodeClose( PCodeInstance instance ) { OSStatus err; InstanceVars * inst = instance; SectionVars * section; ItemCount i; if (!inst) return (noErr); err = PEF_CloseContainer( inst->cRef, 0 ); if (err) LOG( "PEF_CloseContainer = %ld\n", err ); if (inst->sections) { for (i = 0; i < inst->numSections; i++) { section = inst->sections + i; if (section->allocSize) PCodeReleaseMem( section->address); } PCodeReleaseMem(inst->sections); } return (err); } OSStatus PCodeFindExport( PCodeInstance instance, const char * symbolName, LogicalAddress * address, CFragSymbolClass * symbolClass ) { CFContExportedSymbolInfo symInfo; CFContHashedName hashName; OSStatus err; InstanceVars * inst = instance; hashName.nameHash = CFContHashName( (UInt8 *) symbolName, strlen( symbolName) ); hashName.nameText = (UInt8 *) symbolName; err = PEF_FindExportedSymbolInfo( inst->cRef, &hashName, kCFContExportedSymbolInfoVersion, (void *) 0, &symInfo ); if (err) { LOG( "PEF_FindExportedSymbolInfo = %ld\n", err ); return (err); } if (address) ; err = LocationToAddress( inst, &symInfo.location, address ); if (symbolClass) *symbolClass = symInfo.symbolClass; return (err); } OSStatus PCodeFindMain( PCodeInstance instance, LogicalAddress * mainAddress ) { InstanceVars * inst = instance; CFContLogicalLocation mainLocation; OSStatus err; err = PEF_GetAnonymousSymbolLocations( inst->cRef, &mainLocation, NULL, NULL ); if (err == noErr) err = LocationToAddress( inst, &mainLocation, mainAddress ); return (err); } // =========================================================================================== static OSStatus LocationToAddress( InstanceVars * inst, CFContLogicalLocation * location, LogicalAddress * address ) { BytePtr sectionBase; OSStatus err = noErr; if (location->section >= 0) { sectionBase = (BytePtr) (inst->sections + location->section)->address; *address = (LogicalAddress) (sectionBase + location->offset); } else if (location->section == kCFContAbsoluteSectionIndex) { *address = (LogicalAddress) location->offset; } else if (location->section == kCFContNoSectionIndex) { *address = (LogicalAddress) kUnresolvedCFragSymbolAddress; } else err = cfragFragmentFormatErr; return (err); } static OSStatus Instantiate( InstanceVars * inst ) { CFContHandlerRef cRef; ItemCount numSects, sectionIndex; CFContSectionInfo sectionInfo; CFContSectionInfo * section; OSStatus err; cRef = inst->cRef; err = PEF_GetSectionCount( cRef, &numSects ); if (err) LOG( "PEF_GetSectionCount = %ld\n", err ); INFO( "Num sects = %ld\n", numSects ); inst->numSections = numSects; inst->sections = PCodeAllocateMem( numSects * sizeof( SectionVars )); for (sectionIndex = 0; sectionIndex < numSects; sectionIndex++) { Boolean isPacked, isMappable; Boolean needAlloc, needCopy, needClear; LogicalAddress sectionAddress; SectionVars * sectionVars; sectionVars = inst->sections + sectionIndex; section = §ionInfo; err = PEF_GetSectionInfo( cRef, sectionIndex, kCFContSectionInfoVersion, section ); if (err) LOG( "PEF_GetSectionInfo = %ld\n", err ); #if 0 if (sectionInfo.sharing == kCFContShareSectionInClosure) goto SectionSharingError; if ((! (sectionInfo.access & kCFContMemWriteMask)) && (sectionInfo.options & kRelocatedCFContSectionMask)) goto SectionOptionsError; #endif isPacked = ((section->options & kPackedCFContSectionMask) != 0); isMappable = (! isPacked) && (! (section->options & kRelocatedCFContSectionMask)) && (! (section->access & kCFContMemWriteMask)); if (! isMappable) { // ---------------------------------------------------------------------------------- // Mappable really means "fully expanded in container", so sections that are not mappable // need to be allocated. The loader will do the initialization copying. This is the // standard case for packed PEF data sections. needAlloc = true; needCopy = (! isPacked); needClear = (section->totalLength != section->unpackedLength); } else if (! (section->access & kCFContMemWriteMask) ) { // ----------------------------------------------------------------------------------- // A "mappable" read only section. Make sure it is fully present, i.e. no zero filled // extension. This is the standard case for code and literal sections. if (section->totalLength != section->unpackedLength) { err = cfragFragmentUsageErr; // !!! Needs error label & message. // goto ERROR; } needAlloc = false; needCopy = false; needClear = false; } else { // ----------------------------------------------------------------------------------- // A "mappable", writeable, don't use in place section. This is the standard case for // unpacked data sections. needAlloc = true; needCopy = true; needClear = (section->totalLength != section->unpackedLength); } if (needAlloc) { // *** Should honor the container's alignment specifications. sectionAddress = PCodeAllocateMem( section->totalLength ); //, 4, allocMode ); } else { sectionAddress = inst->pef + section->containerOffset; } // -------------------------------------------------------------------------------------- // !!! The copy/clear code should be moved to the loader as part of the split of the // !!! unpack/relocate operations. It isn't clear at this point if both the read and // !!! write sides should be touched. What if the write side pushes out pages brought in // !!! by the read side? We should also have better advice to say all bytes are changed. if (needCopy) { BytePtr source = inst->pef + section->containerOffset; BytePtr dest = sectionAddress; ByteCount length = section->unpackedLength; PCFM_BlockCopy ( source, dest, length ); } if (needClear) { BytePtr dest = (BytePtr) sectionAddress + section->unpackedLength; ByteCount length = section->totalLength - section->unpackedLength; PCFM_BlockClear ( dest, length ); } // ------------------------------------------------------------------------------------- // If CFM was responsible for bringing the container into memory then we have to get the // I&D caches in sync for the (read-only & use-in-place) code sections. if ((section->access & kCFContMemExecuteMask) && (! (section->access & kCFContMemWriteMask)) && isMappable) { PCFM_MakeExecutable ( sectionAddress, section->unpackedLength ); } err = PEF_SetSectionAddress( cRef, sectionIndex, sectionAddress, sectionAddress ); if (err) LOG( "PEF_SetSectionAddress = %ld\n", err ); sectionVars->address = sectionAddress; sectionVars->unpackedLength = section->unpackedLength; sectionVars->isPacked = isPacked; if (needAlloc) sectionVars->allocSize = section->totalLength; else sectionVars->allocSize = 0; } // ------------------------------------------------------------------------------------- err = SatisfyImports( inst ); if (err) LOG( "SatisfyImports = %ld\n", err ); // ------------------------------------------------------------------------------------- for (sectionIndex = 0; sectionIndex < numSects; sectionIndex++) { SectionVars * sectionVars; sectionVars = inst->sections + sectionIndex; INFO("Section[%ld] ", sectionIndex ); if (sectionVars->isPacked) { INFO("unpacking..."); err = PEF_UnpackSection( cRef, sectionIndex, 0, // Unpack the whole section. sectionVars->address, sectionVars->unpackedLength ); if (err) LOG( "PEF_UnpackSection = %ld\n", err ); } INFO("reloc..."); err = PEF_RelocateSection( cRef, sectionIndex ); INFO(" address = 0x%08lx\n", (UInt32) sectionVars->address ); } if (err) LOG( "Instantiate = %ld\n", err ); return (err); } struct StubFunction { LogicalAddress pc; LogicalAddress toc; char name[64]; }; typedef struct StubFunction StubFunction; OSStatus IONDRVUnimplementedVector( UInt32 p1, UInt32 p2, UInt32 p3, UInt32 p4 ) { char * name = (char *) get_R2(); LOG("-*- %s : %lx, %lx, %lx, %lx\n", name, p1, p2, p3, p4); set_R2( (UInt32) name); return (-53); } static OSStatus SatisfyImports( InstanceVars * inst ) { CFContImportedSymbolInfo symInfo; OSStatus err = 0; CFContHandlerRef cRef; ItemCount numLibs, numSyms, index, i; struct CFLibInfo { CFContImportedLibraryInfo info; LibraryEntry * found; }; struct CFLibInfo * libInfo; struct CFLibInfo * curLib; FunctionEntry * funcs; const IOTVector * symAddr; StubFunction * stub; cRef = inst->cRef; err = PEF_GetImportCounts( cRef, &numLibs, &numSyms ); if (err) LOG( "PEF_GetImportCounts = %ld\n", err ); libInfo = PCodeAllocateMem( numLibs * sizeof( struct CFLibInfo)); PCFM_BlockClear( libInfo, numLibs * sizeof( struct CFLibInfo)); for (index = 0; index < numLibs; index++) { curLib = libInfo + index; err = PEF_GetImportedLibraryInfo( cRef, index, kCFContImportedLibraryInfoVersion, &curLib->info); if (err) LOG( "PEF_GetImportCounts = %ld\n", err ); for (i = 0; i < IONumNDRVLibraries; i++) { if (strcmp((char *) curLib->info.libraryName.nameText, IONDRVLibraries[ i ].name) == 0) { curLib->found = &IONDRVLibraries[ i ]; break; } } } for (index = 0; index < numSyms; index++) { err = PEF_GetImportedSymbolInfo( cRef, index, kCFContImportedSymbolInfoVersion, &symInfo ); if (err) LOG( "PEF_GetImportedSymbolInfo = %ld\n", err ); curLib = libInfo + symInfo.libraryIndex; symAddr = NULL; if (curLib->found) { for (i = 0; i < curLib->found->numSyms; i++) { funcs = curLib->found->functions + i; if (strcmp((char *) symInfo.symbolName.nameText, funcs->name) == 0) { symAddr = (IOTVector *) &funcs->address; break; } } } else if (inst->undefinedHandler) symAddr = (*inst->undefinedHandler)(inst->undefHandlerSelf, (const char *) curLib->info.libraryName.nameText, (const char *) symInfo.symbolName.nameText ); if (symAddr == NULL) { LOG("Undefined %s:%s ", curLib->info.libraryName.nameText, symInfo.symbolName.nameText ); stub = IOMalloc( sizeof( StubFunction)); symAddr = (IOTVector *) &stub->pc; stub->pc = IONDRVUnimplementedVector; stub->toc = &stub->name[0]; strncpy( stub->name, (char *) symInfo.symbolName.nameText, 60); } err = PEF_SetImportedSymbolAddress( cRef, index, (IOTVector *) symAddr ); if (err) LOG( "PEF_SetImportedSymbolAddress = %ld\n", err ); } PCodeReleaseMem( libInfo); return (err); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #endif /* __ppc__ */