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