]> git.saurik.com Git - apple/xnu.git/blob - libsa/catalogue.cpp
3cb88a1e389c1918b6620cba5d81c9054fc6eb40
[apple/xnu.git] / libsa / catalogue.cpp
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
14 * agreement.
15 *
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
18 * file.
19 *
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
27 *
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
29 */
30 #include <libkern/c++/OSContainers.h>
31 #include <IOKit/IODeviceTreeSupport.h>
32 #include <IOKit/IORegistryEntry.h>
33 #include <IOKit/IOCatalogue.h>
34 #include <libkern/c++/OSUnserialize.h>
35 #include <libkern/OSByteOrder.h>
36 #include <libsa/catalogue.h>
37
38 extern "C" {
39 #include <machine/machine_routines.h>
40 #include <mach/host_info.h>
41 #include <mach/kmod.h>
42 #include <libsa/mkext.h>
43 #include <libsa/vers_rsrc.h>
44 #include <mach-o/loader.h>
45 };
46
47 #include <IOKit/IOLib.h>
48
49 #include <IOKit/assert.h>
50
51 extern "C" {
52 extern void IODTFreeLoaderInfo( char *key, void *infoAddr, int infoSize );
53 // extern kern_return_t host_info(host_t host,
54 // host_flavor_t flavor,
55 // host_info_t info,
56 // mach_msg_type_number_t *count);
57 extern int grade_binary(cpu_type_t exectype, cpu_subtype_t execsubtype);
58 // Return the address of the named Mach-O segment from the currently
59 // executing 32 bit kernel, or NULL.
60 extern struct segment_command *getsegbyname(char *seg_name);
61 // Return the address of the named section from the named Mach-O segment
62 // from the currently executing 32 bit kernel, or NULL.
63 extern struct section *getsectbyname(char *segname, char *sectname);
64 };
65
66 #define LOG_DELAY()
67
68 #if 0
69 #define VTYELLOW "\033[33m"
70 #define VTRESET "\033[0m"
71 #else
72 #define VTYELLOW ""
73 #define VTRESET ""
74 #endif
75
76 /*********************************************************************
77 *********************************************************************/
78 static OSDictionary * gStartupExtensions = 0;
79 static OSArray * gBootLoaderObjects = 0;
80 extern OSArray * gIOPrelinkedModules;
81
82 OSDictionary * getStartupExtensions(void) {
83 if (gStartupExtensions) {
84 return gStartupExtensions;
85 }
86 gStartupExtensions = OSDictionary::withCapacity(1);
87 assert (gStartupExtensions);
88
89 return gStartupExtensions;
90 }
91
92 /* This array holds objects that are needed to be held around during
93 * boot before kextd starts up. Currently it contains OSData objects
94 * copied from OF entries for mkext archives in device ROMs. Because
95 * the Device Tree support code dumps these after initially handing
96 * them to us, we have to be able to clean them up later.
97 */
98 OSArray * getBootLoaderObjects(void) {
99 if (gBootLoaderObjects) {
100 return gBootLoaderObjects;
101 }
102 gBootLoaderObjects = OSArray::withCapacity(1);
103 assert (gBootLoaderObjects);
104
105 return gBootLoaderObjects;
106 }
107
108 /*********************************************************************
109 * This function checks that a driver dict has all the required
110 * entries and does a little bit of value checking too.
111 *
112 * index is nonnegative if the index of an entry from an mkext
113 * archive.
114 *********************************************************************/
115 bool validateExtensionDict(OSDictionary * extension, int index) {
116
117 bool result = true;
118 bool not_a_dict = false;
119 bool id_missing = false;
120 bool is_kernel_resource = false;
121 bool has_executable = false;
122 OSString * bundleIdentifier = NULL; // do not release
123 OSObject * rawValue = NULL; // do not release
124 OSString * stringValue = NULL; // do not release
125 OSBoolean * booleanValue = NULL; // do not release
126 OSDictionary * personalities = NULL; // do not release
127 OSDictionary * libraries = NULL; // do not release
128 OSCollectionIterator * keyIterator = NULL; // must release
129 OSString * key = NULL; // do not release
130 VERS_version vers;
131 VERS_version compatible_vers;
132
133 // Info dict is a dictionary
134 if (!OSDynamicCast(OSDictionary, extension)) {
135 not_a_dict = true;
136 result = false;
137 goto finish;
138 }
139
140 // CFBundleIdentifier is a string - REQUIRED
141 bundleIdentifier = OSDynamicCast(OSString,
142 extension->getObject("CFBundleIdentifier"));
143 if (!bundleIdentifier) {
144 id_missing = true;
145 result = false;
146 goto finish;
147 }
148
149 // Length of CFBundleIdentifier is not >= KMOD_MAX_NAME
150 if (bundleIdentifier->getLength() >= KMOD_MAX_NAME) {
151 result = false;
152 goto finish;
153 }
154
155 // CFBundlePackageType is "KEXT" - REQUIRED
156 stringValue = OSDynamicCast(OSString,
157 extension->getObject("CFBundlePackageType"));
158 if (!stringValue) {
159 result = false;
160 goto finish;
161 }
162 if (!stringValue->isEqualTo("KEXT")) {
163 result = false;
164 goto finish;
165 }
166
167 // CFBundleVersion is a string - REQUIRED
168 stringValue = OSDynamicCast(OSString,
169 extension->getObject("CFBundleVersion"));
170 if (!stringValue) {
171 result = false;
172 goto finish;
173 }
174 // CFBundleVersion is of valid form
175 vers = VERS_parse_string(stringValue->getCStringNoCopy());
176 if (vers < 0) {
177 result = false;
178 goto finish;
179 }
180
181 // OSBundleCompatibleVersion is a string - OPTIONAL
182 rawValue = extension->getObject("OSBundleCompatibleVersion");
183 if (rawValue) {
184 stringValue = OSDynamicCast(OSString, rawValue);
185 if (!stringValue) {
186 result = false;
187 goto finish;
188 }
189
190 // OSBundleCompatibleVersion is of valid form
191 compatible_vers = VERS_parse_string(stringValue->getCStringNoCopy());
192 if (compatible_vers < 0) {
193 result = false;
194 goto finish;
195 }
196
197 // OSBundleCompatibleVersion <= CFBundleVersion
198 if (compatible_vers > vers) {
199 result = false;
200 goto finish;
201 }
202 }
203
204 // CFBundleExecutable is a string - OPTIONAL
205 rawValue = extension->getObject("CFBundleExecutable");
206 if (rawValue) {
207 stringValue = OSDynamicCast(OSString, rawValue);
208 if (!stringValue || stringValue->getLength() == 0) {
209 result = false;
210 goto finish;
211 }
212 has_executable = true;
213 }
214
215 // OSKernelResource is a boolean value - OPTIONAL
216 rawValue = extension->getObject("OSKernelResource");
217 if (rawValue) {
218 booleanValue = OSDynamicCast(OSBoolean, rawValue);
219 if (!booleanValue) {
220 result = false;
221 goto finish;
222 }
223 is_kernel_resource = booleanValue->isTrue();
224 }
225
226 // IOKitPersonalities is a dictionary - OPTIONAL
227 rawValue = extension->getObject("IOKitPersonalities");
228 if (rawValue) {
229 personalities = OSDynamicCast(OSDictionary, rawValue);
230 if (!personalities) {
231 result = false;
232 goto finish;
233 }
234
235 keyIterator = OSCollectionIterator::withCollection(personalities);
236 if (!keyIterator) {
237 IOLog("Error: Failed to allocate iterator for personalities.\n");
238 LOG_DELAY();
239 result = false;
240 goto finish;
241 }
242
243 while ((key = OSDynamicCast(OSString, keyIterator->getNextObject()))) {
244 OSDictionary * personality = NULL; // do not release
245
246 // Each personality is a dictionary
247 personality = OSDynamicCast(OSDictionary,
248 personalities->getObject(key));
249 if (!personality) {
250 result = false;
251 goto finish;
252 }
253
254 // IOClass exists as a string - REQUIRED
255 if (!OSDynamicCast(OSString, personality->getObject("IOClass"))) {
256 result = false;
257 goto finish;
258 }
259
260 // IOProviderClass exists as a string - REQUIRED
261 if (!OSDynamicCast(OSString,
262 personality->getObject("IOProviderClass"))) {
263
264 result = false;
265 goto finish;
266 }
267
268 // CFBundleIdentifier is a string - OPTIONAL - INSERT IF ABSENT!
269 rawValue = personality->getObject("CFBundleIdentifier");
270 if (!rawValue) {
271 personality->setObject("CFBundleIdentifier", bundleIdentifier);
272 } else {
273 OSString * personalityID = NULL; // do not release
274 personalityID = OSDynamicCast(OSString, rawValue);
275 if (!personalityID) {
276 result = false;
277 goto finish;
278 } else {
279 // Length of CFBundleIdentifier is not >= KMOD_MAX_NAME
280 if (personalityID->getLength() >= KMOD_MAX_NAME) {
281 result = false;
282 goto finish;
283 }
284 }
285 }
286
287 // IOKitDebug is a number - OPTIONAL
288 rawValue = personality->getObject("IOKitDebug");
289 if (rawValue && !OSDynamicCast(OSNumber, rawValue)) {
290 result = false;
291 goto finish;
292 }
293 }
294
295 keyIterator->release();
296 keyIterator = NULL;
297 }
298
299
300 // OSBundleLibraries is a dictionary - REQUIRED if
301 // not kernel resource & has executable
302 //
303 rawValue = extension->getObject("OSBundleLibraries");
304 if (!rawValue && !is_kernel_resource && has_executable) {
305 result = false;
306 goto finish;
307 }
308
309 if (rawValue) {
310 libraries = OSDynamicCast(OSDictionary, rawValue);
311 if (!libraries) {
312 result = false;
313 goto finish;
314 }
315
316 keyIterator = OSCollectionIterator::withCollection(libraries);
317 if (!keyIterator) {
318 IOLog("Error: Failed to allocate iterator for libraries.\n");
319 LOG_DELAY();
320 result = false;
321 goto finish;
322 }
323
324 while ((key = OSDynamicCast(OSString,
325 keyIterator->getNextObject()))) {
326
327 OSString * libraryVersion = NULL; // do not release
328
329 // Each key's length is not >= KMOD_MAX_NAME
330 if (key->getLength() >= KMOD_MAX_NAME) {
331 result = false;
332 goto finish;
333 }
334
335 libraryVersion = OSDynamicCast(OSString,
336 libraries->getObject(key));
337 if (!libraryVersion) {
338 result = false;
339 goto finish;
340 }
341
342 // Each value is a valid version string
343 vers = VERS_parse_string(libraryVersion->getCStringNoCopy());
344 if (vers < 0) {
345 result = false;
346 goto finish;
347 }
348 }
349
350 keyIterator->release();
351 keyIterator = NULL;
352 }
353
354 // OSBundleRequired is a legal value - *not* required at boot time
355 // so we can do install CDs and the like with mkext files containing
356 // all normally-used drivers.
357 rawValue = extension->getObject("OSBundleRequired");
358 if (rawValue) {
359 stringValue = OSDynamicCast(OSString, rawValue);
360 if (!stringValue) {
361 result = false;
362 goto finish;
363 }
364 if (!stringValue->isEqualTo("Root") &&
365 !stringValue->isEqualTo("Local-Root") &&
366 !stringValue->isEqualTo("Network-Root") &&
367 !stringValue->isEqualTo("Safe Boot") &&
368 !stringValue->isEqualTo("Console")) {
369
370 result = false;
371 goto finish;
372 }
373
374 }
375
376
377 finish:
378 if (keyIterator) keyIterator->release();
379
380 if (!result) {
381 if (not_a_dict) {
382 if (index > -1) {
383 IOLog(VTYELLOW "mkext entry %d:." VTRESET, index);
384 } else {
385 IOLog(VTYELLOW "kernel extension" VTRESET);
386 }
387 IOLog(VTYELLOW "info dictionary isn't a dictionary\n"
388 VTRESET);
389 } else if (id_missing) {
390 if (index > -1) {
391 IOLog(VTYELLOW "mkext entry %d:." VTRESET, index);
392 } else {
393 IOLog(VTYELLOW "kernel extension" VTRESET);
394 }
395 IOLog(VTYELLOW "\"CFBundleIdentifier\" property is "
396 "missing or not a string\n"
397 VTRESET);
398 } else {
399 IOLog(VTYELLOW "kernel extension \"%s\": info dictionary is invalid\n"
400 VTRESET, bundleIdentifier->getCStringNoCopy());
401 }
402 LOG_DELAY();
403 }
404
405 return result;
406 }
407
408
409 /*********************************************************************
410 *********************************************************************/
411 OSDictionary * compareExtensionVersions(
412 OSDictionary * incumbent,
413 OSDictionary * candidate) {
414
415 OSDictionary * winner = NULL;
416
417 OSDictionary * incumbentPlist = NULL;
418 OSDictionary * candidatePlist = NULL;
419 OSString * incumbentName = NULL;
420 OSString * candidateName = NULL;
421 OSString * incumbentVersionString = NULL;
422 OSString * candidateVersionString = NULL;
423 VERS_version incumbent_vers = 0;
424 VERS_version candidate_vers = 0;
425
426 incumbentPlist = OSDynamicCast(OSDictionary,
427 incumbent->getObject("plist"));
428 candidatePlist = OSDynamicCast(OSDictionary,
429 candidate->getObject("plist"));
430
431 if (!incumbentPlist || !candidatePlist) {
432 IOLog("compareExtensionVersions() called with invalid "
433 "extension dictionaries.\n");
434 LOG_DELAY();
435 winner = NULL;
436 goto finish;
437 }
438
439 incumbentName = OSDynamicCast(OSString,
440 incumbentPlist->getObject("CFBundleIdentifier"));
441 candidateName = OSDynamicCast(OSString,
442 candidatePlist->getObject("CFBundleIdentifier"));
443 incumbentVersionString = OSDynamicCast(OSString,
444 incumbentPlist->getObject("CFBundleVersion"));
445 candidateVersionString = OSDynamicCast(OSString,
446 candidatePlist->getObject("CFBundleVersion"));
447
448 if (!incumbentName || !candidateName ||
449 !incumbentVersionString || !candidateVersionString) {
450
451 IOLog("compareExtensionVersions() called with invalid "
452 "extension dictionaries.\n");
453 LOG_DELAY();
454 winner = NULL;
455 goto finish;
456 }
457
458 if (strcmp(incumbentName->getCStringNoCopy(),
459 candidateName->getCStringNoCopy())) {
460
461 IOLog("compareExtensionVersions() called with different "
462 "extension names (%s and %s).\n",
463 incumbentName->getCStringNoCopy(),
464 candidateName->getCStringNoCopy());
465 LOG_DELAY();
466 winner = NULL;
467 goto finish;
468 }
469
470 incumbent_vers = VERS_parse_string(incumbentVersionString->getCStringNoCopy());
471 if (incumbent_vers < 0) {
472
473 IOLog(VTYELLOW "Error parsing version string for extension %s (%s)\n"
474 VTRESET,
475 incumbentName->getCStringNoCopy(),
476 incumbentVersionString->getCStringNoCopy());
477 LOG_DELAY();
478 winner = NULL;
479 goto finish;
480 }
481
482 candidate_vers = VERS_parse_string(candidateVersionString->getCStringNoCopy());
483 if (candidate_vers < 0) {
484
485 IOLog(VTYELLOW "Error parsing version string for extension %s (%s)\n"
486 VTRESET,
487 candidateName->getCStringNoCopy(),
488 candidateVersionString->getCStringNoCopy());
489 LOG_DELAY();
490 winner = NULL;
491 goto finish;
492 }
493
494 if (candidate_vers > incumbent_vers) {
495 IOLog(VTYELLOW "Replacing extension \"%s\" with newer version "
496 "(%s -> %s).\n" VTRESET,
497 incumbentName->getCStringNoCopy(),
498 incumbentVersionString->getCStringNoCopy(),
499 candidateVersionString->getCStringNoCopy());
500 LOG_DELAY();
501 winner = candidate;
502 goto finish;
503 } else {
504 IOLog(VTYELLOW "Skipping duplicate extension \"%s\" with older/same "
505 " version (%s -> %s).\n" VTRESET,
506 candidateName->getCStringNoCopy(),
507 candidateVersionString->getCStringNoCopy(),
508 incumbentVersionString->getCStringNoCopy());
509 LOG_DELAY();
510 winner = incumbent;
511 goto finish;
512 }
513
514 finish:
515
516 // no cleanup, how nice
517 return winner;
518 }
519
520
521 /*********************************************************************
522 * This function merges entries in the mergeFrom dictionary into the
523 * mergeInto dictionary. If it returns false, the two dictionaries are
524 * not altered. If it returns true, then mergeInto may have new
525 * entries; any keys that were already present in mergeInto are
526 * removed from mergeFrom, so that the caller can see what was
527 * actually merged.
528 *********************************************************************/
529 bool mergeExtensionDictionaries(OSDictionary * mergeInto,
530 OSDictionary * mergeFrom) {
531
532 bool result = true;
533 OSDictionary * mergeIntoCopy = NULL; // must release
534 OSDictionary * mergeFromCopy = NULL; // must release
535 OSCollectionIterator * keyIterator = NULL; // must release
536 OSString * key; // don't release
537
538 /* Add 1 to count to guarantee copy can grow (grr).
539 */
540 mergeIntoCopy = OSDictionary::withDictionary(mergeInto,
541 mergeInto->getCount() + 1);
542 if (!mergeIntoCopy) {
543 IOLog("Error: Failed to copy 'into' extensions dictionary "
544 "for merge.\n");
545 LOG_DELAY();
546 result = false;
547 goto finish;
548 }
549
550 /* Add 1 to count to guarantee copy can grow (grr).
551 */
552 mergeFromCopy = OSDictionary::withDictionary(mergeFrom,
553 mergeFrom->getCount() + 1);
554 if (!mergeFromCopy) {
555 IOLog("Error: Failed to copy 'from' extensions dictionary "
556 "for merge.\n");
557 LOG_DELAY();
558 result = false;
559 goto finish;
560 }
561
562 keyIterator = OSCollectionIterator::withCollection(mergeFrom);
563 if (!keyIterator) {
564 IOLog("Error: Failed to allocate iterator for extensions.\n");
565 LOG_DELAY();
566 result = false;
567 goto finish;
568 }
569
570
571 /*****
572 * Loop through "from" dictionary, checking if the identifier already
573 * exists in the "into" dictionary and checking versions if it does.
574 */
575 while ((key = OSDynamicCast(OSString, keyIterator->getNextObject()))) {
576 OSDictionary * incumbentExt = OSDynamicCast(OSDictionary,
577 mergeIntoCopy->getObject(key));
578 OSDictionary * candidateExt = OSDynamicCast(OSDictionary,
579 mergeFrom->getObject(key));
580
581 if (!incumbentExt) {
582 if (!mergeIntoCopy->setObject(key, candidateExt)) {
583
584 /* This is a fatal error, so bail.
585 */
586 IOLog("mergeExtensionDictionaries(): Failed to add "
587 "identifier %s\n",
588 key->getCStringNoCopy());
589 LOG_DELAY();
590 result = false;
591 goto finish;
592 }
593 } else {
594 OSDictionary * mostRecentExtension =
595 compareExtensionVersions(incumbentExt, candidateExt);
596
597 if (mostRecentExtension == incumbentExt) {
598 mergeFromCopy->removeObject(key);
599 } else if (mostRecentExtension == candidateExt) {
600
601 if (!mergeIntoCopy->setObject(key, candidateExt)) {
602
603 /* This is a fatal error, so bail.
604 */
605 IOLog("mergeExtensionDictionaries(): Failed to add "
606 "identifier %s\n",
607 key->getCStringNoCopy());
608 LOG_DELAY();
609 result = false;
610 goto finish;
611 }
612 } else /* should be NULL */ {
613
614 /* This is a nonfatal error, so continue doing others.
615 */
616 IOLog("mergeExtensionDictionaries(): Error comparing "
617 "versions of duplicate extensions %s.\n",
618 key->getCStringNoCopy());
619 LOG_DELAY();
620 continue;
621 }
622 }
623 }
624
625 finish:
626
627 /* If successful, replace the contents of the original
628 * dictionaries with those of the modified copies.
629 */
630 if (result) {
631 mergeInto->flushCollection();
632 mergeInto->merge(mergeIntoCopy);
633 mergeFrom->flushCollection();
634 mergeFrom->merge(mergeFromCopy);
635 }
636
637 if (mergeIntoCopy) mergeIntoCopy->release();
638 if (mergeFromCopy) mergeFromCopy->release();
639 if (keyIterator) keyIterator->release();
640
641 return result;
642 }
643
644
645 /****
646 * These bits are used to parse data made available by bootx.
647 */
648 #define BOOTX_KEXT_PREFIX "Driver-"
649 #define BOOTX_MULTIKEXT_PREFIX "DriversPackage-"
650
651 typedef struct MemoryMapFileInfo {
652 UInt32 paddr;
653 UInt32 length;
654 } MemoryMapFileInfo;
655
656 typedef struct BootxDriverInfo {
657 char *plistAddr;
658 long plistLength;
659 void *moduleAddr;
660 long moduleLength;
661 } BootxDriverInfo;
662
663 typedef struct MkextEntryInfo {
664 vm_address_t base_address;
665 mkext_file * fileinfo;
666 } MkextEntryInfo;
667
668
669 /*********************************************************************
670 * This private function reads the data for a single extension from
671 * the bootx memory-map's propery dict, returning a dictionary with
672 * keys "plist" for the extension's Info.plist as a parsed OSDictionary
673 * and "code" for the extension's executable code as an OSData.
674 *********************************************************************/
675 OSDictionary * readExtension(OSDictionary * propertyDict,
676 const char * memory_map_name) {
677
678 int error = 0;
679 OSData * bootxDriverDataObject = NULL;
680 OSDictionary * driverPlist = NULL;
681 OSString * driverName = NULL;
682 OSData * driverCode = NULL;
683 OSString * errorString = NULL;
684 OSDictionary * driverDict = NULL;
685
686 MemoryMapFileInfo * driverInfo = 0;
687 BootxDriverInfo * dataBuffer;
688
689 kmod_info_t * loaded_kmod = NULL;
690
691 bootxDriverDataObject = OSDynamicCast(OSData,
692 propertyDict->getObject(memory_map_name));
693 // don't release bootxDriverDataObject
694
695 if (!bootxDriverDataObject) {
696 IOLog("Error: No driver data object "
697 "for device tree entry \"%s\".\n",
698 memory_map_name);
699 LOG_DELAY();
700 error = 1;
701 goto finish;
702 }
703
704 driverDict = OSDictionary::withCapacity(2);
705 if (!driverDict) {
706 IOLog("Error: Couldn't allocate dictionary "
707 "for device tree entry \"%s\".\n", memory_map_name);
708 LOG_DELAY();
709 error = 1;
710 goto finish;
711 }
712
713 driverInfo = (MemoryMapFileInfo *)
714 bootxDriverDataObject->getBytesNoCopy(0,
715 sizeof(MemoryMapFileInfo));
716 #if defined (__ppc__)
717 dataBuffer = (BootxDriverInfo *)ml_static_ptovirt(
718 driverInfo->paddr);
719 #elif defined (__i386__)
720 dataBuffer = (BootxDriverInfo *)driverInfo->paddr;
721 dataBuffer->plistAddr = ml_static_ptovirt(dataBuffer->plistAddr);
722 if (dataBuffer->moduleAddr)
723 dataBuffer->moduleAddr = ml_static_ptovirt(dataBuffer->moduleAddr);
724 #else
725 #error unsupported architecture
726 #endif
727 if (!dataBuffer) {
728 IOLog("Error: No data buffer "
729 "for device tree entry \"%s\".\n", memory_map_name);
730 LOG_DELAY();
731 error = 1;
732 goto finish;
733 }
734
735 driverPlist = OSDynamicCast(OSDictionary,
736 OSUnserializeXML(dataBuffer->plistAddr, &errorString));
737 if (!driverPlist) {
738 IOLog("Error: Couldn't read XML property list "
739 "for device tree entry \"%s\".\n", memory_map_name);
740 LOG_DELAY();
741 if (errorString) {
742 IOLog("XML parse error: %s.\n",
743 errorString->getCStringNoCopy());
744 LOG_DELAY();
745 }
746 error = 1;
747 goto finish;
748 }
749
750
751 driverName = OSDynamicCast(OSString,
752 driverPlist->getObject("CFBundleIdentifier")); // do not release
753 if (!driverName) {
754 IOLog("Error: Device tree entry \"%s\" has "
755 "no \"CFBundleIdentifier\" property.\n", memory_map_name);
756 LOG_DELAY();
757 error = 1;
758 goto finish;
759 }
760
761 /* Check if kmod is already loaded and is a real loadable one (has
762 * an address).
763 */
764 loaded_kmod = kmod_lookupbyname_locked(driverName->getCStringNoCopy());
765 if (loaded_kmod && loaded_kmod->address) {
766 IOLog("Skipping new extension \"%s\"; an extension named "
767 "\"%s\" is already loaded.\n",
768 driverName->getCStringNoCopy(),
769 loaded_kmod->name);
770 LOG_DELAY();
771 error = 1;
772 goto finish;
773 }
774
775 if (!validateExtensionDict(driverPlist, -1)) {
776 // validateExtensionsDict() logs an error
777 error = 1;
778 goto finish;
779 }
780
781 driverDict->setObject("plist", driverPlist);
782
783 /* It's perfectly okay for a KEXT to have no executable.
784 * Check that moduleAddr is nonzero before attempting to
785 * get one.
786 *
787 * NOTE: The driverCode object is created "no-copy", so
788 * it doesn't own that memory. The memory must be freed
789 * separately from the OSData object (see
790 * clearStartupExtensionsAndLoaderInfo() at the end of this file).
791 */
792 if (dataBuffer->moduleAddr && dataBuffer->moduleLength) {
793 driverCode = OSData::withBytesNoCopy(dataBuffer->moduleAddr,
794 dataBuffer->moduleLength);
795 if (!driverCode) {
796 IOLog("Error: Couldn't allocate data object "
797 "to hold code for device tree entry \"%s\".\n",
798 memory_map_name);
799 LOG_DELAY();
800 error = 1;
801 goto finish;
802 }
803
804 if (driverCode) {
805 driverDict->setObject("code", driverCode);
806 }
807 }
808
809 finish:
810
811 if (loaded_kmod) {
812 kfree((unsigned int)loaded_kmod, sizeof(kmod_info_t));
813 }
814
815 // do not release bootxDriverDataObject
816 // do not release driverName
817
818 if (driverPlist) {
819 driverPlist->release();
820 }
821 if (errorString) {
822 errorString->release();
823 }
824 if (driverCode) {
825 driverCode->release();
826 }
827 if (error) {
828 if (driverDict) {
829 driverDict->release();
830 driverDict = NULL;
831 }
832 }
833 return driverDict;
834 }
835
836
837 /*********************************************************************
838 * Used to uncompress a single file entry in an mkext archive.
839 *
840 * The OSData returned does not own its memory! You must deallocate
841 * that memory using kmem_free() before releasing the OSData().
842 *********************************************************************/
843 static bool uncompressFile(u_int8_t *base_address, mkext_file * fileinfo,
844 /* out */ OSData ** file) {
845
846 bool result = true;
847 kern_return_t kern_result;
848 u_int8_t * uncompressed_file = 0; // kmem_free() on error
849 OSData * uncompressedFile = 0; // returned
850 size_t uncompressed_size = 0;
851
852 size_t offset = OSSwapBigToHostInt32(fileinfo->offset);
853 size_t compsize = OSSwapBigToHostInt32(fileinfo->compsize);
854 size_t realsize = OSSwapBigToHostInt32(fileinfo->realsize);
855 time_t modifiedsecs = OSSwapBigToHostInt32(fileinfo->modifiedsecs);
856
857 *file = 0;
858
859 /* If these four fields are zero there's no file, but that isn't
860 * an error.
861 */
862 if (offset == 0 && compsize == 0 &&
863 realsize == 0 && modifiedsecs == 0) {
864 goto finish;
865 }
866
867 // Add 1 for '\0' to terminate XML string!
868 kern_result = kmem_alloc(kernel_map, (vm_offset_t *)&uncompressed_file,
869 realsize + 1);
870 if (kern_result != KERN_SUCCESS) {
871 IOLog("Error: Couldn't allocate data buffer "
872 "to uncompress file.\n");
873 LOG_DELAY();
874 result = false;
875 goto finish;
876 }
877
878 uncompressedFile = OSData::withBytesNoCopy(uncompressed_file,
879 realsize + 1);
880 if (!uncompressedFile) {
881 IOLog("Error: Couldn't allocate data object "
882 "to uncompress file.\n");
883 LOG_DELAY();
884 result = false;
885 goto finish;
886 }
887
888 if (compsize != 0) {
889 uncompressed_size = decompress_lzss(uncompressed_file,
890 base_address + offset,
891 compsize);
892 if (uncompressed_size != realsize) {
893 IOLog("Error: Uncompressed file is not the length "
894 "recorded.\n");
895 LOG_DELAY();
896 result = false;
897 goto finish;
898 }
899 uncompressed_file[uncompressed_size] = '\0';
900 } else {
901 bcopy(base_address + offset, uncompressed_file,
902 realsize);
903 uncompressed_file[realsize] = '\0';
904 }
905
906 *file = uncompressedFile;
907
908 finish:
909 if (!result) {
910 if (uncompressed_file) {
911 kmem_free(kernel_map, (vm_address_t)uncompressed_file,
912 realsize + 1);
913 }
914 if (uncompressedFile) {
915 uncompressedFile->release();
916 *file = 0;
917 }
918 }
919 return result;
920 }
921
922 bool uncompressModule(OSData *compData, /* out */ OSData ** file) {
923
924 MkextEntryInfo *info = (MkextEntryInfo *) compData->getBytesNoCopy();
925
926 return uncompressFile((u_int8_t *) info->base_address,
927 info->fileinfo, file);
928 }
929
930
931 /*********************************************************************
932 * Does the work of pulling extensions out of an mkext archive located
933 * in memory.
934 *********************************************************************/
935 bool extractExtensionsFromArchive(MemoryMapFileInfo * mkext_file_info,
936 OSDictionary * extensions) {
937
938 bool result = true;
939
940 u_int8_t * crc_address = 0;
941 u_int32_t checksum;
942 mkext_header * mkext_data = 0; // don't free
943 mkext_kext * onekext_data = 0; // don't free
944 mkext_file * plist_file = 0; // don't free
945 mkext_file * module_file = 0; // don't free
946 kmod_info_t * loaded_kmod = 0; // must free
947
948 OSData * driverPlistDataObject = 0; // must release
949 OSDictionary * driverPlist = 0; // must release
950 OSData * driverCode = 0; // must release
951 OSDictionary * driverDict = 0; // must release
952 OSString * moduleName = 0; // don't release
953 OSString * errorString = NULL; // must release
954
955 OSData * moduleInfo = 0; // must release
956 MkextEntryInfo module_info;
957
958
959 #if defined (__ppc__)
960 mkext_data = (mkext_header *)mkext_file_info->paddr;
961 #elif defined (__i386__)
962 mkext_data = (mkext_header *)ml_static_ptovirt(mkext_file_info->paddr);
963 #else
964 #error unsupported architecture
965 #endif
966 if (OSSwapBigToHostInt32(mkext_data->magic) != MKEXT_MAGIC ||
967 OSSwapBigToHostInt32(mkext_data->signature) != MKEXT_SIGN) {
968 IOLog("Error: Extension archive has invalid magic or signature.\n");
969 LOG_DELAY();
970 result = false;
971 goto finish;
972 }
973
974 if (OSSwapBigToHostInt32(mkext_data->length) != mkext_file_info->length) {
975 IOLog("Error: Mismatch between extension archive & "
976 "recorded length.\n");
977 LOG_DELAY();
978 result = false;
979 goto finish;
980 }
981
982 crc_address = (u_int8_t *)&mkext_data->version;
983 checksum = adler32(crc_address,
984 (unsigned int)mkext_data +
985 OSSwapBigToHostInt32(mkext_data->length) - (unsigned int)crc_address);
986
987 if (OSSwapBigToHostInt32(mkext_data->adler32) != checksum) {
988 IOLog("Error: Extension archive has a bad checksum.\n");
989 LOG_DELAY();
990 result = false;
991 goto finish;
992 }
993
994 /* If the MKEXT archive isn't fat, check that the CPU type & subtype
995 * match that of the running kernel.
996 */
997 if (OSSwapBigToHostInt32(mkext_data->cputype) != (UInt32)CPU_TYPE_ANY) {
998 kern_return_t kresult = KERN_FAILURE;
999 host_basic_info_data_t hostinfo;
1000 host_info_t hostinfo_ptr = (host_info_t)&hostinfo;
1001 mach_msg_type_number_t count = sizeof(hostinfo)/sizeof(integer_t);
1002
1003 kresult = host_info((host_t)1, HOST_BASIC_INFO,
1004 hostinfo_ptr, &count);
1005 if (kresult != KERN_SUCCESS) {
1006 IOLog("Error: Couldn't get current host info.\n");
1007 LOG_DELAY();
1008 result = false;
1009 goto finish;
1010 }
1011 if ((UInt32)hostinfo.cpu_type !=
1012 OSSwapBigToHostInt32(mkext_data->cputype)) {
1013
1014 IOLog("Error: Extension archive doesn't contain software "
1015 "for this computer's CPU type.\n");
1016 LOG_DELAY();
1017 result = false;
1018 goto finish;
1019 }
1020 if (!grade_binary(OSSwapBigToHostInt32(mkext_data->cputype),
1021 OSSwapBigToHostInt32(mkext_data->cpusubtype))) {
1022 IOLog("Error: Extension archive doesn't contain software "
1023 "for this computer's CPU subtype.\n");
1024 LOG_DELAY();
1025 result = false;
1026 goto finish;
1027 }
1028 }
1029
1030 for (unsigned int i = 0;
1031 i < OSSwapBigToHostInt32(mkext_data->numkexts);
1032 i++) {
1033
1034 if (loaded_kmod) {
1035 kfree((unsigned int)loaded_kmod, sizeof(kmod_info_t));
1036 loaded_kmod = 0;
1037 }
1038
1039 if (driverPlistDataObject) {
1040 kmem_free(kernel_map,
1041 (unsigned int)driverPlistDataObject->getBytesNoCopy(),
1042 driverPlistDataObject->getLength());
1043
1044 driverPlistDataObject->release();
1045 driverPlistDataObject = NULL;
1046 }
1047 if (driverPlist) {
1048 driverPlist->release();
1049 driverPlist = NULL;
1050 }
1051 if (driverCode) {
1052 driverCode->release();
1053 driverCode = NULL;
1054 }
1055 if (driverDict) {
1056 driverDict->release();
1057 driverDict = NULL;
1058 }
1059 if (errorString) {
1060 errorString->release();
1061 errorString = NULL;
1062 }
1063
1064 onekext_data = &mkext_data->kext[i];
1065 plist_file = &onekext_data->plist;
1066 module_file = &onekext_data->module;
1067
1068 if (!uncompressFile((u_int8_t *)mkext_data, plist_file,
1069 &driverPlistDataObject)) {
1070
1071 IOLog("Error: couldn't uncompress plist file "
1072 "from multikext archive entry %d.\n", i);
1073 LOG_DELAY();
1074 continue;
1075 }
1076
1077 if (!driverPlistDataObject) {
1078 IOLog("Error: No property list present "
1079 "for multikext archive entry %d.\n", i);
1080 LOG_DELAY();
1081 continue;
1082 } else {
1083 driverPlist = OSDynamicCast(OSDictionary,
1084 OSUnserializeXML(
1085 (char *)driverPlistDataObject->getBytesNoCopy(),
1086 &errorString));
1087 if (!driverPlist) {
1088 IOLog("Error: Couldn't read XML property list "
1089 "for multikext archive entry %d.\n", i);
1090 LOG_DELAY();
1091 if (errorString) {
1092 IOLog("XML parse error: %s.\n",
1093 errorString->getCStringNoCopy());
1094 LOG_DELAY();
1095 }
1096 continue;
1097 }
1098
1099 if (!validateExtensionDict(driverPlist, i)) {
1100 // validateExtensionsDict() logs an error
1101 continue;
1102 }
1103
1104 }
1105
1106 /* Get the extension's module name. This is used to record
1107 * the extension.
1108 */
1109 moduleName = OSDynamicCast(OSString,
1110 driverPlist->getObject("CFBundleIdentifier")); // do not release
1111 if (!moduleName) {
1112 IOLog("Error: Multikext archive entry %d has "
1113 "no \"CFBundleIdentifier\" property.\n", i);
1114 LOG_DELAY();
1115 continue; // assume a kext config error & continue
1116 }
1117
1118 /* Check if kmod is already loaded and is a real loadable one (has
1119 * an address).
1120 */
1121 loaded_kmod = kmod_lookupbyname_locked(moduleName->getCStringNoCopy());
1122 if (loaded_kmod && loaded_kmod->address) {
1123 IOLog("Skipping new extension \"%s\"; an extension named "
1124 "\"%s\" is already loaded.\n",
1125 moduleName->getCStringNoCopy(),
1126 loaded_kmod->name);
1127 continue;
1128 }
1129
1130
1131 driverDict = OSDictionary::withCapacity(2);
1132 if (!driverDict) {
1133 IOLog("Error: Couldn't allocate dictionary "
1134 "for multikext archive entry %d.\n", i);
1135 LOG_DELAY();
1136 result = false;
1137 goto finish;
1138 }
1139
1140 driverDict->setObject("plist", driverPlist);
1141
1142 /*****
1143 * Prepare an entry to hold the mkext entry info for the
1144 * compressed binary module, if there is one. If all four fields
1145 * of the module entry are zero, there isn't one.
1146 */
1147 if (!(loaded_kmod && loaded_kmod->address) && (OSSwapBigToHostInt32(module_file->offset) ||
1148 OSSwapBigToHostInt32(module_file->compsize) ||
1149 OSSwapBigToHostInt32(module_file->realsize) ||
1150 OSSwapBigToHostInt32(module_file->modifiedsecs))) {
1151
1152 moduleInfo = OSData::withCapacity(sizeof(MkextEntryInfo));
1153 if (!moduleInfo) {
1154 IOLog("Error: Couldn't allocate data object "
1155 "for multikext archive entry %d.\n", i);
1156 LOG_DELAY();
1157 result = false;
1158 goto finish;
1159 }
1160
1161 module_info.base_address = (vm_address_t)mkext_data;
1162 module_info.fileinfo = module_file;
1163
1164 if (!moduleInfo->appendBytes(&module_info, sizeof(module_info))) {
1165 IOLog("Error: Couldn't record info "
1166 "for multikext archive entry %d.\n", i);
1167 LOG_DELAY();
1168 result = false;
1169 goto finish;
1170 }
1171
1172 driverDict->setObject("compressedCode", moduleInfo);
1173 }
1174
1175 OSDictionary * incumbentExt = OSDynamicCast(OSDictionary,
1176 extensions->getObject(moduleName));
1177
1178 if (!incumbentExt) {
1179 extensions->setObject(moduleName, driverDict);
1180 } else {
1181 OSDictionary * mostRecentExtension =
1182 compareExtensionVersions(incumbentExt, driverDict);
1183
1184 if (mostRecentExtension == incumbentExt) {
1185 /* Do nothing, we've got the most recent. */
1186 } else if (mostRecentExtension == driverDict) {
1187 if (!extensions->setObject(moduleName, driverDict)) {
1188
1189 /* This is a fatal error, so bail.
1190 */
1191 IOLog("extractExtensionsFromArchive(): Failed to add "
1192 "identifier %s\n",
1193 moduleName->getCStringNoCopy());
1194 LOG_DELAY();
1195 result = false;
1196 goto finish;
1197 }
1198 } else /* should be NULL */ {
1199
1200 /* This is a nonfatal error, so continue.
1201 */
1202 IOLog("extractExtensionsFromArchive(): Error comparing "
1203 "versions of duplicate extensions %s.\n",
1204 moduleName->getCStringNoCopy());
1205 LOG_DELAY();
1206 continue;
1207 }
1208 }
1209 }
1210
1211 finish:
1212
1213 if (loaded_kmod) kfree((unsigned int)loaded_kmod, sizeof(kmod_info_t));
1214 if (driverPlistDataObject) {
1215 kmem_free(kernel_map,
1216 (unsigned int)driverPlistDataObject->getBytesNoCopy(),
1217 driverPlistDataObject->getLength());
1218 driverPlistDataObject->release();
1219 }
1220 if (driverPlist) driverPlist->release();
1221 if (driverCode) driverCode->release();
1222 if (moduleInfo) moduleInfo->release();
1223 if (driverDict) driverDict->release();
1224 if (errorString) errorString->release();
1225
1226 return result;
1227 }
1228
1229 /*********************************************************************
1230 *
1231 *********************************************************************/
1232 bool readExtensions(OSDictionary * propertyDict,
1233 const char * memory_map_name,
1234 OSDictionary * extensions) {
1235
1236 bool result = true;
1237 OSData * mkextDataObject = 0; // don't release
1238 MemoryMapFileInfo * mkext_file_info = 0; // don't free
1239
1240 mkextDataObject = OSDynamicCast(OSData,
1241 propertyDict->getObject(memory_map_name));
1242 // don't release mkextDataObject
1243
1244 if (!mkextDataObject) {
1245 IOLog("Error: No mkext data object "
1246 "for device tree entry \"%s\".\n",
1247 memory_map_name);
1248 LOG_DELAY();
1249 result = false;
1250 goto finish;
1251 }
1252
1253 mkext_file_info = (MemoryMapFileInfo *)mkextDataObject->getBytesNoCopy();
1254 if (!mkext_file_info) {
1255 result = false;
1256 goto finish;
1257 }
1258
1259 result = extractExtensionsFromArchive(mkext_file_info, extensions);
1260
1261 finish:
1262
1263 if (!result && extensions) {
1264 extensions->flushCollection();
1265 }
1266
1267 return result;
1268 }
1269
1270
1271 /*********************************************************************
1272 * Adds the personalities for an extensions dictionary to the global
1273 * IOCatalogue.
1274 *********************************************************************/
1275 bool addPersonalities(OSDictionary * extensions) {
1276 bool result = true;
1277 OSCollectionIterator * keyIterator = NULL; // must release
1278 OSString * key; // don't release
1279 OSDictionary * driverDict = NULL; // don't release
1280 OSDictionary * driverPlist = NULL; // don't release
1281 OSDictionary * thisDriverPersonalities = NULL; // don't release
1282 OSArray * allDriverPersonalities = NULL; // must release
1283
1284 allDriverPersonalities = OSArray::withCapacity(1);
1285 if (!allDriverPersonalities) {
1286 IOLog("Error: Couldn't allocate personality dictionary.\n");
1287 LOG_DELAY();
1288 result = false;
1289 goto finish;
1290 }
1291
1292 /* Record all personalities found so that they can be
1293 * added to the catalogue.
1294 * Note: Not all extensions have personalities.
1295 */
1296
1297 keyIterator = OSCollectionIterator::withCollection(extensions);
1298 if (!keyIterator) {
1299 IOLog("Error: Couldn't allocate iterator to record personalities.\n");
1300 LOG_DELAY();
1301 result = false;
1302 goto finish;
1303 }
1304
1305 while ( ( key = OSDynamicCast(OSString,
1306 keyIterator->getNextObject() ))) {
1307
1308 driverDict = OSDynamicCast(OSDictionary,
1309 extensions->getObject(key));
1310 driverPlist = OSDynamicCast(OSDictionary,
1311 driverDict->getObject("plist"));
1312 thisDriverPersonalities = OSDynamicCast(OSDictionary,
1313 driverPlist->getObject("IOKitPersonalities"));
1314
1315 if (thisDriverPersonalities) {
1316 OSCollectionIterator * pIterator;
1317 OSString * locakKey;
1318 pIterator = OSCollectionIterator::withCollection(
1319 thisDriverPersonalities);
1320 if (!pIterator) {
1321 IOLog("Error: Couldn't allocate iterator "
1322 "to record extension personalities.\n");
1323 LOG_DELAY();
1324 continue;
1325 }
1326 while ( (locakKey = OSDynamicCast(OSString,
1327 pIterator->getNextObject())) ) {
1328
1329 OSDictionary * personality = OSDynamicCast(
1330 OSDictionary,
1331 thisDriverPersonalities->getObject(locakKey));
1332 if (personality) {
1333 allDriverPersonalities->setObject(personality);
1334 }
1335 }
1336 pIterator->release();
1337 }
1338 } /* extract personalities */
1339
1340
1341 /* Add all personalities found to the IOCatalogue,
1342 * but don't start matching.
1343 */
1344 gIOCatalogue->addDrivers(allDriverPersonalities, false);
1345
1346 finish:
1347
1348 if (allDriverPersonalities) allDriverPersonalities->release();
1349 if (keyIterator) keyIterator->release();
1350
1351 return result;
1352 }
1353
1354
1355 /*********************************************************************
1356 * Called from IOCatalogue to add extensions from an mkext archive.
1357 * This function makes a copy of the mkext object passed in because
1358 * the device tree support code dumps it after calling us (indirectly
1359 * through the IOCatalogue).
1360 *********************************************************************/
1361 bool addExtensionsFromArchive(OSData * mkextDataObject) {
1362 bool result = true;
1363
1364 OSDictionary * startupExtensions = NULL; // don't release
1365 OSArray * bootLoaderObjects = NULL; // don't release
1366 OSDictionary * extensions = NULL; // must release
1367 MemoryMapFileInfo mkext_file_info;
1368 OSCollectionIterator * keyIterator = NULL; // must release
1369 OSString * key = NULL; // don't release
1370
1371 startupExtensions = getStartupExtensions();
1372 if (!startupExtensions) {
1373 IOLog("Can't record extension archive; there is no"
1374 " extensions dictionary.\n");
1375 LOG_DELAY();
1376 result = false;
1377 goto finish;
1378 }
1379
1380 bootLoaderObjects = getBootLoaderObjects();
1381 if (! bootLoaderObjects) {
1382 IOLog("Error: Couldn't allocate array to hold temporary objects.\n");
1383 LOG_DELAY();
1384 result = false;
1385 goto finish;
1386 }
1387
1388 extensions = OSDictionary::withCapacity(2);
1389 if (!extensions) {
1390 IOLog("Error: Couldn't allocate dictionary to unpack "
1391 "extension archive.\n");
1392 LOG_DELAY();
1393 result = false;
1394 goto finish;
1395 }
1396
1397 mkext_file_info.paddr = (UInt32)mkextDataObject->getBytesNoCopy();
1398 mkext_file_info.length = mkextDataObject->getLength();
1399
1400 /* Save the local mkext data object so that we can deallocate it later.
1401 */
1402 bootLoaderObjects->setObject(mkextDataObject);
1403
1404 result = extractExtensionsFromArchive(&mkext_file_info, extensions);
1405 if (!result) {
1406 IOLog("Error: Failed to extract extensions from archive.\n");
1407 LOG_DELAY();
1408 result = false;
1409 goto finish;
1410 }
1411
1412 result = mergeExtensionDictionaries(startupExtensions, extensions);
1413 if (!result) {
1414 IOLog("Error: Failed to merge new extensions into existing set.\n");
1415 LOG_DELAY();
1416 goto finish;
1417 }
1418
1419 result = addPersonalities(extensions);
1420 if (!result) {
1421 IOLog("Error: Failed to add personalities for extensions extracted "
1422 "from archive.\n");
1423 LOG_DELAY();
1424 result = false;
1425 goto finish;
1426 }
1427
1428 finish:
1429
1430 if (!result) {
1431 IOLog("Error: Failed to record extensions from archive.\n");
1432 LOG_DELAY();
1433 } else {
1434 keyIterator = OSCollectionIterator::withCollection(
1435 extensions);
1436
1437 if (keyIterator) {
1438 while ( (key = OSDynamicCast(OSString,
1439 keyIterator->getNextObject())) ) {
1440
1441 IOLog("Added extension \"%s\" from archive.\n",
1442 key->getCStringNoCopy());
1443 LOG_DELAY();
1444 }
1445 keyIterator->release();
1446 }
1447 }
1448
1449 if (extensions) extensions->release();
1450
1451 return result;
1452 }
1453
1454
1455 /*********************************************************************
1456 * This function builds dictionaries for the startup extensions
1457 * put into memory by bootx, recording each in the startup extensions
1458 * dictionary. The dictionary format is this:
1459 *
1460 * {
1461 * "plist" = (the extension's Info.plist as an OSDictionary)
1462 * "code" = (an OSData containing the executable file)
1463 * }
1464 *
1465 * This function returns true if any extensions were found and
1466 * recorded successfully, or if there are no start extensions,
1467 * and false if an unrecoverable error occurred. An error reading
1468 * a single extension is not considered fatal, and this function
1469 * will simply skip the problematic extension to try the next one.
1470 *********************************************************************/
1471
1472 bool recordStartupExtensions(void) {
1473 bool result = true;
1474 OSDictionary * startupExtensions = NULL; // must release
1475 OSDictionary * existingExtensions = NULL; // don't release
1476 OSDictionary * mkextExtensions = NULL; // must release
1477 IORegistryEntry * bootxMemoryMap = NULL; // must release
1478 OSDictionary * propertyDict = NULL; // must release
1479 OSCollectionIterator * keyIterator = NULL; // must release
1480 OSString * key = NULL; // don't release
1481
1482 OSDictionary * newDriverDict = NULL; // must release
1483 OSDictionary * driverPlist = NULL; // don't release
1484
1485 struct section * infosect;
1486 struct section * symsect;
1487 unsigned int prelinkedCount = 0;
1488
1489 existingExtensions = getStartupExtensions();
1490 if (!existingExtensions) {
1491 IOLog("Error: There is no dictionary for startup extensions.\n");
1492 LOG_DELAY();
1493 result = false;
1494 goto finish;
1495 }
1496
1497 startupExtensions = OSDictionary::withCapacity(1);
1498 if (!startupExtensions) {
1499 IOLog("Error: Couldn't allocate dictionary "
1500 "to record startup extensions.\n");
1501 LOG_DELAY();
1502 result = false;
1503 goto finish;
1504 }
1505
1506 // --
1507 // add any prelinked modules as startup extensions
1508
1509 infosect = getsectbyname("__PRELINK", "__info");
1510 symsect = getsectbyname("__PRELINK", "__symtab");
1511 if (infosect && infosect->addr && infosect->size
1512 && symsect && symsect->addr && symsect->size) do
1513 {
1514 gIOPrelinkedModules = OSDynamicCast(OSArray,
1515 OSUnserializeXML((const char *) infosect->addr, NULL));
1516
1517 if (!gIOPrelinkedModules)
1518 break;
1519 for( unsigned int idx = 0;
1520 (propertyDict = OSDynamicCast(OSDictionary, gIOPrelinkedModules->getObject(idx)));
1521 idx++)
1522 {
1523 enum { kPrelinkReservedCount = 4 };
1524
1525 /* Get the extension's module name. This is used to record
1526 * the extension. Do *not* release the moduleName.
1527 */
1528 OSString * moduleName = OSDynamicCast(OSString,
1529 propertyDict->getObject("CFBundleIdentifier"));
1530 if (!moduleName) {
1531 IOLog("Error: Prelinked module entry has "
1532 "no \"CFBundleIdentifier\" property.\n");
1533 LOG_DELAY();
1534 continue;
1535 }
1536
1537 /* Add the kext, & its plist.
1538 */
1539 newDriverDict = OSDictionary::withCapacity(4);
1540 assert(newDriverDict);
1541 newDriverDict->setObject("plist", propertyDict);
1542 startupExtensions->setObject(moduleName, newDriverDict);
1543 newDriverDict->release();
1544
1545 /* Add the code if present.
1546 */
1547 OSData * data = OSDynamicCast(OSData, propertyDict->getObject("OSBundlePrelink"));
1548 if (data) {
1549 if (data->getLength() < (kPrelinkReservedCount * sizeof(UInt32))) {
1550 IOLog("Error: Prelinked module entry has "
1551 "invalid \"OSBundlePrelink\" property.\n");
1552 LOG_DELAY();
1553 continue;
1554 }
1555 UInt32 * prelink;
1556 prelink = (UInt32 *) data->getBytesNoCopy();
1557 kmod_info_t * kmod_info = (kmod_info_t *) OSReadBigInt32(prelink, 0);
1558 // end of "file" is end of symbol sect
1559 data = OSData::withBytesNoCopy((void *) kmod_info->address,
1560 symsect->addr + symsect->size - kmod_info->address);
1561 newDriverDict->setObject("code", data);
1562 data->release();
1563 prelinkedCount++;
1564 continue;
1565 }
1566 /* Add the symbols if present.
1567 */
1568 OSNumber * num = OSDynamicCast(OSNumber, propertyDict->getObject("OSBundlePrelinkSymbols"));
1569 if (num) {
1570 UInt32 offset = num->unsigned32BitValue();
1571 data = OSData::withBytesNoCopy((void *) (symsect->addr + offset), symsect->size - offset);
1572 newDriverDict->setObject("code", data);
1573 data->release();
1574 prelinkedCount++;
1575 continue;
1576 }
1577 }
1578 if (gIOPrelinkedModules)
1579 IOLog("%d prelinked modules\n", prelinkedCount);
1580
1581 // free __info
1582 vm_offset_t
1583 virt = ml_static_ptovirt(infosect->addr);
1584 if( virt) {
1585 ml_static_mfree(virt, infosect->size);
1586 }
1587 newDriverDict = NULL;
1588 }
1589 while (false);
1590 // --
1591
1592 bootxMemoryMap =
1593 IORegistryEntry::fromPath(
1594 "/chosen/memory-map", // path
1595 gIODTPlane // plane
1596 );
1597 // return value is retained so be sure to release it
1598
1599 if (!bootxMemoryMap) {
1600 IOLog("Error: Couldn't read booter memory map.\n");
1601 LOG_DELAY();
1602 result = false;
1603 goto finish;
1604 }
1605
1606 propertyDict = bootxMemoryMap->dictionaryWithProperties();
1607 if (!propertyDict) {
1608 IOLog("Error: Couldn't get property dictionary "
1609 "from memory map.\n");
1610 LOG_DELAY();
1611 result = false;
1612 goto finish;
1613 }
1614
1615 keyIterator = OSCollectionIterator::withCollection(propertyDict);
1616 if (!keyIterator) {
1617 IOLog("Error: Couldn't allocate iterator for driver images.\n");
1618 LOG_DELAY();
1619 result = false;
1620 goto finish;
1621 }
1622
1623 while ( (key = OSDynamicCast(OSString,
1624 keyIterator->getNextObject())) ) {
1625 /* Clear newDriverDict & mkextExtensions upon entry to the loop,
1626 * handling both successful and unsuccessful iterations.
1627 */
1628 if (newDriverDict) {
1629 newDriverDict->release();
1630 newDriverDict = NULL;
1631 }
1632 if (mkextExtensions) {
1633 mkextExtensions->release();
1634 mkextExtensions = NULL;
1635 }
1636
1637 const char * keyValue = key->getCStringNoCopy();
1638
1639 if ( !strncmp(keyValue, BOOTX_KEXT_PREFIX,
1640 strlen(BOOTX_KEXT_PREFIX)) ) {
1641
1642 /* Read the extension from the bootx-supplied memory.
1643 */
1644 newDriverDict = readExtension(propertyDict, keyValue);
1645 if (!newDriverDict) {
1646 IOLog("Error: Couldn't read data "
1647 "for device tree entry \"%s\".\n", keyValue);
1648 LOG_DELAY();
1649 continue;
1650 }
1651
1652
1653 /* Preprare to record the extension by getting its info plist.
1654 */
1655 driverPlist = OSDynamicCast(OSDictionary,
1656 newDriverDict->getObject("plist"));
1657 if (!driverPlist) {
1658 IOLog("Error: Extension in device tree entry \"%s\" "
1659 "has no property list.\n", keyValue);
1660 LOG_DELAY();
1661 continue;
1662 }
1663
1664
1665 /* Get the extension's module name. This is used to record
1666 * the extension. Do *not* release the moduleName.
1667 */
1668 OSString * moduleName = OSDynamicCast(OSString,
1669 driverPlist->getObject("CFBundleIdentifier"));
1670 if (!moduleName) {
1671 IOLog("Error: Device tree entry \"%s\" has "
1672 "no \"CFBundleIdentifier\" property.\n", keyValue);
1673 LOG_DELAY();
1674 continue;
1675 }
1676
1677
1678 /* All has gone well so far, so record the extension under
1679 * its module name, checking for an existing duplicate.
1680 *
1681 * Do not release moduleName, as it's part of the extension's
1682 * plist.
1683 */
1684 OSDictionary * incumbentExt = OSDynamicCast(OSDictionary,
1685 startupExtensions->getObject(moduleName));
1686
1687 if (!incumbentExt) {
1688 startupExtensions->setObject(moduleName, newDriverDict);
1689 } else {
1690 OSDictionary * mostRecentExtension =
1691 compareExtensionVersions(incumbentExt, newDriverDict);
1692
1693 if (mostRecentExtension == incumbentExt) {
1694 /* Do nothing, we've got the most recent. */
1695 } else if (mostRecentExtension == newDriverDict) {
1696 if (!startupExtensions->setObject(moduleName,
1697 newDriverDict)) {
1698
1699 /* This is a fatal error, so bail.
1700 */
1701 IOLog("recordStartupExtensions(): Failed to add "
1702 "identifier %s\n",
1703 moduleName->getCStringNoCopy());
1704 LOG_DELAY();
1705 result = false;
1706 goto finish;
1707 }
1708 } else /* should be NULL */ {
1709
1710 /* This is a nonfatal error, so continue.
1711 */
1712 IOLog("recordStartupExtensions(): Error comparing "
1713 "versions of duplicate extensions %s.\n",
1714 moduleName->getCStringNoCopy());
1715 LOG_DELAY();
1716 continue;
1717 }
1718 }
1719
1720
1721 } else if ( !strncmp(keyValue, BOOTX_MULTIKEXT_PREFIX,
1722 strlen(BOOTX_MULTIKEXT_PREFIX)) ) {
1723
1724 mkextExtensions = OSDictionary::withCapacity(10);
1725 if (!mkextExtensions) {
1726 IOLog("Error: Couldn't allocate dictionary to unpack "
1727 "multi-extension archive.\n");
1728 LOG_DELAY();
1729 result = false;
1730 goto finish; // allocation failure is fatal for this routine
1731 }
1732 if (!readExtensions(propertyDict, keyValue, mkextExtensions)) {
1733 IOLog("Error: Couldn't unpack multi-extension archive.\n");
1734 LOG_DELAY();
1735 continue;
1736 } else {
1737 if (!mergeExtensionDictionaries(startupExtensions,
1738 mkextExtensions)) {
1739
1740 IOLog("Error: Failed to merge new extensions into "
1741 "existing set.\n");
1742 LOG_DELAY();
1743 result = false;
1744 goto finish; // merge error is fatal for this routine
1745 }
1746 }
1747 }
1748
1749 // Do not release key.
1750
1751 } /* while ( (key = OSDynamicCast(OSString, ...) ) ) */
1752
1753 if (!mergeExtensionDictionaries(existingExtensions, startupExtensions)) {
1754 IOLog("Error: Failed to merge new extensions into existing set.\n");
1755 LOG_DELAY();
1756 result = false;
1757 goto finish;
1758 }
1759
1760 result = addPersonalities(startupExtensions);
1761 if (!result) {
1762 IOLog("Error: Failed to add personalities for extensions extracted "
1763 "from archive.\n");
1764 LOG_DELAY();
1765 result = false;
1766 goto finish;
1767 }
1768
1769 finish:
1770
1771 // reused so clear first!
1772 if (keyIterator) {
1773 keyIterator->release();
1774 keyIterator = 0;
1775 }
1776
1777 if (!result) {
1778 IOLog("Error: Failed to record startup extensions.\n");
1779 LOG_DELAY();
1780 } else {
1781 #if DEBUG
1782 keyIterator = OSCollectionIterator::withCollection(
1783 startupExtensions);
1784
1785 if (keyIterator) {
1786 while ( (key = OSDynamicCast(OSString,
1787 keyIterator->getNextObject())) ) {
1788
1789 IOLog("Found extension \"%s\".\n",
1790 key->getCStringNoCopy());
1791 LOG_DELAY();
1792 }
1793 keyIterator->release();
1794 keyIterator = 0;
1795 }
1796 #endif /* DEBUG */
1797 }
1798
1799 if (newDriverDict) newDriverDict->release();
1800 if (propertyDict) propertyDict->release();
1801 if (bootxMemoryMap) bootxMemoryMap->release();
1802 if (mkextExtensions) mkextExtensions->release();
1803 if (startupExtensions) startupExtensions->release();
1804
1805 return result;
1806 }
1807
1808
1809 /*********************************************************************
1810 * This function removes an entry from the dictionary of startup
1811 * extensions. It's used when an extension can't be loaded, for
1812 * whatever reason. For drivers, this allows another matching driver
1813 * to be loaded, so that, for example, a driver for the root device
1814 * can be found.
1815 *********************************************************************/
1816 void removeStartupExtension(const char * extensionName) {
1817 OSDictionary * startupExtensions = NULL; // don't release
1818 OSDictionary * extensionDict = NULL; // don't release
1819 OSDictionary * extensionPlist = NULL; // don't release
1820 OSDictionary * extensionPersonalities = NULL; // don't release
1821 OSDictionary * personality = NULL; // don't release
1822 OSCollectionIterator * keyIterator = NULL; // must release
1823 OSString * key = NULL; // don't release
1824
1825 startupExtensions = getStartupExtensions();
1826 if (!startupExtensions) goto finish;
1827
1828
1829 /* Find the extension's entry in the dictionary of
1830 * startup extensions.
1831 */
1832 extensionDict = OSDynamicCast(OSDictionary,
1833 startupExtensions->getObject(extensionName));
1834 if (!extensionDict) goto finish;
1835
1836 extensionPlist = OSDynamicCast(OSDictionary,
1837 extensionDict->getObject("plist"));
1838 if (!extensionPlist) goto finish;
1839
1840 extensionPersonalities = OSDynamicCast(OSDictionary,
1841 extensionPlist->getObject("IOKitPersonalities"));
1842 if (!extensionPersonalities) goto finish;
1843
1844 /* If it was there, remove it from the catalogue proper
1845 * by calling removeDrivers(). Pass true for the second
1846 * argument to trigger a new round of matching, and
1847 * then remove the extension from the dictionary of startup
1848 * extensions.
1849 */
1850 keyIterator = OSCollectionIterator::withCollection(
1851 extensionPersonalities);
1852 if (!keyIterator) {
1853 IOLog("Error: Couldn't allocate iterator to scan"
1854 " personalities for %s.\n", extensionName);
1855 LOG_DELAY();
1856 }
1857
1858 while ((key = OSDynamicCast(OSString, keyIterator->getNextObject()))) {
1859 personality = OSDynamicCast(OSDictionary,
1860 extensionPersonalities->getObject(key));
1861
1862
1863 if (personality) {
1864 gIOCatalogue->removeDrivers(personality, true);
1865 }
1866 }
1867
1868 startupExtensions->removeObject(extensionName);
1869
1870 finish:
1871
1872 if (keyIterator) keyIterator->release();
1873 return;
1874 }
1875
1876 /*********************************************************************
1877 * FIXME: This function invalidates the globals gStartupExtensions and
1878 * FIXME: ...gBootLoaderObjects without setting them to NULL. Since
1879 * FIXME: ...the code itself is immediately unloaded, there may not be
1880 * FIXME: ...any reason to worry about that!
1881 *********************************************************************/
1882 void clearStartupExtensionsAndLoaderInfo(void)
1883 {
1884 OSDictionary * startupExtensions = NULL; // must release
1885 OSArray * bootLoaderObjects = NULL; // must release
1886
1887 IORegistryEntry * bootxMemoryMap = NULL; // must release
1888 OSDictionary * propertyDict = NULL; // must release
1889 OSCollectionIterator * keyIterator = NULL; // must release
1890 OSString * key = NULL; // don't release
1891
1892 /*****
1893 * Drop any temporarily held data objects.
1894 */
1895 bootLoaderObjects = getBootLoaderObjects();
1896 if (bootLoaderObjects) {
1897 bootLoaderObjects->release();
1898 }
1899
1900 /****
1901 * If any "code" entries in driver dictionaries are accompanied
1902 * by "compressedCode" entries, then those data objects were
1903 * created based of of kmem_alloc()'ed memory, which must be
1904 * freed specially.
1905 */
1906 startupExtensions = getStartupExtensions();
1907 if (startupExtensions) {
1908 keyIterator =
1909 OSCollectionIterator::withCollection(startupExtensions);
1910 if (!keyIterator) {
1911 IOLog("Error: Couldn't allocate iterator for startup "
1912 "extensions.\n");
1913 LOG_DELAY();
1914 goto memory_map; // bail to the memory_map label
1915 }
1916
1917 while ( (key = OSDynamicCast(OSString,
1918 keyIterator->getNextObject())) ) {
1919
1920 OSDictionary * driverDict = 0;
1921 OSData * codeData = 0;
1922
1923 driverDict = OSDynamicCast(OSDictionary,
1924 startupExtensions->getObject(key));
1925 if (driverDict) {
1926 codeData = OSDynamicCast(OSData,
1927 driverDict->getObject("code"));
1928
1929 if (codeData &&
1930 driverDict->getObject("compressedCode")) {
1931
1932 kmem_free(kernel_map,
1933 (unsigned int)codeData->getBytesNoCopy(),
1934 codeData->getLength());
1935 }
1936 }
1937 }
1938
1939 keyIterator->release();
1940 startupExtensions->release();
1941 }
1942
1943 memory_map:
1944
1945 /****
1946 * Go through the device tree's memory map and remove any driver
1947 * data entries.
1948 */
1949 bootxMemoryMap =
1950 IORegistryEntry::fromPath(
1951 "/chosen/memory-map", // path
1952 gIODTPlane // plane
1953 );
1954 // return value is retained so be sure to release it
1955
1956 if (!bootxMemoryMap) {
1957 IOLog("Error: Couldn't read booter memory map.\n");
1958 LOG_DELAY();
1959 goto finish;
1960 }
1961
1962 propertyDict = bootxMemoryMap->dictionaryWithProperties();
1963 if (!propertyDict) {
1964 IOLog("Error: Couldn't get property dictionary "
1965 "from memory map.\n");
1966 LOG_DELAY();
1967 goto finish;
1968 }
1969
1970 keyIterator = OSCollectionIterator::withCollection(propertyDict);
1971 if (!keyIterator) {
1972 IOLog("Error: Couldn't allocate iterator for driver images.\n");
1973 LOG_DELAY();
1974 goto finish;
1975 }
1976
1977 while ( (key = OSDynamicCast(OSString,
1978 keyIterator->getNextObject())) ) {
1979
1980 const char * keyValue = key->getCStringNoCopy();
1981
1982 if ( !strncmp(keyValue, BOOTX_KEXT_PREFIX,
1983 strlen(BOOTX_KEXT_PREFIX)) ||
1984 !strncmp(keyValue, BOOTX_MULTIKEXT_PREFIX,
1985 strlen(BOOTX_MULTIKEXT_PREFIX)) ) {
1986
1987 OSData * bootxDriverDataObject = NULL;
1988 MemoryMapFileInfo * driverInfo = 0;
1989
1990 bootxDriverDataObject = OSDynamicCast(OSData,
1991 propertyDict->getObject(keyValue));
1992 // don't release bootxDriverDataObject
1993
1994 if (!bootxDriverDataObject) {
1995 continue;
1996 }
1997 driverInfo = (MemoryMapFileInfo *)
1998 bootxDriverDataObject->getBytesNoCopy(0,
1999 sizeof(MemoryMapFileInfo));
2000 IODTFreeLoaderInfo((char *)keyValue,
2001 (void *)driverInfo->paddr,
2002 (int)driverInfo->length);
2003 }
2004 }
2005
2006 finish:
2007 if (bootxMemoryMap) bootxMemoryMap->release();
2008 if (propertyDict) propertyDict->release();
2009 if (keyIterator) keyIterator->release();
2010
2011 return;
2012 }