]> git.saurik.com Git - apple/boot.git/blob - i386/boot2/drivers.c
7fe6ae2331f02a88c28ae23ea3af6985c6bb44d7
[apple/boot.git] / i386 / boot2 / drivers.c
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /*
26 * drivers.c - Driver Loading Functions.
27 *
28 * Copyright (c) 2000 Apple Computer, Inc.
29 *
30 * DRI: Josh de Cesare
31 */
32
33 #include <mach-o/fat.h>
34 #include <libkern/OSByteOrder.h>
35 #include <mach/machine.h>
36
37 #include "sl.h"
38 #include "boot.h"
39 #include "bootstruct.h"
40 #include "xml.h"
41
42 struct Module {
43 struct Module *nextModule;
44 long willLoad;
45 TagPtr dict;
46 char *plistAddr;
47 long plistLength;
48 char *driverPath;
49 };
50 typedef struct Module Module, *ModulePtr;
51
52 struct DriverInfo {
53 char *plistAddr;
54 long plistLength;
55 void *moduleAddr;
56 long moduleLength;
57 };
58 typedef struct DriverInfo DriverInfo, *DriverInfoPtr;
59
60 #define kDriverPackageSignature1 'MKXT'
61 #define kDriverPackageSignature2 'MOSX'
62
63 struct DriversPackage {
64 unsigned long signature1;
65 unsigned long signature2;
66 unsigned long length;
67 unsigned long alder32;
68 unsigned long version;
69 unsigned long numDrivers;
70 unsigned long reserved1;
71 unsigned long reserved2;
72 };
73 typedef struct DriversPackage DriversPackage;
74
75 enum {
76 kCFBundleType2,
77 kCFBundleType3
78 };
79
80 static unsigned long Alder32( unsigned char * buffer, long length );
81
82 static long FileLoadDrivers(char *dirSpec, long plugin);
83 static long NetLoadDrivers(char *dirSpec);
84 static long LoadDriverMKext(char *fileSpec);
85 static long LoadDriverPList(char *dirSpec, char *name, long bundleType);
86 static long LoadMatchedModules(void);
87 static long MatchPersonalities(void);
88 static long MatchLibraries(void);
89 #ifdef NOTDEF
90 static ModulePtr FindModule(char *name);
91 static void ThinFatFile(void **loadAddrP, unsigned long *lengthP);
92 #endif
93 static long ParseXML(char *buffer, ModulePtr *module, TagPtr *personalities);
94 static long InitDriverSupport(void);
95
96 static ModulePtr gModuleHead, gModuleTail;
97 static TagPtr gPersonalityHead, gPersonalityTail;
98 static char * gExtensionsSpec;
99 static char * gDriverSpec;
100 static char * gFileSpec;
101 static char * gTempSpec;
102 static char * gFileName;
103
104
105 static unsigned long
106 Alder32( unsigned char * buffer, long length )
107 {
108 long cnt;
109 unsigned long result, lowHalf, highHalf;
110
111 lowHalf = 1;
112 highHalf = 0;
113
114 for ( cnt = 0; cnt < length; cnt++ )
115 {
116 if ((cnt % 5000) == 0)
117 {
118 lowHalf %= 65521L;
119 highHalf %= 65521L;
120 }
121
122 lowHalf += buffer[cnt];
123 highHalf += lowHalf;
124 }
125
126 lowHalf %= 65521L;
127 highHalf %= 65521L;
128
129 result = (highHalf << 16) | lowHalf;
130
131 return result;
132 }
133
134
135 //==========================================================================
136 // InitDriverSupport
137
138 static long
139 InitDriverSupport( void )
140 {
141 gExtensionsSpec = (char *) malloc( 4096 );
142 gDriverSpec = (char *) malloc( 4096 );
143 gFileSpec = (char *) malloc( 4096 );
144 gTempSpec = (char *) malloc( 4096 );
145 gFileName = (char *) malloc( 4096 );
146
147 if ( !gExtensionsSpec || !gDriverSpec || !gFileSpec || !gTempSpec || !gFileName )
148 stop("InitDriverSupport error");
149
150 return 0;
151 }
152
153 //==========================================================================
154 // LoadDrivers
155
156 long LoadDrivers( char * dirSpec )
157 {
158 if ( InitDriverSupport() != 0 )
159 return 0;
160
161 if ( gBootFileType == kNetworkDeviceType )
162 {
163 NetLoadDrivers(dirSpec);
164 }
165 else if ( gBootFileType == kBlockDeviceType )
166 {
167 strcpy(gExtensionsSpec, dirSpec);
168 strcat(gExtensionsSpec, "System/Library/");
169 FileLoadDrivers(gExtensionsSpec, 0);
170 }
171 else
172 {
173 return 0;
174 }
175
176 MatchPersonalities();
177
178 MatchLibraries();
179
180 LoadMatchedModules();
181
182 return 0;
183 }
184
185 //==========================================================================
186 // FileLoadDrivers
187
188 static long
189 FileLoadDrivers( char * dirSpec, long plugin )
190 {
191 long ret, length, index, flags, time, bundleType;
192 const char * name;
193
194 if ( !plugin )
195 {
196 long time2;
197
198 ret = GetFileInfo(dirSpec, "Extensions.mkext", &flags, &time);
199 if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeFlat))
200 {
201 ret = GetFileInfo(dirSpec, "Extensions", &flags, &time2);
202 if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeDirectory) ||
203 (((gBootMode & kBootModeSafe) == 0) && (time > time2)))
204 {
205 sprintf(gDriverSpec, "%sExtensions.mkext", dirSpec);
206 verbose("LoadDrivers: Loading from [%s]\n", gDriverSpec);
207 if (LoadDriverMKext(gDriverSpec) == 0) return 0;
208 }
209 }
210
211 strcat(dirSpec, "Extensions");
212 }
213
214 verbose("LoadDrivers: Loading from [%s]\n", dirSpec);
215
216 index = 0;
217 while (1) {
218 ret = GetDirEntry(dirSpec, &index, &name, &flags, &time);
219 if (ret == -1) break;
220
221 // Make sure this is a directory.
222 if ((flags & kFileTypeMask) != kFileTypeDirectory) continue;
223
224 // Make sure this is a kext.
225 length = strlen(name);
226 if (strcmp(name + length - 5, ".kext")) continue;
227
228 // Save the file name.
229 strcpy(gFileName, name);
230
231 // Determine the bundle type.
232 sprintf(gTempSpec, "%s/%s", dirSpec, gFileName);
233 ret = GetFileInfo(gTempSpec, "Contents", &flags, &time);
234 if (ret == 0) bundleType = kCFBundleType2;
235 else bundleType = kCFBundleType3;
236
237 if (!plugin)
238 sprintf(gDriverSpec, "%s/%s/%sPlugIns", dirSpec, gFileName,
239 (bundleType == kCFBundleType2) ? "Contents/" : "");
240
241 ret = LoadDriverPList(dirSpec, gFileName, bundleType);
242 if (ret != 0)
243 {
244 //printf("LoadDrivers: failed for '%s'/'%s'\n", dirSpec, gFileName);
245 }
246
247 if (!plugin)
248 ret = FileLoadDrivers(gDriverSpec, 1);
249 }
250
251 return 0;
252 }
253
254 //==========================================================================
255 //
256
257 static long
258 NetLoadDrivers( char * dirSpec )
259 {
260 long tries;
261
262 #if NODEF
263 long cnt;
264
265 // Get the name of the kernel
266 cnt = strlen(gBootFile);
267 while (cnt--) {
268 if ((gBootFile[cnt] == '\\') || (gBootFile[cnt] == ',')) {
269 cnt++;
270 break;
271 }
272 }
273 #endif
274
275 // INTEL modification
276 sprintf(gDriverSpec, "%s%s.mkext", dirSpec, bootArgs->bootFile);
277
278 verbose("NetLoadDrivers: Loading from [%s]\n", gDriverSpec);
279
280 tries = 3;
281 while (tries--)
282 {
283 if (LoadDriverMKext(gDriverSpec) == 0) break;
284 }
285 if (tries == -1) return -1;
286
287 return 0;
288 }
289
290 //==========================================================================
291 // loadDriverMKext
292
293 static long
294 LoadDriverMKext( char * fileSpec )
295 {
296 unsigned long driversAddr, driversLength;
297 long length;
298 char segName[32];
299 DriversPackage * package = (DriversPackage *)kLoadAddr;
300
301 #define GetPackageElement(e) OSSwapBigToHostInt32(package->e)
302
303 // Load the MKext.
304 length = LoadFile(fileSpec);
305 if (length == -1) return -1;
306
307 ThinFatFile((void **)&package, &length);
308
309 // Verify the MKext.
310 if (( GetPackageElement(signature1) != kDriverPackageSignature1) ||
311 ( GetPackageElement(signature2) != kDriverPackageSignature2) ||
312 ( GetPackageElement(length) > kLoadSize ) ||
313 ( GetPackageElement(alder32) !=
314 Alder32((char *)&package->version, GetPackageElement(length) - 0x10) ) )
315 {
316 return -1;
317 }
318
319 // Make space for the MKext.
320 driversLength = GetPackageElement(length);
321 driversAddr = AllocateKernelMemory(driversLength);
322
323 // Copy the MKext.
324 memcpy((void *)driversAddr, (void *)package, driversLength);
325
326 // Add the MKext to the memory map.
327 sprintf(segName, "DriversPackage-%lx", driversAddr);
328 AllocateMemoryRange(segName, driversAddr, driversLength,
329 kBootDriverTypeMKEXT);
330
331 return 0;
332 }
333
334 //==========================================================================
335 // LoadDriverPList
336
337 static long
338 LoadDriverPList( char * dirSpec, char * name, long bundleType )
339 {
340 long length, driverPathLength;
341 ModulePtr module;
342 TagPtr personalities;
343 char * buffer = 0;
344 char * tmpDriverPath = 0;
345 long ret = -1;
346
347 do {
348 // Save the driver path.
349
350 sprintf(gFileSpec, "%s/%s/%s", dirSpec, name,
351 (bundleType == kCFBundleType2) ? "Contents/MacOS/" : "");
352 driverPathLength = strlen(gFileSpec) + 1;
353
354 tmpDriverPath = malloc(driverPathLength);
355 if (tmpDriverPath == 0) break;
356
357 strcpy(tmpDriverPath, gFileSpec);
358
359 // Construct the file spec to the plist, then load it.
360
361 sprintf(gFileSpec, "%s/%s/%sInfo.plist", dirSpec, name,
362 (bundleType == kCFBundleType2) ? "Contents/" : "");
363
364 length = LoadFile(gFileSpec);
365 if (length == -1) break;
366
367 length = length + 1;
368 buffer = malloc(length);
369 if (buffer == 0) break;
370
371 strlcpy(buffer, (char *)kLoadAddr, length);
372
373 // Parse the plist.
374
375 ret = ParseXML(buffer, &module, &personalities);
376 if (ret != 0) { break; }
377
378 // Allocate memory for the driver path and the plist.
379
380 module->driverPath = tmpDriverPath;
381 module->plistAddr = (void *)malloc(length);
382
383 if ((module->driverPath == 0) || (module->plistAddr == 0))
384 break;
385
386 // Save the driver path in the module.
387 //strcpy(module->driverPath, tmpDriverPath);
388 tmpDriverPath = 0;
389
390 // Add the plist to the module.
391
392 strlcpy(module->plistAddr, (char *)kLoadAddr, length);
393 module->plistLength = length;
394
395 // Add the module to the end of the module list.
396
397 if (gModuleHead == 0)
398 gModuleHead = module;
399 else
400 gModuleTail->nextModule = module;
401 gModuleTail = module;
402
403 // Add the persionalities to the personality list.
404
405 if (personalities) personalities = personalities->tag;
406 while (personalities != 0)
407 {
408 if (gPersonalityHead == 0)
409 gPersonalityHead = personalities->tag;
410 else
411 gPersonalityTail->tagNext = personalities->tag;
412
413 gPersonalityTail = personalities->tag;
414 personalities = personalities->tagNext;
415 }
416
417 ret = 0;
418 }
419 while (0);
420
421 if ( buffer ) free( buffer );
422 if ( tmpDriverPath ) free( tmpDriverPath );
423
424 return ret;
425 }
426
427 #if 0
428 //==========================================================================
429 // ThinFatFile
430 // Checks the loaded file for a fat header; if present, updates
431 // loadAddr and length to be the portion of the fat file relevant
432 // to the current architecture; otherwise leaves them unchanged.
433
434 static void
435 ThinFatFile(void **loadAddrP, unsigned long *lengthP)
436 {
437 // Check for fat files.
438 struct fat_header *fhp = (struct fat_header *)kLoadAddr;
439 struct fat_arch *fap = (struct fat_arch *)((void *)kLoadAddr +
440 sizeof(struct fat_header));
441 int nfat, swapped;
442 void *loadAddr = 0;
443 unsigned long length = 0;
444
445 if (fhp->magic == FAT_MAGIC) {
446 nfat = fhp->nfat_arch;
447 swapped = 0;
448 } else if (fhp->magic == FAT_CIGAM) {
449 nfat = OSSwapInt32(fhp->nfat_arch);
450 swapped = 1;
451 } else {
452 nfat = 0;
453 swapped = 0;
454 }
455
456 for (; nfat > 0; nfat--, fap++) {
457 if (swapped) {
458 fap->cputype = OSSwapInt32(fap->cputype);
459 fap->offset = OSSwapInt32(fap->offset);
460 fap->size = OSSwapInt32(fap->size);
461 }
462 if (fap->cputype == CPU_TYPE_I386) {
463 loadAddr = (void *)kLoadAddr + fap->offset;
464 length = fap->size;
465 break;
466 }
467 }
468 if (loadAddr)
469 *loadAddrP = loadAddr;
470 if (length)
471 *lengthP = length;
472 }
473 #endif
474
475 //==========================================================================
476 // LoadMatchedModules
477
478 static long
479 LoadMatchedModules( void )
480 {
481 TagPtr prop;
482 ModulePtr module;
483 char *fileName, segName[32];
484 DriverInfoPtr driver;
485 long length, driverAddr, driverLength;
486
487 module = gModuleHead;
488
489 while (module != 0)
490 {
491 if (module->willLoad)
492 {
493 prop = XMLGetProperty(module->dict, kPropCFBundleExecutable);
494
495 if (prop != 0)
496 {
497 fileName = prop->string;
498 sprintf(gFileSpec, "%s%s", module->driverPath, fileName);
499 length = LoadFile(gFileSpec);
500 }
501 else
502 length = 0;
503
504 if (length != -1)
505 {
506 void *driverModuleAddr = (void *)kLoadAddr;
507 if (length != 0)
508 {
509 ThinFatFile(&driverModuleAddr, &length);
510 }
511
512 // Make make in the image area.
513 driverLength = sizeof(DriverInfo) + module->plistLength + length;
514 driverAddr = AllocateKernelMemory(driverLength);
515
516 // Set up the DriverInfo.
517 driver = (DriverInfoPtr)driverAddr;
518 driver->plistAddr = (char *)(driverAddr + sizeof(DriverInfo));
519 driver->plistLength = module->plistLength;
520 if (length != 0)
521 {
522 driver->moduleAddr = (void *)(driverAddr + sizeof(DriverInfo) +
523 module->plistLength);
524 driver->moduleLength = length;
525 }
526 else
527 {
528 driver->moduleAddr = 0;
529 driver->moduleLength = 0;
530 }
531
532 // Save the plist and module.
533 strcpy(driver->plistAddr, module->plistAddr);
534 if (length != 0)
535 {
536 memcpy(driver->moduleAddr, driverModuleAddr, length);
537 }
538
539 // Add an entry to the memory map.
540 sprintf(segName, "Driver-%lx", (unsigned long)driver);
541 AllocateMemoryRange(segName, driverAddr, driverLength,
542 kBootDriverTypeKEXT);
543 }
544 }
545 module = module->nextModule;
546 }
547
548 return 0;
549 }
550
551 //==========================================================================
552 // MatchPersonalities
553
554 static long
555 MatchPersonalities( void )
556 {
557 /* IONameMatch support not implemented */
558 return 0;
559 }
560
561 //==========================================================================
562 // MatchLibraries
563
564 static long
565 MatchLibraries( void )
566 {
567 TagPtr prop, prop2;
568 ModulePtr module, module2;
569 long done;
570
571 do {
572 done = 1;
573 module = gModuleHead;
574
575 while (module != 0)
576 {
577 if (module->willLoad == 1)
578 {
579 prop = XMLGetProperty(module->dict, kPropOSBundleLibraries);
580 if (prop != 0)
581 {
582 prop = prop->tag;
583 while (prop != 0)
584 {
585 module2 = gModuleHead;
586 while (module2 != 0)
587 {
588 prop2 = XMLGetProperty(module2->dict, kPropCFBundleIdentifier);
589 if ((prop2 != 0) && (!strcmp(prop->string, prop2->string)))
590 {
591 if (module2->willLoad == 0) module2->willLoad = 1;
592 break;
593 }
594 module2 = module2->nextModule;
595 }
596 prop = prop->tagNext;
597 }
598 }
599 module->willLoad = 2;
600 done = 0;
601 }
602 module = module->nextModule;
603 }
604 }
605 while (!done);
606
607 return 0;
608 }
609
610
611 //==========================================================================
612 // FindModule
613
614 #if NOTDEF
615 static ModulePtr
616 FindModule( char * name )
617 {
618 ModulePtr module;
619 TagPtr prop;
620
621 module = gModuleHead;
622
623 while (module != 0)
624 {
625 prop = GetProperty(module->dict, kPropCFBundleIdentifier);
626 if ((prop != 0) && !strcmp(name, prop->string)) break;
627 module = module->nextModule;
628 }
629
630 return module;
631 }
632 #endif /* NOTDEF */
633
634 //==========================================================================
635 // ParseXML
636
637 static long
638 ParseXML( char * buffer, ModulePtr * module, TagPtr * personalities )
639 {
640 long length, pos;
641 TagPtr moduleDict, required;
642 ModulePtr tmpModule;
643
644 pos = 0;
645
646 while (1)
647 {
648 length = XMLParseNextTag(buffer + pos, &moduleDict);
649 if (length == -1) break;
650
651 pos += length;
652
653 if (moduleDict == 0) continue;
654 if (moduleDict->type == kTagTypeDict) break;
655
656 XMLFreeTag(moduleDict);
657 }
658
659 if (length == -1) return -1;
660
661 required = XMLGetProperty(moduleDict, kPropOSBundleRequired);
662 if ( (required == 0) ||
663 (required->type != kTagTypeString) ||
664 !strcmp(required->string, "Safe Boot"))
665 {
666 XMLFreeTag(moduleDict);
667 return -2;
668 }
669
670 tmpModule = (ModulePtr)malloc(sizeof(Module));
671 if (tmpModule == 0)
672 {
673 XMLFreeTag(moduleDict);
674 return -1;
675 }
676 tmpModule->dict = moduleDict;
677
678 // For now, load any module that has OSBundleRequired != "Safe Boot".
679
680 tmpModule->willLoad = 1;
681
682 *module = tmpModule;
683
684 // Get the personalities.
685
686 *personalities = XMLGetProperty(moduleDict, kPropIOKitPersonalities);
687
688 return 0;
689 }
690
691 #if NOTDEF
692 static char gPlatformName[64];
693 #endif
694
695 long
696 DecodeKernel(void *binary, entry_t *rentry, char **raddr, int *rsize)
697 {
698 long ret;
699 compressed_kernel_header * kernel_header = (compressed_kernel_header *) binary;
700 u_int32_t uncompressed_size, size;
701 void *buffer;
702
703 #if 0
704 printf("kernel header:\n");
705 printf("signature: 0x%x\n", kernel_header->signature);
706 printf("compress_type: 0x%x\n", kernel_header->compress_type);
707 printf("adler32: 0x%x\n", kernel_header->adler32);
708 printf("uncompressed_size: 0x%x\n", kernel_header->uncompressed_size);
709 printf("compressed_size: 0x%x\n", kernel_header->compressed_size);
710 getc();
711 #endif
712
713 if (kernel_header->signature == OSSwapBigToHostConstInt32('comp')) {
714 if (kernel_header->compress_type != OSSwapBigToHostConstInt32('lzss')) {
715 error("kernel compression is bad\n");
716 return -1;
717 }
718 #if NOTDEF
719 if (kernel_header->platform_name[0] && strcmp(gPlatformName, kernel_header->platform_name))
720 return -1;
721 if (kernel_header->root_path[0] && strcmp(gBootFile, kernel_header->root_path))
722 return -1;
723 #endif
724
725 uncompressed_size = OSSwapBigToHostInt32(kernel_header->uncompressed_size);
726 binary = buffer = malloc(uncompressed_size);
727
728 size = decompress_lzss((u_int8_t *) binary, &kernel_header->data[0],
729 OSSwapBigToHostInt32(kernel_header->compressed_size));
730 if (uncompressed_size != size) {
731 error("size mismatch from lzss: %x\n", size);
732 return -1;
733 }
734 if (OSSwapBigToHostInt32(kernel_header->adler32) !=
735 Alder32(binary, uncompressed_size)) {
736 printf("adler mismatch\n");
737 return -1;
738 }
739 }
740
741 ThinFatFile(&binary, 0);
742
743 ret = DecodeMachO(binary, rentry, raddr, rsize);
744
745 return ret;
746 }