2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
20 * @APPLE_LICENSE_HEADER_END@
23 * drivers.c - Driver Loading Functions.
25 * Copyright (c) 2000-2005 Apple Computer, Inc.
32 #define DRIVER_DEBUG 0
34 #define kPropCFBundleIdentifier ("CFBundleIdentifier")
35 #define kPropCFBundleExecutable ("CFBundleExecutable")
36 #define kPropOSBundleRequired ("OSBundleRequired")
37 #define kPropOSBundleLibraries ("OSBundleLibraries")
38 #define kPropIOKitPersonalities ("IOKitPersonalities")
39 #define kPropIONameMatch ("IONameMatch")
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 adler32
;
67 unsigned long version
;
68 unsigned long numDrivers
;
69 unsigned long reserved1
;
70 unsigned long reserved2
;
72 typedef struct DriversPackage DriversPackage
;
79 static long FileLoadDrivers(char *dirSpec
, long plugin
);
80 static long NetLoadDrivers(char *dirSpec
);
81 static long LoadDriverMKext(char *fileSpec
);
82 static long LoadDriverPList(char *dirSpec
, char *name
, long bundleType
);
83 static long LoadMatchedModules(void);
84 static long MatchPersonalities(void);
85 static long MatchLibraries(void);
86 static ModulePtr
FindModule(char *name
);
87 static long XML2Module(char *buffer
, ModulePtr
*module, TagPtr
*personalities
);
89 static ModulePtr gModuleHead
, gModuleTail
;
90 static TagPtr gPersonalityHead
, gPersonalityTail
;
91 static char gDriverSpec
[4096];
92 static char gFileSpec
[4096];
93 static char gTempSpec
[4096];
94 static char gFileName
[4096];
98 long LoadDrivers(char *dirSpec
)
100 if (gBootFileType
== kNetworkDeviceType
) {
101 if(NetLoadDrivers(dirSpec
) < 0) return -1;
102 } else if (gBootFileType
== kBlockDeviceType
) {
103 FileLoadDrivers(dirSpec
, 0); // never returns errors
108 MatchPersonalities();
112 LoadMatchedModules();
119 // XX FileLoadDrivers could use some more error checking
120 static long FileLoadDrivers(char *dirSpec
, long plugin
)
122 long ret
, length
, index
, flags
, time
, time2
, bundleType
;
126 ret
= GetFileInfo(dirSpec
, "Extensions.mkext", &flags
, &time
);
127 if ((ret
== 0) && ((flags
& kFileTypeMask
) == kFileTypeFlat
)) {
128 ret
= GetFileInfo(dirSpec
, "Extensions", &flags
, &time2
);
129 // use mkext if if it looks right or if the folder was bad
131 ((flags
& kFileTypeMask
) != kFileTypeDirectory
) ||
132 (((gBootMode
& kBootModeSafe
) == 0) && (time
== (time2
+ 1)))) {
133 sprintf(gDriverSpec
, "%sExtensions.mkext", dirSpec
);
134 printf("FileLoadDrivers: Loading from [%s]\n", gDriverSpec
);
135 if (LoadDriverMKext(gDriverSpec
) == 0) return 0;
136 } else if(time
!= (time2
+ 1)) {
137 printf("mkext timestamp isn't quite right (delta: %d); ignoring...\n",
142 strcat(dirSpec
, "Extensions");
145 printf("FileLoadDrivers: Loading from [%s]\n", dirSpec
);
149 ret
= GetDirEntry(dirSpec
, &index
, &name
, &flags
, &time
);
150 if (ret
== -1) break;
152 // Make sure this is a directory.
153 if ((flags
& kFileTypeMask
) != kFileTypeDirectory
) continue;
155 // Make sure this is a kext.
156 length
= strlen(name
);
157 if (strcmp(name
+ length
- 5, ".kext")) continue;
159 // Save the file name.
160 strcpy(gFileName
, name
);
162 // Determine the bundle type.
163 sprintf(gTempSpec
, "%s\\%s", dirSpec
, gFileName
);
164 ret
= GetFileInfo(gTempSpec
, "Contents", &flags
, &time
);
165 if (ret
== 0) bundleType
= kCFBundleType2
;
166 else bundleType
= kCFBundleType3
;
169 sprintf(gDriverSpec
, "%s\\%s\\%sPlugIns", dirSpec
, gFileName
,
170 (bundleType
== kCFBundleType2
) ? "Contents\\" : "");
173 ret
= LoadDriverPList(dirSpec
, gFileName
, bundleType
);
176 ret
= FileLoadDrivers(gDriverSpec
, 1);
184 static long NetLoadDrivers(char *dirSpec
)
188 // Get the name of the kernel
189 cnt
= strlen(gBootFile
);
191 if ((gBootFile
[cnt
] == '\\') || (gBootFile
[cnt
] == ',')) {
197 sprintf(gDriverSpec
, "%s%s.mkext", dirSpec
, gBootFile
+ cnt
);
199 printf("NetLoadDrivers: Loading from [%s]\n", gDriverSpec
);
203 if (LoadDriverMKext(gDriverSpec
) == 0) break;
205 if (tries
== -1) return -1;
211 static long LoadDriverMKext(char *fileSpec
)
213 unsigned long driversAddr
, driversLength
, length
;
215 DriversPackage
*package
;
218 length
= LoadThinFatFile(fileSpec
, (void **)&package
);
219 if (length
== -1) return -1;
222 if ((package
->signature1
!= kDriverPackageSignature1
) ||
223 (package
->signature2
!= kDriverPackageSignature2
)) return -1;
224 if (package
->length
> kMaxMKextSize
) {
225 printf("mkext segment too big (%ld bytes)\n", package
->length
);
228 if (package
->adler32
!= Adler32((char *)&package
->version
,
229 package
->length
- 0x10)) return -1;
231 // Make space for the MKext.
232 driversLength
= package
->length
;
233 driversAddr
= AllocateKernelMemory(driversLength
);
236 memcpy((void *)driversAddr
, (void *)package
, driversLength
);
238 // Add the MKext to the memory map.
239 sprintf(segName
, "DriversPackage-%x", driversAddr
);
240 AllocateMemoryRange(segName
, driversAddr
, driversLength
);
246 static long LoadDriverPList(char *dirSpec
, char *name
, long bundleType
)
248 long length
, ret
, driverPathLength
;
251 TagPtr personalities
;
254 // Reset the malloc zone.
255 malloc_init((char *)kMallocAddr
, kMallocSize
);
257 // Save the driver path.
258 sprintf(gFileSpec
, "%s\\%s\\%s", dirSpec
, name
,
259 (bundleType
== kCFBundleType2
) ? "Contents\\MacOS\\" : "");
260 driverPathLength
= strlen(gFileSpec
);
261 tmpDriverPath
= malloc(driverPathLength
+ 1);
262 if (tmpDriverPath
== 0) return -1;
263 strcpy(tmpDriverPath
, gFileSpec
);
265 // Construct the file spec.
266 sprintf(gFileSpec
, "%s\\%s\\%sInfo.plist", dirSpec
, name
,
267 (bundleType
== kCFBundleType2
) ? "Contents\\" : "");
269 length
= LoadFile(gFileSpec
);
270 *((char*)kLoadAddr
+ length
) = '\0'; // terminate for parser safety
276 buffer
= malloc(length
+ 1);
281 strncpy(buffer
, (char *)kLoadAddr
, length
);
283 ret
= XML2Module(buffer
, &module, &personalities
);
286 // could trap ret == -2 and report missing OSBundleRequired
291 // Allocate memory for the driver path and the plist.
292 module->driverPath
= AllocateBootXMemory(driverPathLength
+ 1);
293 module->plistAddr
= AllocateBootXMemory(length
+ 1);
295 if ((module->driverPath
== 0) | (module->plistAddr
== 0)) {
300 // Save the driver path in the module.
301 strcpy(module->driverPath
, tmpDriverPath
);
304 // Add the origin plist to the module.
305 strncpy(module->plistAddr
, (char *)kLoadAddr
, length
);
306 module->plistLength
= length
+ 1;
308 // Add the module to the end of the module list.
309 if (gModuleHead
== 0) gModuleHead
= module;
310 else gModuleTail
->nextModule
= module;
311 gModuleTail
= module;
313 // Add the extracted personalities to the list.
314 if (personalities
) personalities
= personalities
->tag
;
315 while (personalities
!= 0) {
316 if (gPersonalityHead
== 0) gPersonalityHead
= personalities
->tag
;
317 else gPersonalityTail
->tagNext
= personalities
->tag
;
318 gPersonalityTail
= personalities
->tag
;
320 personalities
= personalities
->tagNext
;
327 static long LoadMatchedModules(void)
331 char *fileName
, segName
[32];
332 DriverInfoPtr driver
;
333 unsigned long length
, driverAddr
, driverLength
;
334 void *driverModuleAddr
;
336 module = gModuleHead
;
337 while (module != 0) {
338 if (module->willLoad
) {
339 prop
= GetProperty(module->dict
, kPropCFBundleExecutable
);
341 fileName
= prop
->string
;
342 sprintf(gFileSpec
, "%s%s", module->driverPath
, fileName
);
343 length
= LoadThinFatFile(gFileSpec
, &driverModuleAddr
);
346 // Make make in the image area.
347 driverLength
= sizeof(DriverInfo
) + module->plistLength
+ length
;
348 driverAddr
= AllocateKernelMemory(driverLength
);
350 // Set up the DriverInfo.
351 driver
= (DriverInfoPtr
)driverAddr
;
352 driver
->plistAddr
= (char *)(driverAddr
+ sizeof(DriverInfo
));
353 driver
->plistLength
= module->plistLength
;
355 driver
->moduleAddr
= (void *)(driverAddr
+ sizeof(DriverInfo
) +
356 module->plistLength
);
357 driver
->moduleLength
= length
;
359 driver
->moduleAddr
= 0;
360 driver
->moduleLength
= 0;
363 // Save the plist and module.
364 strcpy(driver
->plistAddr
, module->plistAddr
);
366 memcpy(driver
->moduleAddr
, driverModuleAddr
, driver
->moduleLength
);
369 // Add an entry to the memory map.
370 sprintf(segName
, "Driver-%x", driver
);
371 AllocateMemoryRange(segName
, driverAddr
, driverLength
);
375 module = module->nextModule
;
382 static long MatchPersonalities(void)
389 // Try to match each of the personalities.
390 for(persionality
= gPersonalityHead
; persionality
!= 0;
391 persionality
= persionality
->tagNext
) {
392 // Get the module name. Make sure it exists and has not
393 // already been marked for loading.
394 prop
= GetProperty(persionality
, kPropCFBundleIdentifier
);
395 if (prop
== 0) continue;
396 module = FindModule(prop
->string
);
397 if (module == 0) continue;
398 if (module->willLoad
) continue;
400 // Look for the exact match property.
401 // Try to match with it.
403 // Look for the old match property.
404 // Try to match with it.
406 prop
= GetProperty(persionality
, kPropIONameMatch
);
407 if ((prop
!= 0) && (prop
->tag
!= 0)) prop
= prop
->tag
;
409 ph
= SearchForNodeMatching(0, 1, prop
->string
);
412 prop
= prop
->tagNext
;
415 // If a node was found mark the module to be loaded.
417 module->willLoad
= 1;
425 static long MatchLibraries(void)
428 ModulePtr
module, module2
;
433 module = gModuleHead
;
434 while (module != 0) {
435 if (module->willLoad
== 1) {
436 prop
= GetProperty(module->dict
, kPropOSBundleLibraries
);
440 module2
= gModuleHead
;
441 while (module2
!= 0) {
442 prop2
= GetProperty(module2
->dict
, kPropCFBundleIdentifier
);
443 if ((prop2
!= 0) && (!strcmp(prop
->string
, prop2
->string
))) {
444 if (module2
->willLoad
== 0) module2
->willLoad
= 1;
447 module2
= module2
->nextModule
;
449 prop
= prop
->tagNext
;
452 module->willLoad
= 2;
455 module = module->nextModule
;
463 static ModulePtr
FindModule(char *name
)
468 module = gModuleHead
;
470 while (module != 0) {
471 prop
= GetProperty(module->dict
, kPropCFBundleIdentifier
);
472 if ((prop
!= 0) && !strcmp(name
, prop
->string
)) break;
473 module = module->nextModule
;
479 /* turn buffer of XML into a ModulePtr for driver analysis */
480 static long XML2Module(char *buffer
, ModulePtr
*module, TagPtr
*personalities
)
482 TagPtr moduleDict
= NULL
, required
;
485 if(ParseXML(buffer
, &moduleDict
) < 0)
488 required
= GetProperty(moduleDict
, kPropOSBundleRequired
);
489 if ((required
== 0) || (required
->type
!= kTagTypeString
) ||
490 !strcmp(required
->string
, "Safe Boot")) {
495 tmpModule
= AllocateBootXMemory(sizeof(Module
));
496 if (tmpModule
== 0) {
500 tmpModule
->dict
= moduleDict
;
502 // For now, load any module that has OSBundleRequired != "Safe Boot".
503 tmpModule
->willLoad
= 1;
507 // Get the personalities.
508 *personalities
= GetProperty(moduleDict
, kPropIOKitPersonalities
);