Chameleon

Chameleon Svn Source Tree

Root/branches/cparm/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#include "drivers.h"
41#include "modules.h"
42
43extern char gMacOSVersion[];
44extern char gBootKernelCacheFile[];
45long FileLoadDrivers(char *dirSpec, long plugin);
46#ifdef NBP_SUPPORT
47long NetLoadDrivers(char *dirSpec);
48#endif
49long LoadDriverMKext(char *fileSpec);
50long LoadDriverPList(char *dirSpec, char *name, long bundleType);
51long LoadMatchedModules(void);
52#if UNUSED
53long MatchPersonalities(void);
54#endif
55long MatchLibraries(void);
56
57static long ParseXML(char *buffer, ModulePtr *module, TagPtr *personalities);
58long InitDriverSupport(void);
59
60static ModulePtr gModuleHead, gModuleTail;
61static TagPtr gPersonalityHead, gPersonalityTail;
62char * gExtensionsSpec;
63char * gDriverSpec;
64char * gFileSpec;
65char * gTempSpec;
66char * gFileName;
67
68//==========================================================================
69// InitDriverSupport
70
71long
72InitDriverSupport( void )
73{
74 gExtensionsSpec = malloc( 4096 );
75 gDriverSpec = malloc( 4096 );
76 gFileSpec = malloc( 4096 );
77 gTempSpec = malloc( 4096 );
78 gFileName = malloc( 4096 );
79
80 if ( !gExtensionsSpec || !gDriverSpec || !gFileSpec || !gTempSpec || !gFileName )
81 stop("InitDriverSupport error");
82
83 return 0;
84}
85
86//==========================================================================
87// LoadDrivers
88
89long LoadDrivers( char * dirSpec )
90{
91 char dirSpecExtra[1024];
92
93 if ( InitDriverSupport() != 0 )
94 return 0;
95
96
97
98 // Load extra drivers if a hook has been installed.
99
100int step = 0;
101execute_hook("ramDiskLoadDrivers", &step, NULL, NULL, NULL, NULL, NULL);
102#ifdef NBP_SUPPORT
103 if ( gBootFileType == kNetworkDeviceType )
104 {
105 if (NetLoadDrivers(dirSpec) != 0) {
106 error("Could not load drivers from the network\n");
107 return -1;
108 }
109 }
110 else
111#endif
112if ( gBootFileType == kBlockDeviceType )
113{
114// First try to load Extra extensions from the ramdisk if isn't aliased as bt(0,0).
115#ifndef OPTION_ROM
116// First try a specfic OS version folder ie 10.5
117
118step = 1;
119execute_hook("ramDiskLoadDrivers", &step, NULL, NULL, NULL, NULL, NULL);
120
121#endif
122
123// First try a specfic OS version folder ie 10.5
124sprintf(dirSpecExtra, "/Extra/%s/", &gMacOSVersion);
125if (FileLoadDrivers(dirSpecExtra, 0) != 0)
126{
127// Next try to load Extra extensions from the selected root partition.
128strcpy(dirSpecExtra, "/Extra/");
129if (FileLoadDrivers(dirSpecExtra, 0) != 0)
130{
131// If failed, then try to load Extra extensions from the boot partition
132// in case we have a separate booter partition or a bt(0,0) aliased ramdisk.
133if (!(gBIOSBootVolume->biosdev == gBootVolume->biosdev && gBIOSBootVolume->part_no == gBootVolume->part_no))
134{
135// First try a specfic OS version folder ie 10.5
136sprintf(dirSpecExtra, "bt(0,0)/Extra/%s/", &gMacOSVersion);
137if (FileLoadDrivers(dirSpecExtra, 0) != 0)
138{
139// Next we'll try the base
140strcpy(dirSpecExtra, "bt(0,0)/Extra/");
141FileLoadDrivers(dirSpecExtra, 0);
142}
143}
144#ifndef OPTION_ROM
145step = 2;
146execute_hook("ramDiskLoadDrivers", &step, NULL, NULL, NULL, NULL, NULL);
147#endif
148}
149
150}
151#ifdef BOOT_HELPER_SUPPORT
152// TODO: fix this, the order does matter, and it's not correct now.
153// Also try to load Extensions from boot helper partitions.
154if (gBootVolume->flags & kBVFlagBooter)
155{
156strcpy(dirSpecExtra, "/com.apple.boot.P/System/Library/");
157if (FileLoadDrivers(dirSpecExtra, 0) != 0)
158{
159strcpy(dirSpecExtra, "/com.apple.boot.R/System/Library/");
160if (FileLoadDrivers(dirSpecExtra, 0) != 0)
161{
162strcpy(dirSpecExtra, "/com.apple.boot.S/System/Library/");
163FileLoadDrivers(dirSpecExtra, 0);
164}
165}
166}
167#endif
168
169if (gMKextName[0] != '\0')
170{
171verbose("LoadDrivers: Loading from [%s]\n", gMKextName);
172if ( LoadDriverMKext(gMKextName) != 0 )
173{
174error("Could not load %s\n", gMKextName);
175return -1;
176}
177}
178else
179{
180strcpy(gExtensionsSpec, dirSpec);
181strcat(gExtensionsSpec, "System/Library/");
182FileLoadDrivers(gExtensionsSpec, 0);
183}
184}
185else
186{
187return 0;
188}
189#if UNUSED
190 MatchPersonalities();
191#endif
192
193 MatchLibraries();
194
195 LoadMatchedModules();
196
197 return 0;
198}
199
200//==========================================================================
201// FileLoadMKext
202
203static long
204FileLoadMKext( const char * dirSpec, const char * extDirSpec )
205{
206long ret, flags, time, time2;
207char altDirSpec[512];
208
209sprintf (altDirSpec, "%s%s", dirSpec, extDirSpec);
210ret = GetFileInfo(altDirSpec, "Extensions.mkext", &flags, &time);
211if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeFlat))
212{
213ret = GetFileInfo(dirSpec, "Extensions", &flags, &time2);
214if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeDirectory) ||
215(((gBootMode & kBootModeSafe) == 0) && (time == (time2 + 1))))
216{
217sprintf(gDriverSpec, "%sExtensions.mkext", altDirSpec);
218verbose("LoadDrivers: Loading from [%s]\n", gDriverSpec);
219if (LoadDriverMKext(gDriverSpec) == 0) return 0;
220}
221}
222return -1;
223}
224
225//==========================================================================
226// FileLoadDrivers
227
228long
229FileLoadDrivers( char * dirSpec, long plugin )
230{
231 long ret, length, flags, time, bundleType;
232 long long index;
233 long result = -1;
234 const char * name;
235
236 if ( !plugin )
237 {
238 // First try 10.6's path for loading Extensions.mkext.
239 if (FileLoadMKext(dirSpec, "Caches/com.apple.kext.caches/Startup/") == 0)
240return 0;
241
242 // Next try the legacy path.
243 else if (FileLoadMKext(dirSpec, "") == 0)
244return 0;
245
246 strcat(dirSpec, "Extensions");
247 }
248
249 index = 0;
250 while (1) {
251 ret = GetDirEntry(dirSpec, &index, &name, &flags, &time);
252 if (ret == -1) break;
253
254 // Make sure this is a directory.
255 if ((flags & kFileTypeMask) != kFileTypeDirectory) continue;
256
257 // Make sure this is a kext.
258 length = strlen(name);
259 if (strcmp(name + length - 5, ".kext")) continue;
260
261 // Save the file name.
262 strcpy(gFileName, name);
263
264 // Determine the bundle type.
265 sprintf(gTempSpec, "%s/%s", dirSpec, gFileName);
266 ret = GetFileInfo(gTempSpec, "Contents", &flags, &time);
267 if (ret == 0) bundleType = kCFBundleType2;
268 else bundleType = kCFBundleType3;
269
270 if (!plugin)
271 sprintf(gDriverSpec, "%s/%s/%sPlugIns", dirSpec, gFileName,
272 (bundleType == kCFBundleType2) ? "Contents/" : "");
273
274 ret = LoadDriverPList(dirSpec, gFileName, bundleType);
275
276 if (result != 0)
277result = ret;
278
279 if (!plugin)
280FileLoadDrivers(gDriverSpec, 1);
281 }
282
283 return result;
284}
285
286//==========================================================================
287//
288#ifdef NBP_SUPPORT
289long
290NetLoadDrivers( char * dirSpec )
291{
292 long tries;
293
294#if NODEF
295 long cnt;
296
297 // Get the name of the kernel
298 cnt = strlen(gBootFile);
299 while (cnt--) {
300 if ((gBootFile[cnt] == '\\') || (gBootFile[cnt] == ',')) {
301cnt++;
302break;
303 }
304 }
305#endif
306
307 // INTEL modification
308 sprintf(gDriverSpec, "%s%s.mkext", dirSpec, bootInfo->bootFile);
309
310 verbose("NetLoadDrivers: Loading from [%s]\n", gDriverSpec);
311
312 tries = 3;
313 while (tries--)
314 {
315 if (LoadDriverMKext(gDriverSpec) == 0) break;
316 }
317 if (tries == -1) return -1;
318
319 return 0;
320}
321#endif
322//==========================================================================
323// loadDriverMKext
324
325long
326LoadDriverMKext( char * fileSpec )
327{
328 unsigned long driversAddr, driversLength;
329 long length;
330 char segName[32];
331 DriversPackage * package;
332
333#define GetPackageElement(e) OSSwapBigToHostInt32(package->e)
334
335 // Load the MKext.
336 length = LoadThinFatFile(fileSpec, (void **)&package);
337 if (length < sizeof (DriversPackage)) return -1;
338
339// call hook to notify modules that the mkext has been loaded
340execute_hook("LoadDriverMKext", (void*)fileSpec, (void*)package, (void*) length, NULL, NULL, NULL);
341
342
343 // Verify the MKext.
344 if (( GetPackageElement(signature1) != kDriverPackageSignature1) ||
345 ( GetPackageElement(signature2) != kDriverPackageSignature2) ||
346 ( GetPackageElement(length) > kLoadSize ) ||
347 ( GetPackageElement(alder32) !=
348 local_adler32((unsigned char *)&package->version, GetPackageElement(length) - 0x10) ) )
349 {
350 return -1;
351 }
352
353
354 // Make space for the MKext.
355 driversLength = GetPackageElement(length);
356 driversAddr = AllocateKernelMemory(driversLength);
357
358 // Copy the MKext.
359 memcpy((void *)driversAddr, (void *)package, driversLength);
360
361 // Add the MKext to the memory map.
362 sprintf(segName, "DriversPackage-%lx", driversAddr);
363 AllocateMemoryRange(segName, driversAddr, driversLength,
364 kBootDriverTypeMKEXT);
365
366 return 0;
367}
368
369//==========================================================================
370// LoadDriverPList
371
372long
373LoadDriverPList( char * dirSpec, char * name, long bundleType )
374{
375 long length, executablePathLength, bundlePathLength;
376 ModulePtr module;
377 TagPtr personalities;
378 char * buffer = 0;
379 char * tmpExecutablePath = 0;
380 char * tmpBundlePath = 0;
381 long ret = -1;
382
383 do {
384 // Save the driver path.
385
386 sprintf(gFileSpec, "%s/%s/%s", dirSpec, name,
387 (bundleType == kCFBundleType2) ? "Contents/MacOS/" : "");
388 executablePathLength = strlen(gFileSpec) + 1;
389
390 tmpExecutablePath = malloc(executablePathLength);
391 if (tmpExecutablePath == 0) break;
392
393 strcpy(tmpExecutablePath, gFileSpec);
394
395 sprintf(gFileSpec, "%s/%s", dirSpec, name);
396 bundlePathLength = strlen(gFileSpec) + 1;
397
398 tmpBundlePath = malloc(bundlePathLength);
399 if (tmpBundlePath == 0) break;
400
401 strcpy(tmpBundlePath, gFileSpec);
402
403 // Construct the file spec to the plist, then load it.
404
405 sprintf(gFileSpec, "%s/%s/%sInfo.plist", dirSpec, name,
406 (bundleType == kCFBundleType2) ? "Contents/" : "");
407
408 length = LoadFile(gFileSpec);
409 if (length == -1) break;
410
411 length = length + 1;
412 buffer = malloc(length);
413 if (buffer == 0) break;
414
415 strlcpy(buffer, (char *)kLoadAddr, length);
416
417 // Parse the plist.
418
419 ret = ParseXML(buffer, &module, &personalities);
420 if (ret != 0) { break; }
421
422 // Allocate memory for the driver path and the plist.
423
424 module->executablePath = tmpExecutablePath;
425 module->bundlePath = tmpBundlePath;
426 module->bundlePathLength = bundlePathLength;
427 module->plistAddr = malloc(length);
428
429 if ((module->executablePath == 0) || (module->bundlePath == 0) || (module->plistAddr == 0))
430 break;
431
432 // Save the driver path in the module.
433 //strcpy(module->driverPath, tmpDriverPath);
434 tmpExecutablePath = 0;
435 tmpBundlePath = 0;
436
437 // Add the plist to the module.
438
439 strlcpy(module->plistAddr, (char *)kLoadAddr, length);
440 module->plistLength = length;
441
442 // Add the module to the end of the module list.
443
444 if (gModuleHead == 0)
445 gModuleHead = module;
446 else
447 gModuleTail->nextModule = module;
448 gModuleTail = module;
449
450 // Add the persionalities to the personality list.
451
452 if (personalities) personalities = personalities->tag;
453 while (personalities != 0)
454 {
455 if (gPersonalityHead == 0)
456 gPersonalityHead = personalities->tag;
457 else
458 gPersonalityTail->tagNext = personalities->tag;
459
460 gPersonalityTail = personalities->tag;
461 personalities = personalities->tagNext;
462 }
463
464 ret = 0;
465 }
466 while (0);
467
468 if ( buffer ) free( buffer );
469 if ( tmpExecutablePath ) free( tmpExecutablePath );
470 if ( tmpBundlePath ) free( tmpBundlePath );
471
472 return ret;
473}
474
475
476//==========================================================================
477// LoadMatchedModules
478
479long LoadMatchedModules( void )
480{
481 TagPtr prop;
482 ModulePtr module;
483 char *fileName, segName[32];
484 DriverInfoPtr driver;
485 long length, driverAddr, driverLength;
486 void *executableAddr = 0;
487
488
489 module = gModuleHead;
490
491 while (module != 0)
492 {
493 if (module->willLoad)
494 {
495 prop = XMLGetProperty(module->dict, kPropCFBundleExecutable);
496
497 if (prop != 0)
498 {
499 fileName = prop->string;
500 sprintf(gFileSpec, "%s%s", module->executablePath, fileName);
501 length = LoadThinFatFile(gFileSpec, &executableAddr);
502if (length == 0)
503{
504length = LoadFile(gFileSpec);
505executableAddr = (void *)kLoadAddr;
506}
507 //printf("%s length = %d addr = 0x%x\n", gFileSpec, length, driverModuleAddr); getc();
508 }
509 else
510 length = 0;
511
512 if (length != -1)
513 {
514//driverModuleAddr = (void *)kLoadAddr;
515 //if (length != 0)
516 //{
517// ThinFatFile(&driverModuleAddr, &length);
518//}
519
520 // Make make in the image area.
521
522execute_hook("LoadMatchedModules", module, &length, executableAddr, NULL, NULL, NULL);
523
524 driverLength = sizeof(DriverInfo) + module->plistLength + length + module->bundlePathLength;
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->executableAddr = (void *)(driverAddr + sizeof(DriverInfo) +
534 module->plistLength);
535 driver->executableLength = length;
536 }
537 else
538 {
539 driver->executableAddr = 0;
540 driver->executableLength = 0;
541 }
542 driver->bundlePathAddr = (void *)(driverAddr + sizeof(DriverInfo) +
543 module->plistLength + driver->executableLength);
544 driver->bundlePathLength = module->bundlePathLength;
545
546 // Save the plist, module and bundle.
547 strcpy(driver->plistAddr, module->plistAddr);
548 if (length != 0)
549 {
550 memcpy(driver->executableAddr, executableAddr, length);
551 }
552 strcpy(driver->bundlePathAddr, module->bundlePath);
553
554 // Add an entry to the memory map.
555 sprintf(segName, "Driver-%lx", (unsigned long)driver);
556 AllocateMemoryRange(segName, driverAddr, driverLength,
557 kBootDriverTypeKEXT);
558 }
559 }
560 module = module->nextModule;
561 }
562
563 return 0;
564}
565
566#if UNUSED
567//==========================================================================
568// MatchPersonalities
569
570long MatchPersonalities( void )
571{
572 /* IONameMatch support not implemented */
573 return 0;
574}
575#endif
576
577//==========================================================================
578// MatchLibraries
579
580long MatchLibraries( void )
581{
582 TagPtr prop, prop2;
583 ModulePtr module, module2;
584 long done;
585
586 do {
587 done = 1;
588 module = gModuleHead;
589
590 while (module != 0)
591 {
592 if (module->willLoad == 1)
593 {
594 prop = XMLGetProperty(module->dict, kPropOSBundleLibraries);
595 if (prop != 0)
596 {
597 prop = prop->tag;
598 while (prop != 0)
599 {
600 module2 = gModuleHead;
601 while (module2 != 0)
602 {
603 prop2 = XMLGetProperty(module2->dict, kPropCFBundleIdentifier);
604 if ((prop2 != 0) && (!strcmp(prop->string, prop2->string)))
605 {
606 if (module2->willLoad == 0) module2->willLoad = 1;
607 break;
608 }
609 module2 = module2->nextModule;
610 }
611 prop = prop->tagNext;
612 }
613 }
614 module->willLoad = 2;
615 done = 0;
616 }
617 module = module->nextModule;
618 }
619 }
620 while (!done);
621
622 return 0;
623}
624
625
626//==========================================================================
627// FindModule
628
629#if UNUSED
630static ModulePtr
631FindModule( char * name )
632{
633 ModulePtr module;
634 TagPtr prop;
635
636 module = gModuleHead;
637
638 while (module != 0)
639 {
640 prop = GetProperty(module->dict, kPropCFBundleIdentifier);
641 if ((prop != 0) && !strcmp(name, prop->string)) break;
642 module = module->nextModule;
643 }
644
645 return module;
646}
647#endif
648
649//==========================================================================
650// ParseXML
651
652static long
653ParseXML( char * buffer, ModulePtr * module, TagPtr * personalities )
654{
655long length, pos;
656TagPtr moduleDict, required;
657ModulePtr tmpModule;
658
659 pos = 0;
660
661 while (1)
662 {
663 length = XMLParseNextTag(buffer + pos, &moduleDict);
664 if (length == -1) break;
665
666 pos += length;
667
668 if (moduleDict == 0) continue;
669 if (moduleDict->type == kTagTypeDict) break;
670
671 XMLFreeTag(moduleDict);
672 }
673
674 if (length == -1) return -1;
675
676 required = XMLGetProperty(moduleDict, kPropOSBundleRequired);
677 if ( (required == 0) ||
678(required->type != kTagTypeString) ||
679!strcmp(required->string, "Safe Boot"))
680 {
681 XMLFreeTag(moduleDict);
682 return -2;
683 }
684
685 tmpModule = malloc(sizeof(Module));
686 if (tmpModule == 0)
687 {
688 XMLFreeTag(moduleDict);
689 return -1;
690 }
691 tmpModule->dict = moduleDict;
692
693 // For now, load any module that has OSBundleRequired != "Safe Boot".
694
695 tmpModule->willLoad = 1;
696
697 *module = tmpModule;
698
699 // Get the personalities.
700
701 *personalities = XMLGetProperty(moduleDict, kPropIOKitPersonalities);
702
703 return 0;
704}
705
706
707long
708DecodeKernel(void *binary, entry_t *rentry, char **raddr, int *rsize)
709{
710 long ret;
711 compressed_kernel_header * kernel_header = (compressed_kernel_header *) binary;
712 u_int32_t uncompressed_size, size;
713 void *buffer;
714unsigned long len;
715
716#if 0
717 printf("kernel header:\n");
718 printf("signature: 0x%x\n", kernel_header->signature);
719 printf("compress_type: 0x%x\n", kernel_header->compress_type);
720 printf("adler32: 0x%x\n", kernel_header->adler32);
721 printf("uncompressed_size: 0x%x\n", kernel_header->uncompressed_size);
722 printf("compressed_size: 0x%x\n", kernel_header->compressed_size);
723 getc();
724#endif
725
726
727 if (kernel_header->signature == OSSwapBigToHostConstInt32('comp')) {
728 if (kernel_header->compress_type != OSSwapBigToHostConstInt32('lzss')) {
729 error("kernel compression is bad\n");
730 return -1;
731 }
732
733 uncompressed_size = OSSwapBigToHostInt32(kernel_header->uncompressed_size);
734 binary = buffer = malloc(uncompressed_size);
735
736 size = decompress_lzss((u_int8_t *) binary, &kernel_header->data[0],
737 OSSwapBigToHostInt32(kernel_header->compressed_size));
738 if (uncompressed_size != size) {
739 error("size mismatch from lzss: %x\n", size);
740 return -1;
741 }
742 if (OSSwapBigToHostInt32(kernel_header->adler32) !=
743 local_adler32(binary, uncompressed_size)) {
744 printf("adler mismatch\n");
745 return -1;
746 }
747if (((gBootMode & kBootModeSafe) == 0) && (gBootKernelCacheFile[0] != '\0') && gMacOSVersion[3] == '7')
748bootInfo->adler32 = kernel_header->adler32;
749 }
750
751ret = ThinFatFile(&binary, &len);
752if (ret == 0 && len == 0 && archCpuType==CPU_TYPE_X86_64)
753{
754archCpuType=CPU_TYPE_I386;
755ret = ThinFatFile(&binary, &len);
756}
757
758ret = DecodeMachO(binary, rentry, raddr, rsize);
759
760if (ret<0 && archCpuType==CPU_TYPE_X86_64)
761{
762archCpuType=CPU_TYPE_I386;
763ret = DecodeMachO(binary, rentry, raddr, rsize);
764}
765
766return ret;
767}

Archive Download this file

Revision: 789