]> git.saurik.com Git - apple/xnu.git/blob - libsa/catalogue.cpp
2de5325bdb81cdae0d25fff940fcb158ffdf2df4
[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
429 bootxDriverDataObject = OSDynamicCast(OSData,
430 propertyDict->getObject(memory_map_name));
431 // don't release bootxDriverDataObject
432
433 if (!bootxDriverDataObject) {
434 IOLog("Error: No driver data object "
435 "for device tree entry \"%s\".\n",
436 memory_map_name);
437 LOG_DELAY();
438 error = 1;
439 goto finish;
440 }
441
442 driverDict = OSDictionary::withCapacity(2);
443 if (!driverDict) {
444 IOLog("Error: Couldn't allocate dictionary "
445 "for device tree entry \"%s\".\n", memory_map_name);
446 LOG_DELAY();
447 error = 1;
448 goto finish;
449 }
450
451 driverInfo = (MemoryMapFileInfo *)
452 bootxDriverDataObject->getBytesNoCopy(0,
453 sizeof(MemoryMapFileInfo));
454 dataBuffer = (BootxDriverInfo *)ml_static_ptovirt(
455 driverInfo->paddr);
456 if (!dataBuffer) {
457 IOLog("Error: No data buffer "
458 "for device tree entry \"%s\".\n", memory_map_name);
459 LOG_DELAY();
460 error = 1;
461 goto finish;
462 }
463
464 driverPlist = OSDynamicCast(OSDictionary,
465 OSUnserializeXML(dataBuffer->plistAddr, &errorString));
466 if (!driverPlist) {
467 IOLog("Error: Couldn't read XML property list "
468 "for device tree entry \"%s\".\n", memory_map_name);
469 LOG_DELAY();
470 if (errorString) {
471 IOLog("XML parse error: %s.\n",
472 errorString->getCStringNoCopy());
473 LOG_DELAY();
474 }
475 error = 1;
476 goto finish;
477 }
478
479
480 driverName = OSDynamicCast(OSString,
481 driverPlist->getObject("CFBundleIdentifier")); // do not release
482 if (!driverName) {
483 IOLog("Error: Device tree entry \"%s\" has "
484 "no \"CFBundleIdentifier\" property.\n", memory_map_name);
485 LOG_DELAY();
486 error = 1;
487 goto finish;
488 }
489
490 /* Check if kmod is already loaded and is a real loadable one (has
491 * an address).
492 */
493 loaded_kmod = kmod_lookupbyname(driverName->getCStringNoCopy());
494 if (loaded_kmod && loaded_kmod->address) {
495 IOLog("Skipping new extension \"%s\"; an extension named "
496 "\"%s\" is already loaded.\n",
497 driverName->getCStringNoCopy(),
498 loaded_kmod->name);
499 LOG_DELAY();
500 error = 1;
501 goto finish;
502 }
503
504 if (!validateExtensionDict(driverPlist)) {
505 IOLog("Error: Failed to validate property list "
506 "for device tree entry \"%s\".\n", memory_map_name);
507 LOG_DELAY();
508 error = 1;
509 goto finish;
510 }
511
512 driverDict->setObject("plist", driverPlist);
513
514 /* It's perfectly okay for a KEXT to have no executable.
515 * Check that moduleAddr is nonzero before attempting to
516 * get one.
517 *
518 * NOTE: The driverCode object is created "no-copy", so
519 * it doesn't own that memory. The memory must be freed
520 * separately from the OSData object (see
521 * clearStartupExtensionsAndLoaderInfo() at the end of this file).
522 */
523 if (dataBuffer->moduleAddr && dataBuffer->moduleLength) {
524 driverCode = OSData::withBytesNoCopy(dataBuffer->moduleAddr,
525 dataBuffer->moduleLength);
526 if (!driverCode) {
527 IOLog("Error: Couldn't allocate data object "
528 "to hold code for device tree entry \"%s\".\n",
529 memory_map_name);
530 LOG_DELAY();
531 error = 1;
532 goto finish;
533 }
534
535 if (driverCode) {
536 driverDict->setObject("code", driverCode);
537 }
538 }
539
540 finish:
541
542 // do not release bootxDriverDataObject
543 // do not release driverName
544
545 if (driverPlist) {
546 driverPlist->release();
547 }
548 if (errorString) {
549 errorString->release();
550 }
551 if (driverCode) {
552 driverCode->release();
553 }
554 if (error) {
555 if (driverDict) {
556 driverDict->release();
557 driverDict = NULL;
558 }
559 }
560 return driverDict;
561 }
562
563
564 /*********************************************************************
565 * Used to uncompress a single file entry in an mkext archive.
566 *
567 * The OSData returned does not own its memory! You must deallocate
568 * that memory using kmem_free() before releasing the OSData().
569 *********************************************************************/
570 static bool uncompressFile(u_int8_t *base_address, mkext_file * fileinfo,
571 /* out */ OSData ** file) {
572
573 bool result = true;
574 kern_return_t kern_result;
575 u_int8_t * uncompressed_file = 0; // kmem_free() on error
576 OSData * uncompressedFile = 0; // returned
577 size_t uncompressed_size = 0;
578
579 size_t offset = OSSwapBigToHostInt32(fileinfo->offset);
580 size_t compsize = OSSwapBigToHostInt32(fileinfo->compsize);
581 size_t realsize = OSSwapBigToHostInt32(fileinfo->realsize);
582 time_t modifiedsecs = OSSwapBigToHostInt32(fileinfo->modifiedsecs);
583
584 *file = 0;
585
586 /* If these four fields are zero there's no file, but that isn't
587 * an error.
588 */
589 if (offset == 0 && compsize == 0 &&
590 realsize == 0 && modifiedsecs == 0) {
591 goto finish;
592 }
593
594 // Add 1 for '\0' to terminate XML string!
595 kern_result = kmem_alloc(kernel_map, (vm_offset_t *)&uncompressed_file,
596 realsize + 1);
597 if (kern_result != KERN_SUCCESS) {
598 IOLog("Error: Couldn't allocate data buffer "
599 "to uncompress file.\n");
600 LOG_DELAY();
601 result = false;
602 goto finish;
603 }
604
605 uncompressedFile = OSData::withBytesNoCopy(uncompressed_file,
606 realsize + 1);
607 if (!uncompressedFile) {
608 IOLog("Error: Couldn't allocate data object "
609 "to uncompress file.\n");
610 LOG_DELAY();
611 result = false;
612 goto finish;
613 }
614
615 if (compsize != 0) {
616 uncompressed_size = decompress_lzss(uncompressed_file,
617 base_address + offset,
618 compsize);
619 if (uncompressed_size != realsize) {
620 IOLog("Error: Uncompressed file is not the length "
621 "recorded.\n");
622 LOG_DELAY();
623 result = false;
624 goto finish;
625 }
626 } else {
627 bcopy(base_address + offset, uncompressed_file,
628 compsize);
629 }
630 uncompressed_file[uncompressed_size] = '\0';
631
632 *file = uncompressedFile;
633
634 finish:
635 if (!result) {
636 if (uncompressed_file) {
637 kmem_free(kernel_map, (vm_address_t)uncompressed_file,
638 realsize + 1);
639 }
640 if (uncompressedFile) {
641 uncompressedFile->release();
642 *file = 0;
643 }
644 }
645 return result;
646 }
647
648 bool uncompressModule(OSData *compData, /* out */ OSData ** file) {
649
650 MkextEntryInfo *info = (MkextEntryInfo *) compData->getBytesNoCopy();
651
652 return uncompressFile((u_int8_t *) info->base_address,
653 info->fileinfo, file);
654 }
655
656
657 /*********************************************************************
658 * Does the work of pulling extensions out of an mkext archive located
659 * in memory.
660 *********************************************************************/
661 bool extractExtensionsFromArchive(MemoryMapFileInfo * mkext_file_info,
662 OSDictionary * extensions) {
663
664 bool result = true;
665
666 u_int8_t * crc_address = 0;
667 u_int32_t checksum;
668 mkext_header * mkext_data = 0; // don't free
669 mkext_kext * onekext_data = 0; // don't free
670 mkext_file * plist_file = 0; // don't free
671 mkext_file * module_file = 0; // don't free
672 OSData * driverPlistDataObject = 0; // must release
673 OSDictionary * driverPlist = 0; // must release
674 OSData * driverCode = 0; // must release
675 OSDictionary * driverDict = 0; // must release
676 OSString * moduleName = 0; // don't release
677 OSString * errorString = NULL; // must release
678
679 OSData * moduleInfo = 0; // must release
680 MkextEntryInfo module_info;
681
682 mkext_data = (mkext_header *)mkext_file_info->paddr;
683
684 if (OSSwapBigToHostInt32(mkext_data->magic) != MKEXT_MAGIC ||
685 OSSwapBigToHostInt32(mkext_data->signature) != MKEXT_SIGN) {
686 IOLog("Error: Extension archive has invalid magic or signature.\n");
687 LOG_DELAY();
688 result = false;
689 goto finish;
690 }
691
692 if (OSSwapBigToHostInt32(mkext_data->length) != mkext_file_info->length) {
693 IOLog("Error: Mismatch between extension archive & "
694 "recorded length.\n");
695 LOG_DELAY();
696 result = false;
697 goto finish;
698 }
699
700 crc_address = (u_int8_t *)&mkext_data->version;
701 checksum = adler32(crc_address,
702 (unsigned int)mkext_data +
703 OSSwapBigToHostInt32(mkext_data->length) - (unsigned int)crc_address);
704
705 if (OSSwapBigToHostInt32(mkext_data->adler32) != checksum) {
706 IOLog("Error: Extension archive has a bad checksum.\n");
707 LOG_DELAY();
708 result = false;
709 goto finish;
710 }
711
712 /* If the MKEXT archive isn't fat, check that the CPU type & subtype
713 * match that of the running kernel.
714 */
715 if (OSSwapBigToHostInt32(mkext_data->cputype) != (UInt32)CPU_TYPE_ANY) {
716 kern_return_t kresult = KERN_FAILURE;
717 host_basic_info_data_t hostinfo;
718 host_info_t hostinfo_ptr = (host_info_t)&hostinfo;
719 mach_msg_type_number_t count = sizeof(hostinfo)/sizeof(integer_t);
720
721 kresult = host_info((host_t)1, HOST_BASIC_INFO,
722 hostinfo_ptr, &count);
723 if (kresult != KERN_SUCCESS) {
724 IOLog("Error: Couldn't get current host info.\n");
725 LOG_DELAY();
726 result = false;
727 goto finish;
728 }
729 if ((UInt32)hostinfo.cpu_type !=
730 OSSwapBigToHostInt32(mkext_data->cputype)) {
731
732 IOLog("Error: Extension archive doesn't contain software "
733 "for this computer's CPU type.\n");
734 LOG_DELAY();
735 result = false;
736 goto finish;
737 }
738 if (!check_cpu_subtype(OSSwapBigToHostInt32(mkext_data->cpusubtype))) {
739 IOLog("Error: Extension archive doesn't contain software "
740 "for this computer's CPU subtype.\n");
741 LOG_DELAY();
742 result = false;
743 goto finish;
744 }
745 }
746
747 for (unsigned int i = 0;
748 i < OSSwapBigToHostInt32(mkext_data->numkexts);
749 i++) {
750
751 kmod_info_t * loaded_kmod = 0;
752
753 if (driverPlistDataObject) {
754 driverPlistDataObject->release();
755 driverPlistDataObject = NULL;
756 }
757 if (driverPlist) {
758 driverPlist->release();
759 driverPlist = NULL;
760 }
761 if (driverCode) {
762 driverCode->release();
763 driverCode = NULL;
764 }
765 if (driverDict) {
766 driverDict->release();
767 driverDict = NULL;
768 }
769 if (errorString) {
770 errorString->release();
771 errorString = NULL;
772 }
773
774 onekext_data = &mkext_data->kext[i];
775 plist_file = &onekext_data->plist;
776 module_file = &onekext_data->module;
777
778 if (!uncompressFile((u_int8_t *)mkext_data, plist_file,
779 &driverPlistDataObject)) {
780
781 IOLog("Error: couldn't uncompress plist file "
782 "from multikext archive entry %d.\n", i);
783 LOG_DELAY();
784 continue;
785 }
786
787 if (!driverPlistDataObject) {
788 IOLog("Error: No property list present "
789 "for multikext archive entry %d.\n", i);
790 LOG_DELAY();
791 continue;
792 } else {
793 driverPlist = OSDynamicCast(OSDictionary,
794 OSUnserializeXML(
795 (char *)driverPlistDataObject->getBytesNoCopy(),
796 &errorString));
797 if (!driverPlist) {
798 IOLog("Error: Couldn't read XML property list "
799 "for multikext archive entry %d.\n", i);
800 LOG_DELAY();
801 if (errorString) {
802 IOLog("XML parse error: %s.\n",
803 errorString->getCStringNoCopy());
804 LOG_DELAY();
805 }
806 continue;
807 }
808
809 if (!validateExtensionDict(driverPlist)) {
810 IOLog("Error: Failed to validate property list "
811 "for multikext archive entry %d.\n", i);
812 LOG_DELAY();
813 continue;
814 }
815
816 }
817
818 /* Get the extension's module name. This is used to record
819 * the extension.
820 */
821 moduleName = OSDynamicCast(OSString,
822 driverPlist->getObject("CFBundleIdentifier")); // do not release
823 if (!moduleName) {
824 IOLog("Error: Multikext archive entry %d has "
825 "no \"CFBundleIdentifier\" property.\n", i);
826 LOG_DELAY();
827 continue; // assume a kext config error & continue
828 }
829
830 /* Check if kmod is already loaded and is a real loadable one (has
831 * an address).
832 */
833 loaded_kmod = kmod_lookupbyname(moduleName->getCStringNoCopy());
834 if (loaded_kmod && loaded_kmod->address) {
835 IOLog("Skipping new extension \"%s\"; an extension named "
836 "\"%s\" is already loaded.\n",
837 moduleName->getCStringNoCopy(),
838 loaded_kmod->name);
839 continue;
840 }
841
842
843 driverDict = OSDictionary::withCapacity(2);
844 if (!driverDict) {
845 IOLog("Error: Couldn't allocate dictionary "
846 "for multikext archive entry %d.\n", i);
847 LOG_DELAY();
848 result = false;
849 goto finish;
850 }
851
852 driverDict->setObject("plist", driverPlist);
853
854 /*****
855 * Prepare an entry to hold the mkext entry info for the
856 * compressed binary module, if there is one. If all four fields
857 * of the module entry are zero, there isn't one.
858 */
859 if (OSSwapBigToHostInt32(module_file->offset) ||
860 OSSwapBigToHostInt32(module_file->compsize) ||
861 OSSwapBigToHostInt32(module_file->realsize) ||
862 OSSwapBigToHostInt32(module_file->modifiedsecs)) {
863
864 moduleInfo = OSData::withCapacity(sizeof(MkextEntryInfo));
865 if (!moduleInfo) {
866 IOLog("Error: Couldn't allocate data object "
867 "for multikext archive entry %d.\n", i);
868 LOG_DELAY();
869 result = false;
870 goto finish;
871 }
872
873 module_info.base_address = (vm_address_t)mkext_data;
874 module_info.fileinfo = module_file;
875
876 if (!moduleInfo->appendBytes(&module_info, sizeof(module_info))) {
877 IOLog("Error: Couldn't record info "
878 "for multikext archive entry %d.\n", i);
879 LOG_DELAY();
880 result = false;
881 goto finish;
882 }
883
884 driverDict->setObject("compressedCode", moduleInfo);
885 }
886
887 OSDictionary * incumbentExt = OSDynamicCast(OSDictionary,
888 extensions->getObject(moduleName));
889
890 if (!incumbentExt) {
891 extensions->setObject(moduleName, driverDict);
892 } else {
893 OSDictionary * mostRecentExtension =
894 compareExtensionVersions(incumbentExt, driverDict);
895
896 if (mostRecentExtension == incumbentExt) {
897 /* Do nothing, we've got the most recent. */
898 } else if (mostRecentExtension == driverDict) {
899 if (!extensions->setObject(moduleName, driverDict)) {
900
901 /* This is a fatal error, so bail.
902 */
903 IOLog("extractExtensionsFromArchive(): Failed to add "
904 "identifier %s\n",
905 moduleName->getCStringNoCopy());
906 LOG_DELAY();
907 result = false;
908 goto finish;
909 }
910 } else /* should be NULL */ {
911
912 /* This is a nonfatal error, so continue.
913 */
914 IOLog("extractExtensionsFromArchive(): Error comparing "
915 "versions of duplicate extensions %s.\n",
916 moduleName->getCStringNoCopy());
917 LOG_DELAY();
918 continue;
919 }
920 }
921 }
922
923 finish:
924
925 if (driverPlistDataObject) driverPlistDataObject->release();
926 if (driverPlist) driverPlist->release();
927 if (driverCode) driverCode->release();
928 if (moduleInfo) moduleInfo->release();
929 if (driverDict) driverDict->release();
930 if (errorString) errorString->release();
931
932 return result;
933 }
934
935 /*********************************************************************
936 *
937 *********************************************************************/
938 bool readExtensions(OSDictionary * propertyDict,
939 const char * memory_map_name,
940 OSDictionary * extensions) {
941
942 bool result = true;
943 OSData * mkextDataObject = 0; // don't release
944 MemoryMapFileInfo * mkext_file_info = 0; // don't free
945
946 mkextDataObject = OSDynamicCast(OSData,
947 propertyDict->getObject(memory_map_name));
948 // don't release mkextDataObject
949
950 if (!mkextDataObject) {
951 IOLog("Error: No mkext data object "
952 "for device tree entry \"%s\".\n",
953 memory_map_name);
954 LOG_DELAY();
955 result = false;
956 goto finish;
957 }
958
959 mkext_file_info = (MemoryMapFileInfo *)mkextDataObject->getBytesNoCopy();
960 if (!mkext_file_info) {
961 result = false;
962 goto finish;
963 }
964
965 result = extractExtensionsFromArchive(mkext_file_info, extensions);
966
967 finish:
968
969 if (!result && extensions) {
970 extensions->flushCollection();
971 }
972
973 return result;
974 }
975
976
977 /*********************************************************************
978 * Adds the personalities for an extensions dictionary to the global
979 * IOCatalogue.
980 *********************************************************************/
981 bool addPersonalities(OSDictionary * extensions) {
982 bool result = true;
983 OSCollectionIterator * keyIterator = NULL; // must release
984 OSString * key; // don't release
985 OSDictionary * driverDict = NULL; // don't release
986 OSDictionary * driverPlist = NULL; // don't release
987 OSDictionary * thisDriverPersonalities = NULL; // don't release
988 OSArray * allDriverPersonalities = NULL; // must release
989
990 allDriverPersonalities = OSArray::withCapacity(1);
991 if (!allDriverPersonalities) {
992 IOLog("Error: Couldn't allocate personality dictionary.\n");
993 LOG_DELAY();
994 result = false;
995 goto finish;
996 }
997
998 /* Record all personalities found so that they can be
999 * added to the catalogue.
1000 * Note: Not all extensions have personalities.
1001 */
1002
1003 keyIterator = OSCollectionIterator::withCollection(extensions);
1004 if (!keyIterator) {
1005 IOLog("Error: Couldn't allocate iterator to record personalities.\n");
1006 LOG_DELAY();
1007 result = false;
1008 goto finish;
1009 }
1010
1011 while ( ( key = OSDynamicCast(OSString,
1012 keyIterator->getNextObject() ))) {
1013
1014 driverDict = OSDynamicCast(OSDictionary,
1015 extensions->getObject(key));
1016 driverPlist = OSDynamicCast(OSDictionary,
1017 driverDict->getObject("plist"));
1018 thisDriverPersonalities = OSDynamicCast(OSDictionary,
1019 driverPlist->getObject("IOKitPersonalities"));
1020
1021 if (thisDriverPersonalities) {
1022 OSCollectionIterator * pIterator;
1023 OSString * key;
1024 pIterator = OSCollectionIterator::withCollection(
1025 thisDriverPersonalities);
1026 if (!pIterator) {
1027 IOLog("Error: Couldn't allocate iterator "
1028 "to record extension personalities.\n");
1029 LOG_DELAY();
1030 continue;
1031 }
1032 while ( (key = OSDynamicCast(OSString,
1033 pIterator->getNextObject())) ) {
1034
1035 OSDictionary * personality = OSDynamicCast(
1036 OSDictionary,
1037 thisDriverPersonalities->getObject(key));
1038 if (personality) {
1039 allDriverPersonalities->setObject(personality);
1040 }
1041 }
1042 pIterator->release();
1043 }
1044 } /* extract personalities */
1045
1046
1047 /* Add all personalities found to the IOCatalogue,
1048 * but don't start matching.
1049 */
1050 gIOCatalogue->addDrivers(allDriverPersonalities, false);
1051
1052 finish:
1053
1054 if (allDriverPersonalities) allDriverPersonalities->release();
1055 if (keyIterator) keyIterator->release();
1056
1057 return result;
1058 }
1059
1060
1061 /*********************************************************************
1062 * Called from IOCatalogue to add extensions from an mkext archive.
1063 * This function makes a copy of the mkext object passed in because
1064 * the device tree support code dumps it after calling us (indirectly
1065 * through the IOCatalogue).
1066 *********************************************************************/
1067 bool addExtensionsFromArchive(OSData * mkextDataObject) {
1068 bool result = true;
1069
1070 OSDictionary * startupExtensions = NULL; // don't release
1071 OSArray * bootLoaderObjects = NULL; // don't release
1072 OSData * localMkextDataObject = NULL; // don't release
1073 OSDictionary * extensions = NULL; // must release
1074 MemoryMapFileInfo mkext_file_info;
1075 OSCollectionIterator * keyIterator = NULL; // must release
1076 OSString * key = NULL; // don't release
1077
1078 startupExtensions = getStartupExtensions();
1079 if (!startupExtensions) {
1080 IOLog("Can't record extension archive; there is no
1081 extensions dictionary.\n");
1082 LOG_DELAY();
1083 result = false;
1084 goto finish;
1085 }
1086
1087 bootLoaderObjects = getBootLoaderObjects();
1088 if (! bootLoaderObjects) {
1089 IOLog("Error: Couldn't allocate array to hold temporary objects.\n");
1090 LOG_DELAY();
1091 result = false;
1092 goto finish;
1093 }
1094
1095 extensions = OSDictionary::withCapacity(2);
1096 if (!extensions) {
1097 IOLog("Error: Couldn't allocate dictionary to unpack "
1098 "extension archive.\n");
1099 LOG_DELAY();
1100 result = false;
1101 goto finish;
1102 }
1103
1104 /* The mkext we've been handed (or the data it references) can go away,
1105 * so we need to make a local copy to keep around as long as it might
1106 * be needed.
1107 */
1108 localMkextDataObject = OSData::withData(mkextDataObject);
1109 if (!localMkextDataObject) {
1110 IOLog("Error: Couldn't copy extension archive.\n");
1111 LOG_DELAY();
1112 result = false;
1113 goto finish;
1114 }
1115
1116 mkext_file_info.paddr = (UInt32)localMkextDataObject->getBytesNoCopy();
1117 mkext_file_info.length = localMkextDataObject->getLength();
1118
1119 /* Save the local mkext data object so that we can deallocate it later.
1120 */
1121 bootLoaderObjects->setObject(localMkextDataObject);
1122 localMkextDataObject->release();
1123
1124 result = extractExtensionsFromArchive(&mkext_file_info, extensions);
1125 if (!result) {
1126 IOLog("Error: Failed to extract extensions from archive.\n");
1127 LOG_DELAY();
1128 result = false;
1129 goto finish;
1130 }
1131
1132 result = mergeExtensionDictionaries(startupExtensions, extensions);
1133 if (!result) {
1134 IOLog("Error: Failed to merge new extensions into existing set.\n");
1135 LOG_DELAY();
1136 goto finish;
1137 }
1138
1139 result = addPersonalities(extensions);
1140 if (!result) {
1141 IOLog("Error: Failed to add personalities for extensions extracted "
1142 "from archive.\n");
1143 LOG_DELAY();
1144 result = false;
1145 goto finish;
1146 }
1147
1148 finish:
1149
1150 if (!result) {
1151 IOLog("Error: Failed to record extensions from archive.\n");
1152 LOG_DELAY();
1153 } else {
1154 keyIterator = OSCollectionIterator::withCollection(
1155 extensions);
1156
1157 if (keyIterator) {
1158 while ( (key = OSDynamicCast(OSString,
1159 keyIterator->getNextObject())) ) {
1160
1161 IOLog("Added extension \"%s\" from archive.\n",
1162 key->getCStringNoCopy());
1163 LOG_DELAY();
1164 }
1165 keyIterator->release();
1166 }
1167 }
1168
1169 if (extensions) extensions->release();
1170
1171 return result;
1172 }
1173
1174
1175 /*********************************************************************
1176 * This function builds dictionaries for the startup extensions
1177 * put into memory by bootx, recording each in the startup extensions
1178 * dictionary. The dictionary format is this:
1179 *
1180 * {
1181 * "plist" = (the extension's Info.plist as an OSDictionary)
1182 * "code" = (an OSData containing the executable file)
1183 * }
1184 *
1185 * This function returns true if any extensions were found and
1186 * recorded successfully, or if there are no start extensions,
1187 * and false if an unrecoverable error occurred. An error reading
1188 * a single extension is not considered fatal, and this function
1189 * will simply skip the problematic extension to try the next one.
1190 *********************************************************************/
1191 bool recordStartupExtensions(void) {
1192 bool result = true;
1193 OSDictionary * startupExtensions = NULL; // must release
1194 OSDictionary * existingExtensions = NULL; // don't release
1195 OSDictionary * mkextExtensions = NULL; // must release
1196 IORegistryEntry * bootxMemoryMap = NULL; // must release
1197 OSDictionary * propertyDict = NULL; // must release
1198 OSCollectionIterator * keyIterator = NULL; // must release
1199 OSString * key = NULL; // don't release
1200
1201 OSDictionary * newDriverDict = NULL; // must release
1202 OSDictionary * driverPlist = NULL; // don't release
1203
1204 IOLog("Recording startup extensions.\n");
1205 LOG_DELAY();
1206
1207 existingExtensions = getStartupExtensions();
1208 if (!existingExtensions) {
1209 IOLog("Error: There is no dictionary for startup extensions.\n");
1210 LOG_DELAY();
1211 result = false;
1212 goto finish;
1213 }
1214
1215 startupExtensions = OSDictionary::withCapacity(1);
1216 if (!startupExtensions) {
1217 IOLog("Error: Couldn't allocate dictionary "
1218 "to record startup extensions.\n");
1219 LOG_DELAY();
1220 result = false;
1221 goto finish;
1222 }
1223
1224 bootxMemoryMap =
1225 IORegistryEntry::fromPath(
1226 "/chosen/memory-map", // path
1227 gIODTPlane // plane
1228 );
1229 // return value is retained so be sure to release it
1230
1231 if (!bootxMemoryMap) {
1232 IOLog("Error: Couldn't read booter memory map.\n");
1233 LOG_DELAY();
1234 result = false;
1235 goto finish;
1236 }
1237
1238 propertyDict = bootxMemoryMap->dictionaryWithProperties();
1239 if (!propertyDict) {
1240 IOLog("Error: Couldn't get property dictionary "
1241 "from memory map.\n");
1242 LOG_DELAY();
1243 result = false;
1244 goto finish;
1245 }
1246
1247 keyIterator = OSCollectionIterator::withCollection(propertyDict);
1248 if (!keyIterator) {
1249 IOLog("Error: Couldn't allocate iterator for driver images.\n");
1250 LOG_DELAY();
1251 result = false;
1252 goto finish;
1253 }
1254
1255 while ( (key = OSDynamicCast(OSString,
1256 keyIterator->getNextObject())) ) {
1257
1258 /* Clear newDriverDict & mkextExtensions upon entry to the loop,
1259 * handling both successful and unsuccessful iterations.
1260 */
1261 if (newDriverDict) {
1262 newDriverDict->release();
1263 newDriverDict = NULL;
1264 }
1265 if (mkextExtensions) {
1266 mkextExtensions->release();
1267 mkextExtensions = NULL;
1268 }
1269
1270 const char * keyValue = key->getCStringNoCopy();
1271
1272 if ( !strncmp(keyValue, BOOTX_KEXT_PREFIX,
1273 strlen(BOOTX_KEXT_PREFIX)) ) {
1274
1275 /* Read the extension from the bootx-supplied memory.
1276 */
1277 newDriverDict = readExtension(propertyDict, keyValue);
1278 if (!newDriverDict) {
1279 IOLog("Error: Couldn't read data "
1280 "for device tree entry \"%s\".\n", keyValue);
1281 LOG_DELAY();
1282 continue;
1283 }
1284
1285
1286 /* Preprare to record the extension by getting its info plist.
1287 */
1288 driverPlist = OSDynamicCast(OSDictionary,
1289 newDriverDict->getObject("plist"));
1290 if (!driverPlist) {
1291 IOLog("Error: Extension in device tree entry \"%s\" "
1292 "has no property list.\n", keyValue);
1293 LOG_DELAY();
1294 continue;
1295 }
1296
1297
1298 /* Get the extension's module name. This is used to record
1299 * the extension. Do *not* release the moduleName.
1300 */
1301 OSString * moduleName = OSDynamicCast(OSString,
1302 driverPlist->getObject("CFBundleIdentifier"));
1303 if (!moduleName) {
1304 IOLog("Error: Device tree entry \"%s\" has "
1305 "no \"CFBundleIdentifier\" property.\n", keyValue);
1306 LOG_DELAY();
1307 continue;
1308 }
1309
1310
1311 /* All has gone well so far, so record the extension under
1312 * its module name, checking for an existing duplicate.
1313 *
1314 * Do not release moduleName, as it's part of the extension's
1315 * plist.
1316 */
1317 OSDictionary * incumbentExt = OSDynamicCast(OSDictionary,
1318 startupExtensions->getObject(moduleName));
1319
1320 if (!incumbentExt) {
1321 startupExtensions->setObject(moduleName, newDriverDict);
1322 } else {
1323 OSDictionary * mostRecentExtension =
1324 compareExtensionVersions(incumbentExt, newDriverDict);
1325
1326 if (mostRecentExtension == incumbentExt) {
1327 /* Do nothing, we've got the most recent. */
1328 } else if (mostRecentExtension == newDriverDict) {
1329 if (!startupExtensions->setObject(moduleName,
1330 newDriverDict)) {
1331
1332 /* This is a fatal error, so bail.
1333 */
1334 IOLog("recordStartupExtensions(): Failed to add "
1335 "identifier %s\n",
1336 moduleName->getCStringNoCopy());
1337 LOG_DELAY();
1338 result = false;
1339 goto finish;
1340 }
1341 } else /* should be NULL */ {
1342
1343 /* This is a nonfatal error, so continue.
1344 */
1345 IOLog("recordStartupExtensions(): Error comparing "
1346 "versions of duplicate extensions %s.\n",
1347 moduleName->getCStringNoCopy());
1348 LOG_DELAY();
1349 continue;
1350 }
1351 }
1352
1353
1354 } else if ( !strncmp(keyValue, BOOTX_MULTIKEXT_PREFIX,
1355 strlen(BOOTX_MULTIKEXT_PREFIX)) ) {
1356
1357 mkextExtensions = OSDictionary::withCapacity(10);
1358 if (!mkextExtensions) {
1359 IOLog("Error: Couldn't allocate dictionary to unpack "
1360 "multi-extension archive.\n");
1361 LOG_DELAY();
1362 result = false;
1363 goto finish; // allocation failure is fatal for this routine
1364 }
1365 if (!readExtensions(propertyDict, keyValue, mkextExtensions)) {
1366 IOLog("Error: Couldn't unpack multi-extension archive.\n");
1367 LOG_DELAY();
1368 continue;
1369 } else {
1370 if (!mergeExtensionDictionaries(startupExtensions,
1371 mkextExtensions)) {
1372
1373 IOLog("Error: Failed to merge new extensions into "
1374 "existing set.\n");
1375 LOG_DELAY();
1376 result = false;
1377 goto finish; // merge error is fatal for this routine
1378 }
1379 }
1380 }
1381
1382 // Do not release key.
1383
1384 } /* while ( (key = OSDynamicCast(OSString, ... */
1385
1386 if (!mergeExtensionDictionaries(existingExtensions, startupExtensions)) {
1387 IOLog("Error: Failed to merge new extensions into existing set.\n");
1388 LOG_DELAY();
1389 result = false;
1390 goto finish;
1391 }
1392
1393 result = addPersonalities(startupExtensions);
1394 if (!result) {
1395 IOLog("Error: Failed to add personalities for extensions extracted "
1396 "from archive.\n");
1397 LOG_DELAY();
1398 result = false;
1399 goto finish;
1400 }
1401
1402 finish:
1403
1404 // reused so clear first!
1405 if (keyIterator) {
1406 keyIterator->release();
1407 keyIterator = 0;
1408 }
1409
1410 if (!result) {
1411 IOLog("Error: Failed to record startup extensions.\n");
1412 LOG_DELAY();
1413 } else {
1414 #if DEBUG
1415 keyIterator = OSCollectionIterator::withCollection(
1416 startupExtensions);
1417
1418 if (keyIterator) {
1419 while ( (key = OSDynamicCast(OSString,
1420 keyIterator->getNextObject())) ) {
1421
1422 IOLog("Found extension \"%s\".\n",
1423 key->getCStringNoCopy());
1424 LOG_DELAY();
1425 }
1426 keyIterator->release();
1427 keyIterator = 0;
1428 }
1429 #endif DEBUG
1430 }
1431
1432 if (newDriverDict) newDriverDict->release();
1433 if (propertyDict) propertyDict->release();
1434 if (bootxMemoryMap) bootxMemoryMap->release();
1435 if (mkextExtensions) mkextExtensions->release();
1436 if (startupExtensions) startupExtensions->release();
1437
1438 return result;
1439 }
1440
1441
1442 /*********************************************************************
1443 * This function removes an entry from the dictionary of startup
1444 * extensions. It's used when an extension can't be loaded, for
1445 * whatever reason. For drivers, this allows another matching driver
1446 * to be loaded, so that, for example, a driver for the root device
1447 * can be found.
1448 *********************************************************************/
1449 void removeStartupExtension(const char * extensionName) {
1450 OSDictionary * startupExtensions = NULL; // don't release
1451 OSDictionary * extensionDict = NULL; // don't release
1452 OSDictionary * extensionPlist = NULL; // don't release
1453 OSDictionary * extensionPersonalities = NULL; // don't release
1454 OSDictionary * personality = NULL; // don't release
1455 OSCollectionIterator * keyIterator = NULL; // must release
1456 OSString * key = NULL; // don't release
1457
1458 startupExtensions = getStartupExtensions();
1459 if (!startupExtensions) goto finish;
1460
1461
1462 /* Find the extension's entry in the dictionary of
1463 * startup extensions.
1464 */
1465 extensionDict = OSDynamicCast(OSDictionary,
1466 startupExtensions->getObject(extensionName));
1467 if (!extensionDict) goto finish;
1468
1469 extensionPlist = OSDynamicCast(OSDictionary,
1470 extensionDict->getObject("plist"));
1471 if (!extensionPlist) goto finish;
1472
1473 extensionPersonalities = OSDynamicCast(OSDictionary,
1474 extensionPlist->getObject("IOKitPersonalities"));
1475 if (!extensionPersonalities) goto finish;
1476
1477 /* If it was there, remove it from the catalogue proper
1478 * by calling removeDrivers(). Pass true for the second
1479 * argument to trigger a new round of matching, and
1480 * then remove the extension from the dictionary of startup
1481 * extensions.
1482 */
1483 keyIterator = OSCollectionIterator::withCollection(
1484 extensionPersonalities);
1485 if (!keyIterator) {
1486 IOLog("Error: Couldn't allocate iterator to scan
1487 personalities for %s.\n", extensionName);
1488 LOG_DELAY();
1489 }
1490
1491 while ((key = OSDynamicCast(OSString, keyIterator->getNextObject()))) {
1492 personality = OSDynamicCast(OSDictionary,
1493 extensionPersonalities->getObject(key));
1494
1495
1496 if (personality) {
1497 gIOCatalogue->removeDrivers(personality, true);
1498 }
1499 }
1500
1501 startupExtensions->removeObject(extensionName);
1502
1503 finish:
1504
1505 if (keyIterator) keyIterator->release();
1506 return;
1507 }
1508
1509 /*********************************************************************
1510 * FIXME: This function invalidates the globals gStartupExtensions and
1511 * FIXME: ...gBootLoaderObjects without setting them to NULL. Since
1512 * FIXME: ...the code itself is immediately unloaded, there may not be
1513 * FIXME: ...any reason to worry about that!
1514 *********************************************************************/
1515 void clearStartupExtensionsAndLoaderInfo(void)
1516 {
1517 OSDictionary * startupExtensions = NULL; // must release
1518 OSArray * bootLoaderObjects = NULL; // must release
1519
1520 IORegistryEntry * bootxMemoryMap = NULL; // must release
1521 OSDictionary * propertyDict = NULL; // must release
1522 OSCollectionIterator * keyIterator = NULL; // must release
1523 OSString * key = NULL; // don't release
1524
1525 /*****
1526 * Drop any temporarily held data objects.
1527 */
1528 bootLoaderObjects = getBootLoaderObjects();
1529 if (bootLoaderObjects) {
1530 bootLoaderObjects->release();
1531 }
1532
1533 /****
1534 * If any "code" entries in driver dictionaries are accompanied
1535 * by "compressedCode" entries, then those data objects were
1536 * created based of of kmem_alloc()'ed memory, which must be
1537 * freed specially.
1538 */
1539 startupExtensions = getStartupExtensions();
1540 if (startupExtensions) {
1541 keyIterator =
1542 OSCollectionIterator::withCollection(startupExtensions);
1543 if (!keyIterator) {
1544 IOLog("Error: Couldn't allocate iterator for startup "
1545 "extensions.\n");
1546 LOG_DELAY();
1547 goto memory_map; // bail to the memory_map label
1548 }
1549
1550 while ( (key = OSDynamicCast(OSString,
1551 keyIterator->getNextObject())) ) {
1552
1553 OSDictionary * driverDict = 0;
1554 OSData * codeData = 0;
1555
1556 driverDict = OSDynamicCast(OSDictionary,
1557 startupExtensions->getObject(key));
1558 if (driverDict) {
1559 codeData = OSDynamicCast(OSData,
1560 driverDict->getObject("code"));
1561
1562 if (codeData &&
1563 driverDict->getObject("compressedCode")) {
1564
1565 kmem_free(kernel_map,
1566 (unsigned int)codeData->getBytesNoCopy(),
1567 codeData->getLength());
1568 }
1569 }
1570 }
1571
1572 keyIterator->release();
1573 startupExtensions->release();
1574 }
1575
1576 memory_map:
1577
1578 /****
1579 * Go through the device tree's memory map and remove any driver
1580 * data entries.
1581 */
1582 bootxMemoryMap =
1583 IORegistryEntry::fromPath(
1584 "/chosen/memory-map", // path
1585 gIODTPlane // plane
1586 );
1587 // return value is retained so be sure to release it
1588
1589 if (!bootxMemoryMap) {
1590 IOLog("Error: Couldn't read booter memory map.\n");
1591 LOG_DELAY();
1592 goto finish;
1593 }
1594
1595 propertyDict = bootxMemoryMap->dictionaryWithProperties();
1596 if (!propertyDict) {
1597 IOLog("Error: Couldn't get property dictionary "
1598 "from memory map.\n");
1599 LOG_DELAY();
1600 goto finish;
1601 }
1602
1603 keyIterator = OSCollectionIterator::withCollection(propertyDict);
1604 if (!keyIterator) {
1605 IOLog("Error: Couldn't allocate iterator for driver images.\n");
1606 LOG_DELAY();
1607 goto finish;
1608 }
1609
1610 while ( (key = OSDynamicCast(OSString,
1611 keyIterator->getNextObject())) ) {
1612
1613 const char * keyValue = key->getCStringNoCopy();
1614
1615 if ( !strncmp(keyValue, BOOTX_KEXT_PREFIX,
1616 strlen(BOOTX_KEXT_PREFIX)) ||
1617 !strncmp(keyValue, BOOTX_MULTIKEXT_PREFIX,
1618 strlen(BOOTX_MULTIKEXT_PREFIX)) ) {
1619
1620 OSData * bootxDriverDataObject = NULL;
1621 MemoryMapFileInfo * driverInfo = 0;
1622
1623 bootxDriverDataObject = OSDynamicCast(OSData,
1624 propertyDict->getObject(keyValue));
1625 // don't release bootxDriverDataObject
1626
1627 if (!bootxDriverDataObject) {
1628 continue;
1629 }
1630 driverInfo = (MemoryMapFileInfo *)
1631 bootxDriverDataObject->getBytesNoCopy(0,
1632 sizeof(MemoryMapFileInfo));
1633 IODTFreeLoaderInfo((char *)keyValue,
1634 (void *)driverInfo->paddr,
1635 (int)driverInfo->length);
1636 }
1637 }
1638
1639 finish:
1640 if (bootxMemoryMap) bootxMemoryMap->release();
1641 if (propertyDict) propertyDict->release();
1642 if (keyIterator) keyIterator->release();
1643
1644 return;
1645 }