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