]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOCatalogue.cpp
xnu-1228.12.14.tar.gz
[apple/xnu.git] / iokit / Kernel / IOCatalogue.cpp
1 /*
2 * Copyright (c) 1998-2006 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /*
29 * Copyright (c) 1998 Apple Computer, Inc. All rights reserved.
30 *
31 * HISTORY
32 *
33 */
34 /*
35 * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce
36 * support for mandatory and extensible security protections. This notice
37 * is included in support of clause 2.2 (b) of the Apple Public License,
38 * Version 2.0.
39 */
40
41 #include <IOKit/IODeviceTreeSupport.h>
42 #include <IOKit/IOService.h>
43 #include <libkern/c++/OSContainers.h>
44 #include <IOKit/IOCatalogue.h>
45 #include <libkern/c++/OSUnserialize.h>
46 extern "C" {
47 #include <machine/machine_routines.h>
48 #include <mach/kmod.h>
49 #include <mach-o/mach_header.h>
50 #include <kern/host.h>
51 #include <security/mac_data.h>
52 };
53
54 #include <IOKit/IOLib.h>
55
56 #include <IOKit/assert.h>
57
58
59 extern "C" {
60 int IODTGetLoaderInfo( char *key, void **infoAddr, int *infoSize );
61 extern void IODTFreeLoaderInfo( char *key, void *infoAddr, int infoSize );
62 /* operates on 32 bit segments */
63 extern void OSRuntimeUnloadCPPForSegment(struct segment_command * segment);
64 };
65
66
67 /*****
68 * At startup these function pointers are set to use the libsa in-kernel
69 * linker for recording and loading kmods. Once the root filesystem
70 * is available, the kmod_load_function pointer gets switched to point
71 * at the kmod_load_extension() function built into the kernel, and the
72 * others are set to zero. Those two functions must *always* be checked
73 * before being invoked.
74 */
75 extern "C" {
76 kern_return_t (*kmod_load_function)(char *extension_name) =
77 &kmod_load_extension;
78 bool (*record_startup_extensions_function)(void) = 0;
79 bool (*add_from_mkext_function)(OSData * mkext) = 0;
80 void (*remove_startup_extension_function)(const char * name) = 0;
81 };
82
83
84 /*****
85 * A few parts of IOCatalogue require knowledge of
86 * whether the in-kernel linker is present. This
87 * variable is set by libsa's bootstrap code.
88 */
89 int kernelLinkerPresent = 0;
90
91 #define kModuleKey "CFBundleIdentifier"
92
93 #define super OSObject
94 OSDefineMetaClassAndStructors(IOCatalogue, OSObject)
95
96 #define CATALOGTEST 0
97
98 IOCatalogue * gIOCatalogue;
99 const OSSymbol * gIOClassKey;
100 const OSSymbol * gIOProbeScoreKey;
101 const OSSymbol * gIOModuleIdentifierKey;
102 OSSet * gIOCatalogModuleRequests;
103 OSSet * gIOCatalogCacheMisses;
104 OSSet * gIOCatalogROMMkexts;
105 IOLock * gIOCatalogLock;
106 IOLock * gIOKLDLock;
107
108 /*********************************************************************
109 *********************************************************************/
110
111 OSArray * gIOPrelinkedModules = 0;
112
113 extern "C" kern_return_t
114 kmod_create_internal(
115 kmod_info_t *info,
116 kmod_t *id);
117
118 extern "C" kern_return_t
119 kmod_destroy_internal(kmod_t id);
120
121 extern "C" kern_return_t
122 kmod_start_or_stop(
123 kmod_t id,
124 int start,
125 kmod_args_t *data,
126 mach_msg_type_number_t *dataCount);
127
128 extern "C" kern_return_t kmod_retain(kmod_t id);
129 extern "C" kern_return_t kmod_release(kmod_t id);
130
131 #if CONFIG_MACF_KEXT
132 /* MAC Framework support */
133
134 /*
135 * define IOC_DEBUG to display run-time debugging information
136 * #define IOC_DEBUG 1
137 */
138
139 #ifdef IOC_DEBUG
140 #define DPRINTF(x) printf x
141 #else
142 #define IOC_DEBUG
143 #define DPRINTF(x)
144 #endif
145
146 static bool
147 primitive_type(OSObject *obj)
148 {
149 const OSMetaClass *typeID;
150
151 typeID = OSTypeIDInst(obj);
152 if (typeID == OSTypeID(OSString) || typeID == OSTypeID(OSNumber) ||
153 typeID == OSTypeID(OSBoolean) || typeID == OSTypeID(OSData))
154 return(true);
155 else
156 return(false);
157 }
158
159 static int
160 primitive_type_length(OSObject *obj)
161 {
162 const OSMetaClass *typeID;
163 int len;
164
165 typeID = OSTypeIDInst(obj);
166 if (typeID == OSTypeID(OSString)) {
167 OSString * stringObj = OSDynamicCast(OSString, obj);
168 len = stringObj->getLength() + 1;
169 }
170 else if (typeID == OSTypeID(OSNumber)) {
171 len = sizeof("4294967295"); /* UINT32_MAX */
172 }
173 else if (typeID == OSTypeID(OSBoolean)) {
174 OSBoolean * boolObj = OSDynamicCast(OSBoolean, obj);
175 len = boolObj->isTrue() ? sizeof("true") : sizeof("false");
176 }
177 else if (typeID == OSTypeID(OSData)) {
178 OSData * dataObj = OSDynamicCast(OSData, obj);
179 len = dataObj->getLength();
180 }
181 else {
182 len = 0;
183 }
184 return(len);
185 }
186
187 static void
188 primitive_type_collect(struct mac_module_data_element *element, OSObject *value)
189 {
190 const OSMetaClass *typeID;
191
192 typeID = OSTypeIDInst(value);
193 if (typeID == OSTypeID(OSString)) {
194 OSString *stringObj = OSDynamicCast(OSString, value);
195 element->value_type = MAC_DATA_TYPE_PRIMITIVE;
196 element->value_size = stringObj->getLength() + 1;
197 DPRINTF(("osdict: string %s size %d\n",
198 stringObj->getCStringNoCopy(), element->value_size));
199 memcpy(element->value, stringObj->getCStringNoCopy(),
200 element->value_size);
201 } else if (typeID == OSTypeID(OSNumber)) {
202 OSNumber *numberObj = OSDynamicCast(OSNumber, value);
203 element->value_type = MAC_DATA_TYPE_PRIMITIVE;
204 element->value_size = sprintf(element->value, "%u",
205 numberObj->unsigned32BitValue()) + 1;
206 } else if (typeID == OSTypeID(OSBoolean)) {
207 OSBoolean *boolObj = OSDynamicCast(OSBoolean, value);
208 element->value_type = MAC_DATA_TYPE_PRIMITIVE;
209 if (boolObj->isTrue()) {
210 strcpy(element->value, "true");
211 element->value_size = 5;
212 } else {
213 strcpy(element->value, "false");
214 element->value_size = 6;
215 }
216 } else if (typeID == OSTypeID(OSData)) {
217 OSData *dataObj = OSDynamicCast(OSData, value);
218 element->value_type = MAC_DATA_TYPE_PRIMITIVE;
219 element->value_size = dataObj->getLength();
220 DPRINTF(("osdict: data size %d\n", dataObj->getLength()));
221 memcpy(element->value, dataObj->getBytesNoCopy(),
222 element->value_size);
223 }
224 }
225
226 /*********************************************************************
227 * This function takes an OSDictionary and returns a struct mac_module_data
228 * list.
229 *********************************************************************/
230 struct mac_module_data *
231 osdict_encode(OSDictionary *dict)
232 {
233 const OSMetaClass * typeID; // don't release
234 OSString * key = NULL; // don't release
235 OSCollectionIterator * keyIterator = 0; // must release
236 struct mac_module_data * module_data = 0;
237 struct mac_module_data_element * element;
238 unsigned int strtabsize = 0;
239 unsigned int listtabsize = 0;
240 unsigned int dicttabsize = 0;
241 unsigned int nkeys = 0;
242 unsigned int datalen;
243 char *strtab = NULL;
244 char *listtab = NULL;
245 char *dicttab = NULL;
246 vm_offset_t data_addr;
247
248 keyIterator = OSCollectionIterator::withCollection(dict);
249 if (!keyIterator)
250 goto finish;
251
252 /* Iterate over OSModuleData to figure out total size */
253 while ( (key = OSDynamicCast(OSString, keyIterator->getNextObject())) ) {
254
255 // Get the key's value and determine its type
256 OSObject * value = dict->getObject(key);
257 if (!value)
258 continue;
259
260 typeID = OSTypeIDInst(value);
261 if (primitive_type(value)) {
262 strtabsize += primitive_type_length(value);
263 }
264 else if (typeID == OSTypeID(OSArray)) {
265 unsigned int k, cnt, nents;
266 OSArray *arrayObj = OSDynamicCast(OSArray, value);
267
268 nents = 0;
269 cnt = arrayObj->getCount();
270 for (k = 0; k < cnt; k++) {
271 value = arrayObj->getObject(k);
272 typeID = OSTypeIDInst(value);
273 if (primitive_type(value)) {
274 listtabsize += primitive_type_length(value);
275 nents++;
276 }
277 else if (typeID == OSTypeID(OSDictionary)) {
278 unsigned int dents;
279 OSDictionary *dictObj;
280 OSString *dictkey;
281 OSCollectionIterator *dictIterator;
282
283 dents = 0;
284 dictObj = OSDynamicCast(OSDictionary, value);
285 dictIterator = OSCollectionIterator::withCollection(dictObj);
286 if (!dictIterator)
287 goto finish;
288 while ((dictkey = OSDynamicCast(OSString,
289 dictIterator->getNextObject()))) {
290 OSObject *dictvalue;
291
292 dictvalue = dictObj->getObject(dictkey);
293 if (!dictvalue)
294 continue;
295 if (primitive_type(dictvalue)) {
296 strtabsize += primitive_type_length(dictvalue);
297 }
298 else {
299 continue; /* Only handle primitive types here. */
300 }
301 /*
302 * Allow for the "arraynnn/" prefix in the key length.
303 */
304 strtabsize += dictkey->getLength() + 1;
305 dents++;
306 }
307 dictIterator->release();
308 if (dents-- > 0) {
309 dicttabsize += sizeof(struct mac_module_data_list) +
310 dents * sizeof(struct mac_module_data_element);
311 nents++;
312 }
313 }
314 else {
315 continue; /* Skip everything else. */
316 }
317 }
318 if (nents == 0)
319 continue;
320 listtabsize += sizeof(struct mac_module_data_list) +
321 (nents - 1) * sizeof(struct mac_module_data_element);
322 }
323 else {
324 continue; /* skip anything else */
325 }
326 strtabsize += key->getLength() + 1;
327 nkeys++;
328 }
329 if (nkeys == 0)
330 goto finish;
331
332 /*
333 * Allocate and fill in the module data structures.
334 */
335 datalen = sizeof(struct mac_module_data) +
336 sizeof(mac_module_data_element) * (nkeys - 1) +
337 strtabsize + listtabsize + dicttabsize;
338 DPRINTF(("osdict: datalen %d strtabsize %d listtabsize %d dicttabsize %d\n",
339 datalen, strtabsize, listtabsize, dicttabsize));
340 if (kmem_alloc(kernel_map, &data_addr, datalen) != KERN_SUCCESS)
341 goto finish;
342 module_data = (mac_module_data *)data_addr;
343 module_data->base_addr = data_addr;
344 module_data->size = datalen;
345 module_data->count = nkeys;
346 strtab = (char *)&module_data->data[nkeys];
347 listtab = strtab + strtabsize;
348 dicttab = listtab + listtabsize;
349 DPRINTF(("osdict: data_addr %p strtab %p listtab %p dicttab %p end %p\n",
350 data_addr, strtab, listtab, dicttab, data_addr + datalen));
351
352 keyIterator->reset();
353 nkeys = 0;
354 element = &module_data->data[0];
355 DPRINTF(("osdict: element %p\n", element));
356 while ( (key = OSDynamicCast(OSString, keyIterator->getNextObject())) ) {
357
358 // Get the key's value and determine its type
359 OSObject * value = dict->getObject(key);
360 if (!value)
361 continue;
362
363 /* Store key */
364 DPRINTF(("osdict: element @%p\n", element));
365 element->key = strtab;
366 element->key_size = key->getLength() + 1;
367 DPRINTF(("osdict: key %s size %d @%p\n", key->getCStringNoCopy(), element->key_size, strtab));
368 memcpy(element->key, key->getCStringNoCopy(), element->key_size);
369
370 typeID = OSTypeIDInst(value);
371 if (primitive_type(value)) {
372 /* Store value */
373 element->value = element->key + element->key_size;
374 DPRINTF(("osdict: primitive element value %p\n", element->value));
375 primitive_type_collect(element, value);
376 strtab += element->key_size + element->value_size;
377 DPRINTF(("osdict: new strtab %p\n", strtab));
378 }
379 else if (typeID == OSTypeID(OSArray)) {
380 unsigned int k, cnt, nents;
381 char *astrtab;
382 struct mac_module_data_list *arrayhd;
383 struct mac_module_data_element *ele;
384 OSArray *arrayObj = OSDynamicCast(OSArray, value);
385
386 element->value = listtab;
387 DPRINTF(("osdict: array element value %p\n", element->value));
388 element->value_type = MAC_DATA_TYPE_ARRAY;
389 arrayhd = (struct mac_module_data_list *)element->value;
390 arrayhd->type = 0;
391 DPRINTF(("osdict: arrayhd %p\n", arrayhd));
392 nents = 0;
393 astrtab = strtab + element->key_size;
394 ele = &(arrayhd->list[0]);
395 cnt = arrayObj->getCount();
396 for (k = 0; k < cnt; k++) {
397 value = arrayObj->getObject(k);
398 DPRINTF(("osdict: array ele %d @%p\n", nents, ele));
399 ele->key = NULL;
400 ele->key_size = 0;
401 typeID = OSTypeIDInst(value);
402 if (primitive_type(value)) {
403 if (arrayhd->type != 0 &&
404 arrayhd->type != MAC_DATA_TYPE_PRIMITIVE)
405 continue;
406 arrayhd->type = MAC_DATA_TYPE_PRIMITIVE;
407 ele->value = astrtab;
408 primitive_type_collect(ele, value);
409 astrtab += ele->value_size;
410 DPRINTF(("osdict: array new astrtab %p\n", astrtab));
411 }
412 else if (typeID == OSTypeID(OSDictionary)) {
413 unsigned int dents;
414 char *dstrtab;
415 OSDictionary *dictObj;
416 OSString *dictkey;
417 OSCollectionIterator *dictIterator;
418 struct mac_module_data_list *dicthd;
419 struct mac_module_data_element *dele;
420
421 if (arrayhd->type != 0 &&
422 arrayhd->type != MAC_DATA_TYPE_DICT)
423 continue;
424 dictObj = OSDynamicCast(OSDictionary, value);
425 dictIterator = OSCollectionIterator::withCollection(dictObj);
426 if (!dictIterator)
427 goto finish;
428 DPRINTF(("osdict: dict\n"));
429 ele->value = dicttab;
430 ele->value_type = MAC_DATA_TYPE_DICT;
431 dicthd = (struct mac_module_data_list *)ele->value;
432 DPRINTF(("osdict: dicthd %p\n", dicthd));
433 dstrtab = astrtab;
434 dents = 0;
435 while ((dictkey = OSDynamicCast(OSString,
436 dictIterator->getNextObject()))) {
437 OSObject *dictvalue;
438
439 dictvalue = dictObj->getObject(dictkey);
440 if (!dictvalue)
441 continue;
442 dele = &(dicthd->list[dents]);
443 DPRINTF(("osdict: dict ele %d @%p\n", dents, dele));
444 if (primitive_type(dictvalue)) {
445 dele->key = dstrtab;
446 dele->key_size = dictkey->getLength() + 1;
447 DPRINTF(("osdict: dictkey %s size %d @%p\n",
448 dictkey->getCStringNoCopy(), dictkey->getLength(), dstrtab));
449 memcpy(dele->key, dictkey->getCStringNoCopy(),
450 dele->key_size);
451 dele->value = dele->key + dele->key_size;
452 primitive_type_collect(dele, dictvalue);
453 dstrtab += dele->key_size + dele->value_size;
454 DPRINTF(("osdict: dict new dstrtab %p\n", dstrtab));
455 }
456 else {
457 continue; /* Only handle primitive types here. */
458 }
459 dents++;
460 }
461 dictIterator->release();
462 if (dents == 0)
463 continue;
464 arrayhd->type = MAC_DATA_TYPE_DICT;
465 ele->value_size = sizeof(struct mac_module_data_list) +
466 (dents - 1) * sizeof(struct mac_module_data_element);
467 DPRINTF(("osdict: dict ele size %d ents %d\n", ele->value_size, dents));
468 dicttab += ele->value_size;
469 DPRINTF(("osdict: new dicttab %p\n", dicttab));
470 dicthd->count = dents;
471 astrtab = dstrtab;
472 }
473 else {
474 continue; /* Skip everything else. */
475 }
476 nents++;
477 ele++;
478 }
479 if (nents == 0)
480 continue;
481 element->value_size = sizeof(struct mac_module_data_list) +
482 (nents - 1) * sizeof(struct mac_module_data_element);
483 listtab += element->value_size;
484 DPRINTF(("osdict: new listtab %p\n", listtab));
485 arrayhd->count = nents;
486 strtab = astrtab;
487 DPRINTF(("osdict: new strtab %p\n", strtab));
488 }
489 else {
490 continue; /* skip anything else */
491 }
492 element++;
493 }
494 DPRINTF(("module_data list @%p, key %p value %p\n",
495 module_data, module_data->data[0].key, module_data->data[0].value));
496 finish:
497 if (keyIterator)
498 keyIterator->release();
499 return(module_data);
500 }
501
502 /*********************************************************************
503 * This function takes a plist and looks for an OSModuleData dictionary.
504 * If it is found, an encoded copy is returned.
505 *********************************************************************/
506 kmod_args_t
507 get_module_data(OSDictionary * kextPlist, mach_msg_type_number_t * datalen)
508 {
509
510 OSDictionary * kextModuleData = 0; // don't release
511 struct mac_module_data * module_data = 0;
512 vm_map_copy_t copy = 0;
513
514 kextModuleData = OSDynamicCast(OSDictionary,
515 kextPlist->getObject("OSModuleData"));
516 if (!kextModuleData)
517 goto finish;
518
519 module_data = osdict_encode(kextModuleData);
520 if (!module_data)
521 goto finish;
522 *datalen = module_data->size;
523 /*
524 * Make a CoW copy of data and free the original. The copy is
525 * consumed by a call to vm_map_copyout() in kmod_start_or_stop().
526 */
527 vm_map_copyin(kernel_map, (vm_offset_t)module_data, *datalen, FALSE, &copy);
528 kmem_free(kernel_map, (vm_offset_t)module_data, *datalen);
529 DPRINTF(("get_module_data: copy @ %p\n", copy));
530 finish:
531 return (kmod_args_t)copy;
532 }
533 #endif /* MAC */
534
535 static
536 kern_return_t start_prelink_module(UInt32 moduleIndex)
537 {
538 kern_return_t kr = KERN_SUCCESS;
539 UInt32 * togo;
540 SInt32 count, where, end;
541 UInt32 * prelink;
542 SInt32 next, lastDep;
543 OSData * data;
544 OSString * str;
545 OSDictionary * dict;
546
547 OSArray *
548 prelinkedModules = gIOPrelinkedModules;
549
550 togo = IONew(UInt32, prelinkedModules->getCount());
551 togo[0] = moduleIndex;
552 count = 1;
553
554 for (next = 0; next < count; next++)
555 {
556 dict = (OSDictionary *) prelinkedModules->getObject(togo[next]);
557
558 data = OSDynamicCast(OSData, dict->getObject("OSBundlePrelink"));
559 if (!data)
560 {
561 // already started or no code
562 if (togo[next] == moduleIndex)
563 {
564 kr = KERN_FAILURE;
565 break;
566 }
567 continue;
568 }
569 prelink = (UInt32 *) data->getBytesNoCopy();
570 lastDep = OSReadBigInt32(prelink, 12);
571 for (SInt32 idx = OSReadBigInt32(prelink, 8); idx < lastDep; idx += sizeof(UInt32))
572 {
573 UInt32 depIdx = OSReadBigInt32(prelink, idx) - 1;
574
575 for (where = next + 1;
576 (where < count) && (togo[where] > depIdx);
577 where++) {}
578
579 if (where != count)
580 {
581 if (togo[where] == depIdx)
582 continue;
583 for (end = count; end != where; end--)
584 togo[end] = togo[end - 1];
585 }
586 count++;
587 togo[where] = depIdx;
588 }
589 }
590
591 if (KERN_SUCCESS != kr)
592 return kr;
593
594 for (next = (count - 1); next >= 0; next--)
595 {
596 dict = (OSDictionary *) prelinkedModules->getObject(togo[next]);
597
598 data = OSDynamicCast(OSData, dict->getObject("OSBundlePrelink"));
599 if (!data)
600 continue;
601 prelink = (UInt32 *) data->getBytesNoCopy();
602
603 kmod_t id;
604 kmod_info_t * kmod_info = (kmod_info_t *) OSReadBigInt32(prelink, 0);
605
606 kr = kmod_create_internal(kmod_info, &id);
607 if (KERN_SUCCESS != kr)
608 break;
609
610 lastDep = OSReadBigInt32(prelink, 12);
611 for (SInt32 idx = OSReadBigInt32(prelink, 8); idx < lastDep; idx += sizeof(UInt32))
612 {
613 OSDictionary * depDict;
614 kmod_info_t * depInfo;
615
616 depDict = (OSDictionary *) prelinkedModules->getObject(OSReadBigInt32(prelink, idx) - 1);
617 str = OSDynamicCast(OSString, depDict->getObject(kModuleKey));
618 depInfo = kmod_lookupbyname_locked(str->getCStringNoCopy());
619 if (depInfo)
620 {
621 kr = kmod_retain(KMOD_PACK_IDS(id, depInfo->id));
622 kfree(depInfo, sizeof(kmod_info_t));
623 } else
624 IOLog("%s: NO DEP %s\n", kmod_info->name, str->getCStringNoCopy());
625 }
626 dict->removeObject("OSBundlePrelink");
627
628 if (kmod_info->start)
629 kr = kmod_start_or_stop(kmod_info->id, 1, 0, 0);
630 }
631
632 IODelete(togo, UInt32, prelinkedModules->getCount());
633
634 return kr;
635 }
636
637 /*********************************************************************
638 * This is a function that IOCatalogue calls in order to load a kmod.
639 *********************************************************************/
640
641 static
642 kern_return_t kmod_load_from_cache_sym(const OSSymbol * kmod_name)
643 {
644 OSArray * prelinkedModules = gIOPrelinkedModules;
645 kern_return_t result = KERN_FAILURE;
646 OSDictionary * dict;
647 OSObject * ident;
648 UInt32 idx;
649
650 if (!gIOPrelinkedModules)
651 return KERN_FAILURE;
652
653 for (idx = 0;
654 (dict = (OSDictionary *) prelinkedModules->getObject(idx));
655 idx++)
656 {
657 if ((ident = dict->getObject(kModuleKey))
658 && kmod_name->isEqualTo(ident))
659 break;
660 }
661 if (dict)
662 {
663 if (kernelLinkerPresent && dict->getObject("OSBundleDefer"))
664 {
665 kmod_load_extension((char *) kmod_name->getCStringNoCopy());
666 result = kIOReturnOffline;
667 }
668 else
669 result = start_prelink_module(idx);
670 }
671
672 return result;
673 }
674
675 extern "C" Boolean kmod_load_request(const char * moduleName, Boolean make_request)
676 {
677 bool ret, cacheMiss = false;
678 kern_return_t kr;
679 const OSSymbol * sym = 0;
680 kmod_info_t * kmod_info;
681
682 if (!moduleName)
683 return false;
684
685 /* To make sure this operation completes even if a bad extension needs
686 * to be removed, take the kld lock for this whole block, spanning the
687 * kmod_load_function() and remove_startup_extension_function() calls.
688 */
689 IOLockLock(gIOKLDLock);
690 do
691 {
692 // Is the module already loaded?
693 ret = (0 != (kmod_info = kmod_lookupbyname_locked((char *)moduleName)));
694 if (ret) {
695 kfree(kmod_info, sizeof(kmod_info_t));
696 break;
697 }
698 sym = OSSymbol::withCString(moduleName);
699 if (!sym) {
700 ret = false;
701 break;
702 }
703
704 kr = kmod_load_from_cache_sym(sym);
705 ret = (kIOReturnSuccess == kr);
706 cacheMiss = !ret;
707 if (ret || !make_request || (kr == kIOReturnOffline))
708 break;
709
710 // If the module hasn't been loaded, then load it.
711 if (!kmod_load_function) {
712 IOLog("IOCatalogue: %s cannot be loaded "
713 "(kmod load function not set).\n",
714 moduleName);
715 ret = true;
716 break;
717 }
718
719 kr = kmod_load_function((char *)moduleName);
720
721 if (ret != kIOReturnSuccess) {
722 IOLog("IOCatalogue: %s cannot be loaded.\n", moduleName);
723
724 /* If the extension couldn't be loaded this time,
725 * make it unavailable so that no more requests are
726 * made in vain. This also enables other matching
727 * extensions to have a chance.
728 */
729 if (kernelLinkerPresent && remove_startup_extension_function) {
730 (*remove_startup_extension_function)(moduleName);
731 }
732 ret = false;
733
734 } else if (kernelLinkerPresent) {
735 // If kern linker is here, the driver is actually loaded,
736 // so return true.
737 ret = true;
738
739 } else {
740 // kern linker isn't here, a request has been queued
741 // but the module isn't necessarily loaded yet, so stall.
742 ret = false;
743 }
744 }
745 while (false);
746
747 IOLockUnlock(gIOKLDLock);
748
749 if (sym)
750 {
751 IOLockLock(gIOCatalogLock);
752 gIOCatalogModuleRequests->setObject(sym);
753 if (cacheMiss)
754 gIOCatalogCacheMisses->setObject(sym);
755 IOLockUnlock(gIOCatalogLock);
756 }
757
758 return ret;
759 }
760
761 extern "C" kern_return_t kmod_unload_cache(void)
762 {
763 OSArray * prelinkedModules = gIOPrelinkedModules;
764 kern_return_t result = KERN_FAILURE;
765 OSDictionary * dict;
766 UInt32 idx;
767 UInt32 * prelink;
768 OSData * data;
769
770 if (!gIOPrelinkedModules)
771 return KERN_SUCCESS;
772
773 IOLockLock(gIOKLDLock);
774 for (idx = 0;
775 (dict = (OSDictionary *) prelinkedModules->getObject(idx));
776 idx++)
777 {
778 data = OSDynamicCast(OSData, dict->getObject("OSBundlePrelink"));
779 if (!data)
780 continue;
781 prelink = (UInt32 *) data->getBytesNoCopy();
782
783 kmod_info_t * kmod_info = (kmod_info_t *) OSReadBigInt32(prelink, 0);
784 vm_offset_t
785 virt = ml_static_ptovirt(kmod_info->address);
786 if( virt) {
787 ml_static_mfree(virt, kmod_info->size);
788 }
789 }
790
791 gIOPrelinkedModules->release();
792 gIOPrelinkedModules = 0;
793
794 IOLockUnlock(gIOKLDLock);
795
796 return result;
797 }
798
799 extern "C" kern_return_t kmod_load_from_cache(const char * kmod_name)
800 {
801 kern_return_t kr;
802 const OSSymbol * sym = OSSymbol::withCStringNoCopy(kmod_name);
803
804 if (sym)
805 {
806 kr = kmod_load_from_cache_sym(sym);
807 sym->release();
808 }
809 else
810 kr = kIOReturnNoMemory;
811
812 return kr;
813 }
814
815 /*********************************************************************
816 *********************************************************************/
817
818 static void UniqueProperties( OSDictionary * dict )
819 {
820 OSString * data;
821
822 data = OSDynamicCast( OSString, dict->getObject( gIOClassKey ));
823 if( data) {
824 const OSSymbol *classSymbol = OSSymbol::withString(data);
825
826 dict->setObject( gIOClassKey, (OSSymbol *) classSymbol);
827 classSymbol->release();
828 }
829
830 data = OSDynamicCast( OSString, dict->getObject( gIOMatchCategoryKey ));
831 if( data) {
832 const OSSymbol *classSymbol = OSSymbol::withString(data);
833
834 dict->setObject( gIOMatchCategoryKey, (OSSymbol *) classSymbol);
835 classSymbol->release();
836 }
837 }
838
839 void IOCatalogue::initialize( void )
840 {
841 OSArray * array;
842 OSString * errorString;
843 bool rc;
844
845 extern const char * gIOKernelConfigTables;
846
847 array = OSDynamicCast(OSArray, OSUnserialize(gIOKernelConfigTables, &errorString));
848 if (!array && errorString) {
849 IOLog("KernelConfigTables syntax error: %s\n",
850 errorString->getCStringNoCopy());
851 errorString->release();
852 }
853
854 gIOClassKey = OSSymbol::withCStringNoCopy( kIOClassKey );
855 gIOProbeScoreKey = OSSymbol::withCStringNoCopy( kIOProbeScoreKey );
856 gIOModuleIdentifierKey = OSSymbol::withCStringNoCopy( kModuleKey );
857 gIOCatalogModuleRequests = OSSet::withCapacity(16);
858 gIOCatalogCacheMisses = OSSet::withCapacity(16);
859 gIOCatalogROMMkexts = OSSet::withCapacity(4);
860
861 assert( array && gIOClassKey && gIOProbeScoreKey
862 && gIOModuleIdentifierKey && gIOCatalogModuleRequests);
863
864 gIOCatalogue = new IOCatalogue;
865 assert(gIOCatalogue);
866 rc = gIOCatalogue->init(array);
867 assert(rc);
868 array->release();
869 }
870
871 // Initialize the IOCatalog object.
872 bool IOCatalogue::init(OSArray * initArray)
873 {
874 OSDictionary * dict;
875
876 if ( !super::init() )
877 return false;
878
879 generation = 1;
880
881 array = initArray;
882 array->retain();
883 kernelTables = OSCollectionIterator::withCollection( array );
884
885 gIOCatalogLock = IOLockAlloc();
886 gIOKLDLock = IOLockAlloc();
887
888 lock = gIOCatalogLock;
889 kld_lock = gIOKLDLock;
890
891 kernelTables->reset();
892 while( (dict = (OSDictionary *) kernelTables->getNextObject())) {
893 UniqueProperties(dict);
894 if( 0 == dict->getObject( gIOClassKey ))
895 IOLog("Missing or bad \"%s\" key\n",
896 gIOClassKey->getCStringNoCopy());
897 }
898
899 #if CATALOGTEST
900 AbsoluteTime deadline;
901 clock_interval_to_deadline( 1000, kMillisecondScale );
902 thread_call_func_delayed( ping, this, deadline );
903 #endif
904
905 return true;
906 }
907
908 // Release all resources used by IOCatalogue and deallocate.
909 // This will probably never be called.
910 void IOCatalogue::free( void )
911 {
912 if ( array )
913 array->release();
914
915 if ( kernelTables )
916 kernelTables->release();
917
918 super::free();
919 }
920
921 #if CATALOGTEST
922
923 static int hackLimit;
924
925 enum { kDriversPerIter = 4 };
926
927 void IOCatalogue::ping( thread_call_param_t arg, thread_call_param_t)
928 {
929 IOCatalogue * self = (IOCatalogue *) arg;
930 OSOrderedSet * set;
931 OSDictionary * table;
932 int newLimit;
933
934 set = OSOrderedSet::withCapacity( 1 );
935
936 IOLockLock( &self->lock );
937
938 for( newLimit = 0; newLimit < kDriversPerIter; newLimit++) {
939 table = (OSDictionary *) self->array->getObject(
940 hackLimit + newLimit );
941 if( table) {
942 set->setLastObject( table );
943
944 OSSymbol * sym = (OSSymbol *) table->getObject( gIOClassKey );
945 kprintf("enabling %s\n", sym->getCStringNoCopy());
946
947 } else {
948 newLimit--;
949 break;
950 }
951 }
952
953 IOService::catalogNewDrivers( set );
954
955 hackLimit += newLimit;
956 self->generation++;
957
958 IOLockUnlock( &self->lock );
959
960 if( kDriversPerIter == newLimit) {
961 AbsoluteTime deadline;
962 clock_interval_to_deadline( 500, kMillisecondScale );
963 thread_call_func_delayed( ping, this, deadline );
964 }
965 }
966 #endif
967
968 OSOrderedSet * IOCatalogue::findDrivers( IOService * service,
969 SInt32 * generationCount )
970 {
971 OSDictionary * nextTable;
972 OSOrderedSet * set;
973 OSString * imports;
974
975 set = OSOrderedSet::withCapacity( 1, IOServiceOrdering,
976 (void *)gIOProbeScoreKey );
977 if( !set )
978 return( 0 );
979
980 IOLockLock( lock );
981 kernelTables->reset();
982
983 #if CATALOGTEST
984 int hackIndex = 0;
985 #endif
986 while( (nextTable = (OSDictionary *) kernelTables->getNextObject())) {
987 #if CATALOGTEST
988 if( hackIndex++ > hackLimit)
989 break;
990 #endif
991 imports = OSDynamicCast( OSString,
992 nextTable->getObject( gIOProviderClassKey ));
993 if( imports && service->metaCast( imports ))
994 set->setObject( nextTable );
995 }
996
997 *generationCount = getGenerationCount();
998
999 IOLockUnlock( lock );
1000
1001 return( set );
1002 }
1003
1004 // Is personality already in the catalog?
1005 OSOrderedSet * IOCatalogue::findDrivers( OSDictionary * matching,
1006 SInt32 * generationCount)
1007 {
1008 OSDictionary * dict;
1009 OSOrderedSet * set;
1010
1011 UniqueProperties(matching);
1012
1013 set = OSOrderedSet::withCapacity( 1, IOServiceOrdering,
1014 (void *)gIOProbeScoreKey );
1015
1016 IOLockLock( lock );
1017 kernelTables->reset();
1018 while ( (dict = (OSDictionary *) kernelTables->getNextObject()) ) {
1019
1020 /* This comparison must be done with only the keys in the
1021 * "matching" dict to enable general searches.
1022 */
1023 if ( dict->isEqualTo(matching, matching) )
1024 set->setObject(dict);
1025 }
1026 *generationCount = getGenerationCount();
1027 IOLockUnlock( lock );
1028
1029 return set;
1030 }
1031
1032 // Add a new personality to the set if it has a unique IOResourceMatchKey value.
1033 // XXX -- svail: This should be optimized.
1034 // esb - There doesn't seem like any reason to do this - it causes problems
1035 // esb - when there are more than one loadable driver matching on the same provider class
1036 static void AddNewImports( OSOrderedSet * set, OSDictionary * dict )
1037 {
1038 set->setObject(dict);
1039 }
1040
1041 // Add driver config tables to catalog and start matching process.
1042 bool IOCatalogue::addDrivers(OSArray * drivers,
1043 bool doNubMatching )
1044 {
1045 OSCollectionIterator * iter;
1046 OSDictionary * dict;
1047 OSOrderedSet * set;
1048 OSArray * persons;
1049 OSString * moduleName;
1050 bool ret;
1051
1052 ret = true;
1053 persons = OSDynamicCast(OSArray, drivers);
1054 if ( !persons )
1055 return false;
1056
1057 iter = OSCollectionIterator::withCollection( persons );
1058 if (!iter )
1059 return false;
1060
1061 set = OSOrderedSet::withCapacity( 10, IOServiceOrdering,
1062 (void *)gIOProbeScoreKey );
1063 if ( !set ) {
1064 iter->release();
1065 return false;
1066 }
1067
1068 IOLockLock( lock );
1069 while ( (dict = (OSDictionary *) iter->getNextObject()) )
1070 {
1071 if ((moduleName = OSDynamicCast(OSString, dict->getObject("OSBundleModuleDemand"))))
1072 {
1073 IOLockUnlock( lock );
1074 ret = kmod_load_request(moduleName->getCStringNoCopy(), false);
1075 IOLockLock( lock );
1076 ret = true;
1077 }
1078 else
1079 {
1080 SInt count;
1081
1082 UniqueProperties( dict );
1083
1084 // Add driver personality to catalogue.
1085 count = array->getCount();
1086 while ( count-- ) {
1087 OSDictionary * driver;
1088
1089 // Be sure not to double up on personalities.
1090 driver = (OSDictionary *)array->getObject(count);
1091
1092 /* Unlike in other functions, this comparison must be exact!
1093 * The catalogue must be able to contain personalities that
1094 * are proper supersets of others.
1095 * Do not compare just the properties present in one driver
1096 * pesonality or the other.
1097 */
1098 if (dict->isEqualTo(driver))
1099 break;
1100 }
1101 if (count >= 0)
1102 // its a dup
1103 continue;
1104
1105 ret = array->setObject( dict );
1106 if (!ret)
1107 break;
1108
1109 AddNewImports( set, dict );
1110 }
1111 }
1112 // Start device matching.
1113 if (doNubMatching && (set->getCount() > 0)) {
1114 IOService::catalogNewDrivers( set );
1115 generation++;
1116 }
1117 IOLockUnlock( lock );
1118
1119 set->release();
1120 iter->release();
1121
1122 return ret;
1123 }
1124
1125 // Remove drivers from the catalog which match the
1126 // properties in the matching dictionary.
1127 bool IOCatalogue::removeDrivers( OSDictionary * matching,
1128 bool doNubMatching)
1129 {
1130 OSCollectionIterator * tables;
1131 OSDictionary * dict;
1132 OSOrderedSet * set;
1133 OSArray * arrayCopy;
1134
1135 if ( !matching )
1136 return false;
1137
1138 set = OSOrderedSet::withCapacity(10,
1139 IOServiceOrdering,
1140 (void *)gIOProbeScoreKey);
1141 if ( !set )
1142 return false;
1143
1144 arrayCopy = OSArray::withCapacity(100);
1145 if ( !arrayCopy ) {
1146 set->release();
1147 return false;
1148 }
1149
1150 tables = OSCollectionIterator::withCollection(arrayCopy);
1151 arrayCopy->release();
1152 if ( !tables ) {
1153 set->release();
1154 return false;
1155 }
1156
1157 UniqueProperties( matching );
1158
1159 IOLockLock( lock );
1160 kernelTables->reset();
1161 arrayCopy->merge(array);
1162 array->flushCollection();
1163 tables->reset();
1164 while ( (dict = (OSDictionary *)tables->getNextObject()) ) {
1165
1166 /* This comparison must be done with only the keys in the
1167 * "matching" dict to enable general searches.
1168 */
1169 if ( dict->isEqualTo(matching, matching) ) {
1170 AddNewImports( set, dict );
1171 continue;
1172 }
1173
1174 array->setObject(dict);
1175 }
1176 // Start device matching.
1177 if ( doNubMatching && (set->getCount() > 0) ) {
1178 IOService::catalogNewDrivers(set);
1179 generation++;
1180 }
1181 IOLockUnlock( lock );
1182
1183 set->release();
1184 tables->release();
1185
1186 return true;
1187 }
1188
1189 // Return the generation count.
1190 SInt32 IOCatalogue::getGenerationCount( void ) const
1191 {
1192 return( generation );
1193 }
1194
1195 bool IOCatalogue::isModuleLoaded( OSString * moduleName ) const
1196 {
1197 return isModuleLoaded(moduleName->getCStringNoCopy());
1198 }
1199
1200 bool IOCatalogue::isModuleLoaded( const char * moduleName ) const
1201 {
1202 return (kmod_load_request(moduleName, true));
1203 }
1204
1205 // Check to see if module has been loaded already.
1206 bool IOCatalogue::isModuleLoaded( OSDictionary * driver ) const
1207 {
1208 OSString * moduleName = NULL;
1209
1210 if ( !driver )
1211 return false;
1212
1213 moduleName = OSDynamicCast(OSString, driver->getObject(gIOModuleIdentifierKey));
1214 if ( moduleName )
1215 return isModuleLoaded(moduleName);
1216
1217 /* If a personality doesn't hold the "CFBundleIdentifier" key
1218 * it is assumed to be an "in-kernel" driver.
1219 */
1220 return true;
1221 }
1222
1223 // This function is called after a module has been loaded.
1224 void IOCatalogue::moduleHasLoaded( OSString * moduleName )
1225 {
1226 OSDictionary * dict;
1227
1228 dict = OSDictionary::withCapacity(2);
1229 dict->setObject(gIOModuleIdentifierKey, moduleName);
1230 startMatching(dict);
1231 dict->release();
1232 }
1233
1234 void IOCatalogue::moduleHasLoaded( const char * moduleName )
1235 {
1236 OSString * name;
1237
1238 name = OSString::withCString(moduleName);
1239 moduleHasLoaded(name);
1240 name->release();
1241 }
1242
1243 IOReturn IOCatalogue::unloadModule( OSString * moduleName ) const
1244 {
1245 kmod_info_t * k_info = 0;
1246 kern_return_t ret;
1247 const char * name;
1248
1249 ret = kIOReturnBadArgument;
1250 if ( moduleName ) {
1251 name = moduleName->getCStringNoCopy();
1252 k_info = kmod_lookupbyname_locked((char *)name);
1253 if ( k_info && (k_info->reference_count < 1) ) {
1254 record_kext_unload(k_info->id);
1255 if ( k_info->stop &&
1256 !((ret = k_info->stop(k_info, 0)) == kIOReturnSuccess) ) {
1257
1258 kfree(k_info, sizeof(kmod_info_t));
1259 return ret;
1260 }
1261
1262 ret = kmod_destroy(host_priv_self(), k_info->id);
1263 }
1264 }
1265
1266 if (k_info) {
1267 kfree(k_info, sizeof(kmod_info_t));
1268 }
1269
1270 return ret;
1271 }
1272
1273 static IOReturn _terminateDrivers( OSDictionary * matching )
1274 {
1275 OSDictionary * dict;
1276 OSIterator * iter;
1277 IOService * service;
1278 IOReturn ret;
1279
1280 if ( !matching )
1281 return kIOReturnBadArgument;
1282
1283 ret = kIOReturnSuccess;
1284 dict = 0;
1285 iter = IORegistryIterator::iterateOver(gIOServicePlane,
1286 kIORegistryIterateRecursively);
1287 if ( !iter )
1288 return kIOReturnNoMemory;
1289
1290 UniqueProperties( matching );
1291
1292 // terminate instances.
1293 do {
1294 iter->reset();
1295 while( (service = (IOService *)iter->getNextObject()) ) {
1296 dict = service->getPropertyTable();
1297 if ( !dict )
1298 continue;
1299
1300 /* Terminate only for personalities that match the matching dictionary.
1301 * This comparison must be done with only the keys in the
1302 * "matching" dict to enable general matching.
1303 */
1304 if ( !dict->isEqualTo(matching, matching) )
1305 continue;
1306
1307 if ( !service->terminate(kIOServiceRequired|kIOServiceSynchronous) ) {
1308 ret = kIOReturnUnsupported;
1309 break;
1310 }
1311 }
1312 } while( !service && !iter->isValid());
1313 iter->release();
1314
1315 return ret;
1316 }
1317
1318 static IOReturn _removeDrivers( OSArray * array, OSDictionary * matching )
1319 {
1320 OSCollectionIterator * tables;
1321 OSDictionary * dict;
1322 OSArray * arrayCopy;
1323 IOReturn ret = kIOReturnSuccess;
1324
1325 // remove configs from catalog.
1326
1327 arrayCopy = OSArray::withCapacity(100);
1328 if ( !arrayCopy )
1329 return kIOReturnNoMemory;
1330
1331 tables = OSCollectionIterator::withCollection(arrayCopy);
1332 arrayCopy->release();
1333 if ( !tables )
1334 return kIOReturnNoMemory;
1335
1336 arrayCopy->merge(array);
1337 array->flushCollection();
1338 tables->reset();
1339 while ( (dict = (OSDictionary *)tables->getNextObject()) ) {
1340
1341 /* Remove from the catalogue's array any personalities
1342 * that match the matching dictionary.
1343 * This comparison must be done with only the keys in the
1344 * "matching" dict to enable general matching.
1345 */
1346 if ( dict->isEqualTo(matching, matching) )
1347 continue;
1348
1349 array->setObject(dict);
1350 }
1351
1352 tables->release();
1353
1354 return ret;
1355 }
1356
1357 IOReturn IOCatalogue::terminateDrivers( OSDictionary * matching )
1358 {
1359 IOReturn ret;
1360
1361 ret = _terminateDrivers(matching);
1362 IOLockLock( lock );
1363 if (kIOReturnSuccess == ret)
1364 ret = _removeDrivers(array, matching);
1365 kernelTables->reset();
1366 IOLockUnlock( lock );
1367
1368 return ret;
1369 }
1370
1371 IOReturn IOCatalogue::terminateDriversForModule(
1372 OSString * moduleName,
1373 bool unload )
1374 {
1375 IOReturn ret;
1376 OSDictionary * dict;
1377
1378 dict = OSDictionary::withCapacity(1);
1379 if ( !dict )
1380 return kIOReturnNoMemory;
1381
1382 dict->setObject(gIOModuleIdentifierKey, moduleName);
1383
1384 ret = _terminateDrivers(dict);
1385 IOLockLock( lock );
1386 if (kIOReturnSuccess == ret)
1387 ret = _removeDrivers(array, dict);
1388 kernelTables->reset();
1389
1390 // Unload the module itself.
1391 if ( unload && ret == kIOReturnSuccess ) {
1392 // Do kmod stop first.
1393 ret = unloadModule(moduleName);
1394 }
1395
1396 IOLockUnlock( lock );
1397
1398 dict->release();
1399
1400 return ret;
1401 }
1402
1403 IOReturn IOCatalogue::terminateDriversForModule(
1404 const char * moduleName,
1405 bool unload )
1406 {
1407 OSString * name;
1408 IOReturn ret;
1409
1410 name = OSString::withCString(moduleName);
1411 if ( !name )
1412 return kIOReturnNoMemory;
1413
1414 ret = terminateDriversForModule(name, unload);
1415 name->release();
1416
1417 return ret;
1418 }
1419
1420 bool IOCatalogue::startMatching( OSDictionary * matching )
1421 {
1422 OSDictionary * dict;
1423 OSOrderedSet * set;
1424
1425 if ( !matching )
1426 return false;
1427
1428 set = OSOrderedSet::withCapacity(10, IOServiceOrdering,
1429 (void *)gIOProbeScoreKey);
1430 if ( !set )
1431 return false;
1432
1433 IOLockLock( lock );
1434 kernelTables->reset();
1435
1436 while ( (dict = (OSDictionary *)kernelTables->getNextObject()) ) {
1437
1438 /* This comparison must be done with only the keys in the
1439 * "matching" dict to enable general matching.
1440 */
1441 if ( dict->isEqualTo(matching, matching) )
1442 AddNewImports(set, dict);
1443 }
1444 // Start device matching.
1445 if ( set->getCount() > 0 ) {
1446 IOService::catalogNewDrivers(set);
1447 generation++;
1448 }
1449
1450 IOLockUnlock( lock );
1451
1452 set->release();
1453
1454 return true;
1455 }
1456
1457 void IOCatalogue::reset(void)
1458 {
1459 IOLog("Resetting IOCatalogue.\n");
1460 }
1461
1462 bool IOCatalogue::serialize(OSSerialize * s) const
1463 {
1464 if ( !s )
1465 return false;
1466
1467 return super::serialize(s);
1468 }
1469
1470 bool IOCatalogue::serializeData(IOOptionBits kind, OSSerialize * s) const
1471 {
1472 kern_return_t kr = kIOReturnSuccess;
1473
1474 switch ( kind )
1475 {
1476 case kIOCatalogGetContents:
1477 if (!array->serialize(s))
1478 kr = kIOReturnNoMemory;
1479 break;
1480
1481 case kIOCatalogGetModuleDemandList:
1482 IOLockLock( lock );
1483 if (!gIOCatalogModuleRequests->serialize(s))
1484 kr = kIOReturnNoMemory;
1485 IOLockUnlock( lock );
1486 break;
1487
1488 case kIOCatalogGetCacheMissList:
1489 IOLockLock( lock );
1490 if (!gIOCatalogCacheMisses->serialize(s))
1491 kr = kIOReturnNoMemory;
1492 IOLockUnlock( lock );
1493 break;
1494
1495 case kIOCatalogGetROMMkextList:
1496 IOLockLock( lock );
1497
1498 if (!gIOCatalogROMMkexts || !gIOCatalogROMMkexts->getCount())
1499 kr = kIOReturnNoResources;
1500 else if (!gIOCatalogROMMkexts->serialize(s))
1501 kr = kIOReturnNoMemory;
1502
1503 if (gIOCatalogROMMkexts)
1504 {
1505 gIOCatalogROMMkexts->release();
1506 gIOCatalogROMMkexts = 0;
1507 }
1508
1509 IOLockUnlock( lock );
1510 break;
1511
1512 default:
1513 kr = kIOReturnBadArgument;
1514 break;
1515 }
1516
1517 return kr;
1518 }
1519
1520
1521 bool IOCatalogue::recordStartupExtensions(void) {
1522 bool result = false;
1523
1524 IOLockLock(kld_lock);
1525 if (kernelLinkerPresent && record_startup_extensions_function) {
1526 result = (*record_startup_extensions_function)();
1527 } else {
1528 IOLog("Can't record startup extensions; "
1529 "kernel linker is not present.\n");
1530 result = false;
1531 }
1532 IOLockUnlock(kld_lock);
1533
1534 return result;
1535 }
1536
1537
1538 /*********************************************************************
1539 * This function operates on sections retrieved from the currently running
1540 * 32 bit mach kernel.
1541 *********************************************************************/
1542 bool IOCatalogue::addExtensionsFromArchive(OSData * mkext)
1543 {
1544 OSData * copyData;
1545 bool result = false;
1546 bool prelinked;
1547
1548 /* The mkext we've been handed (or the data it references) can go away,
1549 * so we need to make a local copy to keep around as long as it might
1550 * be needed.
1551 */
1552 copyData = OSData::withData(mkext);
1553 if (copyData)
1554 {
1555 struct section * infosect;
1556
1557 infosect = getsectbyname("__PRELINK", "__info");
1558 prelinked = (infosect && infosect->addr && infosect->size);
1559
1560 IOLockLock(kld_lock);
1561
1562 if (gIOCatalogROMMkexts)
1563 gIOCatalogROMMkexts->setObject(copyData);
1564
1565 if (prelinked) {
1566 result = true;
1567 } else if (kernelLinkerPresent && add_from_mkext_function) {
1568 result = (*add_from_mkext_function)(copyData);
1569 } else {
1570 IOLog("Can't add startup extensions from archive; "
1571 "kernel linker is not present.\n");
1572 result = false;
1573 }
1574
1575 IOLockUnlock(kld_lock);
1576
1577 copyData->release();
1578 }
1579
1580 return result;
1581 }
1582
1583 /*********************************************************************
1584 * This function clears out all references to the in-kernel linker,
1585 * frees the list of startup extensions in extensionDict, and
1586 * deallocates the kernel's __KLD segment to reclaim that memory.
1587 *
1588 * The segments it operates on are strictly 32 bit segments.
1589 *********************************************************************/
1590 kern_return_t IOCatalogue::removeKernelLinker(void) {
1591 kern_return_t result = KERN_SUCCESS;
1592 struct segment_command * segmentLE, *segmentKLD;
1593 boolean_t keepsyms = FALSE;
1594 #if __ppc__ || __arm__
1595 char * dt_segment_name;
1596 void * segment_paddress;
1597 int segment_size;
1598 #endif
1599
1600 /* This must be the very first thing done by this function.
1601 */
1602 IOLockLock(kld_lock);
1603
1604
1605 /* If the kernel linker isn't here, that's automatically
1606 * a success.
1607 */
1608 if (!kernelLinkerPresent) {
1609 result = KERN_SUCCESS;
1610 goto finish;
1611 }
1612
1613 PE_parse_boot_argn("keepsyms", &keepsyms, sizeof (keepsyms));
1614
1615 IOLog("Jettisoning kernel linker.\n");
1616
1617 kernelLinkerPresent = 0;
1618
1619 /* Set the kmod_load_extension function as the means for loading
1620 * a kernel extension.
1621 */
1622 kmod_load_function = &kmod_load_extension;
1623
1624 record_startup_extensions_function = 0;
1625 add_from_mkext_function = 0;
1626 remove_startup_extension_function = 0;
1627
1628
1629 /* Invoke destructors for the __KLD and __LINKEDIT segments.
1630 * Do this for all segments before actually freeing their
1631 * memory so that any cross-dependencies (not that there
1632 * should be any) are handled.
1633 */
1634 segmentKLD = getsegbyname("__KLD");
1635 if (!segmentKLD) {
1636 IOLog("error removing kernel linker: can't find __KLD segment\n");
1637 result = KERN_FAILURE;
1638 goto finish;
1639 }
1640 OSRuntimeUnloadCPPForSegment(segmentKLD);
1641
1642 #if __ppc__ || __arm__
1643 /* Free the memory that was set up by bootx.
1644 */
1645 dt_segment_name = "Kernel-__KLD";
1646 if (0 == IODTGetLoaderInfo(dt_segment_name, &segment_paddress, &segment_size)) {
1647 IODTFreeLoaderInfo(dt_segment_name, (void *)segment_paddress,
1648 (int)segment_size);
1649 }
1650 #elif __i386__
1651 /* On x86, use the mapping data from the segment load command to
1652 * unload KLD directly, unless the keepsyms boot-arg was enabled.
1653 * This may invalidate any assumptions about "avail_start"
1654 * defining the lower bound for valid physical addresses.
1655 */
1656 if (!keepsyms && segmentKLD->vmaddr && segmentKLD->vmsize)
1657 ml_static_mfree(segmentKLD->vmaddr, segmentKLD->vmsize);
1658 #else
1659 #error arch
1660 #endif
1661
1662 struct section * sect;
1663 sect = getsectbyname("__PRELINK", "__symtab");
1664 if (sect && sect->addr) {
1665 ml_static_mfree(sect->addr, sect->size);
1666 }
1667
1668 finish:
1669
1670 /* This must be the very last thing done before returning.
1671 */
1672 IOLockUnlock(kld_lock);
1673
1674 return result;
1675 }
1676
1677 /*********************************************************************
1678 * This function stops the catalogue from making kextd requests during
1679 * shutdown.
1680 *********************************************************************/
1681 void IOCatalogue::disableExternalLinker(void) {
1682 IOLockLock(gIOKLDLock);
1683 /* If kmod_load_extension (the kextd requester function) is in use,
1684 * disable new module requests.
1685 */
1686 if (kmod_load_function == &kmod_load_extension) {
1687 kmod_load_function = NULL;
1688 }
1689
1690 IOLockUnlock(gIOKLDLock);
1691 }
1692
1693 extern "C"
1694 void jettison_kernel_linker(void)
1695 {
1696 if (gIOCatalogue != NULL)
1697 gIOCatalogue->removeKernelLinker();
1698 }