2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
22 * @APPLE_LICENSE_HEADER_END@
25 * Copyright (c) 1997 Doug Rabson
26 * All rights reserved.
28 * Redistribution and use in source and binary forms, with or without
29 * modification, are permitted provided that the following conditions
31 * 1. Redistributions of source code must retain the above copyright
32 * notice, this list of conditions and the following disclaimer.
33 * 2. Redistributions in binary form must reproduce the above copyright
34 * notice, this list of conditions and the following disclaimer in the
35 * documentation and/or other materials provided with the distribution.
37 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
38 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
39 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
40 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
41 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
42 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
43 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
44 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
45 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
46 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50 * "kldload.c,v 1.5 1998/07/06 06:58:32 charnier Exp"
53 static const char rcsid
[] =
54 "$Id: kmodload.c,v 1.14 2002/04/15 20:28:30 lindak Exp $";
63 #include <sys/param.h>
69 #include <mach/mach.h>
70 #include <mach/mach_error.h>
71 #include <mach/mach_host.h>
72 #include <mach-o/kld.h>
73 #include <mach-o/fat.h>
75 #include <CoreFoundation/CoreFoundation.h>
77 #include "kld_patch.h"
78 #include "vers_rsrc.h"
80 #define KMOD_ERROR_USAGE 1
81 #define KMOD_ERROR_PERMS 2
82 #define KMOD_ERROR_LOADING 3
83 #define KMOD_ERROR_INTERNAL 4
84 #define KMOD_ERROR_ALREADY 5
86 #define kKMOD_INFO_SYMBOLNAME "_kmod_info"
87 #define kKmodsymsName "kmodsyms"
89 static mach_port_t kernel_port
;
90 static mach_port_t kernel_priv_port
;
92 static kmod_info_t
*module_dependencies
= 0;
93 static vm_address_t kernel_alloc_address
= 0;
94 static unsigned long kernel_alloc_size
= 0;
95 static vm_address_t kernel_load_address
= 0;
96 static unsigned long kernel_load_size
= 0;
97 static unsigned long kernel_hdr_size
= 0;
98 static unsigned long kernel_hdr_pad
= 0;
99 static unsigned long faked_kernel_load_address
= 0;
101 static kmod_info_t
*loaded_modules
= 0;
102 static int loaded_count
= 0;
104 static char *progname
= "program name?";
105 static int kmodsyms
= 0;
106 static int link_addrs_set
= 0;
107 static int verbose
= 0;
109 static char *debugdumpfile
= NULL
;
111 // must not be static; kld library calls
112 extern void kld_error_vprintf(const char *format
, va_list ap
);
113 static void e_printf(const char *fmt
, ...);
114 static void v_printf(const char *fmt
, ...);
116 static void machwarn(int error
, const char *message
);
117 static void macherr(int error
, const char *message
);
119 static unsigned long linkedit_address(unsigned long size
,
120 unsigned long headers_size
);
121 static void abort_load(int exitcode
, const char *fmt
, ...);
122 static void map_and_patch(const char *base
,
123 const char **library_paths
,
125 static void link_base(const char *base
,
126 const char **dependency_paths
,
127 const vm_address_t
*dependency_addrs
);
128 static void clear_globals(void);
129 static kmod_info_t
*map_module(const char *filename
);
130 static struct mach_header
*link_module(const char *filename
,
132 static vm_address_t
update_kmod_info(struct mach_header
*mach_header
);
133 static kmod_t
load_module(struct mach_header
*mach_header
,
135 static void set_module_dependencies(kmod_t id
);
136 static void start_module(kmod_t id
);
142 fprintf(stderr
, "usage: %s [-v] [-k kernelfile] [-d dependencyfile] -o symbolfile modulefile\n", progname
);
143 fprintf(stderr
, " %s [-v] -k kernelfile [-d dependencyfile@address] -o symbolfile modulefile@address\n",
146 fprintf(stderr
, "usage: %s [-v] [-k kernelfile] [-d dependencyfile] [-o symbolfile] modulefile\n", progname
);
149 exit(KMOD_ERROR_USAGE
);
153 main(int argc
, char** argv
)
156 char * kernel
= _PATH_UNIX
;
159 #define MAX_DEPENDANCIES 128
160 char * dependencies
[MAX_DEPENDANCIES
];
161 vm_address_t loaded_addresses
[MAX_DEPENDANCIES
];
162 int dependency_count
= 0;
163 struct mach_header
*rld_header
;
165 char * module_path
= "";
166 vm_address_t module_info
= 0;
167 vm_address_t module_faked_address
= 0;
168 kmod_t module_id
= 0;
169 kmod_info_t
*file_kinfo
;
171 if ((progname
= strrchr(argv
[0], '/')) == NULL
)
176 kmodsyms
= !strcmp(progname
, kKmodsymsName
);
178 fprintf(stderr
, "%s is deprecated; use kextload(8) instead\n", progname
);
181 // XXX things to add:
182 // -p data string to send as outofband data on start
183 // -P data file to send as outofband data on start
185 while ((c
= getopt(argc
, argv
, "D:d:o:k:v")) != -1)
188 dependencies
[dependency_count
] = optarg
;
191 if ((address
= strrchr(optarg
, '@'))) {
193 loaded_addresses
[dependency_count
] = strtoul(address
, NULL
, 0);
196 loaded_addresses
[dependency_count
] = 0;
199 if (++dependency_count
== MAX_DEPENDANCIES
) {
200 abort_load(KMOD_ERROR_INTERNAL
,
201 "internal error, dependency count overflow.");
215 debugdumpfile
= optarg
;
223 dependencies
[dependency_count
] = 0;
224 loaded_addresses
[dependency_count
] = 0;
226 if (argc
!= 1) usage();
228 module_path
= argv
[0];
233 if (!gdbfile
) usage();
235 // check for @address
236 if ((address
= strrchr(module_path
, '@'))) {
238 module_faked_address
= strtoul(address
, NULL
, 0);
241 module_faked_address
= 0;
244 // if any arg uses @address then they all must be and the kernel must be set
245 if (link_addrs_set
) {
246 if (!kernel_set
) usage();
247 if (!module_faked_address
) usage();
248 for (i
=0; i
< dependency_count
; i
++) {
249 if (!loaded_addresses
[i
]) usage();
254 // map the module if possible, map_module will fail if there is a problem
255 file_kinfo
= map_module(module_path
);
257 if (!link_addrs_set
) {
260 // we only need the kernel port if we need to lookup loaded kmods
261 r
= task_for_pid(mach_task_self(), 0, &kernel_port
);
262 machwarn(r
, "unable to get kernel task port");
263 if (KERN_SUCCESS
!= r
) {
264 abort_load(KMOD_ERROR_PERMS
,
265 "You must be running as root to load modules in the kernel.");
269 r
= kmod_get_info(kernel_port
, (void *)&loaded_modules
, &loaded_count
); // never freed
270 macherr(r
, "kmod_get_info() failed");
272 // check to see if the module has been loaded
275 if (!strcmp(k
->name
, file_kinfo
->name
)) {
277 abort_load(KMOD_ERROR_ALREADY
,
278 "the module named '%s' is already loaded.", k
->name
);
280 module_faked_address
= k
->address
;
284 k
= (k
->next
) ? (k
+ 1) : 0;
287 if (kmodsyms
&& !module_faked_address
) {
288 abort_load(KMOD_ERROR_USAGE
,
289 "the module named '%s' has not been loaded.", file_kinfo
->name
);
292 //XXX it would be nice to be able to verify this is the correct kernel
293 //XXX by comparing the kernel version strings (once we have them)
296 map_and_patch(kernel
, dependencies
, module_path
);
298 // Tell the kld linker where to get its load address from
299 kld_address_func(linkedit_address
);
301 // link the kernel along with any dependencies
302 link_base(kernel
, dependencies
, loaded_addresses
);
305 faked_kernel_load_address
= module_faked_address
;
307 if (!faked_kernel_load_address
) {
308 abort_load(KMOD_ERROR_INTERNAL
,
309 "internal error, fell thru without setting module load address.");
313 rld_header
= link_module(module_path
, gdbfile
);
314 module_info
= update_kmod_info(rld_header
);
317 kld_file_debug_dump(module_path
, debugdumpfile
);
319 if (kmodsyms
) return 0;
321 // we need the priv port to load modules into the kernel
322 kernel_priv_port
= mach_host_self(); /* if we are privileged */
324 module_id
= load_module(rld_header
, module_info
);
325 set_module_dependencies(module_id
);
326 start_module(module_id
);
332 machwarn(int error
, const char *message
)
334 if (KERN_SUCCESS
!= error
)
335 e_printf("%s: %s", message
, mach_error_string(error
));
339 macherr(int error
, const char *message
)
341 if (KERN_SUCCESS
!= error
)
342 abort_load(KMOD_ERROR_INTERNAL
,
343 "%s: %s", message
, mach_error_string(error
));
346 static kmod_info_t
*map_module(const char *filename
)
348 kmod_info_t
*file_kinfo
;
350 if (!kld_file_map(filename
))
351 exit(KMOD_ERROR_LOADING
);
353 file_kinfo
= kld_file_lookupsymbol(filename
, kKMOD_INFO_SYMBOLNAME
);
355 abort_load(KMOD_ERROR_USAGE
,
356 "%s is not a valid kernel module.", filename
);
363 map_and_patch(const char *base
, const char **library_paths
, const char *module)
365 if (!kld_file_map(base
))
366 exit(KMOD_ERROR_INTERNAL
);
367 if (!kld_file_merge_OSObjects(base
))
368 abort_load(KMOD_ERROR_LOADING
, NULL
);
370 if (*library_paths
) {
372 for (library
= library_paths
; *library
; library
++) {
373 map_module(*library
);
374 if (!kld_file_patch_OSObjects(*library
))
375 abort_load(KMOD_ERROR_LOADING
, NULL
);
379 // Patch the vtables of the object module we are about to load
380 // The module has already been mapped in the main() routine as part
382 if (!kld_file_patch_OSObjects(module))
383 abort_load(KMOD_ERROR_LOADING
, NULL
);
385 // During the patch up process the mapped images were modified
386 // to avoid having to allocate more data than necessary.
387 // Now we have to give the patcher a chance to clean up after itself.
388 if (!kld_file_prepare_for_link())
389 abort_load(KMOD_ERROR_LOADING
, NULL
);
393 link_base(const char *base
,
394 const char **dependency_paths
,
395 const vm_address_t
*dependency_addrs
)
397 struct mach_header
*rld_header
;
402 // Get the address and size of the base, usually the kernel
403 base_addr
= kld_file_getaddr(base
, &base_size
);
405 exit(KMOD_ERROR_INTERNAL
); // Error reported by kld library.
407 ok
= kld_load_basefile_from_memory(base
, base_addr
, base_size
);
410 abort_load(KMOD_ERROR_LOADING
, "kld_load_basefile(%s) failed.", base
);
412 if (*dependency_paths
) {
413 char **dependency
= dependency_paths
;
414 const vm_address_t
*load_addr
= dependency_addrs
;
416 while (*dependency
) {
417 kmod_info_t
*file_kinfo
;
419 // Find the kmod_info structure in the image.
421 kld_file_lookupsymbol(*dependency
, kKMOD_INFO_SYMBOLNAME
);
423 abort_load(KMOD_ERROR_USAGE
,
424 "%s is not a valid kernel module.", *dependency
);
427 // find the address that this dependency is loaded at
428 if (kmodsyms
&& *load_addr
) {
429 faked_kernel_load_address
= *load_addr
;
435 // match up file version of kmod_info with kernel version
438 if (!strcmp(k
->name
, file_kinfo
->name
)) {
439 UInt32 kernel_kmod_version
;
440 UInt32 file_kmod_version
;
442 if (!VERS_parse_string(k
->version
, &kernel_kmod_version
)) {
443 e_printf("can't parse version string \"%s\" in kernel kmod",
445 abort_load(KMOD_ERROR_LOADING
,
446 "can't parse kernel kmod version string \"%s\"", k
->version
);
449 if (!VERS_parse_string(file_kinfo
->version
, & file_kmod_version
)) {
450 e_printf("can't parse version string \"%s\" in kmod file %s",
451 file_kinfo
->version
, *dependency
);
452 abort_load(KMOD_ERROR_LOADING
,
453 "can't parse version string \"%s\" in kmod file %s",
454 file_kinfo
->version
, *dependency
);
457 if (kernel_kmod_version
!= file_kmod_version
) {
458 e_printf("loaded kernel module '%s' version differs.", *dependency
);
459 abort_load(KMOD_ERROR_LOADING
,
460 "loaded version '%s', file version '%s'.",
461 k
->version
, file_kinfo
->version
);
466 k
= (k
->next
) ? (k
+ 1) : 0;
469 abort_load(KMOD_ERROR_USAGE
,
470 "kernel module '%s' is not loaded.", *dependency
);
473 tmp
= malloc(sizeof(kmod_info_t
));
475 abort_load(KMOD_ERROR_LOADING
, "no memory.");
478 tmp
->next
= module_dependencies
;
479 module_dependencies
= tmp
;
481 faked_kernel_load_address
= k
->address
;
484 rld_header
= link_module(*dependency
, 0);
486 (void) update_kmod_info(rld_header
);
488 dependency
++; load_addr
++;
490 /* make sure we clear these so clean up does the right thing. */
495 #if !defined(page_round)
496 #define page_trunc(p) ((int)(p)&~(vm_page_size-1))
497 #define page_round(p) page_trunc((int)(p)+vm_page_size-1)
501 linkedit_address(unsigned long size
, unsigned long headers_size
)
504 unsigned long round_segments_size
;
505 unsigned long round_headers_size
;
506 unsigned long round_size
;
508 kernel_load_size
= size
; // The actual size allocated by kld_load...
510 round_headers_size
= page_round(headers_size
);
511 round_segments_size
= page_round(size
- headers_size
);
512 round_size
= round_headers_size
+ round_segments_size
;
514 kernel_alloc_size
= round_size
;
515 kernel_hdr_size
= headers_size
; // will need to be rounded to page *after* link.
516 kernel_hdr_pad
= round_headers_size
- headers_size
;
518 if (faked_kernel_load_address
) {
519 kernel_load_address
= faked_kernel_load_address
+ kernel_hdr_pad
;
520 v_printf("Returning fake load address of 0x%8x", kernel_load_address
);
521 return kernel_load_address
;
524 abort_load(KMOD_ERROR_INTERNAL
,
525 "internal error, almost tried to alloc kernel memory.");
528 r
= vm_allocate(kernel_port
, &kernel_alloc_address
,
529 kernel_alloc_size
, TRUE
);
530 macherr(r
, "unable to allocate kernel memory");
532 v_printf("allocated %ld bytes in kernel space at 0x%8x",
533 kernel_alloc_size
, kernel_alloc_address
);
535 kernel_load_address
= kernel_alloc_address
+ kernel_hdr_pad
;
537 v_printf("Returning load address of 0x%x", kernel_load_address
);
539 return kernel_load_address
;
545 faked_kernel_load_address
= 0;
546 kernel_alloc_address
= 0;
547 kernel_alloc_size
= 0;
548 kernel_load_address
= 0;
549 kernel_load_size
= 0;
555 static struct mach_header
*
556 link_module(const char *filename
, const char *output
)
558 struct mach_header
*rld_header
;
563 // Get the address of the thined MachO image.
564 object_addr
= kld_file_getaddr(filename
, &object_size
);
566 abort_load(KMOD_ERROR_LOADING
, NULL
);
568 ok
= kld_load_from_memory(&rld_header
, filename
,
569 object_addr
, object_size
, output
);
572 abort_load(KMOD_ERROR_LOADING
, "kld_load() failed.");
577 // Update the kmod_info_t structure in the image to be laoded
578 // Side effect of removing the kKMOD_INFO_SYMBOLNAME from the
579 // loaded symbol name space, otherwise we would have a duplicate
580 // defined symbol failure
582 update_kmod_info(struct mach_header
*mach_header
)
584 char * symbol
= kKMOD_INFO_SYMBOLNAME
;
589 ok
= kld_lookup(symbol
, &value
); fflush(stdout
);
591 abort_load(KMOD_ERROR_LOADING
, "kld_lookup(%s) failed.", symbol
);
593 ok
= kld_forget_symbol(symbol
); fflush(stdout
);
595 abort_load(KMOD_ERROR_LOADING
, "kld_forget_symbol(%s) failed.", symbol
);
597 /* Get the kmod info by translating from the kernel address at value.
599 info
= (kmod_info_t
*)(value
- (unsigned long)kernel_load_address
+ (unsigned long)mach_header
);
600 v_printf("kmod name: %s", info
->name
);
601 v_printf("kmod start @ 0x%x", (vm_address_t
)info
->start
);
602 v_printf("kmod stop @ 0x%x", (vm_address_t
)info
->stop
);
604 /* Record link info in kmod info struct, rounding the hdr_size to fit
605 * the adjustment that was made.
607 info
->address
= kernel_alloc_address
;
608 info
->size
= kernel_alloc_size
;
609 info
->hdr_size
= page_round(kernel_hdr_size
);
612 abort_load(KMOD_ERROR_LOADING
, "invalid start address?");
613 else if (!info
->stop
)
614 abort_load(KMOD_ERROR_LOADING
, "invalid stop address?");
616 return (vm_address_t
)value
;
620 load_module(struct mach_header
*mach_header
, vm_address_t info
)
624 vm_address_t vm_buffer
= 0;
626 r
= vm_allocate(mach_task_self(), &vm_buffer
,
627 kernel_alloc_size
, TRUE
);
628 macherr(r
, "unable to vm_allocate() copy buffer");
630 /* Copy the linked segment data into the page-aligned buffer.
631 * Do not round the header size here.
633 bzero((void *)vm_buffer
, kernel_alloc_size
);
634 memcpy((void *)vm_buffer
, mach_header
, kernel_hdr_size
);
635 memcpy((void *)vm_buffer
+ page_round(kernel_hdr_size
),
636 (void *)((unsigned long)mach_header
+ kernel_hdr_size
),
637 kernel_load_size
- kernel_hdr_size
);
639 // copy linked header into kernel address space
640 r
= vm_write(kernel_port
, kernel_alloc_address
,
641 vm_buffer
, kernel_alloc_size
);
642 macherr(r
, "unable to write module into kernel memory");
644 // let the kernel know about it
645 r
= kmod_create(kernel_priv_port
, info
, &id
);
646 macherr(r
, "unable to register module with kernel");
648 v_printf("kmod id %d successfully created at 0x%x size %ld.\n",
649 id
, kernel_alloc_address
, kernel_alloc_size
);
651 // FIXME: make sure this happens even on failure
653 vm_deallocate(mach_task_self(), vm_buffer
, kernel_alloc_size
);
658 set_module_dependencies(kmod_t id
)
663 kmod_info_t
*module = module_dependencies
;
667 r
= kmod_control(kernel_priv_port
, KMOD_PACK_IDS(id
, module->id
), KMOD_CNTL_RETAIN
, &args
, &argsCount
);
668 machwarn(r
, "kmod_control(retain) failed");
671 r
= kmod_destroy(kernel_priv_port
, id
);
672 macherr(r
, "kmod_destroy failed");
675 v_printf("kmod id %d reference count was sucessfully incremented.", module->id
);
677 module = module->next
;
682 start_module(kmod_t id
)
688 r
= kmod_control(kernel_priv_port
, id
, KMOD_CNTL_START
, &args
, &argsCount
);
689 machwarn(r
, "kmod_control(start) failed");
692 kmod_destroy(kernel_priv_port
, id
);
693 macherr(r
, "kmod_destroy failed");
696 v_printf("kmod id %d successfully started.", id
);
699 static void e_printf(const char *fmt
, ...)
705 vsnprintf(msg
, sizeof(msg
), fmt
, ap
);
708 fprintf(stderr
, "%s: %s\n", progname
, msg
);
711 static void v_printf(const char *fmt
, ...)
716 if (!verbose
) return;
719 vsnprintf(msg
, sizeof(msg
), fmt
, ap
);
722 printf("%s: %s\n", progname
, msg
);
725 static void abort_load(int exitcode
, const char *fmt
, ...)
732 vsnprintf(msg
, sizeof(msg
), fmt
, ap
);
735 fprintf(stderr
, "%s: %s\n", progname
, msg
);
738 if (!faked_kernel_load_address
739 && (kernel_alloc_address
|| kernel_alloc_size
)) {
742 v_printf("freeing %ld bytes in kernel space at 0x%x",
743 kernel_alloc_size
, kernel_alloc_address
);
744 r
= vm_deallocate(kernel_port
, kernel_alloc_address
, kernel_alloc_size
);
745 machwarn(r
, "unable to cleanup kernel memory");
751 __private_extern__
void
752 kld_error_vprintf(const char *fmt
, va_list ap
)
754 vfprintf(stderr
, fmt
, ap
);