]> git.saurik.com Git - apple/xnu.git/blob - iokit/Families/IONDRVSupport/IOPEFLoader.c
27e50ba4a08f30f1a800d8b6bcbfbdaca7ce1190
[apple/xnu.git] / iokit / Families / IONDRVSupport / IOPEFLoader.c
1 /*
2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /*
23 * Copyright (c) 1997 Apple Computer, Inc.
24 *
25 *
26 * HISTORY
27 *
28 * From pieces of ProtoCFM, Alan Lillich.
29 *
30 * sdouglas 22 Oct 97 - first checked in.
31 * sdouglas 21 July 98 - start IOKit
32 */
33
34
35 #include <IOKit/IOLib.h>
36 #include <IOKit/ndrvsupport/IONDRVSupport.h>
37
38 #include "IOPEFLibraries.h"
39 #include "IOPEFLoader.h"
40 #include "IOPEFInternals.h"
41
42
43
44 #define LOG if(0) IOLog
45 #define INFO if(0) IOLog
46
47 struct SectionVars {
48 LogicalAddress address;
49 ByteCount allocSize;
50 ByteCount unpackedLength;
51 Boolean isPacked;
52 };
53 typedef struct SectionVars SectionVars;
54
55 struct InstanceVars {
56 BytePtr pef; // container in memory
57 CFContHandlerRef cRef;
58 CFContHandlerProcs * cProcs;
59 ItemCount numSections;
60 SectionVars * sections;
61 IONDRVUndefinedSymbolHandler undefinedHandler;
62 void * undefHandlerSelf;
63 };
64 typedef struct InstanceVars InstanceVars;
65
66
67 static OSStatus LocationToAddress( InstanceVars * inst,
68 CFContLogicalLocation * location, LogicalAddress * address );
69 static OSStatus SatisfyImports( InstanceVars * inst );
70 static OSStatus Instantiate( InstanceVars * inst );
71
72
73 #define PCFM_BlockCopy(src,dst,len) memcpy(dst,src,len)
74 #define PCFM_BlockClear(dst,len) memset(dst,0,len)
75 #define PCFM_MakeExecutable(addr,len) flush_dcache((vm_offset_t)addr, len, 0); \
76 invalidate_icache((vm_offset_t)addr, len, 0)
77
78 extern OSStatus CallTVector(
79 void * p1, void * p2, void * p3, void * p4, void * p5, void * p6,
80 LogicalAddress entry );
81
82 // ¤
83 // ===========================================================================================
84 // CFContHashName ()
85 // =================
86
87
88 CFContStringHash CFContHashName ( BytePtr nameText,
89 ByteCount nameLength )
90 {
91 BytePtr currChar = nameText;
92 SInt32 hashValue = 0; // ! Signed to match old published PEF algorithm.
93 ByteCount length = 0;
94 ByteCount limit;
95 CFContStringHash result;
96
97 #define PseudoRotate(x) ( ( (x) << 1 ) - ( (x) >> (16) ) )
98
99
100 for ( limit = nameLength; limit > 0; limit -= 1 ) {
101 if ( *currChar == NULL ) break;
102 hashValue = (PseudoRotate ( hashValue )) ^ *currChar;
103 currChar += 1;
104 length += 1;
105 }
106
107 result = (length << 16) | ((UInt16) ((hashValue ^ (hashValue >> 16)) & 0xFFFF));
108
109 return result;
110
111
112 } // CFContHashName ()
113
114
115 // ¤
116 // ===========================================================================================
117 // PCFM_CompareBytes ()
118 // ====================
119
120
121 Boolean PCFM_CompareBytes ( const Byte * left,
122 const Byte * right,
123 ByteCount count )
124 {
125 // !!! Blechola! Switch to a standard routine ASAP!
126
127 UInt32 * wLeft;
128 UInt32 * wRight;
129 UInt8 * bLeft;
130 UInt8 * bRight;
131
132 ByteCount leftMiss = (UInt32)left & 0x00000003;
133 ByteCount rightMiss = (UInt32)right & 0x00000003;
134
135
136 bLeft = (UInt8 *) left;
137 bRight = (UInt8 *) right;
138
139 if ( (leftMiss != 0) && (rightMiss != 0) ) {
140 ByteCount align = leftMiss;
141 if ( align > count ) align = count;
142 while ( align > 0 ) {
143 if ( *bLeft++ != *bRight++ ) goto NoMatch;
144 align -= 1;
145 count -= 1;
146 }
147 }
148
149 wLeft = (UInt32 *) bLeft;
150 wRight = (UInt32 *) bRight;
151 while ( count >= 4 ) {
152 if ( *wLeft++ != *wRight++ ) goto NoMatch;
153 count -= 4;
154 }
155
156 bLeft = (UInt8 *) wLeft;
157 bRight = (UInt8 *) wRight;
158 while ( count > 0 ) {
159 if ( *bLeft++ != *bRight++ ) goto NoMatch;
160 count -= 1;
161 }
162
163 return true;
164
165
166 NoMatch:
167 return false;
168
169
170 } // PCFM_CompareBytes ()
171
172 // ===========================================================================================
173
174 LogicalAddress PCodeAllocateMem( ByteCount size );
175 void PCodeReleaseMem( LogicalAddress address );
176 extern void *kern_os_malloc(size_t size);
177 extern void kern_os_free(void * addr);
178
179 LogicalAddress
180 PCodeAllocateMem( ByteCount size )
181 {
182 return( (LogicalAddress) kern_os_malloc( (size_t) size ));
183 }
184
185 void
186 PCodeReleaseMem( LogicalAddress address )
187 {
188 kern_os_free( (void *) address );
189 }
190
191 // ===========================================================================================
192
193 OSStatus
194 PCodeOpen( LogicalAddress container, ByteCount containerSize, PCodeInstance * instance )
195 {
196 OSStatus err;
197 InstanceVars * inst;
198
199 inst = PCodeAllocateMem( sizeof( InstanceVars));
200 *instance = inst;
201
202 inst->pef = (BytePtr) container;
203 // procID, name, options
204 err = PEF_OpenContainer( container, container, containerSize, 0, 0, 0,
205 PCodeAllocateMem, PCodeReleaseMem,
206 &inst->cRef, &inst->cProcs );
207 if( err) LOG( "PEF_OpenContainer = %ld\n", err );
208
209 return( err);
210 }
211
212 OSStatus
213 PCodeInstantiate( PCodeInstance instance,
214 IONDRVUndefinedSymbolHandler handler, void * self )
215 {
216 OSStatus err;
217 InstanceVars * inst = instance;
218 CFContLogicalLocation initLocation;
219 LogicalAddress tv;
220 CFragInitBlock initInfo;
221
222 inst->undefinedHandler = handler;
223 inst->undefHandlerSelf = self;
224
225 do {
226 err = Instantiate( inst );
227 if( err)
228 continue;
229
230 // call INIT
231 err = PEF_GetAnonymousSymbolLocations( inst->cRef, NULL, &initLocation, NULL );
232 if( err)
233 continue;
234 err = LocationToAddress( inst, &initLocation, &tv );
235 if( err || (tv == NULL) )
236 continue;
237 bzero( &initInfo, sizeof( initInfo));
238 err = CallTVector( &initInfo, 0, 0, 0, 0, 0, tv );
239
240 } while( false);
241
242 return( err);
243 }
244
245
246 OSStatus
247 PCodeClose( PCodeInstance instance )
248 {
249 OSStatus err;
250 InstanceVars * inst = instance;
251 SectionVars * section;
252 int i;
253
254 if( !inst)
255 return( noErr);
256
257 err = PEF_CloseContainer( inst->cRef, 0 );
258 if( err) LOG( "PEF_CloseContainer = %ld\n", err );
259
260 if( inst->sections ) {
261 for( i = 0; i < inst->numSections; i++) {
262 section = inst->sections + i;
263 if( section->allocSize)
264 PCodeReleaseMem( section->address);
265 }
266 PCodeReleaseMem(inst->sections);
267 }
268
269 return( err);
270 }
271
272 OSStatus
273 PCodeFindExport( PCodeInstance instance, const char * symbolName, LogicalAddress * address, CFragSymbolClass * symbolClass )
274 {
275 CFContExportedSymbolInfo symInfo;
276 CFContHashedName hashName;
277 OSStatus err;
278 InstanceVars * inst = instance;
279
280 hashName.nameHash = CFContHashName( (UInt8 *) symbolName, strlen( symbolName) );
281 hashName.nameText = (UInt8 *) symbolName;
282
283 err = PEF_FindExportedSymbolInfo( inst->cRef, &hashName,
284 kCFContExportedSymbolInfoVersion, (void *) 0, &symInfo );
285 if( err) {
286 LOG( "PEF_FindExportedSymbolInfo = %ld\n", err );
287 return( err);
288 }
289
290 if( address);
291 err = LocationToAddress( inst, &symInfo.location, address );
292 if( symbolClass)
293 *symbolClass = symInfo.symbolClass;
294
295 return( err);
296 }
297
298 OSStatus
299 PCodeFindMain( PCodeInstance instance, LogicalAddress * mainAddress )
300 {
301 InstanceVars * inst = instance;
302 CFContLogicalLocation mainLocation;
303 OSStatus err;
304
305 err = PEF_GetAnonymousSymbolLocations( inst->cRef, &mainLocation, NULL, NULL );
306
307 if( err == noErr)
308 err = LocationToAddress( inst, &mainLocation, mainAddress );
309
310 return( err);
311 }
312
313
314
315 // ===========================================================================================
316
317 static OSStatus
318 LocationToAddress( InstanceVars * inst, CFContLogicalLocation * location,
319 LogicalAddress * address )
320 {
321 BytePtr sectionBase;
322 OSStatus err = noErr;
323
324 if ( location->section >= 0 ) {
325 sectionBase = (BytePtr) (inst->sections + location->section)->address;
326 *address = (LogicalAddress) (sectionBase + location->offset);
327
328 } else if ( location->section == kCFContAbsoluteSectionIndex ) {
329 *address = (LogicalAddress) location->offset;
330
331 } else if ( location->section == kCFContNoSectionIndex ) {
332 *address = (LogicalAddress) kUnresolvedCFragSymbolAddress;
333
334 } else
335 err = cfragFragmentFormatErr;
336
337 return( err);
338 }
339
340
341 static OSStatus
342 Instantiate( InstanceVars * inst )
343 {
344 CFContHandlerRef cRef;
345 ItemCount numSects, sectionIndex;
346 CFContSectionInfo sectionInfo;
347 CFContSectionInfo * section;
348 OSStatus err;
349
350 cRef = inst->cRef;
351
352 err = PEF_GetSectionCount( cRef, &numSects );
353 if( err) LOG( "PEF_GetSectionCount = %ld\n", err );
354 INFO( "Num sects = %ld\n", numSects );
355
356 inst->numSections = numSects;
357 inst->sections = PCodeAllocateMem( numSects * sizeof( SectionVars ));
358
359 for( sectionIndex = 0; sectionIndex < numSects; sectionIndex++ )
360 {
361 Boolean isPacked, isMappable;
362 Boolean needAlloc, needCopy, needClear;
363 LogicalAddress sectionAddress;
364 SectionVars * sectionVars;
365
366 sectionVars = inst->sections + sectionIndex;
367 section = &sectionInfo;
368
369 err = PEF_GetSectionInfo( cRef, sectionIndex, kCFContSectionInfoVersion, section );
370 if( err) LOG( "PEF_GetSectionInfo = %ld\n", err );
371
372 #if 0
373 if ( sectionInfo.sharing == kCFContShareSectionInClosure ) goto SectionSharingError;
374 if ( (! (sectionInfo.access & kCFContMemWriteMask)) &&
375 (sectionInfo.options & kRelocatedCFContSectionMask) ) goto SectionOptionsError;
376 #endif
377
378 isPacked = ((section->options & kPackedCFContSectionMask) != 0);
379 isMappable = (! isPacked) &&
380 (! (section->options & kRelocatedCFContSectionMask)) &&
381 (! (section->access & kCFContMemWriteMask));
382
383 if ( ! isMappable ) {
384 // ----------------------------------------------------------------------------------
385 // Mappable really means "fully expanded in container", so sections that are not mappable
386 // need to be allocated. The loader will do the initialization copying. This is the
387 // standard case for packed PEF data sections.
388 needAlloc = true;
389 needCopy = (! isPacked);
390 needClear = (section->totalLength != section->unpackedLength);
391
392 } else if ( ! (section->access & kCFContMemWriteMask) ) {
393 // -----------------------------------------------------------------------------------
394 // A "mappable" read only section. Make sure it is fully present, i.e. no zero filled
395 // extension. This is the standard case for code and literal sections.
396 if ( section->totalLength != section->unpackedLength ) {
397 err = cfragFragmentUsageErr; // !!! Needs error label & message.
398 // goto ERROR;
399 }
400 needAlloc = false;
401 needCopy = false;
402 needClear = false;
403
404 } else {
405 // -----------------------------------------------------------------------------------
406 // A "mappable", writeable, don't use in place section. This is the standard case for
407 // unpacked data sections.
408 needAlloc = true;
409 needCopy = true;
410 needClear = (section->totalLength != section->unpackedLength);
411 }
412
413 if ( needAlloc ) {
414 // *** Should honor the container's alignment specifications.
415 sectionAddress = PCodeAllocateMem( section->totalLength ); //, 4, allocMode );
416 } else {
417 sectionAddress = inst->pef + section->containerOffset;
418 }
419
420 // --------------------------------------------------------------------------------------
421 // !!! The copy/clear code should be moved to the loader as part of the split of the
422 // !!! unpack/relocate operations. It isn't clear at this point if both the read and
423 // !!! write sides should be touched. What if the write side pushes out pages brought in
424 // !!! by the read side? We should also have better advice to say all bytes are changed.
425
426 if ( needCopy ) {
427 BytePtr source = inst->pef + section->containerOffset;
428 BytePtr dest = sectionAddress;
429 ByteCount length = section->unpackedLength;
430
431 PCFM_BlockCopy ( source, dest, length );
432 }
433
434 if ( needClear ) {
435 BytePtr dest = (BytePtr) sectionAddress + section->unpackedLength;
436 ByteCount length = section->totalLength - section->unpackedLength;
437
438 PCFM_BlockClear ( dest, length );
439 }
440
441 // -------------------------------------------------------------------------------------
442 // If CFM was responsible for bringing the container into memory then we have to get the
443 // I&D caches in sync for the (read-only & use-in-place) code sections.
444
445 if ( (section->access & kCFContMemExecuteMask)
446 && (! (section->access & kCFContMemWriteMask)) && isMappable ) {
447 PCFM_MakeExecutable ( sectionAddress, section->unpackedLength );
448 }
449
450 err = PEF_SetSectionAddress( cRef, sectionIndex, sectionAddress, sectionAddress );
451 if( err) LOG( "PEF_SetSectionAddress = %ld\n", err );
452
453 sectionVars->address = sectionAddress;
454 sectionVars->unpackedLength = section->unpackedLength;
455 sectionVars->isPacked = isPacked;
456 if( needAlloc)
457 sectionVars->allocSize = section->totalLength;
458 else
459 sectionVars->allocSize = 0;
460 }
461
462 // -------------------------------------------------------------------------------------
463
464 err = SatisfyImports( inst );
465 if( err) LOG( "SatisfyImports = %ld\n", err );
466
467 // -------------------------------------------------------------------------------------
468
469 for( sectionIndex = 0; sectionIndex < numSects; sectionIndex++ )
470 {
471 SectionVars * sectionVars;
472
473 sectionVars = inst->sections + sectionIndex;
474
475 INFO("Section[%ld] ", sectionIndex );
476
477 if ( sectionVars->isPacked ) {
478 INFO("unpacking...");
479 err = PEF_UnpackSection( cRef,
480 sectionIndex,
481 0, // Unpack the whole section.
482 sectionVars->address,
483 sectionVars->unpackedLength );
484 if( err) LOG( "PEF_UnpackSection = %ld\n", err );
485 }
486
487 INFO("reloc...");
488 err = PEF_RelocateSection( cRef, sectionIndex );
489
490 INFO(" address = 0x%08lx\n", (UInt32) sectionVars->address );
491 }
492
493 if( err) LOG( "Instantiate = %ld\n", err );
494
495 return( err);
496 }
497
498 struct StubFunction {
499 LogicalAddress pc;
500 LogicalAddress toc;
501 char name[64];
502 };
503 typedef struct StubFunction StubFunction;
504
505 OSStatus IONDRVUnimplementedVector( UInt32 p1, UInt32 p2, UInt32 p3, UInt32 p4 )
506 {
507 char * name = (char *) get_R2();
508
509 LOG("-*- %s : %lx, %lx, %lx, %lx\n", name, p1, p2, p3, p4);
510
511 set_R2( (UInt32) name);
512
513 return( -53);
514 }
515
516 static OSStatus
517 SatisfyImports( InstanceVars * inst )
518 {
519 CFContImportedSymbolInfo symInfo;
520
521 OSStatus err = 0;
522 CFContHandlerRef cRef;
523 ItemCount numLibs, numSyms, index, i;
524 struct CFLibInfo {
525 CFContImportedLibraryInfo info;
526 LibraryEntry * found;
527 };
528 struct CFLibInfo * libInfo;
529 struct CFLibInfo * curLib;
530 FunctionEntry * funcs;
531 const IOTVector * symAddr;
532 StubFunction * stub;
533
534 cRef = inst->cRef;
535 err = PEF_GetImportCounts( cRef, &numLibs, &numSyms );
536 if( err) LOG( "PEF_GetImportCounts = %ld\n", err );
537
538 libInfo = PCodeAllocateMem( numLibs * sizeof( struct CFLibInfo));
539 PCFM_BlockClear( libInfo, numLibs * sizeof( struct CFLibInfo));
540
541 for( index = 0; index < numLibs; index++ )
542 {
543 curLib = libInfo + index;
544 err = PEF_GetImportedLibraryInfo( cRef, index, kCFContImportedLibraryInfoVersion, &curLib->info);
545 if( err) LOG( "PEF_GetImportCounts = %ld\n", err );
546
547 for( i = 0; i < IONumNDRVLibraries; i++ ) {
548 if( strcmp( (char *) curLib->info.libraryName.nameText,
549 IONDRVLibraries[ i ].name) == 0) {
550 curLib->found = &IONDRVLibraries[ i ];
551 break;
552 }
553 }
554 }
555
556 for( index = 0; index < numSyms; index++ )
557 {
558 err = PEF_GetImportedSymbolInfo( cRef, index, kCFContImportedSymbolInfoVersion, &symInfo );
559 if( err) LOG( "PEF_GetImportedSymbolInfo = %ld\n", err );
560
561 curLib = libInfo + symInfo.libraryIndex;
562
563 symAddr = NULL;
564 if( curLib->found) {
565 for( i = 0; i < curLib->found->numSyms; i++ ) {
566
567 funcs = curLib->found->functions + i;
568 if( strcmp( (char *) symInfo.symbolName.nameText, funcs->name ) == 0) {
569 symAddr = (IOTVector *) &funcs->address;
570 break;
571 }
572 }
573
574 } else if( inst->undefinedHandler)
575 symAddr = (*inst->undefinedHandler)(inst->undefHandlerSelf,
576 curLib->info.libraryName.nameText,
577 symInfo.symbolName.nameText );
578 if( symAddr == NULL) {
579
580 LOG("Undefined %s:%s ", curLib->info.libraryName.nameText, symInfo.symbolName.nameText );
581
582 stub = IOMalloc( sizeof( StubFunction));
583 symAddr = (IOTVector *) &stub->pc;
584 stub->pc = IONDRVUnimplementedVector;
585 stub->toc = &stub->name[0];
586 strncpy( stub->name, symInfo.symbolName.nameText, 60);
587 }
588
589 err = PEF_SetImportedSymbolAddress( cRef, index, (IOTVector *) symAddr );
590 if( err) LOG( "PEF_SetImportedSymbolAddress = %ld\n", err );
591 }
592
593 PCodeReleaseMem( libInfo);
594
595 return( err);
596 }
597
598
599
600