]> git.saurik.com Git - apple/bootx.git/blame - bootx.tproj/sl.subproj/drivers.c
BootX-81.tar.gz
[apple/bootx.git] / bootx.tproj / sl.subproj / drivers.c
CommitLineData
04fee52e
A
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
8be739c0
A
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.
04fee52e 11 *
8be739c0
A
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
04fee52e
A
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
8be739c0
A
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.
04fee52e
A
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22/*
23 * drivers.c - Driver Loading Functions.
24 *
95a2ba82 25 * Copyright (c) 2000-2005 Apple Computer, Inc.
04fee52e
A
26 *
27 * DRI: Josh de Cesare
28 */
29
30#include <sl.h>
31
71019aa0
A
32#define DRIVER_DEBUG 0
33
04fee52e
A
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
04fee52e
A
41struct Module {
42 struct Module *nextModule;
43 long willLoad;
44 TagPtr dict;
45 char *plistAddr;
46 long plistLength;
47 char *driverPath;
48};
49typedef struct Module Module, *ModulePtr;
50
51struct DriverInfo {
52 char *plistAddr;
53 long plistLength;
54 void *moduleAddr;
55 long moduleLength;
56};
57typedef struct DriverInfo DriverInfo, *DriverInfoPtr;
58
59#define kDriverPackageSignature1 'MKXT'
60#define kDriverPackageSignature2 'MOSX'
61
62struct DriversPackage {
63 unsigned long signature1;
64 unsigned long signature2;
65 unsigned long length;
8be739c0 66 unsigned long adler32;
04fee52e
A
67 unsigned long version;
68 unsigned long numDrivers;
69 unsigned long reserved1;
70 unsigned long reserved2;
71};
72typedef struct DriversPackage DriversPackage;
73
366defd1
A
74enum {
75 kCFBundleType2,
76 kCFBundleType3
77};
78
04fee52e
A
79static long FileLoadDrivers(char *dirSpec, long plugin);
80static long NetLoadDrivers(char *dirSpec);
81static long LoadDriverMKext(char *fileSpec);
366defd1 82static long LoadDriverPList(char *dirSpec, char *name, long bundleType);
04fee52e
A
83static long LoadMatchedModules(void);
84static long MatchPersonalities(void);
85static long MatchLibraries(void);
04fee52e 86static ModulePtr FindModule(char *name);
8be739c0 87static long XML2Module(char *buffer, ModulePtr *module, TagPtr *personalities);
04fee52e
A
88
89static ModulePtr gModuleHead, gModuleTail;
90static TagPtr gPersonalityHead, gPersonalityTail;
04fee52e
A
91static char gDriverSpec[4096];
92static char gFileSpec[4096];
366defd1
A
93static char gTempSpec[4096];
94static char gFileName[4096];
04fee52e
A
95
96// Public Functions
97
98long LoadDrivers(char *dirSpec)
99{
100 if (gBootFileType == kNetworkDeviceType) {
95a2ba82 101 if(NetLoadDrivers(dirSpec) < 0) return -1;
04fee52e 102 } else if (gBootFileType == kBlockDeviceType) {
95a2ba82 103 FileLoadDrivers(dirSpec, 0); // never returns errors
04fee52e
A
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
95a2ba82 119// XX FileLoadDrivers could use some more error checking
04fee52e
A
120static long FileLoadDrivers(char *dirSpec, long plugin)
121{
366defd1
A
122 long ret, length, index, flags, time, time2, bundleType;
123 char *name;
04fee52e
A
124
125 if (!plugin) {
126 ret = GetFileInfo(dirSpec, "Extensions.mkext", &flags, &time);
366defd1 127 if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeFlat)) {
04fee52e 128 ret = GetFileInfo(dirSpec, "Extensions", &flags, &time2);
873b6fa6
A
129 // try mkext if if it looks right or if the folder was bad
130 if ((ret != 0) || // ret == 0 -> flags is good
8be739c0
A
131 ((flags & kFileTypeMask) != kFileTypeDirectory) ||
132 (((gBootMode & kBootModeSafe) == 0) && (time == (time2 + 1)))) {
04fee52e 133 sprintf(gDriverSpec, "%sExtensions.mkext", dirSpec);
8be739c0 134 printf("FileLoadDrivers: Loading from [%s]\n", gDriverSpec);
04fee52e 135 if (LoadDriverMKext(gDriverSpec) == 0) return 0;
8be739c0
A
136 } else if(time != (time2 + 1)) {
137 printf("mkext timestamp isn't quite right (delta: %d); ignoring...\n",
138 time2 - time);
139 }
04fee52e
A
140 }
141
142 strcat(dirSpec, "Extensions");
143 }
144
8be739c0 145 printf("FileLoadDrivers: Loading from [%s]\n", dirSpec);
04fee52e
A
146
147 index = 0;
148 while (1) {
149 ret = GetDirEntry(dirSpec, &index, &name, &flags, &time);
150 if (ret == -1) break;
8be739c0 151
04fee52e 152 // Make sure this is a directory.
366defd1 153 if ((flags & kFileTypeMask ) != kFileTypeDirectory) continue;
04fee52e
A
154
155 // Make sure this is a kext.
156 length = strlen(name);
157 if (strcmp(name + length - 5, ".kext")) continue;
158
366defd1
A
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;
04fee52e 167
366defd1
A
168 if (!plugin) {
169 sprintf(gDriverSpec, "%s\\%s\\%sPlugIns", dirSpec, gFileName,
170 (bundleType == kCFBundleType2) ? "Contents\\" : "");
171 }
172
173 ret = LoadDriverPList(dirSpec, gFileName, bundleType);
04fee52e 174
366defd1 175 if (!plugin) {
04fee52e 176 ret = FileLoadDrivers(gDriverSpec, 1);
366defd1 177 }
04fee52e
A
178 }
179
180 return 0;
181}
182
183
184static 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
211static long LoadDriverMKext(char *fileSpec)
212{
71019aa0 213 unsigned long driversAddr, driversLength, length;
04fee52e 214 char segName[32];
8be739c0 215 DriversPackage *package;
04fee52e
A
216
217 // Load the MKext.
8be739c0 218 length = LoadThinFatFile(fileSpec, (void **)&package);
71019aa0
A
219 if (length == -1) return -1;
220
04fee52e
A
221 // Verify the MKext.
222 if ((package->signature1 != kDriverPackageSignature1) ||
223 (package->signature2 != kDriverPackageSignature2)) return -1;
95a2ba82
A
224 if (package->length > kMaxMKextSize) {
225 printf("mkext segment too big (%ld bytes)\n", package->length);
226 return -1;
227 }
8be739c0 228 if (package->adler32 != Adler32((char *)&package->version,
04fee52e
A
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.
71019aa0 236 memcpy((void *)driversAddr, (void *)package, driversLength);
04fee52e
A
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
366defd1 246static long LoadDriverPList(char *dirSpec, char *name, long bundleType)
04fee52e
A
247{
248 long length, ret, driverPathLength;
249 char *buffer;
250 ModulePtr module;
251 TagPtr personalities;
252 char *tmpDriverPath;
253
366defd1
A
254 // Reset the malloc zone.
255 malloc_init((char *)kMallocAddr, kMallocSize);
256
04fee52e 257 // Save the driver path.
366defd1
A
258 sprintf(gFileSpec, "%s\\%s\\%s", dirSpec, name,
259 (bundleType == kCFBundleType2) ? "Contents\\MacOS\\" : "");
04fee52e
A
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.
366defd1
A
266 sprintf(gFileSpec, "%s\\%s\\%sInfo.plist", dirSpec, name,
267 (bundleType == kCFBundleType2) ? "Contents\\" : "");
04fee52e
A
268
269 length = LoadFile(gFileSpec);
8be739c0 270 *((char*)kLoadAddr + length) = '\0'; // terminate for parser safety
04fee52e
A
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
8be739c0 283 ret = XML2Module(buffer, &module, &personalities);
04fee52e
A
284 free(buffer);
285 if (ret != 0) {
8be739c0 286 // could trap ret == -2 and report missing OSBundleRequired
04fee52e
A
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
8be739c0 313 // Add the extracted personalities to the list.
04fee52e
A
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
327static long LoadMatchedModules(void)
328{
329 TagPtr prop;
330 ModulePtr module;
331 char *fileName, segName[32];
332 DriverInfoPtr driver;
71019aa0
A
333 unsigned long length, driverAddr, driverLength;
334 void *driverModuleAddr;
04fee52e
A
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);
8be739c0 343 length = LoadThinFatFile(gFileSpec, &driverModuleAddr);
04fee52e
A
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) {
71019aa0 366 memcpy(driver->moduleAddr, driverModuleAddr, driver->moduleLength);
04fee52e
A
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
382static 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
425static 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
04fee52e
A
463static 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
8be739c0
A
479/* turn buffer of XML into a ModulePtr for driver analysis */
480static long XML2Module(char *buffer, ModulePtr *module, TagPtr *personalities)
04fee52e 481{
8be739c0 482 TagPtr moduleDict = NULL, required;
04fee52e 483 ModulePtr tmpModule;
8be739c0
A
484
485 if(ParseXML(buffer, &moduleDict) < 0)
486 return -1;
487
873b6fa6
A
488 // to be loaded by BootX, you must have OSBundleRequired and it
489 // must not be set to Safe Boot (that's for kextd later)
490 // <http://developer.apple.com/documentation/Darwin/Conceptual/KEXTConcept/KEXTConceptLoading/loading_kexts.html>
491 // in other words, BootX always loads the minimal number of kexts
492 // if loading them one at a time
04fee52e
A
493 required = GetProperty(moduleDict, kPropOSBundleRequired);
494 if ((required == 0) || (required->type != kTagTypeString) ||
495 !strcmp(required->string, "Safe Boot")) {
496 FreeTag(moduleDict);
8be739c0 497 return -2;
04fee52e
A
498 }
499
500 tmpModule = AllocateBootXMemory(sizeof(Module));
501 if (tmpModule == 0) {
502 FreeTag(moduleDict);
503 return -1;
504 }
505 tmpModule->dict = moduleDict;
506
04fee52e
A
507 tmpModule->willLoad = 1;
508
509 *module = tmpModule;
510
511 // Get the personalities.
512 *personalities = GetProperty(moduleDict, kPropIOKitPersonalities);
513
514 return 0;
515}