]> git.saurik.com Git - apple/bootx.git/blob - bootx.tproj/sl.subproj/drivers.c
BootX-75.tar.gz
[apple/bootx.git] / bootx.tproj / sl.subproj / drivers.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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.
11 *
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
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /*
23 * drivers.c - Driver Loading Functions.
24 *
25 * Copyright (c) 2000-2005 Apple Computer, Inc.
26 *
27 * DRI: Josh de Cesare
28 */
29
30 #include <sl.h>
31
32 #define DRIVER_DEBUG 0
33
34 #define kPropCFBundleIdentifier ("CFBundleIdentifier")
35 #define kPropCFBundleExecutable ("CFBundleExecutable")
36 #define kPropOSBundleRequired ("OSBundleRequired")
37 #define kPropOSBundleLibraries ("OSBundleLibraries")
38 #define kPropIOKitPersonalities ("IOKitPersonalities")
39 #define kPropIONameMatch ("IONameMatch")
40
41 struct Module {
42 struct Module *nextModule;
43 long willLoad;
44 TagPtr dict;
45 char *plistAddr;
46 long plistLength;
47 char *driverPath;
48 };
49 typedef struct Module Module, *ModulePtr;
50
51 struct DriverInfo {
52 char *plistAddr;
53 long plistLength;
54 void *moduleAddr;
55 long moduleLength;
56 };
57 typedef struct DriverInfo DriverInfo, *DriverInfoPtr;
58
59 #define kDriverPackageSignature1 'MKXT'
60 #define kDriverPackageSignature2 'MOSX'
61
62 struct DriversPackage {
63 unsigned long signature1;
64 unsigned long signature2;
65 unsigned long length;
66 unsigned long adler32;
67 unsigned long version;
68 unsigned long numDrivers;
69 unsigned long reserved1;
70 unsigned long reserved2;
71 };
72 typedef struct DriversPackage DriversPackage;
73
74 enum {
75 kCFBundleType2,
76 kCFBundleType3
77 };
78
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);
88
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];
95
96 // Public Functions
97
98 long LoadDrivers(char *dirSpec)
99 {
100 if (gBootFileType == kNetworkDeviceType) {
101 if(NetLoadDrivers(dirSpec) < 0) return -1;
102 } else if (gBootFileType == kBlockDeviceType) {
103 FileLoadDrivers(dirSpec, 0); // never returns errors
104 } else {
105 return 0;
106 }
107
108 MatchPersonalities();
109
110 MatchLibraries();
111
112 LoadMatchedModules();
113
114 return 0;
115 }
116
117 // Private Functions
118
119 // XX FileLoadDrivers could use some more error checking
120 static long FileLoadDrivers(char *dirSpec, long plugin)
121 {
122 long ret, length, index, flags, time, time2, bundleType;
123 char *name;
124
125 if (!plugin) {
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
130 if ((ret != 0) ||
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",
138 time2 - time);
139 }
140 }
141
142 strcat(dirSpec, "Extensions");
143 }
144
145 printf("FileLoadDrivers: Loading from [%s]\n", dirSpec);
146
147 index = 0;
148 while (1) {
149 ret = GetDirEntry(dirSpec, &index, &name, &flags, &time);
150 if (ret == -1) break;
151
152 // Make sure this is a directory.
153 if ((flags & kFileTypeMask ) != kFileTypeDirectory) continue;
154
155 // Make sure this is a kext.
156 length = strlen(name);
157 if (strcmp(name + length - 5, ".kext")) continue;
158
159 // Save the file name.
160 strcpy(gFileName, name);
161
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;
167
168 if (!plugin) {
169 sprintf(gDriverSpec, "%s\\%s\\%sPlugIns", dirSpec, gFileName,
170 (bundleType == kCFBundleType2) ? "Contents\\" : "");
171 }
172
173 ret = LoadDriverPList(dirSpec, gFileName, bundleType);
174
175 if (!plugin) {
176 ret = FileLoadDrivers(gDriverSpec, 1);
177 }
178 }
179
180 return 0;
181 }
182
183
184 static long NetLoadDrivers(char *dirSpec)
185 {
186 long tries, cnt;
187
188 // Get the name of the kernel
189 cnt = strlen(gBootFile);
190 while (cnt--) {
191 if ((gBootFile[cnt] == '\\') || (gBootFile[cnt] == ',')) {
192 cnt++;
193 break;
194 }
195 }
196
197 sprintf(gDriverSpec, "%s%s.mkext", dirSpec, gBootFile + cnt);
198
199 printf("NetLoadDrivers: Loading from [%s]\n", gDriverSpec);
200
201 tries = 10;
202 while (tries--) {
203 if (LoadDriverMKext(gDriverSpec) == 0) break;
204 }
205 if (tries == -1) return -1;
206
207 return 0;
208 }
209
210
211 static long LoadDriverMKext(char *fileSpec)
212 {
213 unsigned long driversAddr, driversLength, length;
214 char segName[32];
215 DriversPackage *package;
216
217 // Load the MKext.
218 length = LoadThinFatFile(fileSpec, (void **)&package);
219 if (length == -1) return -1;
220
221 // Verify the MKext.
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);
226 return -1;
227 }
228 if (package->adler32 != Adler32((char *)&package->version,
229 package->length - 0x10)) return -1;
230
231 // Make space for the MKext.
232 driversLength = package->length;
233 driversAddr = AllocateKernelMemory(driversLength);
234
235 // Copy the MKext.
236 memcpy((void *)driversAddr, (void *)package, driversLength);
237
238 // Add the MKext to the memory map.
239 sprintf(segName, "DriversPackage-%x", driversAddr);
240 AllocateMemoryRange(segName, driversAddr, driversLength);
241
242 return 0;
243 }
244
245
246 static long LoadDriverPList(char *dirSpec, char *name, long bundleType)
247 {
248 long length, ret, driverPathLength;
249 char *buffer;
250 ModulePtr module;
251 TagPtr personalities;
252 char *tmpDriverPath;
253
254 // Reset the malloc zone.
255 malloc_init((char *)kMallocAddr, kMallocSize);
256
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);
264
265 // Construct the file spec.
266 sprintf(gFileSpec, "%s\\%s\\%sInfo.plist", dirSpec, name,
267 (bundleType == kCFBundleType2) ? "Contents\\" : "");
268
269 length = LoadFile(gFileSpec);
270 *((char*)kLoadAddr + length) = '\0'; // terminate for parser safety
271 if (length == -1) {
272 free(tmpDriverPath);
273 return -1;
274 }
275
276 buffer = malloc(length + 1);
277 if (buffer == 0) {
278 free(tmpDriverPath);
279 return -1;
280 }
281 strncpy(buffer, (char *)kLoadAddr, length);
282
283 ret = XML2Module(buffer, &module, &personalities);
284 free(buffer);
285 if (ret != 0) {
286 // could trap ret == -2 and report missing OSBundleRequired
287 free(tmpDriverPath);
288 return -1;
289 }
290
291 // Allocate memory for the driver path and the plist.
292 module->driverPath = AllocateBootXMemory(driverPathLength + 1);
293 module->plistAddr = AllocateBootXMemory(length + 1);
294
295 if ((module->driverPath == 0) | (module->plistAddr == 0)) {
296 free(tmpDriverPath);
297 return -1;
298 }
299
300 // Save the driver path in the module.
301 strcpy(module->driverPath, tmpDriverPath);
302 free(tmpDriverPath);
303
304 // Add the origin plist to the module.
305 strncpy(module->plistAddr, (char *)kLoadAddr, length);
306 module->plistLength = length + 1;
307
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;
312
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;
319
320 personalities = personalities->tagNext;
321 }
322
323 return 0;
324 }
325
326
327 static long LoadMatchedModules(void)
328 {
329 TagPtr prop;
330 ModulePtr module;
331 char *fileName, segName[32];
332 DriverInfoPtr driver;
333 unsigned long length, driverAddr, driverLength;
334 void *driverModuleAddr;
335
336 module = gModuleHead;
337 while (module != 0) {
338 if (module->willLoad) {
339 prop = GetProperty(module->dict, kPropCFBundleExecutable);
340 if (prop != 0) {
341 fileName = prop->string;
342 sprintf(gFileSpec, "%s%s", module->driverPath, fileName);
343 length = LoadThinFatFile(gFileSpec, &driverModuleAddr);
344 } else length = 0;
345 if (length != -1) {
346 // Make make in the image area.
347 driverLength = sizeof(DriverInfo) + module->plistLength + length;
348 driverAddr = AllocateKernelMemory(driverLength);
349
350 // Set up the DriverInfo.
351 driver = (DriverInfoPtr)driverAddr;
352 driver->plistAddr = (char *)(driverAddr + sizeof(DriverInfo));
353 driver->plistLength = module->plistLength;
354 if (length != 0) {
355 driver->moduleAddr = (void *)(driverAddr + sizeof(DriverInfo) +
356 module->plistLength);
357 driver->moduleLength = length;
358 } else {
359 driver->moduleAddr = 0;
360 driver->moduleLength = 0;
361 }
362
363 // Save the plist and module.
364 strcpy(driver->plistAddr, module->plistAddr);
365 if (length != 0) {
366 memcpy(driver->moduleAddr, driverModuleAddr, driver->moduleLength);
367 }
368
369 // Add an entry to the memory map.
370 sprintf(segName, "Driver-%x", driver);
371 AllocateMemoryRange(segName, driverAddr, driverLength);
372 }
373 }
374
375 module = module->nextModule;
376 }
377
378 return 0;
379 }
380
381
382 static long MatchPersonalities(void)
383 {
384 TagPtr persionality;
385 TagPtr prop;
386 ModulePtr module;
387 CICell ph;
388
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;
399
400 // Look for the exact match property.
401 // Try to match with it.
402
403 // Look for the old match property.
404 // Try to match with it.
405 ph = 0;
406 prop = GetProperty(persionality, kPropIONameMatch);
407 if ((prop != 0) && (prop->tag != 0)) prop = prop->tag;
408 while (prop != 0) {
409 ph = SearchForNodeMatching(0, 1, prop->string);
410 if (ph != 0) break;
411
412 prop = prop->tagNext;
413 }
414
415 // If a node was found mark the module to be loaded.
416 if (ph != 0) {
417 module->willLoad = 1;
418 }
419 }
420
421 return 0;
422 }
423
424
425 static long MatchLibraries(void)
426 {
427 TagPtr prop, prop2;
428 ModulePtr module, module2;
429 long done;
430
431 do {
432 done = 1;
433 module = gModuleHead;
434 while (module != 0) {
435 if (module->willLoad == 1) {
436 prop = GetProperty(module->dict, kPropOSBundleLibraries);
437 if (prop != 0) {
438 prop = prop->tag;
439 while (prop != 0) {
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;
445 break;
446 }
447 module2 = module2->nextModule;
448 }
449 prop = prop->tagNext;
450 }
451 }
452 module->willLoad = 2;
453 done = 0;
454 }
455 module = module->nextModule;
456 }
457 } while (!done);
458
459 return 0;
460 }
461
462
463 static ModulePtr FindModule(char *name)
464 {
465 ModulePtr module;
466 TagPtr prop;
467
468 module = gModuleHead;
469
470 while (module != 0) {
471 prop = GetProperty(module->dict, kPropCFBundleIdentifier);
472 if ((prop != 0) && !strcmp(name, prop->string)) break;
473 module = module->nextModule;
474 }
475
476 return module;
477 }
478
479 /* turn buffer of XML into a ModulePtr for driver analysis */
480 static long XML2Module(char *buffer, ModulePtr *module, TagPtr *personalities)
481 {
482 TagPtr moduleDict = NULL, required;
483 ModulePtr tmpModule;
484
485 if(ParseXML(buffer, &moduleDict) < 0)
486 return -1;
487
488 required = GetProperty(moduleDict, kPropOSBundleRequired);
489 if ((required == 0) || (required->type != kTagTypeString) ||
490 !strcmp(required->string, "Safe Boot")) {
491 FreeTag(moduleDict);
492 return -2;
493 }
494
495 tmpModule = AllocateBootXMemory(sizeof(Module));
496 if (tmpModule == 0) {
497 FreeTag(moduleDict);
498 return -1;
499 }
500 tmpModule->dict = moduleDict;
501
502 // For now, load any module that has OSBundleRequired != "Safe Boot".
503 tmpModule->willLoad = 1;
504
505 *module = tmpModule;
506
507 // Get the personalities.
508 *personalities = GetProperty(moduleDict, kPropIOKitPersonalities);
509
510 return 0;
511 }