]> git.saurik.com Git - apple/xnu.git/blame - libsa/kext.cpp
xnu-792.21.3.tar.gz
[apple/xnu.git] / libsa / kext.cpp
CommitLineData
55e303ae
A
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
8f6c56a5 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
55e303ae 5 *
8f6c56a5
A
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
8ad349bb 24 * limitations under the License.
8f6c56a5
A
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
55e303ae
A
27 */
28#include <libkern/c++/OSContainers.h>
29#include <IOKit/IOCatalogue.h>
30#include <IOKit/IOLib.h>
31#include <libsa/kext.h>
32#include <libsa/catalogue.h>
33
34extern "C" {
35#include <mach-o/kld.h>
36#include <libsa/vers_rsrc.h>
37#include <libsa/stdlib.h>
38#include <mach/kmod.h>
39#include <vm/vm_kern.h>
40#include <mach/kern_return.h>
41#include <mach-o/fat.h>
42#include <mach_loader.h>
43
44#include "kld_patch.h"
45#include "dgraph.h"
46#include "load.h"
47};
48
49
50extern "C" {
51extern kern_return_t
52kmod_create_internal(
53 kmod_info_t *info,
54 kmod_t *id);
55
56extern kern_return_t
57kmod_destroy_internal(kmod_t id);
58
59extern kern_return_t
60kmod_start_or_stop(
61 kmod_t id,
62 int start,
63 kmod_args_t *data,
64 mach_msg_type_number_t *dataCount);
65
66extern kern_return_t kmod_retain(kmod_t id);
67extern kern_return_t kmod_release(kmod_t id);
68
69extern void flush_dcache(vm_offset_t addr, unsigned cnt, int phys);
70extern void invalidate_icache(vm_offset_t addr, unsigned cnt, int phys);
71};
72
73#define DEBUG
74#ifdef DEBUG
75#define LOG_DELAY(x) IODelay((x) * 1000000)
76#define VTYELLOW "\033[33m"
77#define VTRESET "\033[0m"
78#else
79#define LOG_DELAY(x)
80#define VTYELLOW
81#define VTRESET
82#endif /* DEBUG */
83
84/*********************************************************************
85*
86*********************************************************************/
87static
88bool getKext(
89 const char * bundleid,
90 OSDictionary ** plist,
91 unsigned char ** code,
92 unsigned long * code_size,
93 bool * caller_owns_code)
94{
95 bool result = true;
96 OSDictionary * extensionsDict; // don't release
97 OSDictionary * extDict; // don't release
98 OSDictionary * extPlist; // don't release
99 unsigned long code_size_local;
100
101 /* Get the dictionary of startup extensions.
102 * This is keyed by module name.
103 */
104 extensionsDict = getStartupExtensions();
105 if (!extensionsDict) {
106 IOLog("startup extensions dictionary is missing\n");
107 result = false;
108 goto finish;
109 }
110
111 /* Get the requested extension's dictionary entry and its property
112 * list, containing module dependencies.
113 */
114 extDict = OSDynamicCast(OSDictionary,
115 extensionsDict->getObject(bundleid));
116
117 if (!extDict) {
118 IOLog("extension \"%s\" cannot be found\n",
119 bundleid);
120 result = false;
121 goto finish;
122 }
123
124 if (plist) {
125 extPlist = OSDynamicCast(OSDictionary, extDict->getObject("plist"));
126 if (!extPlist) {
127 IOLog("extension \"%s\" has no info dictionary\n",
128 bundleid);
129 result = false;
130 goto finish;
131 }
132 *plist = extPlist;
133 }
134
135 if (code) {
136
137 /* If asking for code, the caller must provide a return buffer
138 * for ownership!
139 */
140 if (!caller_owns_code) {
141 IOLog("getKext(): invalid usage (caller_owns_code not provided)\n");
142 result = false;
143 goto finish;
144 }
145
146 *code = 0;
147 if (code_size) {
148 *code_size = 0;
149 }
150 *caller_owns_code = false;
151
152 *code = (unsigned char *)kld_file_getaddr(bundleid,
153 (long *)&code_size_local);
154 if (*code) {
155 if (code_size) {
156 *code_size = code_size_local;
157 }
158 } else {
159 OSData * driverCode = 0; // release only if uncompressing!
160
161 driverCode = OSDynamicCast(OSData, extDict->getObject("code"));
162 if (driverCode) {
163 *code = (unsigned char *)driverCode->getBytesNoCopy();
164 if (code_size) {
165 *code_size = driverCode->getLength();
166 }
167 } else { // Look for compressed code and uncompress it
168 OSData * compressedCode = 0;
169 compressedCode = OSDynamicCast(OSData,
170 extDict->getObject("compressedCode"));
171 if (compressedCode) {
172 if (!uncompressModule(compressedCode, &driverCode)) {
173 IOLog("extension \"%s\": couldn't uncompress code\n",
174 bundleid);
21362eb3 175 LOG_DELAY(1);
55e303ae
A
176 result = false;
177 goto finish;
178 }
179 *caller_owns_code = true;
180 *code = (unsigned char *)driverCode->getBytesNoCopy();
181 if (code_size) {
182 *code_size = driverCode->getLength();
183 }
184 driverCode->release();
185 }
186 }
187 }
188 }
189
190finish:
191
192 return result;
193}
194
195
196/*********************************************************************
197*
198*********************************************************************/
199static
200bool verifyCompatibility(OSString * extName, OSString * requiredVersion)
201{
202 OSDictionary * extPlist; // don't release
203 OSString * extVersion; // don't release
204 OSString * extCompatVersion; // don't release
205 VERS_version ext_version;
206 VERS_version ext_compat_version;
207 VERS_version required_version;
208
209 if (!getKext(extName->getCStringNoCopy(), &extPlist, NULL, NULL, NULL)) {
210 return false;
211 }
212
213 extVersion = OSDynamicCast(OSString,
214 extPlist->getObject("CFBundleVersion"));
215 if (!extVersion) {
216 IOLog("verifyCompatibility(): "
217 "Extension \"%s\" has no \"CFBundleVersion\" property.\n",
218 extName->getCStringNoCopy());
219 return false;
220 }
221
222 extCompatVersion = OSDynamicCast(OSString,
223 extPlist->getObject("OSBundleCompatibleVersion"));
224 if (!extCompatVersion) {
225 IOLog("verifyCompatibility(): "
226 "Extension \"%s\" has no \"OSBundleCompatibleVersion\" property.\n",
227 extName->getCStringNoCopy());
228 return false;
229 }
230
231 required_version = VERS_parse_string(requiredVersion->getCStringNoCopy());
232 if (required_version < 0) {
233 IOLog("verifyCompatibility(): "
234 "Can't parse required version \"%s\" of dependency %s.\n",
235 requiredVersion->getCStringNoCopy(),
236 extName->getCStringNoCopy());
237 return false;
238 }
239 ext_version = VERS_parse_string(extVersion->getCStringNoCopy());
240 if (ext_version < 0) {
241 IOLog("verifyCompatibility(): "
242 "Can't parse version \"%s\" of dependency %s.\n",
243 extVersion->getCStringNoCopy(),
244 extName->getCStringNoCopy());
245 return false;
246 }
247 ext_compat_version = VERS_parse_string(extCompatVersion->getCStringNoCopy());
248 if (ext_compat_version < 0) {
249 IOLog("verifyCompatibility(): "
250 "Can't parse compatible version \"%s\" of dependency %s.\n",
251 extCompatVersion->getCStringNoCopy(),
252 extName->getCStringNoCopy());
253 return false;
254 }
255
256 if (required_version > ext_version || required_version < ext_compat_version) {
257 return false;
258 }
259
260 return true;
261}
262
263/*********************************************************************
264*********************************************************************/
265static
266bool kextIsDependency(const char * kext_name, char * is_kernel) {
267 bool result = true;
268 OSDictionary * extensionsDict = 0; // don't release
269 OSDictionary * extDict = 0; // don't release
270 OSDictionary * extPlist = 0; // don't release
271 OSBoolean * isKernelResourceObj = 0; // don't release
272 OSData * driverCode = 0; // don't release
273 OSData * compressedCode = 0; // don't release
274
275 if (is_kernel) {
276 *is_kernel = false;
277 }
278
279 /* Get the dictionary of startup extensions.
280 * This is keyed by module name.
281 */
282 extensionsDict = getStartupExtensions();
283 if (!extensionsDict) {
284 IOLog("startup extensions dictionary is missing\n");
285 result = false;
286 goto finish;
287 }
288
289 /* Get the requested extension's dictionary entry and its property
290 * list, containing module dependencies.
291 */
292 extDict = OSDynamicCast(OSDictionary,
293 extensionsDict->getObject(kext_name));
294
295 if (!extDict) {
296 IOLog("extension \"%s\" cannot be found\n",
297 kext_name);
298 result = false;
299 goto finish;
300 }
301
302 extPlist = OSDynamicCast(OSDictionary, extDict->getObject("plist"));
303 if (!extPlist) {
304 IOLog("extension \"%s\" has no info dictionary\n",
305 kext_name);
306 result = false;
307 goto finish;
308 }
309
310 /* A kext that is a kernel component is still a dependency, as there
311 * are fake kmod entries for them.
312 */
313 isKernelResourceObj = OSDynamicCast(OSBoolean,
314 extPlist->getObject("OSKernelResource"));
315 if (isKernelResourceObj && isKernelResourceObj->isTrue()) {
316 if (is_kernel) {
317 *is_kernel = true;
318 }
319 }
320
321 driverCode = OSDynamicCast(OSData, extDict->getObject("code"));
322 compressedCode = OSDynamicCast(OSData,
323 extDict->getObject("compressedCode"));
324
325 if ((driverCode || compressedCode) && is_kernel && *is_kernel) {
21362eb3 326 *is_kernel = 2;
55e303ae
A
327 }
328
329 if (!driverCode && !compressedCode && !isKernelResourceObj) {
330 result = false;
331 goto finish;
332 }
333
334finish:
335
336 return result;
337}
338
339/*********************************************************************
340*********************************************************************/
341static bool
21362eb3
A
342figureDependenciesForKext(OSDictionary * kextPlist,
343 OSDictionary * dependencies,
91447636
A
344 OSString * trueParent,
345 Boolean skipKernelDependencies)
55e303ae
A
346{
347 bool result = true;
91447636 348 bool hasDirectKernelDependency = false;
55e303ae
A
349 OSString * kextName = 0; // don't release
350 OSDictionary * libraries = 0; // don't release
351 OSCollectionIterator * keyIterator = 0; // must release
352 OSString * libraryName = 0; // don't release
353
354 kextName = OSDynamicCast(OSString,
355 kextPlist->getObject("CFBundleIdentifier"));
356 if (!kextName) {
357 // XXX: Add log message
358 result = false;
359 goto finish;
360 }
361
362 libraries = OSDynamicCast(OSDictionary,
363 kextPlist->getObject("OSBundleLibraries"));
364 if (!libraries) {
365 result = true;
366 goto finish;
367 }
368
369 keyIterator = OSCollectionIterator::withCollection(libraries);
370 if (!keyIterator) {
371 // XXX: Add log message
372 result = false;
373 goto finish;
374 }
375
376 while ( (libraryName = OSDynamicCast(OSString,
377 keyIterator->getNextObject())) ) {
378
379 OSString * libraryVersion = OSDynamicCast(OSString,
380 libraries->getObject(libraryName));
381 if (!libraryVersion) {
382 // XXX: Add log message
383 result = false;
384 goto finish;
385 }
386 if (!verifyCompatibility(libraryName, libraryVersion)) {
387 result = false;
388 goto finish;
389 } else {
91447636
A
390 char is_kernel_component;
391
21362eb3 392 if (!kextIsDependency(libraryName->getCStringNoCopy(), &is_kernel_component))
91447636
A
393 is_kernel_component = false;
394
395 if (!skipKernelDependencies || !is_kernel_component) {
21362eb3
A
396 dependencies->setObject(libraryName,
397 trueParent ? trueParent : kextName);
91447636
A
398 }
399 if (!hasDirectKernelDependency && is_kernel_component) {
400 hasDirectKernelDependency = true;
401 }
55e303ae
A
402 }
403 }
91447636
A
404 if (!hasDirectKernelDependency) {
405 /* a kext without any kernel dependency is assumed dependent on 6.0 */
21362eb3
A
406 dependencies->setObject("com.apple.kernel.libkern",
407 trueParent ? trueParent : kextName);
91447636 408 IOLog("Extension \"%s\" has no kernel dependency.\n",
21362eb3 409 kextName->getCStringNoCopy());
91447636 410 }
55e303ae
A
411
412finish:
413 if (keyIterator) keyIterator->release();
414 return result;
415}
416
417/*********************************************************************
418*********************************************************************/
419static
420bool getVersionForKext(OSDictionary * kextPlist, char ** version)
421{
422 OSString * kextName = 0; // don't release
423 OSString * kextVersion; // don't release
424
425 kextName = OSDynamicCast(OSString,
426 kextPlist->getObject("CFBundleIdentifier"));
427 if (!kextName) {
428 // XXX: Add log message
429 return false;
430 }
431
432 kextVersion = OSDynamicCast(OSString,
433 kextPlist->getObject("CFBundleVersion"));
434 if (!kextVersion) {
435 IOLog("getVersionForKext(): "
436 "Extension \"%s\" has no \"CFBundleVersion\" property.\n",
437 kextName->getCStringNoCopy());
438 return false;
439 }
440
441 if (version) {
442 *version = (char *)kextVersion->getCStringNoCopy();
443 }
444
445 return true;
446}
447
448/*********************************************************************
449*********************************************************************/
450static
451bool add_dependencies_for_kmod(const char * kmod_name, dgraph_t * dgraph)
452{
453 bool result = true;
454 OSDictionary * kextPlist = 0; // don't release
21362eb3
A
455 OSDictionary * workingDependencies = 0; // must release
456 OSDictionary * pendingDependencies = 0; // must release
457 OSDictionary * swapDict = 0; // don't release
458 OSString * dependentName = 0; // don't release
459 const char * dependent_name = 0; // don't free
460 OSString * libraryName = 0; // don't release
461 const char * library_name = 0; // don't free
462 OSCollectionIterator * dependencyIterator = 0; // must release
55e303ae
A
463 unsigned char * code = 0;
464 unsigned long code_length = 0;
465 bool code_is_kmem = false;
466 char * kmod_vers = 0; // from plist, don't free
467 char is_kernel_component = false;
468 dgraph_entry_t * dgraph_entry = 0; // don't free
469 dgraph_entry_t * dgraph_dependency = 0; // don't free
21362eb3 470 unsigned int graph_depth = 0;
55e303ae
A
471 bool kext_is_dependency = true;
472
473 if (!getKext(kmod_name, &kextPlist, &code, &code_length,
474 &code_is_kmem)) {
475 IOLog("can't find extension %s\n", kmod_name);
476 result = false;
477 goto finish;
478 }
479
480 if (!kextIsDependency(kmod_name, &is_kernel_component)) {
481 IOLog("extension %s is not loadable\n", kmod_name);
482 result = false;
483 goto finish;
484 }
485
486 if (!getVersionForKext(kextPlist, &kmod_vers)) {
487 IOLog("can't get version for extension %s\n", kmod_name);
488 result = false;
489 goto finish;
490 }
491
492 dgraph_entry = dgraph_add_dependent(dgraph, kmod_name,
493 code, code_length, code_is_kmem,
494 kmod_name, kmod_vers,
495 0 /* load_address not yet known */, is_kernel_component);
496 if (!dgraph_entry) {
497 IOLog("can't record %s in dependency graph\n", kmod_name);
498 result = false;
499 // kmem_alloc()ed code is freed in finish: block.
500 goto finish;
501 }
502
503 // pass ownership of code to kld patcher
21362eb3
A
504 if (code)
505 {
55e303ae
A
506 if (kload_map_entry(dgraph_entry) != kload_error_none) {
507 IOLog("can't map %s in preparation for loading\n", kmod_name);
508 result = false;
509 // kmem_alloc()ed code is freed in finish: block.
510 goto finish;
511 }
512 }
513 // clear local record of code
514 code = 0;
515 code_length = 0;
516 code_is_kmem = false;
517
21362eb3
A
518 workingDependencies = OSDictionary::withCapacity(5);
519 if (!workingDependencies) {
8f6c56a5
A
520 IOLog("memory allocation failure\n");
521 result = false;
522 goto finish;
523 }
524
21362eb3
A
525 pendingDependencies = OSDictionary::withCapacity(5);
526 if (!pendingDependencies) {
527 IOLog("memory allocation failure\n");
528 result = false;
529 goto finish;
530 }
531
532 if (!figureDependenciesForKext(kextPlist, workingDependencies, NULL, false)) {
55e303ae
A
533 IOLog("can't determine immediate dependencies for extension %s\n",
534 kmod_name);
535 result = false;
536 goto finish;
537 }
538
21362eb3
A
539 graph_depth = 0;
540 while (workingDependencies->getCount()) {
541 if (graph_depth > 255) {
55e303ae
A
542 IOLog("extension dependency graph ridiculously long, indicating a loop\n");
543 result = false;
544 goto finish;
545 }
546
21362eb3
A
547 if (dependencyIterator) {
548 dependencyIterator->release();
549 dependencyIterator = 0;
550 }
55e303ae 551
21362eb3
A
552 dependencyIterator = OSCollectionIterator::withCollection(
553 workingDependencies);
554 if (!dependencyIterator) {
555 IOLog("memory allocation failure\n");
55e303ae
A
556 result = false;
557 goto finish;
558 }
559
21362eb3
A
560 while ( (libraryName =
561 OSDynamicCast(OSString, dependencyIterator->getNextObject())) ) {
55e303ae 562
21362eb3 563 library_name = libraryName->getCStringNoCopy();
55e303ae 564
21362eb3
A
565 dependentName = OSDynamicCast(OSString,
566 workingDependencies->getObject(libraryName));
567
568 dependent_name = dependentName->getCStringNoCopy();
55e303ae
A
569
570 if (!getKext(library_name, &kextPlist, NULL, NULL, NULL)) {
571 IOLog("can't find extension %s\n", library_name);
572 result = false;
573 goto finish;
574 }
575
21362eb3
A
576 OSString * string;
577 if ((string = OSDynamicCast(OSString,
578 kextPlist->getObject("OSBundleSharedExecutableIdentifier"))))
579 {
580 library_name = string->getCStringNoCopy();
581 if (!getKext(library_name, &kextPlist, NULL, NULL, NULL)) {
582 IOLog("can't find extension %s\n", library_name);
583 result = false;
584 goto finish;
585 }
586 }
587
588 kext_is_dependency = kextIsDependency(library_name,
589 &is_kernel_component);
590
591 if (!kext_is_dependency) {
592
593 /* For binaryless kexts, add a new pending dependency from the
594 * original dependent onto the dependencies of the current,
595 * binaryless, dependency.
596 */
597 if (!figureDependenciesForKext(kextPlist, pendingDependencies,
598 dependentName, true)) {
55e303ae 599
21362eb3
A
600 IOLog("can't determine immediate dependencies for extension %s\n",
601 library_name);
602 result = false;
603 goto finish;
604 }
605 continue;
606 } else {
55e303ae
A
607 dgraph_entry = dgraph_find_dependent(dgraph, dependent_name);
608 if (!dgraph_entry) {
609 IOLog("internal error with dependency graph\n");
610 LOG_DELAY(1);
611 result = false;
612 goto finish;
613 }
614
615 if (!getVersionForKext(kextPlist, &kmod_vers)) {
616 IOLog("can't get version for extension %s\n", library_name);
617 result = false;
618 goto finish;
619 }
620
621 /* It's okay for code to be zero, as for a pseudokext
622 * representing a kernel component.
623 */
624 if (!getKext(library_name, NULL /* already got it */,
625 &code, &code_length, &code_is_kmem)) {
626 IOLog("can't find extension %s\n", library_name);
627 result = false;
628 goto finish;
629 }
630
631 dgraph_dependency = dgraph_add_dependency(dgraph, dgraph_entry,
632 library_name, code, code_length, code_is_kmem,
633 library_name, kmod_vers,
634 0 /* load_address not yet known */, is_kernel_component);
635
636 if (!dgraph_dependency) {
637 IOLog("can't record dependency %s -> %s\n", dependent_name,
638 library_name);
639 result = false;
640 // kmem_alloc()ed code is freed in finish: block.
641 goto finish;
642 }
643
644 // pass ownership of code to kld patcher
645 if (code) {
646 if (kload_map_entry(dgraph_dependency) != kload_error_none) {
647 IOLog("can't map %s in preparation for loading\n", library_name);
648 result = false;
649 // kmem_alloc()ed code is freed in finish: block.
650 goto finish;
651 }
652 }
653 // clear local record of code
654 code = 0;
655 code_length = 0;
656 code_is_kmem = false;
657 }
658
659 /* Now put the library's dependencies onto the pending set.
660 */
21362eb3
A
661 if (!figureDependenciesForKext(kextPlist, pendingDependencies,
662 NULL, false)) {
55e303ae
A
663
664 IOLog("can't determine immediate dependencies for extension %s\n",
665 library_name);
666 result = false;
667 goto finish;
668 }
669 }
670
21362eb3
A
671 dependencyIterator->release();
672 dependencyIterator = 0;
673
674 workingDependencies->flushCollection();
675 swapDict = workingDependencies;
676 workingDependencies = pendingDependencies;
677 pendingDependencies = swapDict;
678 graph_depth++;
679 }
680
55e303ae
A
681finish:
682 if (code && code_is_kmem) {
683 kmem_free(kernel_map, (unsigned int)code, code_length);
684 }
21362eb3
A
685 if (workingDependencies) workingDependencies->release();
686 if (pendingDependencies) pendingDependencies->release();
687 if (dependencyIterator) dependencyIterator->release();
55e303ae
A
688 return result;
689}
690
691/*********************************************************************
692* This is the function that IOCatalogue calls in order to load a kmod.
693* It first checks whether the kmod is already loaded. If the kmod
694* isn't loaded, this function builds a dependency list and calls
695* load_kmod() repeatedly to guarantee that each dependency is in fact
696* loaded.
697*********************************************************************/
698__private_extern__
699kern_return_t load_kernel_extension(char * kmod_name)
700{
701 kern_return_t result = KERN_SUCCESS;
702 kload_error load_result = kload_error_none;
703 dgraph_t dgraph;
704 bool free_dgraph = false;
705 kmod_info_t * kmod_info;
706
707// Put this in for lots of messages about kext loading.
708#if 0
709 kload_set_log_level(kload_log_level_load_details);
710#endif
711
712 /* See if the kmod is already loaded.
713 */
714 if ((kmod_info = kmod_lookupbyname_locked(kmod_name))) {
21362eb3 715 kfree((vm_offset_t) kmod_info, sizeof(kmod_info_t));
55e303ae
A
716 return KERN_SUCCESS;
717 }
718
719 if (dgraph_init(&dgraph) != dgraph_valid) {
720 IOLog("Can't initialize dependency graph to load %s.\n",
721 kmod_name);
722 result = KERN_FAILURE;
723 goto finish;
724 }
725
726 free_dgraph = true;
727 if (!add_dependencies_for_kmod(kmod_name, &dgraph)) {
728 IOLog("Can't determine dependencies for %s.\n",
729 kmod_name);
730 result = KERN_FAILURE;
731 goto finish;
732 }
733
734 dgraph.root = dgraph_find_root(&dgraph);
735
736 if (!dgraph.root) {
737 IOLog("Dependency graph to load %s has no root.\n",
738 kmod_name);
739 result = KERN_FAILURE;
740 goto finish;
741 }
742
743 /* A kernel component is built in and need not be loaded.
744 */
745 if (dgraph.root->is_kernel_component) {
746 result = KERN_SUCCESS;
747 goto finish;
748 }
749
750 dgraph_establish_load_order(&dgraph);
751
752 load_result = kload_load_dgraph(&dgraph);
753 if (load_result != kload_error_none &&
754 load_result != kload_error_already_loaded) {
755
756 IOLog(VTYELLOW "Failed to load extension %s.\n" VTRESET, kmod_name);
757
758 result = KERN_FAILURE;
759 goto finish;
760 }
761
762finish:
763
764 if (free_dgraph) {
765 dgraph_free(&dgraph, 0 /* don't free dgraph itself */);
766 }
767 return result;
768}