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