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