]> git.saurik.com Git - apple/xnu.git/blob - libsa/catalogue.cpp
xnu-792.6.76.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 grade_binary(cpu_type_t exectype, cpu_subtype_t execsubtype);
50 // Return the address of the named Mach-O segment from the currently
51 // executing 32 bit kernel, or NULL.
52 extern struct segment_command *getsegbyname(char *seg_name);
53 // Return the address of the named section from the named Mach-O segment
54 // from the currently executing 32 bit kernel, or NULL.
55 extern struct section *getsectbyname(char *segname, char *sectname);
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 #if defined (__ppc__)
709 dataBuffer = (BootxDriverInfo *)ml_static_ptovirt(
710 driverInfo->paddr);
711 #elif defined (__i386__)
712 dataBuffer = (BootxDriverInfo *)driverInfo->paddr;
713 dataBuffer->plistAddr = ml_static_ptovirt(dataBuffer->plistAddr);
714 if (dataBuffer->moduleAddr)
715 dataBuffer->moduleAddr = ml_static_ptovirt(dataBuffer->moduleAddr);
716 #else
717 #error unsupported architecture
718 #endif
719 if (!dataBuffer) {
720 IOLog("Error: No data buffer "
721 "for device tree entry \"%s\".\n", memory_map_name);
722 LOG_DELAY();
723 error = 1;
724 goto finish;
725 }
726
727 driverPlist = OSDynamicCast(OSDictionary,
728 OSUnserializeXML(dataBuffer->plistAddr, &errorString));
729 if (!driverPlist) {
730 IOLog("Error: Couldn't read XML property list "
731 "for device tree entry \"%s\".\n", memory_map_name);
732 LOG_DELAY();
733 if (errorString) {
734 IOLog("XML parse error: %s.\n",
735 errorString->getCStringNoCopy());
736 LOG_DELAY();
737 }
738 error = 1;
739 goto finish;
740 }
741
742
743 driverName = OSDynamicCast(OSString,
744 driverPlist->getObject("CFBundleIdentifier")); // do not release
745 if (!driverName) {
746 IOLog("Error: Device tree entry \"%s\" has "
747 "no \"CFBundleIdentifier\" property.\n", memory_map_name);
748 LOG_DELAY();
749 error = 1;
750 goto finish;
751 }
752
753 /* Check if kmod is already loaded and is a real loadable one (has
754 * an address).
755 */
756 loaded_kmod = kmod_lookupbyname_locked(driverName->getCStringNoCopy());
757 if (loaded_kmod && loaded_kmod->address) {
758 IOLog("Skipping new extension \"%s\"; an extension named "
759 "\"%s\" is already loaded.\n",
760 driverName->getCStringNoCopy(),
761 loaded_kmod->name);
762 LOG_DELAY();
763 error = 1;
764 goto finish;
765 }
766
767 if (!validateExtensionDict(driverPlist, -1)) {
768 // validateExtensionsDict() logs an error
769 error = 1;
770 goto finish;
771 }
772
773 driverDict->setObject("plist", driverPlist);
774
775 /* It's perfectly okay for a KEXT to have no executable.
776 * Check that moduleAddr is nonzero before attempting to
777 * get one.
778 *
779 * NOTE: The driverCode object is created "no-copy", so
780 * it doesn't own that memory. The memory must be freed
781 * separately from the OSData object (see
782 * clearStartupExtensionsAndLoaderInfo() at the end of this file).
783 */
784 if (dataBuffer->moduleAddr && dataBuffer->moduleLength) {
785 driverCode = OSData::withBytesNoCopy(dataBuffer->moduleAddr,
786 dataBuffer->moduleLength);
787 if (!driverCode) {
788 IOLog("Error: Couldn't allocate data object "
789 "to hold code for device tree entry \"%s\".\n",
790 memory_map_name);
791 LOG_DELAY();
792 error = 1;
793 goto finish;
794 }
795
796 if (driverCode) {
797 driverDict->setObject("code", driverCode);
798 }
799 }
800
801 finish:
802
803 if (loaded_kmod) {
804 kfree((unsigned int)loaded_kmod, sizeof(kmod_info_t));
805 }
806
807 // do not release bootxDriverDataObject
808 // do not release driverName
809
810 if (driverPlist) {
811 driverPlist->release();
812 }
813 if (errorString) {
814 errorString->release();
815 }
816 if (driverCode) {
817 driverCode->release();
818 }
819 if (error) {
820 if (driverDict) {
821 driverDict->release();
822 driverDict = NULL;
823 }
824 }
825 return driverDict;
826 }
827
828
829 /*********************************************************************
830 * Used to uncompress a single file entry in an mkext archive.
831 *
832 * The OSData returned does not own its memory! You must deallocate
833 * that memory using kmem_free() before releasing the OSData().
834 *********************************************************************/
835 static bool uncompressFile(u_int8_t *base_address, mkext_file * fileinfo,
836 /* out */ OSData ** file) {
837
838 bool result = true;
839 kern_return_t kern_result;
840 u_int8_t * uncompressed_file = 0; // kmem_free() on error
841 OSData * uncompressedFile = 0; // returned
842 size_t uncompressed_size = 0;
843
844 size_t offset = OSSwapBigToHostInt32(fileinfo->offset);
845 size_t compsize = OSSwapBigToHostInt32(fileinfo->compsize);
846 size_t realsize = OSSwapBigToHostInt32(fileinfo->realsize);
847 time_t modifiedsecs = OSSwapBigToHostInt32(fileinfo->modifiedsecs);
848
849 *file = 0;
850
851 /* If these four fields are zero there's no file, but that isn't
852 * an error.
853 */
854 if (offset == 0 && compsize == 0 &&
855 realsize == 0 && modifiedsecs == 0) {
856 goto finish;
857 }
858
859 // Add 1 for '\0' to terminate XML string!
860 kern_result = kmem_alloc(kernel_map, (vm_offset_t *)&uncompressed_file,
861 realsize + 1);
862 if (kern_result != KERN_SUCCESS) {
863 IOLog("Error: Couldn't allocate data buffer "
864 "to uncompress file.\n");
865 LOG_DELAY();
866 result = false;
867 goto finish;
868 }
869
870 uncompressedFile = OSData::withBytesNoCopy(uncompressed_file,
871 realsize + 1);
872 if (!uncompressedFile) {
873 IOLog("Error: Couldn't allocate data object "
874 "to uncompress file.\n");
875 LOG_DELAY();
876 result = false;
877 goto finish;
878 }
879
880 if (compsize != 0) {
881 uncompressed_size = decompress_lzss(uncompressed_file,
882 base_address + offset,
883 compsize);
884 if (uncompressed_size != realsize) {
885 IOLog("Error: Uncompressed file is not the length "
886 "recorded.\n");
887 LOG_DELAY();
888 result = false;
889 goto finish;
890 }
891 uncompressed_file[uncompressed_size] = '\0';
892 } else {
893 bcopy(base_address + offset, uncompressed_file,
894 realsize);
895 uncompressed_file[realsize] = '\0';
896 }
897
898 *file = uncompressedFile;
899
900 finish:
901 if (!result) {
902 if (uncompressed_file) {
903 kmem_free(kernel_map, (vm_address_t)uncompressed_file,
904 realsize + 1);
905 }
906 if (uncompressedFile) {
907 uncompressedFile->release();
908 *file = 0;
909 }
910 }
911 return result;
912 }
913
914 bool uncompressModule(OSData *compData, /* out */ OSData ** file) {
915
916 MkextEntryInfo *info = (MkextEntryInfo *) compData->getBytesNoCopy();
917
918 return uncompressFile((u_int8_t *) info->base_address,
919 info->fileinfo, file);
920 }
921
922
923 /*********************************************************************
924 * Does the work of pulling extensions out of an mkext archive located
925 * in memory.
926 *********************************************************************/
927 bool extractExtensionsFromArchive(MemoryMapFileInfo * mkext_file_info,
928 OSDictionary * extensions) {
929
930 bool result = true;
931
932 u_int8_t * crc_address = 0;
933 u_int32_t checksum;
934 mkext_header * mkext_data = 0; // don't free
935 mkext_kext * onekext_data = 0; // don't free
936 mkext_file * plist_file = 0; // don't free
937 mkext_file * module_file = 0; // don't free
938 kmod_info_t * loaded_kmod = 0; // must free
939
940 OSData * driverPlistDataObject = 0; // must release
941 OSDictionary * driverPlist = 0; // must release
942 OSData * driverCode = 0; // must release
943 OSDictionary * driverDict = 0; // must release
944 OSString * moduleName = 0; // don't release
945 OSString * errorString = NULL; // must release
946
947 OSData * moduleInfo = 0; // must release
948 MkextEntryInfo module_info;
949
950
951 #if defined (__ppc__)
952 mkext_data = (mkext_header *)mkext_file_info->paddr;
953 #elif defined (__i386__)
954 mkext_data = (mkext_header *)ml_static_ptovirt(mkext_file_info->paddr);
955 #else
956 #error unsupported architecture
957 #endif
958 if (OSSwapBigToHostInt32(mkext_data->magic) != MKEXT_MAGIC ||
959 OSSwapBigToHostInt32(mkext_data->signature) != MKEXT_SIGN) {
960 IOLog("Error: Extension archive has invalid magic or signature.\n");
961 LOG_DELAY();
962 result = false;
963 goto finish;
964 }
965
966 if (OSSwapBigToHostInt32(mkext_data->length) != mkext_file_info->length) {
967 IOLog("Error: Mismatch between extension archive & "
968 "recorded length.\n");
969 LOG_DELAY();
970 result = false;
971 goto finish;
972 }
973
974 crc_address = (u_int8_t *)&mkext_data->version;
975 checksum = adler32(crc_address,
976 (unsigned int)mkext_data +
977 OSSwapBigToHostInt32(mkext_data->length) - (unsigned int)crc_address);
978
979 if (OSSwapBigToHostInt32(mkext_data->adler32) != checksum) {
980 IOLog("Error: Extension archive has a bad checksum.\n");
981 LOG_DELAY();
982 result = false;
983 goto finish;
984 }
985
986 /* If the MKEXT archive isn't fat, check that the CPU type & subtype
987 * match that of the running kernel.
988 */
989 if (OSSwapBigToHostInt32(mkext_data->cputype) != (UInt32)CPU_TYPE_ANY) {
990 kern_return_t kresult = KERN_FAILURE;
991 host_basic_info_data_t hostinfo;
992 host_info_t hostinfo_ptr = (host_info_t)&hostinfo;
993 mach_msg_type_number_t count = sizeof(hostinfo)/sizeof(integer_t);
994
995 kresult = host_info((host_t)1, HOST_BASIC_INFO,
996 hostinfo_ptr, &count);
997 if (kresult != KERN_SUCCESS) {
998 IOLog("Error: Couldn't get current host info.\n");
999 LOG_DELAY();
1000 result = false;
1001 goto finish;
1002 }
1003 if ((UInt32)hostinfo.cpu_type !=
1004 OSSwapBigToHostInt32(mkext_data->cputype)) {
1005
1006 IOLog("Error: Extension archive doesn't contain software "
1007 "for this computer's CPU type.\n");
1008 LOG_DELAY();
1009 result = false;
1010 goto finish;
1011 }
1012 if (!grade_binary(OSSwapBigToHostInt32(mkext_data->cputype),
1013 OSSwapBigToHostInt32(mkext_data->cpusubtype))) {
1014 IOLog("Error: Extension archive doesn't contain software "
1015 "for this computer's CPU subtype.\n");
1016 LOG_DELAY();
1017 result = false;
1018 goto finish;
1019 }
1020 }
1021
1022 for (unsigned int i = 0;
1023 i < OSSwapBigToHostInt32(mkext_data->numkexts);
1024 i++) {
1025
1026 if (loaded_kmod) {
1027 kfree((unsigned int)loaded_kmod, sizeof(kmod_info_t));
1028 loaded_kmod = 0;
1029 }
1030
1031 if (driverPlistDataObject) {
1032 kmem_free(kernel_map,
1033 (unsigned int)driverPlistDataObject->getBytesNoCopy(),
1034 driverPlistDataObject->getLength());
1035
1036 driverPlistDataObject->release();
1037 driverPlistDataObject = NULL;
1038 }
1039 if (driverPlist) {
1040 driverPlist->release();
1041 driverPlist = NULL;
1042 }
1043 if (driverCode) {
1044 driverCode->release();
1045 driverCode = NULL;
1046 }
1047 if (driverDict) {
1048 driverDict->release();
1049 driverDict = NULL;
1050 }
1051 if (errorString) {
1052 errorString->release();
1053 errorString = NULL;
1054 }
1055
1056 onekext_data = &mkext_data->kext[i];
1057 plist_file = &onekext_data->plist;
1058 module_file = &onekext_data->module;
1059
1060 if (!uncompressFile((u_int8_t *)mkext_data, plist_file,
1061 &driverPlistDataObject)) {
1062
1063 IOLog("Error: couldn't uncompress plist file "
1064 "from multikext archive entry %d.\n", i);
1065 LOG_DELAY();
1066 continue;
1067 }
1068
1069 if (!driverPlistDataObject) {
1070 IOLog("Error: No property list present "
1071 "for multikext archive entry %d.\n", i);
1072 LOG_DELAY();
1073 continue;
1074 } else {
1075 driverPlist = OSDynamicCast(OSDictionary,
1076 OSUnserializeXML(
1077 (char *)driverPlistDataObject->getBytesNoCopy(),
1078 &errorString));
1079 if (!driverPlist) {
1080 IOLog("Error: Couldn't read XML property list "
1081 "for multikext archive entry %d.\n", i);
1082 LOG_DELAY();
1083 if (errorString) {
1084 IOLog("XML parse error: %s.\n",
1085 errorString->getCStringNoCopy());
1086 LOG_DELAY();
1087 }
1088 continue;
1089 }
1090
1091 if (!validateExtensionDict(driverPlist, i)) {
1092 // validateExtensionsDict() logs an error
1093 continue;
1094 }
1095
1096 }
1097
1098 /* Get the extension's module name. This is used to record
1099 * the extension.
1100 */
1101 moduleName = OSDynamicCast(OSString,
1102 driverPlist->getObject("CFBundleIdentifier")); // do not release
1103 if (!moduleName) {
1104 IOLog("Error: Multikext archive entry %d has "
1105 "no \"CFBundleIdentifier\" property.\n", i);
1106 LOG_DELAY();
1107 continue; // assume a kext config error & continue
1108 }
1109
1110 /* Check if kmod is already loaded and is a real loadable one (has
1111 * an address).
1112 */
1113 loaded_kmod = kmod_lookupbyname_locked(moduleName->getCStringNoCopy());
1114 if (loaded_kmod && loaded_kmod->address) {
1115 IOLog("Skipping new extension \"%s\"; an extension named "
1116 "\"%s\" is already loaded.\n",
1117 moduleName->getCStringNoCopy(),
1118 loaded_kmod->name);
1119 continue;
1120 }
1121
1122
1123 driverDict = OSDictionary::withCapacity(2);
1124 if (!driverDict) {
1125 IOLog("Error: Couldn't allocate dictionary "
1126 "for multikext archive entry %d.\n", i);
1127 LOG_DELAY();
1128 result = false;
1129 goto finish;
1130 }
1131
1132 driverDict->setObject("plist", driverPlist);
1133
1134 /*****
1135 * Prepare an entry to hold the mkext entry info for the
1136 * compressed binary module, if there is one. If all four fields
1137 * of the module entry are zero, there isn't one.
1138 */
1139 if (!(loaded_kmod && loaded_kmod->address) && (OSSwapBigToHostInt32(module_file->offset) ||
1140 OSSwapBigToHostInt32(module_file->compsize) ||
1141 OSSwapBigToHostInt32(module_file->realsize) ||
1142 OSSwapBigToHostInt32(module_file->modifiedsecs))) {
1143
1144 moduleInfo = OSData::withCapacity(sizeof(MkextEntryInfo));
1145 if (!moduleInfo) {
1146 IOLog("Error: Couldn't allocate data object "
1147 "for multikext archive entry %d.\n", i);
1148 LOG_DELAY();
1149 result = false;
1150 goto finish;
1151 }
1152
1153 module_info.base_address = (vm_address_t)mkext_data;
1154 module_info.fileinfo = module_file;
1155
1156 if (!moduleInfo->appendBytes(&module_info, sizeof(module_info))) {
1157 IOLog("Error: Couldn't record info "
1158 "for multikext archive entry %d.\n", i);
1159 LOG_DELAY();
1160 result = false;
1161 goto finish;
1162 }
1163
1164 driverDict->setObject("compressedCode", moduleInfo);
1165 }
1166
1167 OSDictionary * incumbentExt = OSDynamicCast(OSDictionary,
1168 extensions->getObject(moduleName));
1169
1170 if (!incumbentExt) {
1171 extensions->setObject(moduleName, driverDict);
1172 } else {
1173 OSDictionary * mostRecentExtension =
1174 compareExtensionVersions(incumbentExt, driverDict);
1175
1176 if (mostRecentExtension == incumbentExt) {
1177 /* Do nothing, we've got the most recent. */
1178 } else if (mostRecentExtension == driverDict) {
1179 if (!extensions->setObject(moduleName, driverDict)) {
1180
1181 /* This is a fatal error, so bail.
1182 */
1183 IOLog("extractExtensionsFromArchive(): Failed to add "
1184 "identifier %s\n",
1185 moduleName->getCStringNoCopy());
1186 LOG_DELAY();
1187 result = false;
1188 goto finish;
1189 }
1190 } else /* should be NULL */ {
1191
1192 /* This is a nonfatal error, so continue.
1193 */
1194 IOLog("extractExtensionsFromArchive(): Error comparing "
1195 "versions of duplicate extensions %s.\n",
1196 moduleName->getCStringNoCopy());
1197 LOG_DELAY();
1198 continue;
1199 }
1200 }
1201 }
1202
1203 finish:
1204
1205 if (loaded_kmod) kfree((unsigned int)loaded_kmod, sizeof(kmod_info_t));
1206 if (driverPlistDataObject) {
1207 kmem_free(kernel_map,
1208 (unsigned int)driverPlistDataObject->getBytesNoCopy(),
1209 driverPlistDataObject->getLength());
1210 driverPlistDataObject->release();
1211 }
1212 if (driverPlist) driverPlist->release();
1213 if (driverCode) driverCode->release();
1214 if (moduleInfo) moduleInfo->release();
1215 if (driverDict) driverDict->release();
1216 if (errorString) errorString->release();
1217
1218 return result;
1219 }
1220
1221 /*********************************************************************
1222 *
1223 *********************************************************************/
1224 bool readExtensions(OSDictionary * propertyDict,
1225 const char * memory_map_name,
1226 OSDictionary * extensions) {
1227
1228 bool result = true;
1229 OSData * mkextDataObject = 0; // don't release
1230 MemoryMapFileInfo * mkext_file_info = 0; // don't free
1231
1232 mkextDataObject = OSDynamicCast(OSData,
1233 propertyDict->getObject(memory_map_name));
1234 // don't release mkextDataObject
1235
1236 if (!mkextDataObject) {
1237 IOLog("Error: No mkext data object "
1238 "for device tree entry \"%s\".\n",
1239 memory_map_name);
1240 LOG_DELAY();
1241 result = false;
1242 goto finish;
1243 }
1244
1245 mkext_file_info = (MemoryMapFileInfo *)mkextDataObject->getBytesNoCopy();
1246 if (!mkext_file_info) {
1247 result = false;
1248 goto finish;
1249 }
1250
1251 result = extractExtensionsFromArchive(mkext_file_info, extensions);
1252
1253 finish:
1254
1255 if (!result && extensions) {
1256 extensions->flushCollection();
1257 }
1258
1259 return result;
1260 }
1261
1262
1263 /*********************************************************************
1264 * Adds the personalities for an extensions dictionary to the global
1265 * IOCatalogue.
1266 *********************************************************************/
1267 bool addPersonalities(OSDictionary * extensions) {
1268 bool result = true;
1269 OSCollectionIterator * keyIterator = NULL; // must release
1270 OSString * key; // don't release
1271 OSDictionary * driverDict = NULL; // don't release
1272 OSDictionary * driverPlist = NULL; // don't release
1273 OSDictionary * thisDriverPersonalities = NULL; // don't release
1274 OSArray * allDriverPersonalities = NULL; // must release
1275
1276 allDriverPersonalities = OSArray::withCapacity(1);
1277 if (!allDriverPersonalities) {
1278 IOLog("Error: Couldn't allocate personality dictionary.\n");
1279 LOG_DELAY();
1280 result = false;
1281 goto finish;
1282 }
1283
1284 /* Record all personalities found so that they can be
1285 * added to the catalogue.
1286 * Note: Not all extensions have personalities.
1287 */
1288
1289 keyIterator = OSCollectionIterator::withCollection(extensions);
1290 if (!keyIterator) {
1291 IOLog("Error: Couldn't allocate iterator to record personalities.\n");
1292 LOG_DELAY();
1293 result = false;
1294 goto finish;
1295 }
1296
1297 while ( ( key = OSDynamicCast(OSString,
1298 keyIterator->getNextObject() ))) {
1299
1300 driverDict = OSDynamicCast(OSDictionary,
1301 extensions->getObject(key));
1302 driverPlist = OSDynamicCast(OSDictionary,
1303 driverDict->getObject("plist"));
1304 thisDriverPersonalities = OSDynamicCast(OSDictionary,
1305 driverPlist->getObject("IOKitPersonalities"));
1306
1307 if (thisDriverPersonalities) {
1308 OSCollectionIterator * pIterator;
1309 OSString * locakKey;
1310 pIterator = OSCollectionIterator::withCollection(
1311 thisDriverPersonalities);
1312 if (!pIterator) {
1313 IOLog("Error: Couldn't allocate iterator "
1314 "to record extension personalities.\n");
1315 LOG_DELAY();
1316 continue;
1317 }
1318 while ( (locakKey = OSDynamicCast(OSString,
1319 pIterator->getNextObject())) ) {
1320
1321 OSDictionary * personality = OSDynamicCast(
1322 OSDictionary,
1323 thisDriverPersonalities->getObject(locakKey));
1324 if (personality) {
1325 allDriverPersonalities->setObject(personality);
1326 }
1327 }
1328 pIterator->release();
1329 }
1330 } /* extract personalities */
1331
1332
1333 /* Add all personalities found to the IOCatalogue,
1334 * but don't start matching.
1335 */
1336 gIOCatalogue->addDrivers(allDriverPersonalities, false);
1337
1338 finish:
1339
1340 if (allDriverPersonalities) allDriverPersonalities->release();
1341 if (keyIterator) keyIterator->release();
1342
1343 return result;
1344 }
1345
1346
1347 /*********************************************************************
1348 * Called from IOCatalogue to add extensions from an mkext archive.
1349 * This function makes a copy of the mkext object passed in because
1350 * the device tree support code dumps it after calling us (indirectly
1351 * through the IOCatalogue).
1352 *********************************************************************/
1353 bool addExtensionsFromArchive(OSData * mkextDataObject) {
1354 bool result = true;
1355
1356 OSDictionary * startupExtensions = NULL; // don't release
1357 OSArray * bootLoaderObjects = NULL; // don't release
1358 OSDictionary * extensions = NULL; // must release
1359 MemoryMapFileInfo mkext_file_info;
1360 OSCollectionIterator * keyIterator = NULL; // must release
1361 OSString * key = NULL; // don't release
1362
1363 startupExtensions = getStartupExtensions();
1364 if (!startupExtensions) {
1365 IOLog("Can't record extension archive; there is no"
1366 " extensions dictionary.\n");
1367 LOG_DELAY();
1368 result = false;
1369 goto finish;
1370 }
1371
1372 bootLoaderObjects = getBootLoaderObjects();
1373 if (! bootLoaderObjects) {
1374 IOLog("Error: Couldn't allocate array to hold temporary objects.\n");
1375 LOG_DELAY();
1376 result = false;
1377 goto finish;
1378 }
1379
1380 extensions = OSDictionary::withCapacity(2);
1381 if (!extensions) {
1382 IOLog("Error: Couldn't allocate dictionary to unpack "
1383 "extension archive.\n");
1384 LOG_DELAY();
1385 result = false;
1386 goto finish;
1387 }
1388
1389 mkext_file_info.paddr = (UInt32)mkextDataObject->getBytesNoCopy();
1390 mkext_file_info.length = mkextDataObject->getLength();
1391
1392 /* Save the local mkext data object so that we can deallocate it later.
1393 */
1394 bootLoaderObjects->setObject(mkextDataObject);
1395
1396 result = extractExtensionsFromArchive(&mkext_file_info, extensions);
1397 if (!result) {
1398 IOLog("Error: Failed to extract extensions from archive.\n");
1399 LOG_DELAY();
1400 result = false;
1401 goto finish;
1402 }
1403
1404 result = mergeExtensionDictionaries(startupExtensions, extensions);
1405 if (!result) {
1406 IOLog("Error: Failed to merge new extensions into existing set.\n");
1407 LOG_DELAY();
1408 goto finish;
1409 }
1410
1411 result = addPersonalities(extensions);
1412 if (!result) {
1413 IOLog("Error: Failed to add personalities for extensions extracted "
1414 "from archive.\n");
1415 LOG_DELAY();
1416 result = false;
1417 goto finish;
1418 }
1419
1420 finish:
1421
1422 if (!result) {
1423 IOLog("Error: Failed to record extensions from archive.\n");
1424 LOG_DELAY();
1425 } else {
1426 keyIterator = OSCollectionIterator::withCollection(
1427 extensions);
1428
1429 if (keyIterator) {
1430 while ( (key = OSDynamicCast(OSString,
1431 keyIterator->getNextObject())) ) {
1432
1433 IOLog("Added extension \"%s\" from archive.\n",
1434 key->getCStringNoCopy());
1435 LOG_DELAY();
1436 }
1437 keyIterator->release();
1438 }
1439 }
1440
1441 if (extensions) extensions->release();
1442
1443 return result;
1444 }
1445
1446
1447 /*********************************************************************
1448 * This function builds dictionaries for the startup extensions
1449 * put into memory by bootx, recording each in the startup extensions
1450 * dictionary. The dictionary format is this:
1451 *
1452 * {
1453 * "plist" = (the extension's Info.plist as an OSDictionary)
1454 * "code" = (an OSData containing the executable file)
1455 * }
1456 *
1457 * This function returns true if any extensions were found and
1458 * recorded successfully, or if there are no start extensions,
1459 * and false if an unrecoverable error occurred. An error reading
1460 * a single extension is not considered fatal, and this function
1461 * will simply skip the problematic extension to try the next one.
1462 *********************************************************************/
1463
1464 bool recordStartupExtensions(void) {
1465 bool result = true;
1466 OSDictionary * startupExtensions = NULL; // must release
1467 OSDictionary * existingExtensions = NULL; // don't release
1468 OSDictionary * mkextExtensions = NULL; // must release
1469 IORegistryEntry * bootxMemoryMap = NULL; // must release
1470 OSDictionary * propertyDict = NULL; // must release
1471 OSCollectionIterator * keyIterator = NULL; // must release
1472 OSString * key = NULL; // don't release
1473
1474 OSDictionary * newDriverDict = NULL; // must release
1475 OSDictionary * driverPlist = NULL; // don't release
1476
1477 struct section * infosect;
1478 struct section * symsect;
1479 unsigned int prelinkedCount = 0;
1480
1481 existingExtensions = getStartupExtensions();
1482 if (!existingExtensions) {
1483 IOLog("Error: There is no dictionary for startup extensions.\n");
1484 LOG_DELAY();
1485 result = false;
1486 goto finish;
1487 }
1488
1489 startupExtensions = OSDictionary::withCapacity(1);
1490 if (!startupExtensions) {
1491 IOLog("Error: Couldn't allocate dictionary "
1492 "to record startup extensions.\n");
1493 LOG_DELAY();
1494 result = false;
1495 goto finish;
1496 }
1497
1498 // --
1499 // add any prelinked modules as startup extensions
1500
1501 infosect = getsectbyname("__PRELINK", "__info");
1502 symsect = getsectbyname("__PRELINK", "__symtab");
1503 if (infosect && infosect->addr && infosect->size
1504 && symsect && symsect->addr && symsect->size) do
1505 {
1506 gIOPrelinkedModules = OSDynamicCast(OSArray,
1507 OSUnserializeXML((const char *) infosect->addr, NULL));
1508
1509 if (!gIOPrelinkedModules)
1510 break;
1511 for( unsigned int idx = 0;
1512 (propertyDict = OSDynamicCast(OSDictionary, gIOPrelinkedModules->getObject(idx)));
1513 idx++)
1514 {
1515 enum { kPrelinkReservedCount = 4 };
1516
1517 /* Get the extension's module name. This is used to record
1518 * the extension. Do *not* release the moduleName.
1519 */
1520 OSString * moduleName = OSDynamicCast(OSString,
1521 propertyDict->getObject("CFBundleIdentifier"));
1522 if (!moduleName) {
1523 IOLog("Error: Prelinked module entry has "
1524 "no \"CFBundleIdentifier\" property.\n");
1525 LOG_DELAY();
1526 continue;
1527 }
1528
1529 /* Add the kext, & its plist.
1530 */
1531 newDriverDict = OSDictionary::withCapacity(4);
1532 assert(newDriverDict);
1533 newDriverDict->setObject("plist", propertyDict);
1534 startupExtensions->setObject(moduleName, newDriverDict);
1535 newDriverDict->release();
1536
1537 /* Add the code if present.
1538 */
1539 OSData * data = OSDynamicCast(OSData, propertyDict->getObject("OSBundlePrelink"));
1540 if (data) {
1541 if (data->getLength() < (kPrelinkReservedCount * sizeof(UInt32))) {
1542 IOLog("Error: Prelinked module entry has "
1543 "invalid \"OSBundlePrelink\" property.\n");
1544 LOG_DELAY();
1545 continue;
1546 }
1547 UInt32 * prelink;
1548 prelink = (UInt32 *) data->getBytesNoCopy();
1549 kmod_info_t * kmod_info = (kmod_info_t *) OSReadBigInt32(prelink, 0);
1550 // end of "file" is end of symbol sect
1551 data = OSData::withBytesNoCopy((void *) kmod_info->address,
1552 symsect->addr + symsect->size - kmod_info->address);
1553 newDriverDict->setObject("code", data);
1554 data->release();
1555 prelinkedCount++;
1556 continue;
1557 }
1558 /* Add the symbols if present.
1559 */
1560 OSNumber * num = OSDynamicCast(OSNumber, propertyDict->getObject("OSBundlePrelinkSymbols"));
1561 if (num) {
1562 UInt32 offset = num->unsigned32BitValue();
1563 data = OSData::withBytesNoCopy((void *) (symsect->addr + offset), symsect->size - offset);
1564 newDriverDict->setObject("code", data);
1565 data->release();
1566 prelinkedCount++;
1567 continue;
1568 }
1569 }
1570 if (gIOPrelinkedModules)
1571 IOLog("%d prelinked modules\n", prelinkedCount);
1572
1573 // free __info
1574 vm_offset_t
1575 virt = ml_static_ptovirt(infosect->addr);
1576 if( virt) {
1577 ml_static_mfree(virt, infosect->size);
1578 }
1579 newDriverDict = NULL;
1580 }
1581 while (false);
1582 // --
1583
1584 bootxMemoryMap =
1585 IORegistryEntry::fromPath(
1586 "/chosen/memory-map", // path
1587 gIODTPlane // plane
1588 );
1589 // return value is retained so be sure to release it
1590
1591 if (!bootxMemoryMap) {
1592 IOLog("Error: Couldn't read booter memory map.\n");
1593 LOG_DELAY();
1594 result = false;
1595 goto finish;
1596 }
1597
1598 propertyDict = bootxMemoryMap->dictionaryWithProperties();
1599 if (!propertyDict) {
1600 IOLog("Error: Couldn't get property dictionary "
1601 "from memory map.\n");
1602 LOG_DELAY();
1603 result = false;
1604 goto finish;
1605 }
1606
1607 keyIterator = OSCollectionIterator::withCollection(propertyDict);
1608 if (!keyIterator) {
1609 IOLog("Error: Couldn't allocate iterator for driver images.\n");
1610 LOG_DELAY();
1611 result = false;
1612 goto finish;
1613 }
1614
1615 while ( (key = OSDynamicCast(OSString,
1616 keyIterator->getNextObject())) ) {
1617 /* Clear newDriverDict & mkextExtensions upon entry to the loop,
1618 * handling both successful and unsuccessful iterations.
1619 */
1620 if (newDriverDict) {
1621 newDriverDict->release();
1622 newDriverDict = NULL;
1623 }
1624 if (mkextExtensions) {
1625 mkextExtensions->release();
1626 mkextExtensions = NULL;
1627 }
1628
1629 const char * keyValue = key->getCStringNoCopy();
1630
1631 if ( !strncmp(keyValue, BOOTX_KEXT_PREFIX,
1632 strlen(BOOTX_KEXT_PREFIX)) ) {
1633
1634 /* Read the extension from the bootx-supplied memory.
1635 */
1636 newDriverDict = readExtension(propertyDict, keyValue);
1637 if (!newDriverDict) {
1638 IOLog("Error: Couldn't read data "
1639 "for device tree entry \"%s\".\n", keyValue);
1640 LOG_DELAY();
1641 continue;
1642 }
1643
1644
1645 /* Preprare to record the extension by getting its info plist.
1646 */
1647 driverPlist = OSDynamicCast(OSDictionary,
1648 newDriverDict->getObject("plist"));
1649 if (!driverPlist) {
1650 IOLog("Error: Extension in device tree entry \"%s\" "
1651 "has no property list.\n", keyValue);
1652 LOG_DELAY();
1653 continue;
1654 }
1655
1656
1657 /* Get the extension's module name. This is used to record
1658 * the extension. Do *not* release the moduleName.
1659 */
1660 OSString * moduleName = OSDynamicCast(OSString,
1661 driverPlist->getObject("CFBundleIdentifier"));
1662 if (!moduleName) {
1663 IOLog("Error: Device tree entry \"%s\" has "
1664 "no \"CFBundleIdentifier\" property.\n", keyValue);
1665 LOG_DELAY();
1666 continue;
1667 }
1668
1669
1670 /* All has gone well so far, so record the extension under
1671 * its module name, checking for an existing duplicate.
1672 *
1673 * Do not release moduleName, as it's part of the extension's
1674 * plist.
1675 */
1676 OSDictionary * incumbentExt = OSDynamicCast(OSDictionary,
1677 startupExtensions->getObject(moduleName));
1678
1679 if (!incumbentExt) {
1680 startupExtensions->setObject(moduleName, newDriverDict);
1681 } else {
1682 OSDictionary * mostRecentExtension =
1683 compareExtensionVersions(incumbentExt, newDriverDict);
1684
1685 if (mostRecentExtension == incumbentExt) {
1686 /* Do nothing, we've got the most recent. */
1687 } else if (mostRecentExtension == newDriverDict) {
1688 if (!startupExtensions->setObject(moduleName,
1689 newDriverDict)) {
1690
1691 /* This is a fatal error, so bail.
1692 */
1693 IOLog("recordStartupExtensions(): Failed to add "
1694 "identifier %s\n",
1695 moduleName->getCStringNoCopy());
1696 LOG_DELAY();
1697 result = false;
1698 goto finish;
1699 }
1700 } else /* should be NULL */ {
1701
1702 /* This is a nonfatal error, so continue.
1703 */
1704 IOLog("recordStartupExtensions(): Error comparing "
1705 "versions of duplicate extensions %s.\n",
1706 moduleName->getCStringNoCopy());
1707 LOG_DELAY();
1708 continue;
1709 }
1710 }
1711
1712
1713 } else if ( !strncmp(keyValue, BOOTX_MULTIKEXT_PREFIX,
1714 strlen(BOOTX_MULTIKEXT_PREFIX)) ) {
1715
1716 mkextExtensions = OSDictionary::withCapacity(10);
1717 if (!mkextExtensions) {
1718 IOLog("Error: Couldn't allocate dictionary to unpack "
1719 "multi-extension archive.\n");
1720 LOG_DELAY();
1721 result = false;
1722 goto finish; // allocation failure is fatal for this routine
1723 }
1724 if (!readExtensions(propertyDict, keyValue, mkextExtensions)) {
1725 IOLog("Error: Couldn't unpack multi-extension archive.\n");
1726 LOG_DELAY();
1727 continue;
1728 } else {
1729 if (!mergeExtensionDictionaries(startupExtensions,
1730 mkextExtensions)) {
1731
1732 IOLog("Error: Failed to merge new extensions into "
1733 "existing set.\n");
1734 LOG_DELAY();
1735 result = false;
1736 goto finish; // merge error is fatal for this routine
1737 }
1738 }
1739 }
1740
1741 // Do not release key.
1742
1743 } /* while ( (key = OSDynamicCast(OSString, ...) ) ) */
1744
1745 if (!mergeExtensionDictionaries(existingExtensions, startupExtensions)) {
1746 IOLog("Error: Failed to merge new extensions into existing set.\n");
1747 LOG_DELAY();
1748 result = false;
1749 goto finish;
1750 }
1751
1752 result = addPersonalities(startupExtensions);
1753 if (!result) {
1754 IOLog("Error: Failed to add personalities for extensions extracted "
1755 "from archive.\n");
1756 LOG_DELAY();
1757 result = false;
1758 goto finish;
1759 }
1760
1761 finish:
1762
1763 // reused so clear first!
1764 if (keyIterator) {
1765 keyIterator->release();
1766 keyIterator = 0;
1767 }
1768
1769 if (!result) {
1770 IOLog("Error: Failed to record startup extensions.\n");
1771 LOG_DELAY();
1772 } else {
1773 #if DEBUG
1774 keyIterator = OSCollectionIterator::withCollection(
1775 startupExtensions);
1776
1777 if (keyIterator) {
1778 while ( (key = OSDynamicCast(OSString,
1779 keyIterator->getNextObject())) ) {
1780
1781 IOLog("Found extension \"%s\".\n",
1782 key->getCStringNoCopy());
1783 LOG_DELAY();
1784 }
1785 keyIterator->release();
1786 keyIterator = 0;
1787 }
1788 #endif /* DEBUG */
1789 }
1790
1791 if (newDriverDict) newDriverDict->release();
1792 if (propertyDict) propertyDict->release();
1793 if (bootxMemoryMap) bootxMemoryMap->release();
1794 if (mkextExtensions) mkextExtensions->release();
1795 if (startupExtensions) startupExtensions->release();
1796
1797 return result;
1798 }
1799
1800
1801 /*********************************************************************
1802 * This function removes an entry from the dictionary of startup
1803 * extensions. It's used when an extension can't be loaded, for
1804 * whatever reason. For drivers, this allows another matching driver
1805 * to be loaded, so that, for example, a driver for the root device
1806 * can be found.
1807 *********************************************************************/
1808 void removeStartupExtension(const char * extensionName) {
1809 OSDictionary * startupExtensions = NULL; // don't release
1810 OSDictionary * extensionDict = NULL; // don't release
1811 OSDictionary * extensionPlist = NULL; // don't release
1812 OSDictionary * extensionPersonalities = NULL; // don't release
1813 OSDictionary * personality = NULL; // don't release
1814 OSCollectionIterator * keyIterator = NULL; // must release
1815 OSString * key = NULL; // don't release
1816
1817 startupExtensions = getStartupExtensions();
1818 if (!startupExtensions) goto finish;
1819
1820
1821 /* Find the extension's entry in the dictionary of
1822 * startup extensions.
1823 */
1824 extensionDict = OSDynamicCast(OSDictionary,
1825 startupExtensions->getObject(extensionName));
1826 if (!extensionDict) goto finish;
1827
1828 extensionPlist = OSDynamicCast(OSDictionary,
1829 extensionDict->getObject("plist"));
1830 if (!extensionPlist) goto finish;
1831
1832 extensionPersonalities = OSDynamicCast(OSDictionary,
1833 extensionPlist->getObject("IOKitPersonalities"));
1834 if (!extensionPersonalities) goto finish;
1835
1836 /* If it was there, remove it from the catalogue proper
1837 * by calling removeDrivers(). Pass true for the second
1838 * argument to trigger a new round of matching, and
1839 * then remove the extension from the dictionary of startup
1840 * extensions.
1841 */
1842 keyIterator = OSCollectionIterator::withCollection(
1843 extensionPersonalities);
1844 if (!keyIterator) {
1845 IOLog("Error: Couldn't allocate iterator to scan"
1846 " personalities for %s.\n", extensionName);
1847 LOG_DELAY();
1848 }
1849
1850 while ((key = OSDynamicCast(OSString, keyIterator->getNextObject()))) {
1851 personality = OSDynamicCast(OSDictionary,
1852 extensionPersonalities->getObject(key));
1853
1854
1855 if (personality) {
1856 gIOCatalogue->removeDrivers(personality, true);
1857 }
1858 }
1859
1860 startupExtensions->removeObject(extensionName);
1861
1862 finish:
1863
1864 if (keyIterator) keyIterator->release();
1865 return;
1866 }
1867
1868 /*********************************************************************
1869 * FIXME: This function invalidates the globals gStartupExtensions and
1870 * FIXME: ...gBootLoaderObjects without setting them to NULL. Since
1871 * FIXME: ...the code itself is immediately unloaded, there may not be
1872 * FIXME: ...any reason to worry about that!
1873 *********************************************************************/
1874 void clearStartupExtensionsAndLoaderInfo(void)
1875 {
1876 OSDictionary * startupExtensions = NULL; // must release
1877 OSArray * bootLoaderObjects = NULL; // must release
1878
1879 IORegistryEntry * bootxMemoryMap = NULL; // must release
1880 OSDictionary * propertyDict = NULL; // must release
1881 OSCollectionIterator * keyIterator = NULL; // must release
1882 OSString * key = NULL; // don't release
1883
1884 /*****
1885 * Drop any temporarily held data objects.
1886 */
1887 bootLoaderObjects = getBootLoaderObjects();
1888 if (bootLoaderObjects) {
1889 bootLoaderObjects->release();
1890 }
1891
1892 /****
1893 * If any "code" entries in driver dictionaries are accompanied
1894 * by "compressedCode" entries, then those data objects were
1895 * created based of of kmem_alloc()'ed memory, which must be
1896 * freed specially.
1897 */
1898 startupExtensions = getStartupExtensions();
1899 if (startupExtensions) {
1900 keyIterator =
1901 OSCollectionIterator::withCollection(startupExtensions);
1902 if (!keyIterator) {
1903 IOLog("Error: Couldn't allocate iterator for startup "
1904 "extensions.\n");
1905 LOG_DELAY();
1906 goto memory_map; // bail to the memory_map label
1907 }
1908
1909 while ( (key = OSDynamicCast(OSString,
1910 keyIterator->getNextObject())) ) {
1911
1912 OSDictionary * driverDict = 0;
1913 OSData * codeData = 0;
1914
1915 driverDict = OSDynamicCast(OSDictionary,
1916 startupExtensions->getObject(key));
1917 if (driverDict) {
1918 codeData = OSDynamicCast(OSData,
1919 driverDict->getObject("code"));
1920
1921 if (codeData &&
1922 driverDict->getObject("compressedCode")) {
1923
1924 kmem_free(kernel_map,
1925 (unsigned int)codeData->getBytesNoCopy(),
1926 codeData->getLength());
1927 }
1928 }
1929 }
1930
1931 keyIterator->release();
1932 startupExtensions->release();
1933 }
1934
1935 memory_map:
1936
1937 /****
1938 * Go through the device tree's memory map and remove any driver
1939 * data entries.
1940 */
1941 bootxMemoryMap =
1942 IORegistryEntry::fromPath(
1943 "/chosen/memory-map", // path
1944 gIODTPlane // plane
1945 );
1946 // return value is retained so be sure to release it
1947
1948 if (!bootxMemoryMap) {
1949 IOLog("Error: Couldn't read booter memory map.\n");
1950 LOG_DELAY();
1951 goto finish;
1952 }
1953
1954 propertyDict = bootxMemoryMap->dictionaryWithProperties();
1955 if (!propertyDict) {
1956 IOLog("Error: Couldn't get property dictionary "
1957 "from memory map.\n");
1958 LOG_DELAY();
1959 goto finish;
1960 }
1961
1962 keyIterator = OSCollectionIterator::withCollection(propertyDict);
1963 if (!keyIterator) {
1964 IOLog("Error: Couldn't allocate iterator for driver images.\n");
1965 LOG_DELAY();
1966 goto finish;
1967 }
1968
1969 while ( (key = OSDynamicCast(OSString,
1970 keyIterator->getNextObject())) ) {
1971
1972 const char * keyValue = key->getCStringNoCopy();
1973
1974 if ( !strncmp(keyValue, BOOTX_KEXT_PREFIX,
1975 strlen(BOOTX_KEXT_PREFIX)) ||
1976 !strncmp(keyValue, BOOTX_MULTIKEXT_PREFIX,
1977 strlen(BOOTX_MULTIKEXT_PREFIX)) ) {
1978
1979 OSData * bootxDriverDataObject = NULL;
1980 MemoryMapFileInfo * driverInfo = 0;
1981
1982 bootxDriverDataObject = OSDynamicCast(OSData,
1983 propertyDict->getObject(keyValue));
1984 // don't release bootxDriverDataObject
1985
1986 if (!bootxDriverDataObject) {
1987 continue;
1988 }
1989 driverInfo = (MemoryMapFileInfo *)
1990 bootxDriverDataObject->getBytesNoCopy(0,
1991 sizeof(MemoryMapFileInfo));
1992 IODTFreeLoaderInfo((char *)keyValue,
1993 (void *)driverInfo->paddr,
1994 (int)driverInfo->length);
1995 }
1996 }
1997
1998 finish:
1999 if (bootxMemoryMap) bootxMemoryMap->release();
2000 if (propertyDict) propertyDict->release();
2001 if (keyIterator) keyIterator->release();
2002
2003 return;
2004 }