]> git.saurik.com Git - apple/boot.git/blame - i386/boot2/drivers.c
boot-111.1.tar.gz
[apple/boot.git] / i386 / boot2 / drivers.c
CommitLineData
47b0a8bd
A
1/*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
4f6e3300
A
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.
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
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 {
162 NetLoadDrivers(dirSpec);
163 }
f083c6c3 164 else if ( gBootFileType == kBlockDeviceType )
47b0a8bd
A
165 {
166 strcpy(gExtensionsSpec, dirSpec);
167 strcat(gExtensionsSpec, "System/Library/");
168 FileLoadDrivers(gExtensionsSpec, 0);
169 }
47b0a8bd
A
170 else
171 {
172 return 0;
173 }
47b0a8bd
A
174
175 MatchPersonalities();
75b89a82 176
47b0a8bd
A
177 MatchLibraries();
178
179 LoadMatchedModules();
180
181 return 0;
182}
183
184//==========================================================================
185// FileLoadDrivers
186
187static long
188FileLoadDrivers( char * dirSpec, long plugin )
189{
75b89a82
A
190 long ret, length, index, flags, time, bundleType;
191 const char * name;
47b0a8bd
A
192
193 if ( !plugin )
194 {
195 long time2;
196
197 ret = GetFileInfo(dirSpec, "Extensions.mkext", &flags, &time);
75b89a82 198 if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeFlat))
47b0a8bd
A
199 {
200 ret = GetFileInfo(dirSpec, "Extensions", &flags, &time2);
75b89a82
A
201 if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeDirectory) ||
202 (((gBootMode & kBootModeSafe) == 0) && (time > time2)))
47b0a8bd
A
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
47b0a8bd
A
215 index = 0;
216 while (1) {
75b89a82 217 ret = GetDirEntry(dirSpec, &index, &name, &flags, &time);
47b0a8bd
A
218 if (ret == -1) break;
219
220 // Make sure this is a directory.
75b89a82 221 if ((flags & kFileTypeMask) != kFileTypeDirectory) continue;
47b0a8bd
A
222
223 // Make sure this is a kext.
224 length = strlen(name);
225 if (strcmp(name + length - 5, ".kext")) continue;
226
75b89a82
A
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
47b0a8bd 236 if (!plugin)
75b89a82
A
237 sprintf(gDriverSpec, "%s/%s/%sPlugIns", dirSpec, gFileName,
238 (bundleType == kCFBundleType2) ? "Contents/" : "");
47b0a8bd 239
75b89a82 240 ret = LoadDriverPList(dirSpec, gFileName, bundleType);
47b0a8bd
A
241 if (ret != 0)
242 {
f083c6c3 243 //printf("LoadDrivers: failed for '%s'/'%s'\n", dirSpec, gFileName);
47b0a8bd
A
244 }
245
246 if (!plugin)
247 ret = FileLoadDrivers(gDriverSpec, 1);
248 }
249
47b0a8bd
A
250 return 0;
251}
252
253//==========================================================================
254//
255
256static long
257NetLoadDrivers( char * dirSpec )
258{
259 long tries;
260
f083c6c3 261#if NODEF
47b0a8bd
A
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
f083c6c3 275 sprintf(gDriverSpec, "%s%s.mkext", dirSpec, bootArgs->bootFile);
47b0a8bd
A
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
292static long
293LoadDriverMKext( char * fileSpec )
294{
f083c6c3
A
295 unsigned long driversAddr, driversLength;
296 long length;
47b0a8bd
A
297 char segName[32];
298 DriversPackage * package = (DriversPackage *)kLoadAddr;
299
f083c6c3 300#define GetPackageElement(e) OSSwapBigToHostInt32(package->e)
47b0a8bd
A
301
302 // Load the MKext.
f083c6c3
A
303 length = LoadFile(fileSpec);
304 if (length == -1) return -1;
305
306 ThinFatFile((void **)&package, &length);
47b0a8bd
A
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);
f083c6c3 321
47b0a8bd 322 // Copy the MKext.
f083c6c3 323 memcpy((void *)driversAddr, (void *)package, driversLength);
47b0a8bd
A
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
336static long
75b89a82 337LoadDriverPList( char * dirSpec, char * name, long bundleType )
47b0a8bd
A
338{
339 long length, driverPathLength;
340 ModulePtr module;
341 TagPtr personalities;
342 char * buffer = 0;
f083c6c3 343 char * tmpDriverPath = 0;
47b0a8bd
A
344 long ret = -1;
345
346 do {
347 // Save the driver path.
348
75b89a82
A
349 sprintf(gFileSpec, "%s/%s/%s", dirSpec, name,
350 (bundleType == kCFBundleType2) ? "Contents/MacOS/" : "");
f083c6c3 351 driverPathLength = strlen(gFileSpec) + 1;
47b0a8bd 352
f083c6c3 353 tmpDriverPath = malloc(driverPathLength);
47b0a8bd
A
354 if (tmpDriverPath == 0) break;
355
356 strcpy(tmpDriverPath, gFileSpec);
357
358 // Construct the file spec to the plist, then load it.
359
75b89a82
A
360 sprintf(gFileSpec, "%s/%s/%sInfo.plist", dirSpec, name,
361 (bundleType == kCFBundleType2) ? "Contents/" : "");
47b0a8bd
A
362
363 length = LoadFile(gFileSpec);
364 if (length == -1) break;
365
f083c6c3
A
366 length = length + 1;
367 buffer = malloc(length);
47b0a8bd
A
368 if (buffer == 0) break;
369
f083c6c3 370 strlcpy(buffer, (char *)kLoadAddr, length);
47b0a8bd
A
371
372 // Parse the plist.
373
374 ret = ParseXML(buffer, &module, &personalities);
f083c6c3 375 if (ret != 0) { break; }
47b0a8bd
A
376
377 // Allocate memory for the driver path and the plist.
378
f083c6c3
A
379 module->driverPath = tmpDriverPath;
380 module->plistAddr = (void *)malloc(length);
47b0a8bd
A
381
382 if ((module->driverPath == 0) || (module->plistAddr == 0))
383 break;
384
385 // Save the driver path in the module.
f083c6c3
A
386 //strcpy(module->driverPath, tmpDriverPath);
387 tmpDriverPath = 0;
47b0a8bd
A
388
389 // Add the plist to the module.
390
f083c6c3
A
391 strlcpy(module->plistAddr, (char *)kLoadAddr, length);
392 module->plistLength = length;
47b0a8bd
A
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
f083c6c3
A
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
433static void
434ThinFatFile(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
47b0a8bd
A
474//==========================================================================
475// LoadMatchedModules
476
477static long
478LoadMatchedModules( 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 {
f083c6c3
A
492 prop = XMLGetProperty(module->dict, kPropCFBundleExecutable);
493
47b0a8bd
A
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 {
f083c6c3
A
505 void *driverModuleAddr = (void *)kLoadAddr;
506 if (length != 0)
507 {
508 ThinFatFile(&driverModuleAddr, &length);
509 }
510
47b0a8bd
A
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 {
f083c6c3 535 memcpy(driver->moduleAddr, driverModuleAddr, length);
47b0a8bd
A
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
553static long
554MatchPersonalities( void )
555{
f083c6c3 556 /* IONameMatch support not implemented */
47b0a8bd
A
557 return 0;
558}
559
560//==========================================================================
561// MatchLibraries
562
563static long
564MatchLibraries( 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 {
f083c6c3 578 prop = XMLGetProperty(module->dict, kPropOSBundleLibraries);
47b0a8bd
A
579 if (prop != 0)
580 {
581 prop = prop->tag;
582 while (prop != 0)
583 {
584 module2 = gModuleHead;
585 while (module2 != 0)
586 {
f083c6c3 587 prop2 = XMLGetProperty(module2->dict, kPropCFBundleIdentifier);
47b0a8bd
A
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
47b0a8bd
A
609
610//==========================================================================
611// FindModule
612
613#if NOTDEF
614static ModulePtr
615FindModule( 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
636static long
637ParseXML( 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 {
f083c6c3 647 length = XMLParseNextTag(buffer + pos, &moduleDict);
47b0a8bd
A
648 if (length == -1) break;
649
650 pos += length;
651
652 if (moduleDict == 0) continue;
653 if (moduleDict->type == kTagTypeDict) break;
654
f083c6c3 655 XMLFreeTag(moduleDict);
47b0a8bd
A
656 }
657
658 if (length == -1) return -1;
659
f083c6c3 660 required = XMLGetProperty(moduleDict, kPropOSBundleRequired);
47b0a8bd
A
661 if ( (required == 0) ||
662 (required->type != kTagTypeString) ||
663 !strcmp(required->string, "Safe Boot"))
664 {
f083c6c3 665 XMLFreeTag(moduleDict);
47b0a8bd
A
666 return -2;
667 }
668
f083c6c3 669 tmpModule = (ModulePtr)malloc(sizeof(Module));
47b0a8bd
A
670 if (tmpModule == 0)
671 {
f083c6c3 672 XMLFreeTag(moduleDict);
47b0a8bd
A
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
f083c6c3 685 *personalities = XMLGetProperty(moduleDict, kPropIOKitPersonalities);
47b0a8bd
A
686
687 return 0;
688}
689
f083c6c3
A
690#if NOTDEF
691static char gPlatformName[64];
692#endif
47b0a8bd 693
f083c6c3
A
694long
695DecodeKernel(void *binary, entry_t *rentry, char **raddr, int *rsize)
47b0a8bd 696{
f083c6c3
A
697 long ret;
698 compressed_kernel_header * kernel_header = (compressed_kernel_header *) binary;
699 u_int32_t uncompressed_size, size;
700 void *buffer;
47b0a8bd 701
f083c6c3
A
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
47b0a8bd 711
f083c6c3
A
712 if (kernel_header->signature == OSSwapBigToHostConstInt32('comp')) {
713 if (kernel_header->compress_type != OSSwapBigToHostConstInt32('lzss')) {
714 error("kernel compression is bad\n");
47b0a8bd
A
715 return -1;
716 }
f083c6c3
A
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
47b0a8bd 723
f083c6c3
A
724 uncompressed_size = OSSwapBigToHostInt32(kernel_header->uncompressed_size);
725 binary = buffer = malloc(uncompressed_size);
47b0a8bd 726
f083c6c3
A
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;
47b0a8bd 737 }
47b0a8bd
A
738 }
739
f083c6c3 740 ThinFatFile(&binary, 0);
47b0a8bd 741
f083c6c3 742 ret = DecodeMachO(binary, rentry, raddr, rsize);
47b0a8bd 743
f083c6c3 744 return ret;
47b0a8bd 745}