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