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