|
|
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.