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