]> git.saurik.com Git - apple/system_cmds.git/blob - kmodload.tproj/kmodload.c
system_cmds-175.2.tar.gz
[apple/system_cmds.git] / kmodload.tproj / kmodload.c
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
12 * this file.
13 *
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
20 * under the License."
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24 /*-
25 * Copyright (c) 1997 Doug Rabson
26 * All rights reserved.
27 *
28 * Redistribution and use in source and binary forms, with or without
29 * modification, are permitted provided that the following conditions
30 * are met:
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.
36 *
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
47 * SUCH DAMAGE.
48 *
49 * Original code from:
50 * "kldload.c,v 1.5 1998/07/06 06:58:32 charnier Exp"
51 */
52
53 #ifndef lint
54 static const char rcsid[] =
55 "$Id: kmodload.c,v 1.7 2001/02/05 19:53:16 lindak Exp $";
56 #endif /* not lint */
57
58 #include <stdlib.h>
59 #include <err.h>
60 #include <sys/file.h>
61 #include <nlist.h>
62 #include <stdio.h>
63 #include <unistd.h>
64 #include <sys/param.h>
65 #include <sys/stat.h>
66 #include <paths.h>
67
68 #include <mach/mach.h>
69 #include <mach/mach_error.h>
70 #include <mach/mach_host.h>
71 #include <mach-o/kld.h>
72 #include <mach-o/fat.h>
73
74 #define KMOD_ERROR_USAGE 1
75 #define KMOD_ERROR_PERMS 2
76 #define KMOD_ERROR_LOADING 3
77 #define KMOD_ERROR_INTERNAL 4
78 #define KMOD_ERROR_ALREADY 5
79
80 static mach_port_t kernel_port;
81 static mach_port_t kernel_priv_port;
82
83 static kmod_info_t *module_dependencies = 0;
84 static vm_address_t kernel_alloc_address = 0;
85 static unsigned long kernel_alloc_size = 0;
86 static vm_address_t kernel_load_address = 0;
87 static unsigned long kernel_load_size = 0;
88 static unsigned long kernel_hdr_size = 0;
89 static unsigned long kernel_hdr_pad = 0;
90 static unsigned long faked_kernel_load_address = 0;
91
92 static kmod_info_t *loaded_modules = 0;
93 static int loaded_count = 0;
94
95 static char *progname = "program name?";
96 static int kmodsyms = 0;
97 static int link_addrs_set = 0;
98 static int verbose = 0;
99 #define v_printf if (verbose) printf
100
101 // must not be static; kld library calls
102 void kld_error_vprintf(const char *format, va_list ap);
103
104 static void machwarn(int error, const char *message);
105 static void macherr(int error, const char *message);
106
107 static unsigned long linkedit_address(unsigned long size,
108 unsigned long headers_size);
109 static void cleanup_kernel_memory();
110 static void link_base(const char *base,
111 const char **dependency_paths,
112 const vm_address_t *dependency_addrs);
113 static void clear_globals(void);
114 static void map_module(char *module_path, char **object_addr,
115 long *object_size, kmod_info_t **kinfo);
116 static struct mach_header *link_module(const char *filename,
117 const char *output);
118 static vm_address_t patch_module(struct mach_header *mach_header);
119 static kmod_t load_module(struct mach_header *mach_header,
120 vm_address_t info);
121 static void set_module_dependencies(kmod_t id);
122 static void start_module(kmod_t id);
123
124 static void
125 usage(void)
126 {
127 if (kmodsyms) {
128 fprintf(stderr, "usage: kmodsyms [-v] [-k kernelfile] [-d dependencyfile] -o symbolfile modulefile\n");
129 fprintf(stderr, " kmodsyms [-v] -k kernelfile [-d dependencyfile@address] -o symbolfile modulefile@address\n");
130 } else {
131 fprintf(stderr, "usage: kmodload [-v] [-k kernelfile] [-d dependencyfile] [-o symbolfile] modulefile\n");
132 }
133 exit(KMOD_ERROR_USAGE);
134 }
135
136 int
137 main(int argc, char** argv)
138 {
139 int c, r, i;
140 char * kernel = _PATH_UNIX;
141 int kernel_set = 0;
142 char * gdbfile = 0;
143 #define MAX_DEPENDANCIES 128
144 char * dependencies[MAX_DEPENDANCIES];
145 vm_address_t loaded_addresses[MAX_DEPENDANCIES];
146 int dependency_count = 0;
147 struct mach_header *rld_header;
148
149 char * module_path = "";
150 vm_address_t module_info = 0;
151 char *module_addr = 0;
152 long module_size = 0;
153 vm_address_t module_faked_address = 0;
154 kmod_t module_id = 0;
155 kmod_info_t *file_kinfo;
156
157 if ((progname = rindex(argv[0], '/')) == NULL)
158 progname = argv[0];
159 else
160 ++progname;
161
162 kmodsyms = !strcmp(progname, "kmodsyms");
163
164 // XXX things to add:
165 // -p data string to send as outofband data on start
166 // -P data file to send as outofband data on start
167
168 while ((c = getopt(argc, argv, "d:o:k:v")) != -1)
169 switch (c) {
170 case 'd':
171 dependencies[dependency_count] = optarg;
172 if (kmodsyms) {
173 char *address;
174 if ((address = rindex(optarg, '@'))) {
175 *address++ = 0;
176 loaded_addresses[dependency_count] = strtoul(address, NULL, 0);
177 link_addrs_set++;
178 } else {
179 loaded_addresses[dependency_count] = 0;
180 }
181 }
182 if (++dependency_count == MAX_DEPENDANCIES) {
183 fprintf(stderr, "%s: internal error, dependency count overflow.\n", progname);
184 exit(KMOD_ERROR_INTERNAL);
185 }
186 break;
187 case 'o':
188 gdbfile = optarg;
189 break;
190 case 'k':
191 kernel_set++;
192 kernel = optarg;
193 break;
194 case 'v':
195 verbose = 1;
196 break;
197 default:
198 usage();
199 }
200 argc -= optind;
201 argv += optind;
202
203 dependencies[dependency_count] = 0;
204 loaded_addresses[dependency_count] = 0;
205
206 if (argc != 1) usage();
207
208 module_path = argv[0];
209
210 if (kmodsyms) {
211 char *address;
212
213 if (!gdbfile) usage();
214
215 // check for @address
216 if ((address = rindex(module_path, '@'))) {
217 *address++ = 0;
218 module_faked_address = strtoul(address, NULL, 0);
219 link_addrs_set++;
220 } else {
221 module_faked_address = 0;
222 }
223
224 // if any arg uses @address then they all must be and the kernel must be set
225 if (link_addrs_set) {
226 if (!kernel_set) usage();
227 if (!module_faked_address) usage();
228 for (i=0; i < dependency_count; i++) {
229 if (!loaded_addresses[i]) usage();
230 }
231 }
232 }
233
234 // map module and then check if it has been loaded
235 map_module(module_path, &module_addr, &module_size, &file_kinfo);
236
237 if (!link_addrs_set) {
238 kmod_info_t *k;
239
240 // we only need the kernel port if we need to lookup loaded kmods
241 r = task_for_pid(mach_task_self(), 0, &kernel_port);
242 machwarn(r, "unable to get kernel task port");
243 if (r) {
244 fprintf(stderr, "%s: You must be running as root to load/check modules in the kernel.\n", progname);
245 exit(KMOD_ERROR_PERMS);
246 }
247
248 //get loaded modules
249 r = kmod_get_info(kernel_port, (void *)&loaded_modules, &loaded_count); // never freed
250 macherr(r, "kmod_get_info() failed");
251
252 // check to see if the module has been loaded
253 k = loaded_modules;
254 while (k) {
255 if (!strcmp(k->name, file_kinfo->name)) {
256 if (!kmodsyms) {
257 fprintf(stderr, "%s: the module named '%s' is already loaded.\n", progname, k->name);
258 exit(KMOD_ERROR_ALREADY);
259 } else {
260 module_faked_address = k->address;
261 }
262 break;
263 }
264 k = (k->next) ? (k + 1) : 0;
265 }
266
267 if (kmodsyms && !module_faked_address) {
268 fprintf(stderr, "%s: the module named '%s' has not been loaded.\n", progname, file_kinfo->name);
269 exit(KMOD_ERROR_USAGE);
270 }
271
272 //XXX it would be nice to be able to verify this is the correct kernel
273 //XXX by comparing the kernel version strings (once we have them)
274 }
275
276 // link the kernel along with any dependencies
277 link_base(kernel, dependencies, loaded_addresses);
278
279 if (kmodsyms) {
280 faked_kernel_load_address = module_faked_address;
281
282 if (!faked_kernel_load_address) {
283 fprintf(stderr, "%s: internal error, fell thru without setting module load address.\n", progname);
284 exit(KMOD_ERROR_INTERNAL);
285 }
286 }
287
288 rld_header = link_module(module_path, gdbfile);
289 module_info = patch_module(rld_header);
290
291 if (kmodsyms) return 0;
292
293 // we need the priv port to load modules into the kernel
294 kernel_priv_port = mach_host_self(); /* if we are privileged */
295
296 module_id = load_module(rld_header, module_info);
297 set_module_dependencies(module_id);
298 start_module(module_id);
299
300 return 0;
301 }
302
303 static void
304 machwarn(int error, const char *message)
305 {
306 if (error == KERN_SUCCESS) return;
307 fprintf(stderr, "%s: %s: %s\n", progname, message, mach_error_string(error));
308 }
309
310 static void
311 macherr(int error, const char *message)
312 {
313 if (error == KERN_SUCCESS) return;
314 fprintf(stderr, "%s: %s: %s\n", progname, message, mach_error_string(error));
315
316 cleanup_kernel_memory();
317
318 exit(KMOD_ERROR_INTERNAL);
319 }
320
321 static void
322 map_module(char *module_path, char **object_addr, long *object_size, kmod_info_t **kinfo)
323 {
324 int fd;
325 struct stat stat_buf;
326 struct mach_header *mh;
327 char *p;
328
329 struct nlist nl[] = {
330 { "_kmod_info" },
331 { "" },
332 };
333
334 if((fd = open(module_path, O_RDONLY)) == -1){
335 fprintf(stderr, "%s: Can't open: %s\n", progname, module_path);
336 exit(KMOD_ERROR_USAGE);
337 }
338 if (nlist(module_path, nl)) {
339 fprintf(stderr, "%s: %s is not a valid kernel module.\n", progname, module_path);
340 exit(KMOD_ERROR_USAGE);
341 }
342 if(fstat(fd, &stat_buf) == -1){
343 fprintf(stderr, "%s: Can't stat file: %s\n", progname, module_path);
344 exit(KMOD_ERROR_PERMS);
345 }
346 *object_size = stat_buf.st_size;
347 if(map_fd(fd, 0, (vm_offset_t *)object_addr, TRUE, *object_size) != KERN_SUCCESS){
348 fprintf(stderr, "%s: Can't map file: %s\n", progname, module_path);
349 exit(KMOD_ERROR_INTERNAL);
350 }
351 close(fd);
352
353 if (NXSwapBigLongToHost(*((long *)*object_addr)) == FAT_MAGIC) {
354 struct host_basic_info hbi;
355 struct fat_header *fh;
356 struct fat_arch *fat_archs, *fap;
357 unsigned i, nfat_arch;
358
359 /* Get our host info */
360 i = HOST_BASIC_INFO_COUNT;
361 if (host_info(mach_host_self(), HOST_BASIC_INFO, (host_info_t)(&hbi), &i) != KERN_SUCCESS) {
362 fprintf(stderr, "%s: Can't get host's basic info\n", progname);
363 exit(KMOD_ERROR_INTERNAL);
364 }
365
366 // get number of architectures
367 fh = (struct fat_header *)*object_addr;
368 nfat_arch = NXSwapBigLongToHost(fh->nfat_arch);
369
370 // find beginning of fat_arch struct
371 fat_archs = (struct fat_arch *)((char *)fh + sizeof(struct fat_header));
372
373 /*
374 * Convert archs to host byte ordering (a constraint of
375 * cpusubtype_getbestarch()
376 */
377 for (i = 0; i < nfat_arch; i++) {
378 fat_archs[i].cputype =
379 NXSwapBigLongToHost(fat_archs[i].cputype);
380 fat_archs[i].cpusubtype =
381 NXSwapBigLongToHost(fat_archs[i].cpusubtype);
382 fat_archs[i].offset =
383 NXSwapBigLongToHost(fat_archs[i].offset);
384 fat_archs[i].size =
385 NXSwapBigLongToHost(fat_archs[i].size);
386 fat_archs[i].align =
387 NXSwapBigLongToHost(fat_archs[i].align);
388 }
389
390 // this code was lifted from Darwin/Libraries/NeXT/libc/gen.subproj/nlist.c
391 // when cpusubtype_getbestarch exists this code should also be changed.
392 #define CPUSUBTYPE_SUPPORT 0
393
394 #if CPUSUBTYPE_SUPPORT
395 fap = cpusubtype_getbestarch(hbi.cpu_type, hbi.cpu_subtype,
396 fat_archs, nfat_arch);
397 #else CPUSUBTYPE_SUPPORT
398 #warning Use the cpusubtype functions!!!
399 fap = NULL;
400 for (i = 0; i < nfat_arch; i++) {
401 if (fat_archs[i].cputype == hbi.cpu_type) {
402 fap = &fat_archs[i];
403 break;
404 }
405 }
406 #endif CPUSUBTYPE_SUPPORT
407 if (!fap) {
408 fprintf(stderr, "%s: could not find the correct architecture in %s.\n", progname, module_path);
409 exit(KMOD_ERROR_USAGE);
410 }
411
412 *object_addr += fap->offset;
413 *object_size = fap->size;
414 }
415
416 mh = (struct mach_header *)*object_addr;
417 if (*((long *)mh) != MH_MAGIC) {
418 fprintf(stderr, "%s: invalid file format for file: %s\n", progname, module_path);
419 exit(KMOD_ERROR_USAGE);
420 }
421 p = *object_addr + sizeof(struct mach_header) + mh->sizeofcmds + nl->n_value;
422 *kinfo = (kmod_info_t *)p;
423 }
424
425 static void
426 link_base(const char *base,
427 const char **dependency_paths,
428 const vm_address_t *dependency_addrs)
429 {
430 struct mach_header *rld_header;
431 int ok;
432
433 ok = kld_load_basefile(base);
434 fflush(stdout);
435 if (!ok) {
436 fprintf(stderr, "%s: kld_load_basefile(%s) failed.\n", progname, base);
437 exit(KMOD_ERROR_LOADING);
438 }
439
440 if (*dependency_paths) {
441 char **dependency = dependency_paths;
442 const vm_address_t *load_addr = dependency_addrs;
443
444 while (*dependency) {
445 char *object_addr;
446 long object_size;
447 kmod_info_t *file_kinfo;
448
449 map_module(*dependency, &object_addr, &object_size, &file_kinfo);
450
451 // find the address that this dependency is loaded at
452 if (kmodsyms && *load_addr) {
453 faked_kernel_load_address = *load_addr;
454 } else {
455 kmod_info_t *k;
456 kmod_info_t *tmp;
457 int found_it = 0;
458
459 // match up file version of kmod_info with kernel version
460 k = loaded_modules;
461 while (k) {
462 if (!strcmp(k->name, file_kinfo->name)) {
463 if (strcmp(k->version, file_kinfo->version)) {
464 fprintf(stderr, "%s: loaded kernel module '%s' version differs.\n",
465 progname, *dependency);
466 fprintf(stderr, "%s: loaded version '%s', file version '%s'.\n",
467 progname, k->version, file_kinfo->version);
468 exit(KMOD_ERROR_LOADING);
469 }
470 found_it++;
471 break;
472 }
473 k = (k->next) ? (k + 1) : 0;
474 }
475 if (!found_it) {
476 fprintf(stderr, "%s: kernel module '%s' is not loaded.\n",
477 progname, *dependency);
478 exit(KMOD_ERROR_USAGE);
479 }
480
481 tmp = malloc(sizeof(kmod_info_t));
482 if (!tmp) {
483 fprintf(stderr, "%s: no memory.\n", progname);
484 exit(KMOD_ERROR_LOADING);
485 }
486 *tmp = *k;
487 tmp->next = module_dependencies;
488 module_dependencies = tmp;
489
490 faked_kernel_load_address = k->address;
491 }
492
493 rld_header = link_module(*dependency, 0);
494
495 (void)patch_module(rld_header);
496
497 dependency++; load_addr++;
498 }
499 /* make sure we clear these so clean up does the right thing. */
500 clear_globals();
501 }
502 }
503
504 #if !defined(page_round)
505 #define page_trunc(p) ((int)(p)&~(vm_page_size-1))
506 #define page_round(p) page_trunc((int)(p)+vm_page_size-1)
507 #endif
508
509 static unsigned long
510 linkedit_address(unsigned long size, unsigned long headers_size)
511 {
512 int r;
513 unsigned long round_segments_size;
514 unsigned long round_headers_size;
515 unsigned long round_size;
516
517 kernel_load_size = size; // The actual size allocated by kld_load...
518
519 round_headers_size = page_round(headers_size);
520 round_segments_size = page_round(size - headers_size);
521 round_size = round_headers_size + round_segments_size;
522
523 kernel_alloc_size = round_size;
524 kernel_hdr_size = headers_size; // will need to be rounded to page *after* link.
525 kernel_hdr_pad = round_headers_size - headers_size;
526
527 if (faked_kernel_load_address) {
528 kernel_load_address = faked_kernel_load_address + kernel_hdr_pad;
529 v_printf("%s: Returning fake load address of 0x%8x\n",
530 progname, kernel_load_address);
531 return kernel_load_address;
532 }
533 if (kmodsyms) {
534 fprintf(stderr, "%s: internal error, almost tried to alloc kernel memory.\n", progname);
535 exit(KMOD_ERROR_INTERNAL);
536 }
537
538 r = vm_allocate(kernel_port, &kernel_alloc_address,
539 kernel_alloc_size, TRUE);
540 macherr(r, "unable to allocate kernel memory");
541
542 v_printf("%s: allocated %ld bytes in kernel space at 0x%8x\n",
543 progname, kernel_alloc_size, kernel_alloc_address);
544
545 kernel_load_address = kernel_alloc_address + kernel_hdr_pad;
546
547 v_printf("%s: Returning load address of 0x%x\n",
548 progname, kernel_load_address);
549
550 return kernel_load_address;
551 }
552
553 static void
554 cleanup_kernel_memory()
555 {
556 int r;
557
558 if (faked_kernel_load_address) return;
559
560 if (kernel_alloc_address || kernel_alloc_size) {
561 v_printf("%s: freeing %ld bytes in kernel space at 0x%x\n",
562 progname, kernel_alloc_size, kernel_alloc_address);
563 r = vm_deallocate(kernel_port, kernel_alloc_address, kernel_alloc_size);
564 clear_globals();
565 kernel_load_address = kernel_load_size = 0;
566 machwarn(r, "unable to cleanup kernel memory");
567 }
568 }
569
570 static void
571 clear_globals(void)
572 {
573 faked_kernel_load_address = 0;
574 kernel_alloc_address = 0;
575 kernel_alloc_size = 0;
576 kernel_load_address = 0;
577 kernel_load_size = 0;
578 kernel_hdr_size = 0;
579 kernel_hdr_pad = 0;
580 return;
581 }
582
583 static struct mach_header *
584 link_module(const char *filename, const char *output)
585 {
586 struct mach_header *rld_header;
587 int ok;
588
589 kld_address_func(linkedit_address);
590
591 ok = kld_load(&rld_header, filename, output);
592 fflush(stdout);
593 if (!ok) {
594 fprintf(stderr, "%s: kld_load() failed.\n", progname);
595 cleanup_kernel_memory();
596 exit(KMOD_ERROR_LOADING);
597 }
598
599 return rld_header;
600 }
601
602 vm_address_t
603 patch_module(struct mach_header *mach_header)
604 {
605 char * symbol = "_kmod_info";
606 kmod_info_t *info;
607 unsigned long value;
608 int ok;
609
610 ok = kld_lookup(symbol, &value);
611 fflush(stdout);
612 if (!ok) {
613 fprintf(stderr, "%s: kld_lookup(%s) failed.\n", progname, symbol);
614 cleanup_kernel_memory();
615 exit(KMOD_ERROR_LOADING);
616 }
617
618 ok = kld_forget_symbol(symbol);
619 fflush(stdout);
620 if (!ok) {
621 fprintf(stderr, "%s: kld_forget_symbol(%s) failed.\n", progname, symbol);
622 cleanup_kernel_memory();
623 exit(KMOD_ERROR_INTERNAL);
624 }
625
626 /* Get the kmod info by translating from the kernel address at value.
627 */
628 info = (kmod_info_t *)(value - (unsigned long)kernel_load_address + (unsigned long)mach_header);
629 v_printf("%s: kmod name: %s\n", progname, info->name);
630 v_printf("%s: kmod start @ 0x%x\n", progname, (vm_address_t)info->start);
631 v_printf("%s: kmod stop @ 0x%x\n", progname, (vm_address_t)info->stop);
632
633 /* Record link info in kmod info struct, rounding the hdr_size to fit
634 * the adjustment that was made.
635 */
636 info->address = kernel_alloc_address;
637 info->size = kernel_alloc_size;
638 info->hdr_size = page_round(kernel_hdr_size);
639
640 if (!info->start) {
641 fprintf(stderr, "%s: invalid start address?\n", progname);
642 cleanup_kernel_memory();
643 exit(KMOD_ERROR_LOADING);
644 }
645 if (!info->stop) {
646 fprintf(stderr, "%s: invalid stop address?\n", progname);
647 cleanup_kernel_memory();
648 exit(KMOD_ERROR_LOADING);
649 }
650
651 return (vm_address_t)value;
652 }
653
654 static kmod_t
655 load_module(struct mach_header *mach_header, vm_address_t info)
656 {
657 int r;
658 kmod_t id;
659 vm_address_t vm_buffer = 0;
660
661 r = vm_allocate(mach_task_self(), &vm_buffer,
662 kernel_alloc_size, TRUE);
663 macherr(r, "unable to vm_allocate() copy buffer");
664
665 /* Copy the linked segment data into the page-aligned buffer.
666 * Do not round the header size here.
667 */
668 bzero((void *)vm_buffer, kernel_alloc_size);
669 memcpy((void *)vm_buffer, mach_header, kernel_hdr_size);
670 memcpy((void *)vm_buffer + page_round(kernel_hdr_size),
671 (void *)((unsigned long)mach_header + kernel_hdr_size),
672 kernel_load_size - kernel_hdr_size);
673
674 // copy linked header into kernel address space
675 r = vm_write(kernel_port, kernel_alloc_address,
676 vm_buffer, kernel_alloc_size);
677 macherr(r, "unable to write module into kernel memory");
678
679 // let the kernel know about it
680 r = kmod_create(kernel_priv_port, info, &id);
681 macherr(r, "unable to register module with kernel");
682
683 v_printf("%s: kmod id %d successfully created at 0x%x size %ld.\n",
684 progname, id, kernel_alloc_address, kernel_alloc_size);
685
686 // FIXME: make sure this happens even on failure
687
688 vm_deallocate(mach_task_self(), vm_buffer, kernel_alloc_size);
689 return id;
690 }
691
692 static void
693 set_module_dependencies(kmod_t id)
694 {
695 int r;
696 void * args = 0;
697 int argsCount= 0;
698 kmod_info_t *module = module_dependencies;
699
700 while (module) {
701
702 r = kmod_control(kernel_priv_port, KMOD_PACK_IDS(id, module->id), KMOD_CNTL_RETAIN, &args, &argsCount);
703 machwarn(r, "kmod_control(retain) failed");
704 if (r) {
705 clear_globals();
706 r = kmod_destroy(kernel_priv_port, id);
707 macherr(r, "kmod_destroy failed");
708 exit(KMOD_ERROR_INTERNAL);
709 }
710
711 v_printf("%s: kmod id %d reference count was sucessfully incremented.\n", progname, module->id);
712
713 module = module->next;
714 }
715 }
716
717 static void
718 start_module(kmod_t id)
719 {
720 int r;
721 void * args = 0;
722 int argsCount= 0;
723
724 r = kmod_control(kernel_priv_port, id, KMOD_CNTL_START, &args, &argsCount);
725 machwarn(r, "kmod_control(start) failed");
726 if (r) {
727 clear_globals();
728 kmod_destroy(kernel_priv_port, id);
729 macherr(r, "kmod_destroy failed");
730 exit(KMOD_ERROR_INTERNAL);
731 }
732
733 v_printf("%s: kmod id %d successfully started.\n", progname, id);
734 }
735
736 void
737 kld_error_vprintf(const char *format, va_list ap){
738 vfprintf(stderr, format, ap);
739 return;
740 }