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 if (NetLoadDrivers(dirSpec
) != 0) {
163 error("Could not load drivers from the network\n");
167 else if ( gBootFileType
== kBlockDeviceType
)
169 if (gMKextName
[0] != '\0')
171 verbose("LoadDrivers: Loading from [%s]\n", gMKextName
);
172 if ( LoadDriverMKext(gMKextName
) != 0 )
174 error("Could not load %s\n", gMKextName
);
180 strcpy(gExtensionsSpec
, dirSpec
);
181 strcat(gExtensionsSpec
, "System/Library/");
182 FileLoadDrivers(gExtensionsSpec
, 0);
190 MatchPersonalities();
194 LoadMatchedModules();
199 //==========================================================================
203 FileLoadDrivers( char * dirSpec
, long plugin
)
205 long ret
, length
, index
, flags
, time
, bundleType
;
212 ret
= GetFileInfo(dirSpec
, "Extensions.mkext", &flags
, &time
);
213 if ((ret
== 0) && ((flags
& kFileTypeMask
) == kFileTypeFlat
))
215 ret
= GetFileInfo(dirSpec
, "Extensions", &flags
, &time2
);
216 if ((ret
!= 0) || ((flags
& kFileTypeMask
) != kFileTypeDirectory
) ||
217 (((gBootMode
& kBootModeSafe
) == 0) && (time
== (time2
+ 1))))
219 sprintf(gDriverSpec
, "%sExtensions.mkext", dirSpec
);
220 verbose("LoadDrivers: Loading from [%s]\n", gDriverSpec
);
221 if (LoadDriverMKext(gDriverSpec
) == 0) return 0;
225 strcat(dirSpec
, "Extensions");
228 verbose("LoadDrivers: Loading from [%s]\n", dirSpec
);
232 ret
= GetDirEntry(dirSpec
, &index
, &name
, &flags
, &time
);
233 if (ret
== -1) break;
235 // Make sure this is a directory.
236 if ((flags
& kFileTypeMask
) != kFileTypeDirectory
) continue;
238 // Make sure this is a kext.
239 length
= strlen(name
);
240 if (strcmp(name
+ length
- 5, ".kext")) continue;
242 // Save the file name.
243 strcpy(gFileName
, name
);
245 // Determine the bundle type.
246 sprintf(gTempSpec
, "%s/%s", dirSpec
, gFileName
);
247 ret
= GetFileInfo(gTempSpec
, "Contents", &flags
, &time
);
248 if (ret
== 0) bundleType
= kCFBundleType2
;
249 else bundleType
= kCFBundleType3
;
252 sprintf(gDriverSpec
, "%s/%s/%sPlugIns", dirSpec
, gFileName
,
253 (bundleType
== kCFBundleType2
) ? "Contents/" : "");
255 ret
= LoadDriverPList(dirSpec
, gFileName
, bundleType
);
258 //printf("LoadDrivers: failed for '%s'/'%s'\n", dirSpec, gFileName);
262 ret
= FileLoadDrivers(gDriverSpec
, 1);
268 //==========================================================================
272 NetLoadDrivers( char * dirSpec
)
279 // Get the name of the kernel
280 cnt
= strlen(gBootFile
);
282 if ((gBootFile
[cnt
] == '\\') || (gBootFile
[cnt
] == ',')) {
289 // INTEL modification
290 sprintf(gDriverSpec
, "%s%s.mkext", dirSpec
, bootInfo
->bootFile
);
292 verbose("NetLoadDrivers: Loading from [%s]\n", gDriverSpec
);
297 if (LoadDriverMKext(gDriverSpec
) == 0) break;
299 if (tries
== -1) return -1;
304 //==========================================================================
308 LoadDriverMKext( char * fileSpec
)
310 unsigned long driversAddr
, driversLength
;
313 DriversPackage
* package
;
315 #define GetPackageElement(e) OSSwapBigToHostInt32(package->e)
318 length
= LoadThinFatFile(fileSpec
, (void **)&package
);
319 if (length
== -1) return -1;
322 if (( GetPackageElement(signature1
) != kDriverPackageSignature1
) ||
323 ( GetPackageElement(signature2
) != kDriverPackageSignature2
) ||
324 ( GetPackageElement(length
) > kLoadSize
) ||
325 ( GetPackageElement(alder32
) !=
326 Alder32((unsigned char *)&package
->version
, GetPackageElement(length
) - 0x10) ) )
331 // Make space for the MKext.
332 driversLength
= GetPackageElement(length
);
333 driversAddr
= AllocateKernelMemory(driversLength
);
336 memcpy((void *)driversAddr
, (void *)package
, driversLength
);
338 // Add the MKext to the memory map.
339 sprintf(segName
, "DriversPackage-%lx", driversAddr
);
340 AllocateMemoryRange(segName
, driversAddr
, driversLength
,
341 kBootDriverTypeMKEXT
);
346 //==========================================================================
350 LoadDriverPList( char * dirSpec
, char * name
, long bundleType
)
352 long length
, driverPathLength
;
354 TagPtr personalities
;
356 char * tmpDriverPath
= 0;
360 // Save the driver path.
362 sprintf(gFileSpec
, "%s/%s/%s", dirSpec
, name
,
363 (bundleType
== kCFBundleType2
) ? "Contents/MacOS/" : "");
364 driverPathLength
= strlen(gFileSpec
) + 1;
366 tmpDriverPath
= malloc(driverPathLength
);
367 if (tmpDriverPath
== 0) break;
369 strcpy(tmpDriverPath
, gFileSpec
);
371 // Construct the file spec to the plist, then load it.
373 sprintf(gFileSpec
, "%s/%s/%sInfo.plist", dirSpec
, name
,
374 (bundleType
== kCFBundleType2
) ? "Contents/" : "");
376 length
= LoadFile(gFileSpec
);
377 if (length
== -1) break;
380 buffer
= malloc(length
);
381 if (buffer
== 0) break;
383 strlcpy(buffer
, (char *)kLoadAddr
, length
);
387 ret
= ParseXML(buffer
, &module, &personalities
);
388 if (ret
!= 0) { break; }
390 // Allocate memory for the driver path and the plist.
392 module->driverPath
= tmpDriverPath
;
393 module->plistAddr
= (void *)malloc(length
);
395 if ((module->driverPath
== 0) || (module->plistAddr
== 0))
398 // Save the driver path in the module.
399 //strcpy(module->driverPath, tmpDriverPath);
402 // Add the plist to the module.
404 strlcpy(module->plistAddr
, (char *)kLoadAddr
, length
);
405 module->plistLength
= length
;
407 // Add the module to the end of the module list.
409 if (gModuleHead
== 0)
410 gModuleHead
= module;
412 gModuleTail
->nextModule
= module;
413 gModuleTail
= module;
415 // Add the persionalities to the personality list.
417 if (personalities
) personalities
= personalities
->tag
;
418 while (personalities
!= 0)
420 if (gPersonalityHead
== 0)
421 gPersonalityHead
= personalities
->tag
;
423 gPersonalityTail
->tagNext
= personalities
->tag
;
425 gPersonalityTail
= personalities
->tag
;
426 personalities
= personalities
->tagNext
;
433 if ( buffer
) free( buffer
);
434 if ( tmpDriverPath
) free( tmpDriverPath
);
440 //==========================================================================
441 // LoadMatchedModules
444 LoadMatchedModules( void )
448 char *fileName
, segName
[32];
449 DriverInfoPtr driver
;
450 long length
, driverAddr
, driverLength
;
451 void *driverModuleAddr
= 0;
454 module = gModuleHead
;
458 if (module->willLoad
)
460 prop
= XMLGetProperty(module->dict
, kPropCFBundleExecutable
);
464 fileName
= prop
->string
;
465 sprintf(gFileSpec
, "%s%s", module->driverPath
, fileName
);
466 length
= LoadThinFatFile(gFileSpec
, &driverModuleAddr
);
467 //length = LoadFile(gFileSpec);
468 //driverModuleAddr = (void *)kLoadAddr;
469 //printf("%s length = %d addr = 0x%x\n", gFileSpec, length, driverModuleAddr); getc();
476 //driverModuleAddr = (void *)kLoadAddr;
479 // ThinFatFile(&driverModuleAddr, &length);
482 // Make make in the image area.
483 driverLength
= sizeof(DriverInfo
) + module->plistLength
+ length
;
484 driverAddr
= AllocateKernelMemory(driverLength
);
486 // Set up the DriverInfo.
487 driver
= (DriverInfoPtr
)driverAddr
;
488 driver
->plistAddr
= (char *)(driverAddr
+ sizeof(DriverInfo
));
489 driver
->plistLength
= module->plistLength
;
492 driver
->moduleAddr
= (void *)(driverAddr
+ sizeof(DriverInfo
) +
493 module->plistLength
);
494 driver
->moduleLength
= length
;
498 driver
->moduleAddr
= 0;
499 driver
->moduleLength
= 0;
502 // Save the plist and module.
503 strcpy(driver
->plistAddr
, module->plistAddr
);
506 memcpy(driver
->moduleAddr
, driverModuleAddr
, length
);
509 // Add an entry to the memory map.
510 sprintf(segName
, "Driver-%lx", (unsigned long)driver
);
511 AllocateMemoryRange(segName
, driverAddr
, driverLength
,
512 kBootDriverTypeKEXT
);
515 module = module->nextModule
;
521 //==========================================================================
522 // MatchPersonalities
525 MatchPersonalities( void )
527 /* IONameMatch support not implemented */
531 //==========================================================================
535 MatchLibraries( void )
538 ModulePtr
module, module2
;
543 module = gModuleHead
;
547 if (module->willLoad
== 1)
549 prop
= XMLGetProperty(module->dict
, kPropOSBundleLibraries
);
555 module2
= gModuleHead
;
558 prop2
= XMLGetProperty(module2
->dict
, kPropCFBundleIdentifier
);
559 if ((prop2
!= 0) && (!strcmp(prop
->string
, prop2
->string
)))
561 if (module2
->willLoad
== 0) module2
->willLoad
= 1;
564 module2
= module2
->nextModule
;
566 prop
= prop
->tagNext
;
569 module->willLoad
= 2;
572 module = module->nextModule
;
581 //==========================================================================
586 FindModule( char * name
)
591 module = gModuleHead
;
595 prop
= GetProperty(module->dict
, kPropCFBundleIdentifier
);
596 if ((prop
!= 0) && !strcmp(name
, prop
->string
)) break;
597 module = module->nextModule
;
604 //==========================================================================
608 ParseXML( char * buffer
, ModulePtr
* module, TagPtr
* personalities
)
611 TagPtr moduleDict
, required
;
618 length
= XMLParseNextTag(buffer
+ pos
, &moduleDict
);
619 if (length
== -1) break;
623 if (moduleDict
== 0) continue;
624 if (moduleDict
->type
== kTagTypeDict
) break;
626 XMLFreeTag(moduleDict
);
629 if (length
== -1) return -1;
631 required
= XMLGetProperty(moduleDict
, kPropOSBundleRequired
);
632 if ( (required
== 0) ||
633 (required
->type
!= kTagTypeString
) ||
634 !strcmp(required
->string
, "Safe Boot"))
636 XMLFreeTag(moduleDict
);
640 tmpModule
= (ModulePtr
)malloc(sizeof(Module
));
643 XMLFreeTag(moduleDict
);
646 tmpModule
->dict
= moduleDict
;
648 // For now, load any module that has OSBundleRequired != "Safe Boot".
650 tmpModule
->willLoad
= 1;
654 // Get the personalities.
656 *personalities
= XMLGetProperty(moduleDict
, kPropIOKitPersonalities
);
662 static char gPlatformName
[64];
666 DecodeKernel(void *binary
, entry_t
*rentry
, char **raddr
, int *rsize
)
669 compressed_kernel_header
* kernel_header
= (compressed_kernel_header
*) binary
;
670 u_int32_t uncompressed_size
, size
;
674 printf("kernel header:\n");
675 printf("signature: 0x%x\n", kernel_header
->signature
);
676 printf("compress_type: 0x%x\n", kernel_header
->compress_type
);
677 printf("adler32: 0x%x\n", kernel_header
->adler32
);
678 printf("uncompressed_size: 0x%x\n", kernel_header
->uncompressed_size
);
679 printf("compressed_size: 0x%x\n", kernel_header
->compressed_size
);
683 if (kernel_header
->signature
== OSSwapBigToHostConstInt32('comp')) {
684 if (kernel_header
->compress_type
!= OSSwapBigToHostConstInt32('lzss')) {
685 error("kernel compression is bad\n");
689 if (kernel_header
->platform_name
[0] && strcmp(gPlatformName
, kernel_header
->platform_name
))
691 if (kernel_header
->root_path
[0] && strcmp(gBootFile
, kernel_header
->root_path
))
695 uncompressed_size
= OSSwapBigToHostInt32(kernel_header
->uncompressed_size
);
696 binary
= buffer
= malloc(uncompressed_size
);
698 size
= decompress_lzss((u_int8_t
*) binary
, &kernel_header
->data
[0],
699 OSSwapBigToHostInt32(kernel_header
->compressed_size
));
700 if (uncompressed_size
!= size
) {
701 error("size mismatch from lzss: %x\n", size
);
704 if (OSSwapBigToHostInt32(kernel_header
->adler32
) !=
705 Alder32(binary
, uncompressed_size
)) {
706 printf("adler mismatch\n");
711 ThinFatFile(&binary
, 0);
713 ret
= DecodeMachO(binary
, rentry
, raddr
, rsize
);