]> git.saurik.com Git - apple/boot.git/blame - i386/boot2/drivers.c
boot-132.tar.gz
[apple/boot.git] / i386 / boot2 / drivers.c
CommitLineData
47b0a8bd 1/*
57c72a9a 2 * Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved.
47b0a8bd
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
57c72a9a 6 * Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights
4f6e3300
A
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
57c72a9a 9 * Source License Version 2.0 (the 'License'). You may not use this file
4f6e3300
A
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.
47b0a8bd
A
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,
4f6e3300
A
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
57c72a9a 20 * under the License.
47b0a8bd
A
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
f083c6c3
A
32#include <mach-o/fat.h>
33#include <libkern/OSByteOrder.h>
34#include <mach/machine.h>
35
75b89a82 36#include "sl.h"
47b0a8bd 37#include "boot.h"
f083c6c3
A
38#include "bootstruct.h"
39#include "xml.h"
47b0a8bd
A
40
41struct Module {
42 struct Module *nextModule;
43 long willLoad;
44 TagPtr dict;
45 char *plistAddr;
46 long plistLength;
47 char *driverPath;
48};
49typedef struct Module Module, *ModulePtr;
50
51struct DriverInfo {
52 char *plistAddr;
53 long plistLength;
54 void *moduleAddr;
55 long moduleLength;
56};
57typedef struct DriverInfo DriverInfo, *DriverInfoPtr;
58
59#define kDriverPackageSignature1 'MKXT'
60#define kDriverPackageSignature2 'MOSX'
61
62struct 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};
72typedef struct DriversPackage DriversPackage;
73
75b89a82
A
74enum {
75 kCFBundleType2,
76 kCFBundleType3
77};
78
f083c6c3
A
79static unsigned long Alder32( unsigned char * buffer, long length );
80
47b0a8bd
A
81static long FileLoadDrivers(char *dirSpec, long plugin);
82static long NetLoadDrivers(char *dirSpec);
83static long LoadDriverMKext(char *fileSpec);
75b89a82 84static long LoadDriverPList(char *dirSpec, char *name, long bundleType);
47b0a8bd
A
85static long LoadMatchedModules(void);
86static long MatchPersonalities(void);
87static long MatchLibraries(void);
f083c6c3
A
88#ifdef NOTDEF
89static ModulePtr FindModule(char *name);
90static void ThinFatFile(void **loadAddrP, unsigned long *lengthP);
91#endif
47b0a8bd 92static long ParseXML(char *buffer, ModulePtr *module, TagPtr *personalities);
f083c6c3 93static long InitDriverSupport(void);
47b0a8bd
A
94
95static ModulePtr gModuleHead, gModuleTail;
96static TagPtr gPersonalityHead, gPersonalityTail;
97static char * gExtensionsSpec;
98static char * gDriverSpec;
99static char * gFileSpec;
75b89a82
A
100static char * gTempSpec;
101static char * gFileName;
47b0a8bd 102
47b0a8bd
A
103
104static unsigned long
105Alder32( 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
f083c6c3
A
133
134//==========================================================================
135// InitDriverSupport
136
137static long
138InitDriverSupport( 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
47b0a8bd
A
152//==========================================================================
153// LoadDrivers
154
155long LoadDrivers( char * dirSpec )
156{
157 if ( InitDriverSupport() != 0 )
158 return 0;
159
160 if ( gBootFileType == kNetworkDeviceType )
161 {
bba600dd
A
162 if (NetLoadDrivers(dirSpec) != 0) {
163 error("Could not load drivers from the network\n");
164 return -1;
165 }
47b0a8bd 166 }
f083c6c3 167 else if ( gBootFileType == kBlockDeviceType )
47b0a8bd 168 {
57c72a9a
A
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 }
47b0a8bd 184 }
47b0a8bd
A
185 else
186 {
187 return 0;
188 }
47b0a8bd
A
189
190 MatchPersonalities();
75b89a82 191
47b0a8bd
A
192 MatchLibraries();
193
194 LoadMatchedModules();
195
196 return 0;
197}
198
199//==========================================================================
200// FileLoadDrivers
201
202static long
203FileLoadDrivers( char * dirSpec, long plugin )
204{
75b89a82
A
205 long ret, length, index, flags, time, bundleType;
206 const char * name;
47b0a8bd
A
207
208 if ( !plugin )
209 {
210 long time2;
211
212 ret = GetFileInfo(dirSpec, "Extensions.mkext", &flags, &time);
75b89a82 213 if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeFlat))
47b0a8bd
A
214 {
215 ret = GetFileInfo(dirSpec, "Extensions", &flags, &time2);
75b89a82 216 if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeDirectory) ||
57c72a9a 217 (((gBootMode & kBootModeSafe) == 0) && (time == (time2 + 1))))
47b0a8bd
A
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
47b0a8bd
A
230 index = 0;
231 while (1) {
75b89a82 232 ret = GetDirEntry(dirSpec, &index, &name, &flags, &time);
47b0a8bd
A
233 if (ret == -1) break;
234
235 // Make sure this is a directory.
75b89a82 236 if ((flags & kFileTypeMask) != kFileTypeDirectory) continue;
47b0a8bd
A
237
238 // Make sure this is a kext.
239 length = strlen(name);
240 if (strcmp(name + length - 5, ".kext")) continue;
241
75b89a82
A
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
47b0a8bd 251 if (!plugin)
75b89a82
A
252 sprintf(gDriverSpec, "%s/%s/%sPlugIns", dirSpec, gFileName,
253 (bundleType == kCFBundleType2) ? "Contents/" : "");
47b0a8bd 254
75b89a82 255 ret = LoadDriverPList(dirSpec, gFileName, bundleType);
47b0a8bd
A
256 if (ret != 0)
257 {
f083c6c3 258 //printf("LoadDrivers: failed for '%s'/'%s'\n", dirSpec, gFileName);
47b0a8bd
A
259 }
260
261 if (!plugin)
262 ret = FileLoadDrivers(gDriverSpec, 1);
263 }
264
47b0a8bd
A
265 return 0;
266}
267
268//==========================================================================
269//
270
271static long
272NetLoadDrivers( char * dirSpec )
273{
274 long tries;
275
f083c6c3 276#if NODEF
47b0a8bd
A
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
bba600dd 290 sprintf(gDriverSpec, "%s%s.mkext", dirSpec, bootInfo->bootFile);
47b0a8bd
A
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
307static long
308LoadDriverMKext( char * fileSpec )
309{
f083c6c3
A
310 unsigned long driversAddr, driversLength;
311 long length;
47b0a8bd 312 char segName[32];
bba600dd 313 DriversPackage * package;
47b0a8bd 314
f083c6c3 315#define GetPackageElement(e) OSSwapBigToHostInt32(package->e)
47b0a8bd
A
316
317 // Load the MKext.
bba600dd 318 length = LoadThinFatFile(fileSpec, (void **)&package);
f083c6c3
A
319 if (length == -1) return -1;
320
47b0a8bd
A
321 // Verify the MKext.
322 if (( GetPackageElement(signature1) != kDriverPackageSignature1) ||
323 ( GetPackageElement(signature2) != kDriverPackageSignature2) ||
324 ( GetPackageElement(length) > kLoadSize ) ||
325 ( GetPackageElement(alder32) !=
bba600dd 326 Alder32((unsigned char *)&package->version, GetPackageElement(length) - 0x10) ) )
47b0a8bd
A
327 {
328 return -1;
329 }
330
331 // Make space for the MKext.
332 driversLength = GetPackageElement(length);
333 driversAddr = AllocateKernelMemory(driversLength);
f083c6c3 334
47b0a8bd 335 // Copy the MKext.
f083c6c3 336 memcpy((void *)driversAddr, (void *)package, driversLength);
47b0a8bd
A
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
349static long
75b89a82 350LoadDriverPList( char * dirSpec, char * name, long bundleType )
47b0a8bd
A
351{
352 long length, driverPathLength;
353 ModulePtr module;
354 TagPtr personalities;
355 char * buffer = 0;
f083c6c3 356 char * tmpDriverPath = 0;
47b0a8bd
A
357 long ret = -1;
358
359 do {
360 // Save the driver path.
361
75b89a82
A
362 sprintf(gFileSpec, "%s/%s/%s", dirSpec, name,
363 (bundleType == kCFBundleType2) ? "Contents/MacOS/" : "");
f083c6c3 364 driverPathLength = strlen(gFileSpec) + 1;
47b0a8bd 365
f083c6c3 366 tmpDriverPath = malloc(driverPathLength);
47b0a8bd
A
367 if (tmpDriverPath == 0) break;
368
369 strcpy(tmpDriverPath, gFileSpec);
370
371 // Construct the file spec to the plist, then load it.
372
75b89a82
A
373 sprintf(gFileSpec, "%s/%s/%sInfo.plist", dirSpec, name,
374 (bundleType == kCFBundleType2) ? "Contents/" : "");
47b0a8bd
A
375
376 length = LoadFile(gFileSpec);
377 if (length == -1) break;
378
f083c6c3
A
379 length = length + 1;
380 buffer = malloc(length);
47b0a8bd
A
381 if (buffer == 0) break;
382
f083c6c3 383 strlcpy(buffer, (char *)kLoadAddr, length);
47b0a8bd
A
384
385 // Parse the plist.
386
387 ret = ParseXML(buffer, &module, &personalities);
f083c6c3 388 if (ret != 0) { break; }
47b0a8bd
A
389
390 // Allocate memory for the driver path and the plist.
391
f083c6c3
A
392 module->driverPath = tmpDriverPath;
393 module->plistAddr = (void *)malloc(length);
47b0a8bd
A
394
395 if ((module->driverPath == 0) || (module->plistAddr == 0))
396 break;
397
398 // Save the driver path in the module.
f083c6c3
A
399 //strcpy(module->driverPath, tmpDriverPath);
400 tmpDriverPath = 0;
47b0a8bd
A
401
402 // Add the plist to the module.
403
f083c6c3
A
404 strlcpy(module->plistAddr, (char *)kLoadAddr, length);
405 module->plistLength = length;
47b0a8bd
A
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
f083c6c3 439
47b0a8bd
A
440//==========================================================================
441// LoadMatchedModules
442
443static long
444LoadMatchedModules( void )
445{
446 TagPtr prop;
447 ModulePtr module;
448 char *fileName, segName[32];
449 DriverInfoPtr driver;
450 long length, driverAddr, driverLength;
bba600dd
A
451 void *driverModuleAddr = 0;
452
47b0a8bd
A
453
454 module = gModuleHead;
455
456 while (module != 0)
457 {
458 if (module->willLoad)
459 {
f083c6c3
A
460 prop = XMLGetProperty(module->dict, kPropCFBundleExecutable);
461
47b0a8bd
A
462 if (prop != 0)
463 {
464 fileName = prop->string;
465 sprintf(gFileSpec, "%s%s", module->driverPath, fileName);
bba600dd
A
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();
47b0a8bd
A
470 }
471 else
472 length = 0;
473
474 if (length != -1)
475 {
bba600dd
A
476 //driverModuleAddr = (void *)kLoadAddr;
477 //if (length != 0)
478 //{
479 // ThinFatFile(&driverModuleAddr, &length);
480 //}
f083c6c3 481
47b0a8bd
A
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 {
f083c6c3 506 memcpy(driver->moduleAddr, driverModuleAddr, length);
47b0a8bd
A
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
524static long
525MatchPersonalities( void )
526{
f083c6c3 527 /* IONameMatch support not implemented */
47b0a8bd
A
528 return 0;
529}
530
531//==========================================================================
532// MatchLibraries
533
534static long
535MatchLibraries( 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 {
f083c6c3 549 prop = XMLGetProperty(module->dict, kPropOSBundleLibraries);
47b0a8bd
A
550 if (prop != 0)
551 {
552 prop = prop->tag;
553 while (prop != 0)
554 {
555 module2 = gModuleHead;
556 while (module2 != 0)
557 {
f083c6c3 558 prop2 = XMLGetProperty(module2->dict, kPropCFBundleIdentifier);
47b0a8bd
A
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
47b0a8bd
A
580
581//==========================================================================
582// FindModule
583
584#if NOTDEF
585static ModulePtr
586FindModule( 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
607static long
608ParseXML( 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 {
f083c6c3 618 length = XMLParseNextTag(buffer + pos, &moduleDict);
47b0a8bd
A
619 if (length == -1) break;
620
621 pos += length;
622
623 if (moduleDict == 0) continue;
624 if (moduleDict->type == kTagTypeDict) break;
625
f083c6c3 626 XMLFreeTag(moduleDict);
47b0a8bd
A
627 }
628
629 if (length == -1) return -1;
630
f083c6c3 631 required = XMLGetProperty(moduleDict, kPropOSBundleRequired);
47b0a8bd
A
632 if ( (required == 0) ||
633 (required->type != kTagTypeString) ||
634 !strcmp(required->string, "Safe Boot"))
635 {
f083c6c3 636 XMLFreeTag(moduleDict);
47b0a8bd
A
637 return -2;
638 }
639
f083c6c3 640 tmpModule = (ModulePtr)malloc(sizeof(Module));
47b0a8bd
A
641 if (tmpModule == 0)
642 {
f083c6c3 643 XMLFreeTag(moduleDict);
47b0a8bd
A
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
f083c6c3 656 *personalities = XMLGetProperty(moduleDict, kPropIOKitPersonalities);
47b0a8bd
A
657
658 return 0;
659}
660
f083c6c3
A
661#if NOTDEF
662static char gPlatformName[64];
663#endif
47b0a8bd 664
f083c6c3
A
665long
666DecodeKernel(void *binary, entry_t *rentry, char **raddr, int *rsize)
47b0a8bd 667{
f083c6c3
A
668 long ret;
669 compressed_kernel_header * kernel_header = (compressed_kernel_header *) binary;
670 u_int32_t uncompressed_size, size;
671 void *buffer;
47b0a8bd 672
f083c6c3
A
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
47b0a8bd 682
f083c6c3
A
683 if (kernel_header->signature == OSSwapBigToHostConstInt32('comp')) {
684 if (kernel_header->compress_type != OSSwapBigToHostConstInt32('lzss')) {
685 error("kernel compression is bad\n");
47b0a8bd
A
686 return -1;
687 }
f083c6c3
A
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
47b0a8bd 694
f083c6c3
A
695 uncompressed_size = OSSwapBigToHostInt32(kernel_header->uncompressed_size);
696 binary = buffer = malloc(uncompressed_size);
47b0a8bd 697
f083c6c3
A
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;
47b0a8bd 708 }
47b0a8bd
A
709 }
710
f083c6c3 711 ThinFatFile(&binary, 0);
47b0a8bd 712
f083c6c3 713 ret = DecodeMachO(binary, rentry, raddr, rsize);
47b0a8bd 714
f083c6c3 715 return ret;
47b0a8bd 716}