2 * Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Portions Copyright (c) 1999-2003 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 2.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 if (gMKextName
[0] != '\0')
168 verbose("LoadDrivers: Loading from [%s]\n", gMKextName
);
169 if ( LoadDriverMKext(gMKextName
) != 0 )
171 error("Could not load %s\n", gMKextName
);
177 strcpy(gExtensionsSpec
, dirSpec
);
178 strcat(gExtensionsSpec
, "System/Library/");
179 FileLoadDrivers(gExtensionsSpec
, 0);
187 MatchPersonalities();
191 LoadMatchedModules();
196 //==========================================================================
200 FileLoadDrivers( char * dirSpec
, long plugin
)
202 long ret
, length
, index
, flags
, time
, bundleType
;
209 ret
= GetFileInfo(dirSpec
, "Extensions.mkext", &flags
, &time
);
210 if ((ret
== 0) && ((flags
& kFileTypeMask
) == kFileTypeFlat
))
212 ret
= GetFileInfo(dirSpec
, "Extensions", &flags
, &time2
);
213 if ((ret
!= 0) || ((flags
& kFileTypeMask
) != kFileTypeDirectory
) ||
214 (((gBootMode
& kBootModeSafe
) == 0) && (time
== (time2
+ 1))))
216 sprintf(gDriverSpec
, "%sExtensions.mkext", dirSpec
);
217 verbose("LoadDrivers: Loading from [%s]\n", gDriverSpec
);
218 if (LoadDriverMKext(gDriverSpec
) == 0) return 0;
222 strcat(dirSpec
, "Extensions");
225 verbose("LoadDrivers: Loading from [%s]\n", dirSpec
);
229 ret
= GetDirEntry(dirSpec
, &index
, &name
, &flags
, &time
);
230 if (ret
== -1) break;
232 // Make sure this is a directory.
233 if ((flags
& kFileTypeMask
) != kFileTypeDirectory
) continue;
235 // Make sure this is a kext.
236 length
= strlen(name
);
237 if (strcmp(name
+ length
- 5, ".kext")) continue;
239 // Save the file name.
240 strcpy(gFileName
, name
);
242 // Determine the bundle type.
243 sprintf(gTempSpec
, "%s/%s", dirSpec
, gFileName
);
244 ret
= GetFileInfo(gTempSpec
, "Contents", &flags
, &time
);
245 if (ret
== 0) bundleType
= kCFBundleType2
;
246 else bundleType
= kCFBundleType3
;
249 sprintf(gDriverSpec
, "%s/%s/%sPlugIns", dirSpec
, gFileName
,
250 (bundleType
== kCFBundleType2
) ? "Contents/" : "");
252 ret
= LoadDriverPList(dirSpec
, gFileName
, bundleType
);
255 //printf("LoadDrivers: failed for '%s'/'%s'\n", dirSpec, gFileName);
259 ret
= FileLoadDrivers(gDriverSpec
, 1);
265 //==========================================================================
269 NetLoadDrivers( char * dirSpec
)
276 // Get the name of the kernel
277 cnt
= strlen(gBootFile
);
279 if ((gBootFile
[cnt
] == '\\') || (gBootFile
[cnt
] == ',')) {
286 // INTEL modification
287 sprintf(gDriverSpec
, "%s%s.mkext", dirSpec
, bootArgs
->bootFile
);
289 verbose("NetLoadDrivers: Loading from [%s]\n", gDriverSpec
);
294 if (LoadDriverMKext(gDriverSpec
) == 0) break;
296 if (tries
== -1) return -1;
301 //==========================================================================
305 LoadDriverMKext( char * fileSpec
)
307 unsigned long driversAddr
, driversLength
;
310 DriversPackage
* package
= (DriversPackage
*)kLoadAddr
;
312 #define GetPackageElement(e) OSSwapBigToHostInt32(package->e)
315 length
= LoadFile(fileSpec
);
316 if (length
== -1) return -1;
318 ThinFatFile((void **)&package
, &length
);
321 if (( GetPackageElement(signature1
) != kDriverPackageSignature1
) ||
322 ( GetPackageElement(signature2
) != kDriverPackageSignature2
) ||
323 ( GetPackageElement(length
) > kLoadSize
) ||
324 ( GetPackageElement(alder32
) !=
325 Alder32((char *)&package
->version
, GetPackageElement(length
) - 0x10) ) )
330 // Make space for the MKext.
331 driversLength
= GetPackageElement(length
);
332 driversAddr
= AllocateKernelMemory(driversLength
);
335 memcpy((void *)driversAddr
, (void *)package
, driversLength
);
337 // Add the MKext to the memory map.
338 sprintf(segName
, "DriversPackage-%lx", driversAddr
);
339 AllocateMemoryRange(segName
, driversAddr
, driversLength
,
340 kBootDriverTypeMKEXT
);
345 //==========================================================================
349 LoadDriverPList( char * dirSpec
, char * name
, long bundleType
)
351 long length
, driverPathLength
;
353 TagPtr personalities
;
355 char * tmpDriverPath
= 0;
359 // Save the driver path.
361 sprintf(gFileSpec
, "%s/%s/%s", dirSpec
, name
,
362 (bundleType
== kCFBundleType2
) ? "Contents/MacOS/" : "");
363 driverPathLength
= strlen(gFileSpec
) + 1;
365 tmpDriverPath
= malloc(driverPathLength
);
366 if (tmpDriverPath
== 0) break;
368 strcpy(tmpDriverPath
, gFileSpec
);
370 // Construct the file spec to the plist, then load it.
372 sprintf(gFileSpec
, "%s/%s/%sInfo.plist", dirSpec
, name
,
373 (bundleType
== kCFBundleType2
) ? "Contents/" : "");
375 length
= LoadFile(gFileSpec
);
376 if (length
== -1) break;
379 buffer
= malloc(length
);
380 if (buffer
== 0) break;
382 strlcpy(buffer
, (char *)kLoadAddr
, length
);
386 ret
= ParseXML(buffer
, &module, &personalities
);
387 if (ret
!= 0) { break; }
389 // Allocate memory for the driver path and the plist.
391 module->driverPath
= tmpDriverPath
;
392 module->plistAddr
= (void *)malloc(length
);
394 if ((module->driverPath
== 0) || (module->plistAddr
== 0))
397 // Save the driver path in the module.
398 //strcpy(module->driverPath, tmpDriverPath);
401 // Add the plist to the module.
403 strlcpy(module->plistAddr
, (char *)kLoadAddr
, length
);
404 module->plistLength
= length
;
406 // Add the module to the end of the module list.
408 if (gModuleHead
== 0)
409 gModuleHead
= module;
411 gModuleTail
->nextModule
= module;
412 gModuleTail
= module;
414 // Add the persionalities to the personality list.
416 if (personalities
) personalities
= personalities
->tag
;
417 while (personalities
!= 0)
419 if (gPersonalityHead
== 0)
420 gPersonalityHead
= personalities
->tag
;
422 gPersonalityTail
->tagNext
= personalities
->tag
;
424 gPersonalityTail
= personalities
->tag
;
425 personalities
= personalities
->tagNext
;
432 if ( buffer
) free( buffer
);
433 if ( tmpDriverPath
) free( tmpDriverPath
);
439 //==========================================================================
441 // Checks the loaded file for a fat header; if present, updates
442 // loadAddr and length to be the portion of the fat file relevant
443 // to the current architecture; otherwise leaves them unchanged.
446 ThinFatFile(void **loadAddrP
, unsigned long *lengthP
)
448 // Check for fat files.
449 struct fat_header
*fhp
= (struct fat_header
*)kLoadAddr
;
450 struct fat_arch
*fap
= (struct fat_arch
*)((void *)kLoadAddr
+
451 sizeof(struct fat_header
));
454 unsigned long length
= 0;
456 if (fhp
->magic
== FAT_MAGIC
) {
457 nfat
= fhp
->nfat_arch
;
459 } else if (fhp
->magic
== FAT_CIGAM
) {
460 nfat
= OSSwapInt32(fhp
->nfat_arch
);
467 for (; nfat
> 0; nfat
--, fap
++) {
469 fap
->cputype
= OSSwapInt32(fap
->cputype
);
470 fap
->offset
= OSSwapInt32(fap
->offset
);
471 fap
->size
= OSSwapInt32(fap
->size
);
473 if (fap
->cputype
== CPU_TYPE_I386
) {
474 loadAddr
= (void *)kLoadAddr
+ fap
->offset
;
480 *loadAddrP
= loadAddr
;
486 //==========================================================================
487 // LoadMatchedModules
490 LoadMatchedModules( void )
494 char *fileName
, segName
[32];
495 DriverInfoPtr driver
;
496 long length
, driverAddr
, driverLength
;
498 module = gModuleHead
;
502 if (module->willLoad
)
504 prop
= XMLGetProperty(module->dict
, kPropCFBundleExecutable
);
508 fileName
= prop
->string
;
509 sprintf(gFileSpec
, "%s%s", module->driverPath
, fileName
);
510 length
= LoadFile(gFileSpec
);
517 void *driverModuleAddr
= (void *)kLoadAddr
;
520 ThinFatFile(&driverModuleAddr
, &length
);
523 // Make make in the image area.
524 driverLength
= sizeof(DriverInfo
) + module->plistLength
+ length
;
525 driverAddr
= AllocateKernelMemory(driverLength
);
527 // Set up the DriverInfo.
528 driver
= (DriverInfoPtr
)driverAddr
;
529 driver
->plistAddr
= (char *)(driverAddr
+ sizeof(DriverInfo
));
530 driver
->plistLength
= module->plistLength
;
533 driver
->moduleAddr
= (void *)(driverAddr
+ sizeof(DriverInfo
) +
534 module->plistLength
);
535 driver
->moduleLength
= length
;
539 driver
->moduleAddr
= 0;
540 driver
->moduleLength
= 0;
543 // Save the plist and module.
544 strcpy(driver
->plistAddr
, module->plistAddr
);
547 memcpy(driver
->moduleAddr
, driverModuleAddr
, length
);
550 // Add an entry to the memory map.
551 sprintf(segName
, "Driver-%lx", (unsigned long)driver
);
552 AllocateMemoryRange(segName
, driverAddr
, driverLength
,
553 kBootDriverTypeKEXT
);
556 module = module->nextModule
;
562 //==========================================================================
563 // MatchPersonalities
566 MatchPersonalities( void )
568 /* IONameMatch support not implemented */
572 //==========================================================================
576 MatchLibraries( void )
579 ModulePtr
module, module2
;
584 module = gModuleHead
;
588 if (module->willLoad
== 1)
590 prop
= XMLGetProperty(module->dict
, kPropOSBundleLibraries
);
596 module2
= gModuleHead
;
599 prop2
= XMLGetProperty(module2
->dict
, kPropCFBundleIdentifier
);
600 if ((prop2
!= 0) && (!strcmp(prop
->string
, prop2
->string
)))
602 if (module2
->willLoad
== 0) module2
->willLoad
= 1;
605 module2
= module2
->nextModule
;
607 prop
= prop
->tagNext
;
610 module->willLoad
= 2;
613 module = module->nextModule
;
622 //==========================================================================
627 FindModule( char * name
)
632 module = gModuleHead
;
636 prop
= GetProperty(module->dict
, kPropCFBundleIdentifier
);
637 if ((prop
!= 0) && !strcmp(name
, prop
->string
)) break;
638 module = module->nextModule
;
645 //==========================================================================
649 ParseXML( char * buffer
, ModulePtr
* module, TagPtr
* personalities
)
652 TagPtr moduleDict
, required
;
659 length
= XMLParseNextTag(buffer
+ pos
, &moduleDict
);
660 if (length
== -1) break;
664 if (moduleDict
== 0) continue;
665 if (moduleDict
->type
== kTagTypeDict
) break;
667 XMLFreeTag(moduleDict
);
670 if (length
== -1) return -1;
672 required
= XMLGetProperty(moduleDict
, kPropOSBundleRequired
);
673 if ( (required
== 0) ||
674 (required
->type
!= kTagTypeString
) ||
675 !strcmp(required
->string
, "Safe Boot"))
677 XMLFreeTag(moduleDict
);
681 tmpModule
= (ModulePtr
)malloc(sizeof(Module
));
684 XMLFreeTag(moduleDict
);
687 tmpModule
->dict
= moduleDict
;
689 // For now, load any module that has OSBundleRequired != "Safe Boot".
691 tmpModule
->willLoad
= 1;
695 // Get the personalities.
697 *personalities
= XMLGetProperty(moduleDict
, kPropIOKitPersonalities
);
703 static char gPlatformName
[64];
707 DecodeKernel(void *binary
, entry_t
*rentry
, char **raddr
, int *rsize
)
710 compressed_kernel_header
* kernel_header
= (compressed_kernel_header
*) binary
;
711 u_int32_t uncompressed_size
, size
;
715 printf("kernel header:\n");
716 printf("signature: 0x%x\n", kernel_header
->signature
);
717 printf("compress_type: 0x%x\n", kernel_header
->compress_type
);
718 printf("adler32: 0x%x\n", kernel_header
->adler32
);
719 printf("uncompressed_size: 0x%x\n", kernel_header
->uncompressed_size
);
720 printf("compressed_size: 0x%x\n", kernel_header
->compressed_size
);
724 if (kernel_header
->signature
== OSSwapBigToHostConstInt32('comp')) {
725 if (kernel_header
->compress_type
!= OSSwapBigToHostConstInt32('lzss')) {
726 error("kernel compression is bad\n");
730 if (kernel_header
->platform_name
[0] && strcmp(gPlatformName
, kernel_header
->platform_name
))
732 if (kernel_header
->root_path
[0] && strcmp(gBootFile
, kernel_header
->root_path
))
736 uncompressed_size
= OSSwapBigToHostInt32(kernel_header
->uncompressed_size
);
737 binary
= buffer
= malloc(uncompressed_size
);
739 size
= decompress_lzss((u_int8_t
*) binary
, &kernel_header
->data
[0],
740 OSSwapBigToHostInt32(kernel_header
->compressed_size
));
741 if (uncompressed_size
!= size
) {
742 error("size mismatch from lzss: %x\n", size
);
745 if (OSSwapBigToHostInt32(kernel_header
->adler32
) !=
746 Alder32(binary
, uncompressed_size
)) {
747 printf("adler mismatch\n");
752 ThinFatFile(&binary
, 0);
754 ret
= DecodeMachO(binary
, rentry
, raddr
, rsize
);