2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
22 * @APPLE_LICENSE_HEADER_END@
25 * drivers.c - Driver Loading Functions.
27 * Copyright (c) 2000 Apple Computer, Inc.
32 #include <mach-o/fat.h>
33 #include <libkern/OSByteOrder.h>
34 #include <mach/machine.h>
38 #include "bootstruct.h"
42 struct Module
*nextModule
;
49 typedef struct Module Module
, *ModulePtr
;
57 typedef struct DriverInfo DriverInfo
, *DriverInfoPtr
;
59 #define kDriverPackageSignature1 'MKXT'
60 #define kDriverPackageSignature2 'MOSX'
62 struct DriversPackage
{
63 unsigned long signature1
;
64 unsigned long signature2
;
66 unsigned long alder32
;
67 unsigned long version
;
68 unsigned long numDrivers
;
69 unsigned long reserved1
;
70 unsigned long reserved2
;
72 typedef struct DriversPackage DriversPackage
;
79 static unsigned long Alder32( unsigned char * buffer
, long length
);
81 static long FileLoadDrivers(char *dirSpec
, long plugin
);
82 static long NetLoadDrivers(char *dirSpec
);
83 static long LoadDriverMKext(char *fileSpec
);
84 static long LoadDriverPList(char *dirSpec
, char *name
, long bundleType
);
85 static long LoadMatchedModules(void);
86 static long MatchPersonalities(void);
87 static long MatchLibraries(void);
89 static ModulePtr
FindModule(char *name
);
90 static void ThinFatFile(void **loadAddrP
, unsigned long *lengthP
);
92 static long ParseXML(char *buffer
, ModulePtr
*module, TagPtr
*personalities
);
93 static long InitDriverSupport(void);
95 static ModulePtr gModuleHead
, gModuleTail
;
96 static TagPtr gPersonalityHead
, gPersonalityTail
;
97 static char * gExtensionsSpec
;
98 static char * gDriverSpec
;
99 static char * gFileSpec
;
100 static char * gTempSpec
;
101 static char * gFileName
;
105 Alder32( unsigned char * buffer
, long length
)
108 unsigned long result
, lowHalf
, highHalf
;
113 for ( cnt
= 0; cnt
< length
; cnt
++ )
115 if ((cnt
% 5000) == 0)
121 lowHalf
+= buffer
[cnt
];
128 result
= (highHalf
<< 16) | lowHalf
;
134 //==========================================================================
138 InitDriverSupport( void )
140 gExtensionsSpec
= (char *) malloc( 4096 );
141 gDriverSpec
= (char *) malloc( 4096 );
142 gFileSpec
= (char *) malloc( 4096 );
143 gTempSpec
= (char *) malloc( 4096 );
144 gFileName
= (char *) malloc( 4096 );
146 if ( !gExtensionsSpec
|| !gDriverSpec
|| !gFileSpec
|| !gTempSpec
|| !gFileName
)
147 stop("InitDriverSupport error");
152 //==========================================================================
155 long LoadDrivers( char * dirSpec
)
157 if ( InitDriverSupport() != 0 )
160 if ( gBootFileType
== kNetworkDeviceType
)
162 NetLoadDrivers(dirSpec
);
164 else if ( gBootFileType
== kBlockDeviceType
)
166 strcpy(gExtensionsSpec
, dirSpec
);
167 strcat(gExtensionsSpec
, "System/Library/");
168 FileLoadDrivers(gExtensionsSpec
, 0);
175 MatchPersonalities();
179 LoadMatchedModules();
184 //==========================================================================
188 FileLoadDrivers( char * dirSpec
, long plugin
)
190 long ret
, length
, index
, flags
, time
, bundleType
;
197 ret
= GetFileInfo(dirSpec
, "Extensions.mkext", &flags
, &time
);
198 if ((ret
== 0) && ((flags
& kFileTypeMask
) == kFileTypeFlat
))
200 ret
= GetFileInfo(dirSpec
, "Extensions", &flags
, &time2
);
201 if ((ret
!= 0) || ((flags
& kFileTypeMask
) != kFileTypeDirectory
) ||
202 (((gBootMode
& kBootModeSafe
) == 0) && (time
> time2
)))
204 sprintf(gDriverSpec
, "%sExtensions.mkext", dirSpec
);
205 verbose("LoadDrivers: Loading from [%s]\n", gDriverSpec
);
206 if (LoadDriverMKext(gDriverSpec
) == 0) return 0;
210 strcat(dirSpec
, "Extensions");
213 verbose("LoadDrivers: Loading from [%s]\n", dirSpec
);
217 ret
= GetDirEntry(dirSpec
, &index
, &name
, &flags
, &time
);
218 if (ret
== -1) break;
220 // Make sure this is a directory.
221 if ((flags
& kFileTypeMask
) != kFileTypeDirectory
) continue;
223 // Make sure this is a kext.
224 length
= strlen(name
);
225 if (strcmp(name
+ length
- 5, ".kext")) continue;
227 // Save the file name.
228 strcpy(gFileName
, name
);
230 // Determine the bundle type.
231 sprintf(gTempSpec
, "%s/%s", dirSpec
, gFileName
);
232 ret
= GetFileInfo(gTempSpec
, "Contents", &flags
, &time
);
233 if (ret
== 0) bundleType
= kCFBundleType2
;
234 else bundleType
= kCFBundleType3
;
237 sprintf(gDriverSpec
, "%s/%s/%sPlugIns", dirSpec
, gFileName
,
238 (bundleType
== kCFBundleType2
) ? "Contents/" : "");
240 ret
= LoadDriverPList(dirSpec
, gFileName
, bundleType
);
243 //printf("LoadDrivers: failed for '%s'/'%s'\n", dirSpec, gFileName);
247 ret
= FileLoadDrivers(gDriverSpec
, 1);
253 //==========================================================================
257 NetLoadDrivers( char * dirSpec
)
264 // Get the name of the kernel
265 cnt
= strlen(gBootFile
);
267 if ((gBootFile
[cnt
] == '\\') || (gBootFile
[cnt
] == ',')) {
274 // INTEL modification
275 sprintf(gDriverSpec
, "%s%s.mkext", dirSpec
, bootArgs
->bootFile
);
277 verbose("NetLoadDrivers: Loading from [%s]\n", gDriverSpec
);
282 if (LoadDriverMKext(gDriverSpec
) == 0) break;
284 if (tries
== -1) return -1;
289 //==========================================================================
293 LoadDriverMKext( char * fileSpec
)
295 unsigned long driversAddr
, driversLength
;
298 DriversPackage
* package
= (DriversPackage
*)kLoadAddr
;
300 #define GetPackageElement(e) OSSwapBigToHostInt32(package->e)
303 length
= LoadFile(fileSpec
);
304 if (length
== -1) return -1;
306 ThinFatFile((void **)&package
, &length
);
309 if (( GetPackageElement(signature1
) != kDriverPackageSignature1
) ||
310 ( GetPackageElement(signature2
) != kDriverPackageSignature2
) ||
311 ( GetPackageElement(length
) > kLoadSize
) ||
312 ( GetPackageElement(alder32
) !=
313 Alder32((char *)&package
->version
, GetPackageElement(length
) - 0x10) ) )
318 // Make space for the MKext.
319 driversLength
= GetPackageElement(length
);
320 driversAddr
= AllocateKernelMemory(driversLength
);
323 memcpy((void *)driversAddr
, (void *)package
, driversLength
);
325 // Add the MKext to the memory map.
326 sprintf(segName
, "DriversPackage-%lx", driversAddr
);
327 AllocateMemoryRange(segName
, driversAddr
, driversLength
,
328 kBootDriverTypeMKEXT
);
333 //==========================================================================
337 LoadDriverPList( char * dirSpec
, char * name
, long bundleType
)
339 long length
, driverPathLength
;
341 TagPtr personalities
;
343 char * tmpDriverPath
= 0;
347 // Save the driver path.
349 sprintf(gFileSpec
, "%s/%s/%s", dirSpec
, name
,
350 (bundleType
== kCFBundleType2
) ? "Contents/MacOS/" : "");
351 driverPathLength
= strlen(gFileSpec
) + 1;
353 tmpDriverPath
= malloc(driverPathLength
);
354 if (tmpDriverPath
== 0) break;
356 strcpy(tmpDriverPath
, gFileSpec
);
358 // Construct the file spec to the plist, then load it.
360 sprintf(gFileSpec
, "%s/%s/%sInfo.plist", dirSpec
, name
,
361 (bundleType
== kCFBundleType2
) ? "Contents/" : "");
363 length
= LoadFile(gFileSpec
);
364 if (length
== -1) break;
367 buffer
= malloc(length
);
368 if (buffer
== 0) break;
370 strlcpy(buffer
, (char *)kLoadAddr
, length
);
374 ret
= ParseXML(buffer
, &module, &personalities
);
375 if (ret
!= 0) { break; }
377 // Allocate memory for the driver path and the plist.
379 module->driverPath
= tmpDriverPath
;
380 module->plistAddr
= (void *)malloc(length
);
382 if ((module->driverPath
== 0) || (module->plistAddr
== 0))
385 // Save the driver path in the module.
386 //strcpy(module->driverPath, tmpDriverPath);
389 // Add the plist to the module.
391 strlcpy(module->plistAddr
, (char *)kLoadAddr
, length
);
392 module->plistLength
= length
;
394 // Add the module to the end of the module list.
396 if (gModuleHead
== 0)
397 gModuleHead
= module;
399 gModuleTail
->nextModule
= module;
400 gModuleTail
= module;
402 // Add the persionalities to the personality list.
404 if (personalities
) personalities
= personalities
->tag
;
405 while (personalities
!= 0)
407 if (gPersonalityHead
== 0)
408 gPersonalityHead
= personalities
->tag
;
410 gPersonalityTail
->tagNext
= personalities
->tag
;
412 gPersonalityTail
= personalities
->tag
;
413 personalities
= personalities
->tagNext
;
420 if ( buffer
) free( buffer
);
421 if ( tmpDriverPath
) free( tmpDriverPath
);
427 //==========================================================================
429 // Checks the loaded file for a fat header; if present, updates
430 // loadAddr and length to be the portion of the fat file relevant
431 // to the current architecture; otherwise leaves them unchanged.
434 ThinFatFile(void **loadAddrP
, unsigned long *lengthP
)
436 // Check for fat files.
437 struct fat_header
*fhp
= (struct fat_header
*)kLoadAddr
;
438 struct fat_arch
*fap
= (struct fat_arch
*)((void *)kLoadAddr
+
439 sizeof(struct fat_header
));
442 unsigned long length
= 0;
444 if (fhp
->magic
== FAT_MAGIC
) {
445 nfat
= fhp
->nfat_arch
;
447 } else if (fhp
->magic
== FAT_CIGAM
) {
448 nfat
= OSSwapInt32(fhp
->nfat_arch
);
455 for (; nfat
> 0; nfat
--, fap
++) {
457 fap
->cputype
= OSSwapInt32(fap
->cputype
);
458 fap
->offset
= OSSwapInt32(fap
->offset
);
459 fap
->size
= OSSwapInt32(fap
->size
);
461 if (fap
->cputype
== CPU_TYPE_I386
) {
462 loadAddr
= (void *)kLoadAddr
+ fap
->offset
;
468 *loadAddrP
= loadAddr
;
474 //==========================================================================
475 // LoadMatchedModules
478 LoadMatchedModules( void )
482 char *fileName
, segName
[32];
483 DriverInfoPtr driver
;
484 long length
, driverAddr
, driverLength
;
486 module = gModuleHead
;
490 if (module->willLoad
)
492 prop
= XMLGetProperty(module->dict
, kPropCFBundleExecutable
);
496 fileName
= prop
->string
;
497 sprintf(gFileSpec
, "%s%s", module->driverPath
, fileName
);
498 length
= LoadFile(gFileSpec
);
505 void *driverModuleAddr
= (void *)kLoadAddr
;
508 ThinFatFile(&driverModuleAddr
, &length
);
511 // Make make in the image area.
512 driverLength
= sizeof(DriverInfo
) + module->plistLength
+ length
;
513 driverAddr
= AllocateKernelMemory(driverLength
);
515 // Set up the DriverInfo.
516 driver
= (DriverInfoPtr
)driverAddr
;
517 driver
->plistAddr
= (char *)(driverAddr
+ sizeof(DriverInfo
));
518 driver
->plistLength
= module->plistLength
;
521 driver
->moduleAddr
= (void *)(driverAddr
+ sizeof(DriverInfo
) +
522 module->plistLength
);
523 driver
->moduleLength
= length
;
527 driver
->moduleAddr
= 0;
528 driver
->moduleLength
= 0;
531 // Save the plist and module.
532 strcpy(driver
->plistAddr
, module->plistAddr
);
535 memcpy(driver
->moduleAddr
, driverModuleAddr
, length
);
538 // Add an entry to the memory map.
539 sprintf(segName
, "Driver-%lx", (unsigned long)driver
);
540 AllocateMemoryRange(segName
, driverAddr
, driverLength
,
541 kBootDriverTypeKEXT
);
544 module = module->nextModule
;
550 //==========================================================================
551 // MatchPersonalities
554 MatchPersonalities( void )
556 /* IONameMatch support not implemented */
560 //==========================================================================
564 MatchLibraries( void )
567 ModulePtr
module, module2
;
572 module = gModuleHead
;
576 if (module->willLoad
== 1)
578 prop
= XMLGetProperty(module->dict
, kPropOSBundleLibraries
);
584 module2
= gModuleHead
;
587 prop2
= XMLGetProperty(module2
->dict
, kPropCFBundleIdentifier
);
588 if ((prop2
!= 0) && (!strcmp(prop
->string
, prop2
->string
)))
590 if (module2
->willLoad
== 0) module2
->willLoad
= 1;
593 module2
= module2
->nextModule
;
595 prop
= prop
->tagNext
;
598 module->willLoad
= 2;
601 module = module->nextModule
;
610 //==========================================================================
615 FindModule( char * name
)
620 module = gModuleHead
;
624 prop
= GetProperty(module->dict
, kPropCFBundleIdentifier
);
625 if ((prop
!= 0) && !strcmp(name
, prop
->string
)) break;
626 module = module->nextModule
;
633 //==========================================================================
637 ParseXML( char * buffer
, ModulePtr
* module, TagPtr
* personalities
)
640 TagPtr moduleDict
, required
;
647 length
= XMLParseNextTag(buffer
+ pos
, &moduleDict
);
648 if (length
== -1) break;
652 if (moduleDict
== 0) continue;
653 if (moduleDict
->type
== kTagTypeDict
) break;
655 XMLFreeTag(moduleDict
);
658 if (length
== -1) return -1;
660 required
= XMLGetProperty(moduleDict
, kPropOSBundleRequired
);
661 if ( (required
== 0) ||
662 (required
->type
!= kTagTypeString
) ||
663 !strcmp(required
->string
, "Safe Boot"))
665 XMLFreeTag(moduleDict
);
669 tmpModule
= (ModulePtr
)malloc(sizeof(Module
));
672 XMLFreeTag(moduleDict
);
675 tmpModule
->dict
= moduleDict
;
677 // For now, load any module that has OSBundleRequired != "Safe Boot".
679 tmpModule
->willLoad
= 1;
683 // Get the personalities.
685 *personalities
= XMLGetProperty(moduleDict
, kPropIOKitPersonalities
);
691 static char gPlatformName
[64];
695 DecodeKernel(void *binary
, entry_t
*rentry
, char **raddr
, int *rsize
)
698 compressed_kernel_header
* kernel_header
= (compressed_kernel_header
*) binary
;
699 u_int32_t uncompressed_size
, size
;
703 printf("kernel header:\n");
704 printf("signature: 0x%x\n", kernel_header
->signature
);
705 printf("compress_type: 0x%x\n", kernel_header
->compress_type
);
706 printf("adler32: 0x%x\n", kernel_header
->adler32
);
707 printf("uncompressed_size: 0x%x\n", kernel_header
->uncompressed_size
);
708 printf("compressed_size: 0x%x\n", kernel_header
->compressed_size
);
712 if (kernel_header
->signature
== OSSwapBigToHostConstInt32('comp')) {
713 if (kernel_header
->compress_type
!= OSSwapBigToHostConstInt32('lzss')) {
714 error("kernel compression is bad\n");
718 if (kernel_header
->platform_name
[0] && strcmp(gPlatformName
, kernel_header
->platform_name
))
720 if (kernel_header
->root_path
[0] && strcmp(gBootFile
, kernel_header
->root_path
))
724 uncompressed_size
= OSSwapBigToHostInt32(kernel_header
->uncompressed_size
);
725 binary
= buffer
= malloc(uncompressed_size
);
727 size
= decompress_lzss((u_int8_t
*) binary
, &kernel_header
->data
[0],
728 OSSwapBigToHostInt32(kernel_header
->compressed_size
));
729 if (uncompressed_size
!= size
) {
730 error("size mismatch from lzss: %x\n", size
);
733 if (OSSwapBigToHostInt32(kernel_header
->adler32
) !=
734 Alder32(binary
, uncompressed_size
)) {
735 printf("adler mismatch\n");
740 ThinFatFile(&binary
, 0);
742 ret
= DecodeMachO(binary
, rentry
, raddr
, rsize
);