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