|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /*
23: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
24: *
25: * HISTORY
26: *
27: * 1999 Mar 29 rsulack created.
28: */
29:
30: #include <mach/mach_types.h>
31: #include <mach/vm_types.h>
32: #include <mach/kern_return.h>
33: #include <kern/kern_types.h>
34: #include <vm/vm_kern.h>
35: #include <kern/thread.h>
36:
37: #include <mach_host.h>
38:
39: static kmod_info_t *kmod = 0;
40: static int kmod_index = 1;
41:
42: decl_simple_lock_data(,kmod_lock)
43: decl_simple_lock_data(,kmod_queue_lock)
44:
45: typedef struct cmd_queue_entry {
46: queue_chain_t links;
47: vm_address_t data;
48: vm_size_t size;
49: } cmd_queue_entry_t;
50:
51: queue_head_t kmod_cmd_queue;
52:
53: void
54: kmod_init()
55: {
56: simple_lock_init(&kmod_lock, ETAP_MISC_Q);
57: simple_lock_init(&kmod_queue_lock, ETAP_MISC_Q);
58: queue_init(&kmod_cmd_queue);
59:
60: // XXX grab list drivers already loaded by bootloader
61: // XXX when we get such support (include the kernel itself?)
62: }
63:
64: kmod_info_t *
65: kmod_lookupbyid(kmod_t id)
66: {
67: kmod_info_t *k = 0;
68:
69: k = kmod;
70: while (k) {
71: if (k->id == id) break;
72: k = k->next;
73: }
74:
75: return k;
76: }
77:
78: kmod_info_t *
79: kmod_lookupbyname(char * name)
80: {
81: kmod_info_t *k = 0;
82:
83: k = kmod;
84: while (k) {
85: if (!strcmp(k->name, name)) break;
86: k = k->next;
87: }
88:
89: return k;
90: }
91:
92: // XXX add a nocopy flag??
93:
94: kern_return_t
95: kmod_queue_cmd(vm_address_t data, vm_size_t size)
96: {
97: kern_return_t rc;
98: cmd_queue_entry_t *e = (cmd_queue_entry_t *)kalloc(sizeof(struct cmd_queue_entry));
99: if (!e) return KERN_RESOURCE_SHORTAGE;
100:
101: rc = kmem_alloc(kernel_map, &e->data, size);
102: if (rc != KERN_SUCCESS) {
103: kfree((vm_offset_t)e, sizeof(struct cmd_queue_entry));
104: return rc;
105: }
106: e->size = size;
107: bcopy((void *)data, (void *)e->data, size);
108:
109: simple_lock(&kmod_queue_lock);
110: enqueue_tail(&kmod_cmd_queue, (queue_entry_t)e);
111: simple_unlock(&kmod_queue_lock);
112:
113: thread_wakeup_one((event_t)&kmod_cmd_queue);
114:
115: return KERN_SUCCESS;
116: }
117:
118: kern_return_t
119: kmod_load_extension(char *name)
120: {
121: kmod_load_extension_cmd_t *data;
122: vm_size_t size;
123:
124: size = sizeof(kmod_load_extension_cmd_t);
125: data = (kmod_load_extension_cmd_t *)kalloc(size);
126: if (!data) return KERN_RESOURCE_SHORTAGE;
127:
128: data->type = KMOD_LOAD_EXTENSION_PACKET;
129: strncpy(data->name, name, KMOD_MAX_NAME);
130:
131: return kmod_queue_cmd((vm_address_t)data, size);
132: }
133:
134: kern_return_t
135: kmod_load_extension_with_dependencies(char *name, char **dependencies)
136: {
137: kmod_load_with_dependencies_cmd_t *data;
138: vm_size_t size;
139: char **c;
140: int i, count = 0;
141:
142: c = dependencies;
143: if (c) {
144: while (*c) {
145: count++; c++;
146: }
147: }
148: size = sizeof(int) + KMOD_MAX_NAME * (count + 1) + 1;
149: data = (kmod_load_with_dependencies_cmd_t *)kalloc(size);
150: if (!data) return KERN_RESOURCE_SHORTAGE;
151:
152: data->type = KMOD_LOAD_WITH_DEPENDENCIES_PACKET;
153: strncpy(data->name, name, KMOD_MAX_NAME);
154:
155: c = dependencies;
156: for (i=0; i < count; i++) {
157: strncpy(data->dependencies[i], *c, KMOD_MAX_NAME);
158: c++;
159: }
160: data->dependencies[count][0] = 0;
161:
162: return kmod_queue_cmd((vm_address_t)data, size);
163: }
164: kern_return_t
165: kmod_send_generic(int type, void *generic_data, int size)
166: {
167: kmod_generic_cmd_t *data;
168:
169: data = (kmod_generic_cmd_t *)kalloc(size + sizeof(int));
170: if (!data) return KERN_RESOURCE_SHORTAGE;
171:
172: data->type = type;
173: bcopy(data->data, generic_data, size);
174:
175: return kmod_queue_cmd((vm_address_t)data, size + sizeof(int));
176: }
177:
178: kern_return_t
179: kmod_create(host_t host,
180: kmod_info_t *info,
181: kmod_t *id)
182: {
183: kern_return_t rc;
184:
185: if (host == HOST_NULL) return KERN_INVALID_HOST;
186: if (!info) return KERN_INVALID_ADDRESS;
187:
188: // double check for page alignment
189: if ((info->address | info->hdr_size) & (PAGE_SIZE - 1)) {
190: return KERN_INVALID_ADDRESS;
191: }
192:
193: rc = vm_map_wire(kernel_map, info->address + info->hdr_size,
194: info->address + info->size, VM_PROT_DEFAULT, FALSE);
195: if (rc != KERN_SUCCESS) {
196: return rc;
197: }
198:
199: simple_lock(&kmod_lock);
200:
201: // check to see if already loaded
202: if (kmod_lookupbyname(info->name)) {
203: simple_unlock(&kmod_lock);
204: vm_map_unwire(kernel_map, info->address + info->hdr_size,
205: info->address + info->size - info->hdr_size, FALSE);
206: return KERN_INVALID_ARGUMENT;
207: }
208:
209: info->id = kmod_index++;
210: info->reference_count = 0;
211:
212: info->next = kmod;
213: kmod = info;
214:
215: *id = info->id;
216:
217: simple_unlock(&kmod_lock);
218:
219: printf("kmod_create: %s (id %d), %d pages loaded at 0x%x, header size 0x%x\n",
220: info->name, info->id, info->size / PAGE_SIZE, info->address, info->hdr_size);
221:
222: return KERN_SUCCESS;
223: }
224:
225:
226: kern_return_t
227: kmod_destroy(host_t host,
228: kmod_t id)
229: {
230: kmod_info_t *k = kmod;
231: kmod_info_t *p = kmod;
232:
233: if (host == HOST_NULL) return KERN_INVALID_HOST;
234:
235: simple_lock(&kmod_lock);
236: while (k) {
237: if (k->id == id) {
238: kmod_reference_t *r, *t;
239:
240: if (k->reference_count != 0) {
241: simple_unlock(&kmod_lock);
242: return KERN_INVALID_ARGUMENT;
243: }
244:
245: if (k == p) { // first element
246: kmod = k->next;
247: } else {
248: p->next = k->next;
249: }
250: simple_unlock(&kmod_lock);
251:
252: r = k->reference_list;
253: while (r) {
254: r->info->reference_count--;
255: t = r;
256: r = r->next;
257: kfree((vm_offset_t)t, sizeof(struct kmod_reference));
258: }
259:
260: printf("kmod_destroy: %s (id %d), deallocating %d pages starting at 0x%x\n",
261: k->name, k->id, k->size / PAGE_SIZE, k->address);
262:
263: vm_map_unwire(kernel_map, k->address + k->hdr_size,
264: k->address + k->size - k->hdr_size, FALSE);
265: vm_deallocate(kernel_map, k->address, k->size);
266: return KERN_SUCCESS;
267: }
268: p = k;
269: k = k->next;
270: }
271: simple_unlock(&kmod_lock);
272:
273: return KERN_INVALID_ARGUMENT;
274: }
275:
276:
277: kern_return_t
278: kmod_control(host_t host,
279: kmod_t id,
280: kmod_control_flavor_t flavor,
281: kmod_args_t *data,
282: mach_msg_type_number_t *dataCount)
283: {
284: kern_return_t rc = KERN_SUCCESS;
285:
286: if (host == HOST_NULL) return KERN_INVALID_HOST;
287:
288: switch (flavor) {
289:
290: case KMOD_CNTL_START:
291: case KMOD_CNTL_STOP:
292: {
293: void * user_data = 0;
294: kern_return_t (*func)();
295: kmod_info_t *k;
296:
297: simple_lock(&kmod_lock);
298:
299: k = kmod_lookupbyid(id);
300: if (!k || k->reference_count) {
301: simple_unlock(&kmod_lock);
302: rc = KERN_INVALID_ARGUMENT;
303: break;
304: }
305:
306: if (flavor == KMOD_CNTL_START) {
307: func = (void *)k->start;
308: } else {
309: func = (void *)k->stop;
310: }
311:
312: simple_unlock(&kmod_lock);
313:
314: //
315: // call kmod entry point
316: //
317: if (*data && *dataCount) {
318: vm_map_copyout(kernel_map, (vm_offset_t *)&user_data, (vm_map_copy_t)*data);
319: }
320:
321: rc = (*func)(k, user_data);
322:
323: if (user_data) {
324: (void) vm_deallocate(kernel_map, (vm_offset_t)user_data, *dataCount);
325: }
326:
327: break;
328: }
329:
330: case KMOD_CNTL_RETAIN:
331: case KMOD_CNTL_RELEASE:
332: {
333: kmod_info_t *t; // reference to
334: kmod_info_t *f; // reference from
335: kmod_reference_t *r = 0;
336:
337: if (flavor == KMOD_CNTL_RETAIN) {
338: r = (kmod_reference_t *)kalloc(sizeof(struct kmod_reference));
339: if (!r) return KERN_RESOURCE_SHORTAGE;
340: }
341:
342: simple_lock(&kmod_lock);
343:
344: t = kmod_lookupbyid(KMOD_UNPACK_TO_ID(id));
345: f = kmod_lookupbyid(KMOD_UNPACK_FROM_ID(id));
346: if (!t || !f) {
347: simple_unlock(&kmod_lock);
348: if (r) kfree((vm_offset_t)r, sizeof(struct kmod_reference));
349: rc = KERN_INVALID_ARGUMENT;
350: break;
351: }
352: if (flavor == KMOD_CNTL_RETAIN) {
353: r->next = f->reference_list;
354: r->info = t;
355: f->reference_list = r;
356: t->reference_count++;
357: } else {
358: kmod_reference_t *p;
359:
360: p = r = f->reference_list;
361: while (r) {
362: if (r->info == t) {
363: if (p == r) { // first element
364: f->reference_list = r->next;
365: } else {
366: p->next = r->next;
367: }
368: r->info->reference_count--;
369: simple_unlock(&kmod_lock);
370: kfree((vm_offset_t)r, sizeof(struct kmod_reference));
371: return rc;
372: }
373: p = r;
374: r = r->next;
375: }
376: rc = KERN_INVALID_ARGUMENT;
377: }
378: simple_unlock(&kmod_lock);
379:
380: break;
381: }
382:
383: case KMOD_CNTL_GET_CMD: {
384:
385: cmd_queue_entry_t *e;
386:
387: simple_lock(&kmod_queue_lock);
388:
389: if (queue_empty(&kmod_cmd_queue)) {
390: assert_wait((event_t)&kmod_cmd_queue, THREAD_ABORTSAFE);
391: simple_unlock(&kmod_queue_lock);
392: thread_block((void(*)(void))0);
393: simple_lock(&kmod_queue_lock);
394: if (queue_empty(&kmod_cmd_queue)) {
395: // we must have been interrupted!
396: simple_unlock(&kmod_queue_lock);
397: return KERN_ABORTED;
398: }
399: }
400: e = (cmd_queue_entry_t *)dequeue_head(&kmod_cmd_queue);
401: simple_unlock(&kmod_queue_lock);
402:
403: rc = vm_map_copyin(kernel_map, e->data, e->size, TRUE, (vm_map_copy_t *)data);
404: if (rc) {
405: simple_lock(&kmod_queue_lock);
406: enqueue_head(&kmod_cmd_queue, (queue_entry_t)e);
407: simple_unlock(&kmod_queue_lock);
408: *data = 0;
409: *dataCount = 0;
410: return rc;
411: }
412: *dataCount = e->size;
413:
414: kfree((vm_offset_t)e, sizeof(struct cmd_queue_entry));
415:
416: break;
417: }
418:
419: default:
420: rc = KERN_INVALID_ARGUMENT;
421: }
422:
423: return rc;
424: };
425:
426:
427: kern_return_t
428: kmod_get_info(host_t host,
429: kmod_info_array_t *kmods,
430: mach_msg_type_number_t *kmodCount)
431: {
432: vm_offset_t data;
433: kmod_info_t *k, *p1;
434: kmod_reference_t *r, *p2;
435: int ref_count;
436: unsigned size = 0;
437: kern_return_t rc = KERN_SUCCESS;
438:
439: *kmods = (void *)0;
440: *kmodCount = 0;
441:
442: retry:
443: simple_lock(&kmod_lock);
444: k = kmod;
445: while (k) {
446: size += sizeof(kmod_info_t);
447: r = k->reference_list;
448: while (r) {
449: size +=sizeof(kmod_reference_t);
450: r = r->next;
451: }
452: k = k->next;
453: }
454: simple_unlock(&kmod_lock);
455: if (!size) return KERN_SUCCESS;
456:
457: rc = kmem_alloc(kernel_map, &data, size);
458: if (rc) return rc;
459:
460: // copy kmod into data, retry if kmod's size has changed (grown)
461: // the copied out data is tweeked to figure what's what at user level
462: // change the copied out k->next pointers to point to themselves
463: // change the k->reference into a count, tack the references on
464: // the end of the data packet in the order they are found
465:
466: simple_lock(&kmod_lock);
467: k = kmod; p1 = (kmod_info_t *)data;
468: while (k) {
469: if ((p1 + 1) > (kmod_info_t *)(data + size)) {
470: simple_unlock(&kmod_lock);
471: kmem_free(kernel_map, data, size);
472: goto retry;
473: }
474:
475: *p1 = *k;
476: if (k->next) p1->next = k;
477: p1++; k = k->next;
478: }
479:
480: p2 = (kmod_reference_t *)p1;
481: k = kmod; p1 = (kmod_info_t *)data;
482: while (k) {
483: r = k->reference_list; ref_count = 0;
484: while (r) {
485: if ((p2 + 1) > (kmod_reference_t *)(data + size)) {
486: simple_unlock(&kmod_lock);
487: kmem_free(kernel_map, data, size);
488: goto retry;
489: }
490: // note the last 'k' in the chain has its next == 0
491: // since there can only be one like that,
492: // this case is handled by the caller
493: *p2 = *r;
494: p2++; r = r->next; ref_count++;
495: }
496: p1->reference_list = (kmod_reference_t *)ref_count;
497: p1++; k = k->next;
498: }
499: simple_unlock(&kmod_lock);
500:
501: rc = vm_map_copyin(kernel_map, data, size, TRUE, (vm_map_copy_t *)kmods);
502: if (rc) {
503: kmem_free(kernel_map, data, size);
504: *kmods = 0;
505: *kmodCount = 0;
506: return rc;
507: }
508: *kmodCount = size;
509:
510: return KERN_SUCCESS;
511: }
512:
513: #include <mach-o/loader.h>
514:
515: extern void *getsectdatafromheader(struct mach_header *mhp,
516: const char *segname,
517: const char *sectname,
518: int *size);
519:
520: static kern_return_t
521: kmod_call_funcs_in_section(struct mach_header *header, const char *sectName)
522: {
523: typedef void (*Routine)(void);
524: Routine * routines;
525: int size, i;
526:
527: if (header->magic != MH_MAGIC) {
528: return KERN_INVALID_ARGUMENT;
529: }
530:
531: routines = (Routine *) getsectdatafromheader(header, SEG_TEXT, sectName, &size);
532: if (!routines) return KERN_SUCCESS;
533:
534: size /= sizeof(Routine);
535: for (i = 0; i < size; i++) {
536: (*routines[i])();
537: }
538:
539: return KERN_SUCCESS;
540: }
541:
542: kern_return_t
543: kmod_initialize_cpp(kmod_info_t *info)
544: {
545: return kmod_call_funcs_in_section((struct mach_header *)info->address, "__constructor");
546: }
547:
548: kern_return_t
549: kmod_finalize_cpp(kmod_info_t *info)
550: {
551: return kmod_call_funcs_in_section((struct mach_header *)info->address, "__destructor");
552: }
553:
554: kern_return_t
555: kmod_default_start(struct kmod_info *ki, void *data)
556: {
557: return KMOD_RETURN_SUCCESS;
558: }
559:
560: kern_return_t
561: kmod_default_stop(struct kmod_info *ki, void *data)
562: {
563: return KMOD_RETURN_SUCCESS;
564: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.