2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
26 * drivers.c - Driver Loading Functions.
28 * Copyright (c) 2000 Apple Computer, Inc.
33 #include <mach-o/fat.h>
34 #include <libkern/OSByteOrder.h>
35 #include <mach/machine.h>
39 #include "bootstruct.h"
43 struct Module
*nextModule
;
50 typedef struct Module Module
, *ModulePtr
;
58 typedef struct DriverInfo DriverInfo
, *DriverInfoPtr
;
60 #define kDriverPackageSignature1 'MKXT'
61 #define kDriverPackageSignature2 'MOSX'
63 struct DriversPackage
{
64 unsigned long signature1
;
65 unsigned long signature2
;
67 unsigned long alder32
;
68 unsigned long version
;
69 unsigned long numDrivers
;
70 unsigned long reserved1
;
71 unsigned long reserved2
;
73 typedef struct DriversPackage DriversPackage
;
80 static unsigned long Alder32( unsigned char * buffer
, long length
);
82 static long FileLoadDrivers(char *dirSpec
, long plugin
);
83 static long NetLoadDrivers(char *dirSpec
);
84 static long LoadDriverMKext(char *fileSpec
);
85 static long LoadDriverPList(char *dirSpec
, char *name
, long bundleType
);
86 static long LoadMatchedModules(void);
87 static long MatchPersonalities(void);
88 static long MatchLibraries(void);
90 static ModulePtr
FindModule(char *name
);
91 static void ThinFatFile(void **loadAddrP
, unsigned long *lengthP
);
93 static long ParseXML(char *buffer
, ModulePtr
*module, TagPtr
*personalities
);
94 static long InitDriverSupport(void);
96 static ModulePtr gModuleHead
, gModuleTail
;
97 static TagPtr gPersonalityHead
, gPersonalityTail
;
98 static char * gExtensionsSpec
;
99 static char * gDriverSpec
;
100 static char * gFileSpec
;
101 static char * gTempSpec
;
102 static char * gFileName
;
106 Alder32( unsigned char * buffer
, long length
)
109 unsigned long result
, lowHalf
, highHalf
;
114 for ( cnt
= 0; cnt
< length
; cnt
++ )
116 if ((cnt
% 5000) == 0)
122 lowHalf
+= buffer
[cnt
];
129 result
= (highHalf
<< 16) | lowHalf
;
135 //==========================================================================
139 InitDriverSupport( void )
141 gExtensionsSpec
= (char *) malloc( 4096 );
142 gDriverSpec
= (char *) malloc( 4096 );
143 gFileSpec
= (char *) malloc( 4096 );
144 gTempSpec
= (char *) malloc( 4096 );
145 gFileName
= (char *) malloc( 4096 );
147 if ( !gExtensionsSpec
|| !gDriverSpec
|| !gFileSpec
|| !gTempSpec
|| !gFileName
)
148 stop("InitDriverSupport error");
153 //==========================================================================
156 long LoadDrivers( char * dirSpec
)
158 if ( InitDriverSupport() != 0 )
161 if ( gBootFileType
== kNetworkDeviceType
)
163 NetLoadDrivers(dirSpec
);
165 else if ( gBootFileType
== kBlockDeviceType
)
167 strcpy(gExtensionsSpec
, dirSpec
);
168 strcat(gExtensionsSpec
, "System/Library/");
169 FileLoadDrivers(gExtensionsSpec
, 0);
176 MatchPersonalities();
180 LoadMatchedModules();
185 //==========================================================================
189 FileLoadDrivers( char * dirSpec
, long plugin
)
191 long ret
, length
, index
, flags
, time
, bundleType
;
198 ret
= GetFileInfo(dirSpec
, "Extensions.mkext", &flags
, &time
);
199 if ((ret
== 0) && ((flags
& kFileTypeMask
) == kFileTypeFlat
))
201 ret
= GetFileInfo(dirSpec
, "Extensions", &flags
, &time2
);
202 if ((ret
!= 0) || ((flags
& kFileTypeMask
) != kFileTypeDirectory
) ||
203 (((gBootMode
& kBootModeSafe
) == 0) && (time
> time2
)))
205 sprintf(gDriverSpec
, "%sExtensions.mkext", dirSpec
);
206 verbose("LoadDrivers: Loading from [%s]\n", gDriverSpec
);
207 if (LoadDriverMKext(gDriverSpec
) == 0) return 0;
211 strcat(dirSpec
, "Extensions");
214 verbose("LoadDrivers: Loading from [%s]\n", dirSpec
);
218 ret
= GetDirEntry(dirSpec
, &index
, &name
, &flags
, &time
);
219 if (ret
== -1) break;
221 // Make sure this is a directory.
222 if ((flags
& kFileTypeMask
) != kFileTypeDirectory
) continue;
224 // Make sure this is a kext.
225 length
= strlen(name
);
226 if (strcmp(name
+ length
- 5, ".kext")) continue;
228 // Save the file name.
229 strcpy(gFileName
, name
);
231 // Determine the bundle type.
232 sprintf(gTempSpec
, "%s/%s", dirSpec
, gFileName
);
233 ret
= GetFileInfo(gTempSpec
, "Contents", &flags
, &time
);
234 if (ret
== 0) bundleType
= kCFBundleType2
;
235 else bundleType
= kCFBundleType3
;
238 sprintf(gDriverSpec
, "%s/%s/%sPlugIns", dirSpec
, gFileName
,
239 (bundleType
== kCFBundleType2
) ? "Contents/" : "");
241 ret
= LoadDriverPList(dirSpec
, gFileName
, bundleType
);
244 //printf("LoadDrivers: failed for '%s'/'%s'\n", dirSpec, gFileName);
248 ret
= FileLoadDrivers(gDriverSpec
, 1);
254 //==========================================================================
258 NetLoadDrivers( char * dirSpec
)
265 // Get the name of the kernel
266 cnt
= strlen(gBootFile
);
268 if ((gBootFile
[cnt
] == '\\') || (gBootFile
[cnt
] == ',')) {
275 // INTEL modification
276 sprintf(gDriverSpec
, "%s%s.mkext", dirSpec
, bootArgs
->bootFile
);
278 verbose("NetLoadDrivers: Loading from [%s]\n", gDriverSpec
);
283 if (LoadDriverMKext(gDriverSpec
) == 0) break;
285 if (tries
== -1) return -1;
290 //==========================================================================
294 LoadDriverMKext( char * fileSpec
)
296 unsigned long driversAddr
, driversLength
;
299 DriversPackage
* package
= (DriversPackage
*)kLoadAddr
;
301 #define GetPackageElement(e) OSSwapBigToHostInt32(package->e)
304 length
= LoadFile(fileSpec
);
305 if (length
== -1) return -1;
307 ThinFatFile((void **)&package
, &length
);
310 if (( GetPackageElement(signature1
) != kDriverPackageSignature1
) ||
311 ( GetPackageElement(signature2
) != kDriverPackageSignature2
) ||
312 ( GetPackageElement(length
) > kLoadSize
) ||
313 ( GetPackageElement(alder32
) !=
314 Alder32((char *)&package
->version
, GetPackageElement(length
) - 0x10) ) )
319 // Make space for the MKext.
320 driversLength
= GetPackageElement(length
);
321 driversAddr
= AllocateKernelMemory(driversLength
);
324 memcpy((void *)driversAddr
, (void *)package
, driversLength
);
326 // Add the MKext to the memory map.
327 sprintf(segName
, "DriversPackage-%lx", driversAddr
);
328 AllocateMemoryRange(segName
, driversAddr
, driversLength
,
329 kBootDriverTypeMKEXT
);
334 //==========================================================================
338 LoadDriverPList( char * dirSpec
, char * name
, long bundleType
)
340 long length
, driverPathLength
;
342 TagPtr personalities
;
344 char * tmpDriverPath
= 0;
348 // Save the driver path.
350 sprintf(gFileSpec
, "%s/%s/%s", dirSpec
, name
,
351 (bundleType
== kCFBundleType2
) ? "Contents/MacOS/" : "");
352 driverPathLength
= strlen(gFileSpec
) + 1;
354 tmpDriverPath
= malloc(driverPathLength
);
355 if (tmpDriverPath
== 0) break;
357 strcpy(tmpDriverPath
, gFileSpec
);
359 // Construct the file spec to the plist, then load it.
361 sprintf(gFileSpec
, "%s/%s/%sInfo.plist", dirSpec
, name
,
362 (bundleType
== kCFBundleType2
) ? "Contents/" : "");
364 length
= LoadFile(gFileSpec
);
365 if (length
== -1) break;
368 buffer
= malloc(length
);
369 if (buffer
== 0) break;
371 strlcpy(buffer
, (char *)kLoadAddr
, length
);
375 ret
= ParseXML(buffer
, &module, &personalities
);
376 if (ret
!= 0) { break; }
378 // Allocate memory for the driver path and the plist.
380 module->driverPath
= tmpDriverPath
;
381 module->plistAddr
= (void *)malloc(length
);
383 if ((module->driverPath
== 0) || (module->plistAddr
== 0))
386 // Save the driver path in the module.
387 //strcpy(module->driverPath, tmpDriverPath);
390 // Add the plist to the module.
392 strlcpy(module->plistAddr
, (char *)kLoadAddr
, length
);
393 module->plistLength
= length
;
395 // Add the module to the end of the module list.
397 if (gModuleHead
== 0)
398 gModuleHead
= module;
400 gModuleTail
->nextModule
= module;
401 gModuleTail
= module;
403 // Add the persionalities to the personality list.
405 if (personalities
) personalities
= personalities
->tag
;
406 while (personalities
!= 0)
408 if (gPersonalityHead
== 0)
409 gPersonalityHead
= personalities
->tag
;
411 gPersonalityTail
->tagNext
= personalities
->tag
;
413 gPersonalityTail
= personalities
->tag
;
414 personalities
= personalities
->tagNext
;
421 if ( buffer
) free( buffer
);
422 if ( tmpDriverPath
) free( tmpDriverPath
);
428 //==========================================================================
430 // Checks the loaded file for a fat header; if present, updates
431 // loadAddr and length to be the portion of the fat file relevant
432 // to the current architecture; otherwise leaves them unchanged.
435 ThinFatFile(void **loadAddrP
, unsigned long *lengthP
)
437 // Check for fat files.
438 struct fat_header
*fhp
= (struct fat_header
*)kLoadAddr
;
439 struct fat_arch
*fap
= (struct fat_arch
*)((void *)kLoadAddr
+
440 sizeof(struct fat_header
));
443 unsigned long length
= 0;
445 if (fhp
->magic
== FAT_MAGIC
) {
446 nfat
= fhp
->nfat_arch
;
448 } else if (fhp
->magic
== FAT_CIGAM
) {
449 nfat
= OSSwapInt32(fhp
->nfat_arch
);
456 for (; nfat
> 0; nfat
--, fap
++) {
458 fap
->cputype
= OSSwapInt32(fap
->cputype
);
459 fap
->offset
= OSSwapInt32(fap
->offset
);
460 fap
->size
= OSSwapInt32(fap
->size
);
462 if (fap
->cputype
== CPU_TYPE_I386
) {
463 loadAddr
= (void *)kLoadAddr
+ fap
->offset
;
469 *loadAddrP
= loadAddr
;
475 //==========================================================================
476 // LoadMatchedModules
479 LoadMatchedModules( void )
483 char *fileName
, segName
[32];
484 DriverInfoPtr driver
;
485 long length
, driverAddr
, driverLength
;
487 module = gModuleHead
;
491 if (module->willLoad
)
493 prop
= XMLGetProperty(module->dict
, kPropCFBundleExecutable
);
497 fileName
= prop
->string
;
498 sprintf(gFileSpec
, "%s%s", module->driverPath
, fileName
);
499 length
= LoadFile(gFileSpec
);
506 void *driverModuleAddr
= (void *)kLoadAddr
;
509 ThinFatFile(&driverModuleAddr
, &length
);
512 // Make make in the image area.
513 driverLength
= sizeof(DriverInfo
) + module->plistLength
+ length
;
514 driverAddr
= AllocateKernelMemory(driverLength
);
516 // Set up the DriverInfo.
517 driver
= (DriverInfoPtr
)driverAddr
;
518 driver
->plistAddr
= (char *)(driverAddr
+ sizeof(DriverInfo
));
519 driver
->plistLength
= module->plistLength
;
522 driver
->moduleAddr
= (void *)(driverAddr
+ sizeof(DriverInfo
) +
523 module->plistLength
);
524 driver
->moduleLength
= length
;
528 driver
->moduleAddr
= 0;
529 driver
->moduleLength
= 0;
532 // Save the plist and module.
533 strcpy(driver
->plistAddr
, module->plistAddr
);
536 memcpy(driver
->moduleAddr
, driverModuleAddr
, length
);
539 // Add an entry to the memory map.
540 sprintf(segName
, "Driver-%lx", (unsigned long)driver
);
541 AllocateMemoryRange(segName
, driverAddr
, driverLength
,
542 kBootDriverTypeKEXT
);
545 module = module->nextModule
;
551 //==========================================================================
552 // MatchPersonalities
555 MatchPersonalities( void )
557 /* IONameMatch support not implemented */
561 //==========================================================================
565 MatchLibraries( void )
568 ModulePtr
module, module2
;
573 module = gModuleHead
;
577 if (module->willLoad
== 1)
579 prop
= XMLGetProperty(module->dict
, kPropOSBundleLibraries
);
585 module2
= gModuleHead
;
588 prop2
= XMLGetProperty(module2
->dict
, kPropCFBundleIdentifier
);
589 if ((prop2
!= 0) && (!strcmp(prop
->string
, prop2
->string
)))
591 if (module2
->willLoad
== 0) module2
->willLoad
= 1;
594 module2
= module2
->nextModule
;
596 prop
= prop
->tagNext
;
599 module->willLoad
= 2;
602 module = module->nextModule
;
611 //==========================================================================
616 FindModule( char * name
)
621 module = gModuleHead
;
625 prop
= GetProperty(module->dict
, kPropCFBundleIdentifier
);
626 if ((prop
!= 0) && !strcmp(name
, prop
->string
)) break;
627 module = module->nextModule
;
634 //==========================================================================
638 ParseXML( char * buffer
, ModulePtr
* module, TagPtr
* personalities
)
641 TagPtr moduleDict
, required
;
648 length
= XMLParseNextTag(buffer
+ pos
, &moduleDict
);
649 if (length
== -1) break;
653 if (moduleDict
== 0) continue;
654 if (moduleDict
->type
== kTagTypeDict
) break;
656 XMLFreeTag(moduleDict
);
659 if (length
== -1) return -1;
661 required
= XMLGetProperty(moduleDict
, kPropOSBundleRequired
);
662 if ( (required
== 0) ||
663 (required
->type
!= kTagTypeString
) ||
664 !strcmp(required
->string
, "Safe Boot"))
666 XMLFreeTag(moduleDict
);
670 tmpModule
= (ModulePtr
)malloc(sizeof(Module
));
673 XMLFreeTag(moduleDict
);
676 tmpModule
->dict
= moduleDict
;
678 // For now, load any module that has OSBundleRequired != "Safe Boot".
680 tmpModule
->willLoad
= 1;
684 // Get the personalities.
686 *personalities
= XMLGetProperty(moduleDict
, kPropIOKitPersonalities
);
692 static char gPlatformName
[64];
696 DecodeKernel(void *binary
, entry_t
*rentry
, char **raddr
, int *rsize
)
699 compressed_kernel_header
* kernel_header
= (compressed_kernel_header
*) binary
;
700 u_int32_t uncompressed_size
, size
;
704 printf("kernel header:\n");
705 printf("signature: 0x%x\n", kernel_header
->signature
);
706 printf("compress_type: 0x%x\n", kernel_header
->compress_type
);
707 printf("adler32: 0x%x\n", kernel_header
->adler32
);
708 printf("uncompressed_size: 0x%x\n", kernel_header
->uncompressed_size
);
709 printf("compressed_size: 0x%x\n", kernel_header
->compressed_size
);
713 if (kernel_header
->signature
== OSSwapBigToHostConstInt32('comp')) {
714 if (kernel_header
->compress_type
!= OSSwapBigToHostConstInt32('lzss')) {
715 error("kernel compression is bad\n");
719 if (kernel_header
->platform_name
[0] && strcmp(gPlatformName
, kernel_header
->platform_name
))
721 if (kernel_header
->root_path
[0] && strcmp(gBootFile
, kernel_header
->root_path
))
725 uncompressed_size
= OSSwapBigToHostInt32(kernel_header
->uncompressed_size
);
726 binary
= buffer
= malloc(uncompressed_size
);
728 size
= decompress_lzss((u_int8_t
*) binary
, &kernel_header
->data
[0],
729 OSSwapBigToHostInt32(kernel_header
->compressed_size
));
730 if (uncompressed_size
!= size
) {
731 error("size mismatch from lzss: %x\n", size
);
734 if (OSSwapBigToHostInt32(kernel_header
->adler32
) !=
735 Alder32(binary
, uncompressed_size
)) {
736 printf("adler mismatch\n");
741 ThinFatFile(&binary
, 0);
743 ret
= DecodeMachO(binary
, rentry
, raddr
, rsize
);