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