|
|
1.1 ! root 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.1 (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: /* ! 26: * Copyright (c) 1989 NeXT, Inc. ! 27: * ! 28: * HISTORY ! 29: * 4-Jun-91 Gregg Kellogg (gk) at NeXT ! 30: * Abort server_thread before calling thread_dowait when trying to ! 31: * service callouts. ! 32: * ! 33: * 27-Aug-90 Gregg Kellogg (gk) at NeXT ! 34: * Fixed bugs in kern_serv_callout. ! 35: * Remove compatibility for servers < version 2. ! 36: * ! 37: * 12-Jul-90 Gregg Kellogg (gk) at NeXT ! 38: * Don't allocate MSG_SIZE_MAX for in and out messages. Only allocate ! 39: * a minimal amount fo input message and use RCV_TOO_LARGE logic ! 40: * to allocate more. Output message is only allocated for servers ! 41: * and older style handlers. ! 42: * ! 43: * 23-May-90 Gregg kellogg (gk) at NeXT ! 44: * Changed to use thread_reply port instead of bootstrap port. ! 45: * Checks to see if it's running in the kernel_task and uses ! 46: * kernel_ipc_space accordingly. ! 47: * Terminates on shutdown, doesn't suspend. ! 48: * Doesn't depend on being in a separate task now. ! 49: * ! 50: * 06-Feb-89 Gregg Kellogg (gk) at NeXT ! 51: * Created. ! 52: * ! 53: */ ! 54: ! 55: /* ! 56: * Generic Kernel Server for loaded server tasks. ! 57: * ! 58: * This code is run by dynamically loaded Mach kernel servers. It recieves ! 59: * instructions from it's boot port server to set up it's local environment ! 60: * and enter the server loop to do per-server processing. ! 61: * ! 62: * The server basically exists to dispatch messages recieved on ports ! 63: * to procedures. Any un-handled messages are either thrown away or handled ! 64: * directly by the server. Handled messages are either acked, or not acked. ! 65: * If the return status is > 0, then any resources passed (other than ports) ! 66: * are deallocated from the message as well. ! 67: */ ! 68: ! 69: #import <mach/mig_errors.h> ! 70: #import <sys/callout.h> ! 71: #import <mach/notify.h> ! 72: #import <kern/kern_port.h> ! 73: #import <kern/sched_prim.h> ! 74: #import <mach/mach_traps.h> ! 75: #import <kern/kalloc.h> ! 76: #import <kernserv/kern_notify.h> ! 77: #import <mach/vm_param.h> ! 78: #import "kernobjc.h" ! 79: #import <kern/thread_call.h> ! 80: ! 81: #import <machine/spl.h> ! 82: ! 83: #import <kernserv/kern_server_handler.h> ! 84: #import <kernserv/kern_server_reply.h> ! 85: ! 86: #define panic(s) (curipl() == 0 ? kern_serv_panic(ksp->bootstrap_port, s) \ ! 87: : printf("can't panic: %s\n", s)) ! 88: ! 89: /* Now a per server static port_t kernel_port; */ ! 90: ! 91: /* ! 92: * Use internal version of thread_terminate. ! 93: */ ! 94: #undef thread_terminate ! 95: ! 96: /* ! 97: * Locally used functions ! 98: */ ! 99: static kern_return_t kern_serv_dispatch ( ! 100: msg_header_t *in_msg, ! 101: kern_server_t ksp); ! 102: ! 103: static void kern_serv_send_log(void *arg); ! 104: static void kern_serv_log_init ( // initialize server's log buffer ! 105: log_t *log, // uninitialized log struct ! 106: int num_entries); // size of log ! 107: ! 108: static void kern_serv_log_free (log_t *log); // deallocate log structure ! 109: static void kern_serv_interrupt_server(thread_t thread); ! 110: ! 111: const kern_serv_t kern_serv_proto = { ! 112: 0, // arg to be filled in ! 113: 0, // don't wait for message to be sent ! 114: kern_serv_instance_loc, ! 115: kern_serv_boot_port, ! 116: kern_serv_wire_range, ! 117: kern_serv_unwire_range, ! 118: kern_serv_port_proc, ! 119: kern_serv_port_death_proc, ! 120: kern_serv_call_proc, ! 121: kern_serv_shutdown, ! 122: kern_serv_log_level, ! 123: kern_serv_get_log, ! 124: kern_serv_port_serv, ! 125: kern_serv_version, ! 126: kern_serv_load_objc}; ! 127: ! 128: /* ! 129: * Prototypes for kernel functions not yet prototyped. ! 130: */ ! 131: int bcopy(void *to, void *from, int size); ! 132: int curipl(void); ! 133: kern_return_t vm_map_pageable( ! 134: vm_map_t map, ! 135: vm_offset_t start, ! 136: vm_offset_t end, ! 137: boolean_t new_pageable); ! 138: #if DEBUG ! 139: void xpr(char *msg, ...); ! 140: #endif DEBUG ! 141: ! 142: #if DEBUG ! 143: static boolean_t kserv_debug = TRUE; ! 144: #define ks_log(s) {if (kserv_debug) XPR(XPR_LDD, s); } ! 145: #define ks_log2(s) ks_log(s) ! 146: void kern_server_main1(void); ! 147: void kern_server_main2(void); ! 148: #else DEBUG ! 149: #define ks_log(s) ! 150: #define ks_log2(s) ! 151: #endif DEBUG ! 152: ! 153: /* ! 154: * Entry point to kernel server, set up task environment. ! 155: */ ! 156: void kern_server_main(void) ! 157: { ! 158: #if DEBUG ! 159: int foo[10]; ! 160: kern_server_main1(); ! 161: } ! 162: void kern_server_main1(void) ! 163: { ! 164: int foo[10]; ! 165: kern_server_main2(); ! 166: } ! 167: void kern_server_main2(void) ! 168: { ! 169: #endif DEBUG ! 170: kern_return_t r; ! 171: kern_server_t ksp = (kern_server_t)kalloc(sizeof *ksp); ! 172: port_t boot_listener_port; ! 173: port_t reply_port; ! 174: port_set_name_t port_set; ! 175: msg_header_t *in_msg; ! 176: int error; ! 177: register int i, s; ! 178: kern_serv_t kern_serv = kern_serv_proto; ! 179: ! 180: #if 0 ! 181: volatile int instr; ! 182: ! 183: /* ! 184: * Write to the loaded text so that the debugger can set break-points. ! 185: */ ! 186: instr = *(int *)&kern_server_main2; ! 187: *(int *)&kern_server_main2 = instr; ! 188: #endif 0 ! 189: ! 190: kern_serv.arg = (void *)&ksp; ! 191: ! 192: /* ! 193: * Find out who we are. ! 194: */ ! 195: ! 196: if (current_task() != kernel_task) { ! 197: current_task()->kernel_vm_space = TRUE; ! 198: } ! 199: ! 200: bzero((char *)ksp, sizeof(*ksp)); ! 201: ksp->version = -1; ! 202: ! 203: /* ! 204: * Our task port. ! 205: */ ! 206: ksp->task_port = task_self(); ! 207: ! 208: /* ! 209: * Our thread structure. ! 210: */ ! 211: ksp->server_thread = current_thread(); ! 212: simple_lock_init(&ksp->slock); ! 213: ! 214: /* ! 215: * Initialize message send queue. ! 216: */ ! 217: queue_init(&ksp->msg_callout_q); ! 218: queue_init(&ksp->msg_callout_fq); ! 219: queue_init(&ksp->notify_q); ! 220: for ( i = sizeof(ksp->msg_send_array)/sizeof(ksp->msg_send_array[0])-1 ! 221: ; i >= 0 ! 222: ; i--) ! 223: { ! 224: queue_enter(&ksp->msg_callout_fq, &ksp->msg_send_array[i], ! 225: struct msg_send_entry *, link); ! 226: } ! 227: ! 228: /* ! 229: * Use our thread_reply port as the bootstrap port. This is ! 230: * claimed by the kern_loader before we startup, so there's no ! 231: * race condition. ! 232: */ ! 233: r = thread_get_special_port(thread_self(), THREAD_REPLY_PORT, ! 234: &boot_listener_port); ! 235: if (r != KERN_SUCCESS || boot_listener_port == PORT_NULL) { ! 236: printf("k_server: can't find listener port..terminating\n"); ! 237: thread_terminate(current_thread()); ! 238: thread_halt_self(); ! 239: } ! 240: ksp->boot_listener_port = boot_listener_port; ! 241: ! 242: /* ! 243: * Allocate a new reply port. ! 244: */ ! 245: r = port_allocate(task_self(), &reply_port); ! 246: if (r != KERN_SUCCESS) { ! 247: printf("k_server: can't allocate reply port..terminating\n"); ! 248: thread_terminate(current_thread()); ! 249: thread_halt_self(); ! 250: } ! 251: ! 252: r = thread_set_special_port(thread_self(), THREAD_REPLY_PORT, ! 253: reply_port); ! 254: if (r != KERN_SUCCESS) { ! 255: printf("k_server: can't set reply port..terminating\n"); ! 256: thread_terminate(current_thread()); ! 257: thread_halt_self(); ! 258: } ! 259: ! 260: /* ! 261: * Forget the reply_port we were using so that it isn't ! 262: * cached anymore. ! 263: */ ! 264: ! 265: /* ! 266: * Allocate the basic set of ports we need for communication ! 267: * (notify port). ! 268: */ ! 269: r = port_set_allocate(task_self(), &port_set); ! 270: if (r != KERN_SUCCESS) { ! 271: printf("k_server: can't allocate port set..terminating\n"); ! 272: thread_terminate(current_thread()); ! 273: thread_halt_self(); ! 274: } ! 275: ksp->port_set = port_set; ! 276: ! 277: /* ! 278: * Add boot listener port to the port set. ! 279: */ ! 280: if ( port_set_add(task_self(), port_set, boot_listener_port) ! 281: != KERN_SUCCESS) ! 282: { ! 283: printf("k_server: can't add listener port\n"); ! 284: thread_terminate(current_thread()); ! 285: thread_halt_self(); ! 286: } ! 287: ! 288: /* ! 289: * Allocate and set up the notify port. ! 290: */ ! 291: r = port_allocate(ksp->task_port, &ksp->notify_port); ! 292: if (r == KERN_SUCCESS) ! 293: (void) port_set_add(ksp->task_port, ksp->port_set, ! 294: ksp->notify_port); ! 295: else ! 296: kern_serv_panic(ksp->bootstrap_port, ! 297: "k_server: can't get notify port"); ! 298: ! 299: if (current_task() != kernel_task) { ! 300: /* ! 301: * Set this port as our task's notify port. ! 302: */ ! 303: (void) task_set_special_port(task_self(), ! 304: TASK_NOTIFY_PORT, ksp->notify_port); ! 305: } ! 306: ! 307: kern_serv_notify(&ksp, ksp->notify_port, ksp->bootstrap_port); ! 308: ! 309: /* ! 310: * The kernel's task port. ! 311: */ ! 312: ksp->kernel_port = kern_serv_kernel_task_port(); ! 313: ! 314: /* ! 315: * Service loop... receive messages and process them. ! 316: */ ! 317: ! 318: in_msg = (msg_header_t *)kalloc(kern_servMaxRequestSize); ! 319: ksp->msg = in_msg; ! 320: ksp->msg_size = kern_servMaxRequestSize; ! 321: for (;;) { ! 322: /* ! 323: * Look for things to do that need to be done ! 324: * from this task/thread. ! 325: * Send messages. ! 326: */ ! 327: s = splhigh(); ! 328: simple_lock(&ksp->slock); ! 329: ! 330: while (!queue_empty(&ksp->msg_callout_q)) { ! 331: struct msg_send_entry *msep; ! 332: ! 333: queue_remove_first(&ksp->msg_callout_q, ! 334: msep, struct msg_send_entry *, link); ! 335: ! 336: simple_unlock(&ksp->slock); ! 337: splx(s); ! 338: ! 339: ks_log(("kern_server_main: qed callout func 0x%x\n", ! 340: msep->func)); ! 341: (*msep->func)(msep->arg); ! 342: ! 343: s = splhigh(); ! 344: simple_lock(&ksp->slock); ! 345: ! 346: queue_enter(&ksp->msg_callout_fq, msep, ! 347: struct msg_send_entry *, link); ! 348: } ! 349: ! 350: simple_unlock(&ksp->slock); ! 351: splx(s); ! 352: ! 353: /* ! 354: * Wait for the next request. ! 355: */ ! 356: receive: ! 357: in_msg->msg_local_port = port_set; ! 358: in_msg->msg_size = ksp->msg_size; ! 359: r = msg_receive(in_msg, RCV_TIMEOUT|RCV_INTERRUPT|RCV_LARGE, ! 360: 1000); ! 361: ! 362: /* ! 363: * If our receive was interrupted, go back to it. ! 364: */ ! 365: switch (r) { ! 366: case RCV_INTERRUPTED: ! 367: break; ! 368: case RCV_TIMED_OUT: ! 369: continue; ! 370: case RCV_TOO_LARGE: ! 371: { ! 372: vm_size_t new_msg_size = ksp->msg->msg_size; ! 373: /* ! 374: * We need to allocate a larger message to return. ! 375: */ ! 376: kfree(ksp->msg, ksp->msg_size); ! 377: ksp->msg_size = new_msg_size; ! 378: ksp->msg = (void *)kalloc(ksp->msg_size); ! 379: in_msg = ksp->msg; ! 380: goto receive; ! 381: } ! 382: ! 383: case KERN_SUCCESS: ! 384: break; ! 385: default: ! 386: kern_serv_panic(ksp->bootstrap_port, ! 387: "kern_server_main: received return bad return" ! 388: " from msg_receive"); ! 389: break; ! 390: } ! 391: ! 392: ks_log(("kern_server_main: received msgid %d " ! 393: "on port %d\n", in_msg->msg_id, ! 394: in_msg->msg_local_port)); ! 395: ! 396: /* ! 397: * Dispatch the message based on it's port. ! 398: */ ! 399: if (in_msg->msg_local_port == ksp->notify_port) { ! 400: notification_t *n = (notification_t *) in_msg; ! 401: switch(in_msg->msg_id) { ! 402: case NOTIFY_PORT_DELETED: ! 403: /* ! 404: * Give loaded code a chance to handle it ! 405: */ ! 406: if (ksp->pd_proc) { ! 407: if ((*ksp->pd_proc)(n->notify_port)) ! 408: break; ! 409: } else if (ksp->pn_proc) ! 410: (*ksp->pn_proc)(n->notify_port, ! 411: in_msg->msg_id); ! 412: kern_serv_port_gone(&ksp, n->notify_port); ! 413: break; ! 414: default: ! 415: if (ksp->pn_proc) ! 416: (*ksp->pn_proc)(n->notify_port, ! 417: in_msg->msg_id); ! 418: break; ! 419: } ! 420: continue; ! 421: } else if ( in_msg->msg_id >= NOTIFY_FIRST ! 422: && in_msg->msg_id < NOTIFY_LAST) ! 423: { ! 424: notification_t *n = (notification_t *) in_msg; ! 425: ks_notify_t *np; ! 426: ! 427: /* ! 428: * If we have a notify request on this port, forward ! 429: * the message to the requested port. ! 430: */ ! 431: for ( np = (ks_notify_t *)queue_first(&ksp->notify_q) ! 432: ; !queue_end(&ksp->notify_q, (queue_entry_t)np) ! 433: ; np = (ks_notify_t *)queue_next(&np->link)) ! 434: if (np->req_port == n->notify_port) { ! 435: in_msg->msg_remote_port = ! 436: np->reply_port; ! 437: ks_log2(("kern_server_main: " ! 438: "forwarding notification " ! 439: "request to port %d\n", ! 440: np->reply_port)); ! 441: msg_send(in_msg, MSG_OPTION_NONE, 0); ! 442: queue_remove(&ksp->notify_q, np, ! 443: ks_notify_t *, link); ! 444: kfree(np, sizeof(*np)); ! 445: continue; ! 446: } ! 447: } ! 448: ! 449: ksp->local_port = in_msg->msg_local_port; ! 450: ! 451: error = kern_serv_dispatch(in_msg, ksp); ! 452: ks_log2(("kern_server_main: return from ks_disp %d\n", ! 453: error)); ! 454: ! 455: if ( error == MIG_BAD_ID ! 456: && in_msg->msg_local_port == boot_listener_port) ! 457: { ! 458: error = kern_serv_handler(in_msg, &kern_serv); ! 459: ks_log2(("kern_server_main: " ! 460: "return from ks_server %d\n", ! 461: error)); ! 462: } ! 463: } ! 464: } ! 465: ! 466: typedef struct { ! 467: msg_header_t Head; ! 468: msg_type_t RetCodeType; ! 469: kern_return_t RetCode; ! 470: } Reply; ! 471: ! 472: static kern_return_t kern_serv_port_proc_call ( ! 473: msg_header_t *in_msg, ! 474: port_proc_map_t *pp) ! 475: { ! 476: Reply *out_msg; ! 477: kern_return_t ret_code; ! 478: port_t local_port; ! 479: ! 480: if (pp->type == PP_handler) ! 481: return (*pp->proc)(in_msg, pp->uarg); ! 482: ! 483: out_msg = (Reply *)kalloc(MSG_SIZE_MAX); ! 484: local_port = in_msg->msg_local_port; ! 485: in_msg->msg_local_port = (port_t)pp->uarg; ! 486: ! 487: (*((port_map_serv_t)pp->proc))(in_msg, (msg_header_t *)out_msg); ! 488: ret_code = out_msg->RetCode; ! 489: ! 490: if (out_msg->RetCode == MIG_NO_REPLY) ! 491: ret_code = KERN_SUCCESS; ! 492: else ! 493: ret_code = msg_send(&out_msg->Head, MSG_OPTION_NONE, 0); ! 494: ! 495: kfree(out_msg, MSG_SIZE_MAX); ! 496: ! 497: return ret_code; ! 498: } ! 499: ! 500: #define RCV_IN_PROGRESS RCV_ERRORS_START ! 501: /* ! 502: * Call a proc indirectly based on the port. ! 503: */ ! 504: static kern_return_t kern_serv_dispatch ( ! 505: msg_header_t *in_msg, ! 506: kern_server_t ksp) ! 507: { ! 508: int i = ksp->last_rec_index; ! 509: kern_return_t r = RCV_IN_PROGRESS; ! 510: ! 511: if (!ksp) ! 512: return MIG_BAD_ID; ! 513: ! 514: if (in_msg->msg_local_port == ksp->last_unrec_port) { ! 515: ks_log2(("kern_serv_dispatch: port %d was unrec\n", ! 516: in_msg->msg_local_port)); ! 517: r = MIG_BAD_ID; ! 518: } else if (in_msg->msg_local_port == ksp->last_rec_port) { ! 519: ks_log2(("kern_serv_dispatch: port %d was rec(%d), " ! 520: "proc 0x%x(%d)\n", ! 521: in_msg->msg_local_port, i, ksp->port_proc[i].proc, ! 522: ksp->port_proc[i].uarg)); ! 523: r = kern_serv_port_proc_call(in_msg, &ksp->port_proc[i]); ! 524: } else { ! 525: for ( i = 0 ! 526: ; i < KERN_SERVER_NPORTPROC ! 527: && ksp->port_proc[i].port != in_msg->msg_local_port ! 528: ; i++) ! 529: ; ! 530: ! 531: if (i != KERN_SERVER_NPORTPROC) { ! 532: ksp->last_rec_port = in_msg->msg_local_port; ! 533: ksp->last_rec_index = i; ! 534: ks_log2(("kern_serv_dispatch: port %d now rec(%d), " ! 535: "proc 0x%x(%d)\n", ! 536: in_msg->msg_local_port, i, ! 537: ksp->port_proc[i].proc, ! 538: ksp->port_proc[i].uarg)); ! 539: r = kern_serv_port_proc_call(in_msg, ! 540: &ksp->port_proc[i]); ! 541: } ! 542: } ! 543: ! 544: if (r == RCV_IN_PROGRESS) { ! 545: ks_log2(("kern_serv_dispatch: port %d now unrec\n", ! 546: in_msg->msg_local_port)); ! 547: ksp->last_unrec_port = in_msg->msg_local_port; ! 548: r = MIG_BAD_ID; ! 549: } ! 550: ! 551: return r; ! 552: } ! 553: ! 554: /* ! 555: * Got notification that port we have send rights on has gone away, clean up. ! 556: */ ! 557: void kern_serv_port_gone ( ! 558: kern_server_t *kspp, ! 559: port_name_t port) ! 560: { ! 561: kern_server_t ksp = *kspp; ! 562: register int i; ! 563: ! 564: if (ksp == 0) ! 565: return; ! 566: ! 567: if (ksp->last_rec_port == port) ! 568: ksp->last_rec_port = PORT_NULL; ! 569: ! 570: /* ! 571: * If this is the log port, don't try to send anything to it. ! 572: */ ! 573: if (ksp->log_port && port == ksp->log_port) ! 574: ksp->log_port == PORT_NULL; ! 575: ! 576: /* ! 577: * Free up port/proc pairs ! 578: */ ! 579: for (i = 0; i < KERN_SERVER_NPORTPROC; i++) ! 580: if (ksp->port_proc[i].port == port) { ! 581: ksp->port_proc[i].port = PORT_NULL; ! 582: ksp->port_proc[i].proc = 0; ! 583: break; ! 584: } ! 585: return; ! 586: } ! 587: ! 588: kern_return_t kern_serv_instance_loc ( ! 589: void *arg, ! 590: vm_address_t instance_loc) ! 591: { ! 592: kern_server_t ksp = *((kern_server_t *)arg); ! 593: kern_server_t *kspp = (kern_server_t *)instance_loc; ! 594: ! 595: ks_log(("kern_serv_instance_loc: 0x%x\n", instance_loc)); ! 596: *kspp = ksp; ! 597: ! 598: return KERN_SUCCESS; ! 599: } ! 600: ! 601: /* ! 602: * Specify user's version of system user compiled with. ! 603: */ ! 604: kern_return_t kern_serv_version ( ! 605: void *arg, ! 606: int version) ! 607: { ! 608: kern_server_t ksp = *((kern_server_t *)arg); ! 609: ! 610: if (version < KS_COMPAT) ! 611: return KERN_SERVER_BAD_VERSION; ! 612: ksp->version = version; ! 613: ! 614: return KERN_SUCCESS; ! 615: } ! 616: kern_return_t kern_serv_load_objc( ! 617: void *arg, ! 618: vm_address_t header) ! 619: { ! 620: kern_server_t ksp = *((kern_server_t *)arg); ! 621: int error; ! 622: ! 623: #if KERNOBJC ! 624: ksp->mach_header = (struct mach_header *) header; ! 625: error = objc_registerModule (ksp->mach_header, 0); ! 626: #endif KERNOBJC ! 627: return KERN_SUCCESS; ! 628: } ! 629: ! 630: ! 631: kern_return_t kern_serv_boot_port ( // how to talk to loader ! 632: void *arg, ! 633: port_t boot_port) ! 634: { ! 635: kern_server_t ksp = *((kern_server_t *)arg); ! 636: ! 637: ksp->bootstrap_port = boot_port; ! 638: return KERN_SUCCESS; ! 639: } ! 640: ! 641: /* ! 642: * Kernel version of kern_serv_notify, doesn't contact kern_loader, uses ! 643: * internal port_request_notification facility. ! 644: */ ! 645: kern_return_t kern_serv_notify ( ! 646: kern_server_t *kspp, ! 647: port_t reply_port, ! 648: port_t req_port) ! 649: { ! 650: kern_server_t ksp; ! 651: port_t bootstrap_port; ! 652: kern_return_t r; ! 653: kern_port_t rp, np; ! 654: ! 655: ksp = *kspp; ! 656: bootstrap_port = ksp->bootstrap_port; ! 657: ! 658: if (current_task() != kernel_task) { ! 659: ks_notify_t *np; ! 660: ! 661: if (reply_port == ksp->notify_port) ! 662: /* ! 663: * Notification will happen automatically. ! 664: */ ! 665: return KERN_SUCCESS; ! 666: ! 667: /* ! 668: * Make sure that an entry doesn't already exist for this ! 669: * pair. ! 670: */ ! 671: for ( np = (ks_notify_t *)queue_first(&ksp->notify_q) ! 672: ; !queue_end(&ksp->notify_q, (queue_entry_t)np) ! 673: ; np = (ks_notify_t *)queue_next(&np->link)) ! 674: if ( np->reply_port == reply_port ! 675: && np->req_port == req_port) ! 676: return KERN_FAILURE; ! 677: ! 678: np = (kern_port_t)kalloc(sizeof *np); ! 679: np->reply_port = reply_port; ! 680: np->req_port = req_port; ! 681: queue_enter(&ksp->notify_q, np, ks_notify_t *, link); ! 682: ! 683: /* ! 684: * Notification will be forwarded from kern_server. ! 685: */ ! 686: return KERN_SUCCESS; ! 687: } ! 688: ! 689: r = get_kern_port(current_task(), req_port, &rp); ! 690: if (r != KERN_SUCCESS) ! 691: return r; ! 692: r = get_kern_port(current_task(), reply_port, &np); ! 693: if (r != KERN_SUCCESS) ! 694: return r; ! 695: port_request_notification(rp, np); ! 696: return KERN_SUCCESS; ! 697: } ! 698: ! 699: kern_return_t kern_serv_wire_range ( // wire the specified range or memory ! 700: void *arg, ! 701: vm_address_t addr, ! 702: vm_size_t size) ! 703: { ! 704: kern_server_t ksp = *((kern_server_t *)arg); ! 705: ! 706: ks_log(("kern_serv_wire_range: addr 0x%x for 0x%x bytes\n", ! 707: addr, size)); ! 708: #if DIAGNOSTIC ! 709: printf("kern_server: wiring 0x%x to 0x%x\n", trunc_page(addr), ! 710: round_page(addr+size)); ! 711: #endif ! 712: return vm_map_pageable(kernel_task->map, trunc_page(addr), ! 713: round_page(addr+size), FALSE); ! 714: } ! 715: ! 716: kern_return_t kern_serv_unwire_range ( // unwire the specified range or memory ! 717: void *arg, ! 718: vm_address_t addr, ! 719: vm_size_t size) ! 720: { ! 721: kern_server_t ksp = *((kern_server_t *)arg); ! 722: ! 723: ks_log(("kern_serv_unwire_range: addr 0x%x for 0x%x bytes\n", ! 724: addr, size)); ! 725: #if DIAGNOSTIC ! 726: printf("kern_server: unwiring 0x%x to 0x%x\n", trunc_page(addr), ! 727: round_page(addr+size)); ! 728: #endif ! 729: return vm_map_pageable(kernel_task->map, trunc_page(addr), ! 730: round_page(addr+size), TRUE); ! 731: } ! 732: ! 733: /* ! 734: * Map messages coming on on the specified port to call the specified proc. ! 735: * If this mapping can't be made FALSE is returned. ! 736: * The port is added to the portset for this server. ! 737: */ ! 738: kern_return_t kern_serv_port_proc ( // map a message on port to proc/arg ! 739: void *arg, // record into structure ! 740: port_all_t port, // port to map (all rights passed) ! 741: port_map_proc_t proc, // proc to call ! 742: int uarg) // replace local_port with uarg ! 743: { ! 744: register int i; ! 745: kern_return_t r; ! 746: kern_server_t ksp = *((kern_server_t *)arg); ! 747: ! 748: ks_log(("kern_serv_port_proc: port %d proc 0x%x uarg %d\n", ! 749: port, proc, uarg)); ! 750: ! 751: if (ksp->last_unrec_port == port) ! 752: ksp->last_unrec_port = PORT_NULL; ! 753: ! 754: for (i = 0; i < KERN_SERVER_NPORTPROC; i++) ! 755: if (ksp->port_proc[i].port == port) ! 756: ksp->port_proc[i].port = PORT_NULL; ! 757: ! 758: for (i = 0; i < KERN_SERVER_NPORTPROC; i++) ! 759: if (ksp->port_proc[i].port == PORT_NULL) ! 760: break; ! 761: ! 762: r = KERN_RESOURCE_SHORTAGE; ! 763: if ( i == KERN_SERVER_NPORTPROC ! 764: || (r = port_set_add(ksp->task_port, ksp->port_set, port)) ! 765: != KERN_SUCCESS) ! 766: return r; ! 767: ! 768: ksp->port_proc[i].port = port; ! 769: ksp->port_proc[i].proc = proc; ! 770: ksp->port_proc[i].uarg = (void *)uarg; ! 771: ksp->port_proc[i].type = PP_handler; ! 772: ! 773: return KERN_SUCCESS; ! 774: } ! 775: ! 776: /* ! 777: * Map messages coming on on the specified port to call the specified proc. ! 778: * If this mapping can't be made FALSE is returned. ! 779: * The port is added to the portset for this server. ! 780: */ ! 781: kern_return_t kern_serv_port_serv ( // map a message on port to proc/arg ! 782: void *arg, // record into structure ! 783: port_all_t port, // port to map (all rights passed) ! 784: port_map_proc_t proc, // proc to call ! 785: int uarg) // replace local_port with uarg ! 786: { ! 787: register int i; ! 788: kern_return_t r; ! 789: kern_server_t ksp = *((kern_server_t *)arg); ! 790: ! 791: ks_log(("kern_serv_port_serv: port %d proc 0x%x uarg %d\n", ! 792: port, proc, uarg)); ! 793: ! 794: if (ksp->last_unrec_port == port) ! 795: ksp->last_unrec_port = PORT_NULL; ! 796: ! 797: for (i = 0; i < KERN_SERVER_NPORTPROC; i++) ! 798: if (ksp->port_proc[i].port == port) ! 799: ksp->port_proc[i].port = PORT_NULL; ! 800: ! 801: for (i = 0; i < KERN_SERVER_NPORTPROC; i++) ! 802: if (ksp->port_proc[i].port == PORT_NULL) ! 803: break; ! 804: ! 805: r = KERN_RESOURCE_SHORTAGE; ! 806: if ( i == KERN_SERVER_NPORTPROC ! 807: || (r = port_set_add(ksp->task_port, ksp->port_set, port)) ! 808: != KERN_SUCCESS) ! 809: return r; ! 810: ! 811: ksp->port_proc[i].port = port; ! 812: ksp->port_proc[i].proc = proc; ! 813: ksp->port_proc[i].uarg = (void *)uarg; ! 814: ksp->port_proc[i].type = PP_server; ! 815: ! 816: return KERN_SUCCESS; ! 817: } ! 818: ! 819: kern_return_t kern_serv_port_death_proc ( // specify port death handler ! 820: void *arg, // record into structure ! 821: port_death_proc_t proc) // record into structure ! 822: { ! 823: kern_server_t ksp = *((kern_server_t *)arg); ! 824: ! 825: ksp->pd_proc = proc; ! 826: return KERN_SUCCESS; ! 827: } ! 828: ! 829: kern_return_t kern_serv_call_proc ( // call procedure with argument ! 830: void *arg, // record into structure ! 831: call_proc_t proc, // record into structure ! 832: int uarg) // arg to supply ! 833: { ! 834: kern_server_t ksp = *((kern_server_t *)arg); ! 835: ! 836: ks_log(("kern_serv_call_proc: proc 0x%x uarg %d\n", ! 837: proc, uarg)); ! 838: ! 839: if (proc) { ! 840: (*proc)(uarg); ! 841: return KERN_SUCCESS; ! 842: } ! 843: return KERN_SERVER_ERROR; ! 844: } ! 845: ! 846: kern_return_t kern_serv_shutdown ( ! 847: void *arg) ! 848: { ! 849: kern_server_t ksp = *((kern_server_t *)arg); ! 850: int i; ! 851: ! 852: ks_log(("kern_serv_shutdown\n")); ! 853: ! 854: #if KERNOBJC ! 855: /* ! 856: * Detach from Objective-C runtime. ! 857: */ ! 858: if (ksp->mach_header) ! 859: objc_unregisterModule (ksp->mach_header, 0); ! 860: #endif KERNOBJC ! 861: ! 862: /* ! 863: * Stop logging and free the data ! 864: * if we were logging. ! 865: */ ! 866: if (ksp->log.level) { ! 867: kern_serv_log_free(&ksp->log); ! 868: ksp->log.level = 0; ! 869: } ! 870: ! 871: /* ! 872: * Deallocate all the port mappings we have. ! 873: */ ! 874: for (i = 0; i < KERN_SERVER_NPORTPROC; i++) ! 875: if (ksp->port_proc[i].port != PORT_NULL) { ! 876: port_deallocate(ksp->task_port, ! 877: ksp->port_proc[i].port); ! 878: ksp->port_proc[i].port = PORT_NULL; ! 879: ksp->port_proc[i].proc = 0; ! 880: } ! 881: ! 882: /* ! 883: * Deallocate our boot_listener and notify ports. ! 884: */ ! 885: port_deallocate(ksp->task_port, ksp->boot_listener_port); ! 886: port_deallocate(ksp->task_port, ksp->notify_port); ! 887: ! 888: /* ! 889: * Deallocate our port_set ! 890: */ ! 891: port_set_deallocate(ksp->task_port, ksp->port_set); ! 892: ! 893: /* ! 894: * Deallocate our message frame. ! 895: */ ! 896: kfree(ksp->msg, ksp->msg_size); ! 897: kfree(ksp, sizeof *ksp); ! 898: thread_terminate(current_thread()); ! 899: while (1) ! 900: /* ! 901: * Wait to be killed. ! 902: */ ! 903: thread_halt_self(); ! 904: ! 905: return KERN_SUCCESS; ! 906: } ! 907: ! 908: // log level from message on port ! 909: kern_return_t kern_serv_log_level ( ! 910: void *arg, ! 911: int log_level) ! 912: { ! 913: kern_server_t ksp = *((kern_server_t *)arg); ! 914: int old_level = ksp->log.level; ! 915: ! 916: ksp->log.level = log_level; ! 917: ! 918: /* ! 919: * Only keep space around for the log ! 920: * if we need it. ! 921: */ ! 922: if (old_level == 0 && ksp->log.level) ! 923: kern_serv_log_init(&ksp->log, ! 924: KERN_SERVER_LOG_SIZE); ! 925: else if (ksp->log.level == 0 && old_level) ! 926: kern_serv_log_free(&ksp->log); ! 927: ! 928: return KERN_SUCCESS; ! 929: } ! 930: ! 931: kern_return_t kern_serv_get_log ( ! 932: void *arg, ! 933: port_t reply_port) // port to send log information to ! 934: { ! 935: int s, n; ! 936: kern_server_t ksp = *((kern_server_t *)arg); ! 937: ! 938: if (ksp->log.level == 0) { ! 939: port_deallocate(ksp->task_port, reply_port); ! 940: return KERN_SERVER_NOTLOGGING; ! 941: } ! 942: ! 943: if (ksp->log.ptr == ksp->log.base) { ! 944: ksp->log_port = reply_port; ! 945: return KERN_SUCCESS; ! 946: } else { ! 947: vm_size_t size = ! 948: round_page((char *)ksp->log.ptr - (char *)ksp->log.base); ! 949: pointer_t ldata; ! 950: unsigned int ldata_count; ! 951: kern_return_t r; ! 952: ! 953: ASSERT( (void *)ksp->log.base ! 954: == (void *)round_page(ksp->log.base)); ! 955: r = vm_read(ksp->kernel_port, ! 956: (vm_address_t)ksp->log.base, size, &ldata, ! 957: &ldata_count); ! 958: ASSERT(r == KERN_SUCCESS); ! 959: kern_serv_log_data(reply_port, ! 960: (log_entry_t *)ldata, ! 961: ksp->log.ptr - ksp->log.base); ! 962: ! 963: port_deallocate(ksp->task_port, reply_port); ! 964: vm_deallocate(ksp->task_port, ldata, size); ! 965: } ! 966: ! 967: s = splhigh(); ! 968: simple_lock(&ksp->slock); ! 969: ksp->log.ptr = ksp->log.base; ! 970: simple_unlock(&ksp->slock); ! 971: splx(s); ! 972: ! 973: return KERN_SUCCESS; ! 974: } ! 975: ! 976: void kern_serv_log ( // log a message ! 977: kern_server_t *kspp, // kern_server instance vars ! 978: int log_level, // level to log at ! 979: char *msg, // what to log (followed by args) ! 980: int arg1, ! 981: int arg2, ! 982: int arg3, ! 983: int arg4, ! 984: int arg5) ! 985: { ! 986: kern_server_t ksp = *kspp; ! 987: register int s; ! 988: log_entry_t *x; ! 989: ! 990: if (log_level > ksp->log.level || ksp->log.base == 0) ! 991: return; ! 992: ! 993: s = splhigh(); ! 994: simple_lock(&ksp->slock); ! 995: ! 996: x = ksp->log.ptr++; ! 997: if (ksp->log.ptr == ksp->log.last) { ! 998: ksp->log.ptr--; ! 999: simple_unlock(&ksp->slock); ! 1000: splx(s); ! 1001: return; ! 1002: } ! 1003: simple_unlock(&ksp->slock); ! 1004: splx(s); ! 1005: ! 1006: x->msg = msg; ! 1007: x->arg1 = arg1; ! 1008: x->arg2 = arg2; ! 1009: x->arg3 = arg3; ! 1010: x->arg4 = arg4; ! 1011: x->arg5 = arg5; ! 1012: x->timestamp = XPR_TIMESTAMP; ! 1013: x->cpuinfo = log_level; ! 1014: ! 1015: if (ksp->log_port) ! 1016: kern_serv_callout(kspp, kern_serv_send_log, (void *)ksp); ! 1017: } ! 1018: ! 1019: /* ! 1020: * Send the log back to the user. Have to copy the log into our address ! 1021: * space. ! 1022: */ ! 1023: static void kern_serv_send_log(void *arg) ! 1024: { ! 1025: kern_server_t ksp = (kern_server_t)arg; ! 1026: port_name_t log_port; ! 1027: int s; ! 1028: vm_size_t size = ! 1029: round_page((char *)ksp->log.ptr - (char *)ksp->log.base); ! 1030: pointer_t ldata; ! 1031: unsigned int ldata_count; ! 1032: kern_return_t r; ! 1033: ! 1034: s = splhigh(); ! 1035: simple_lock(&ksp->slock); ! 1036: ! 1037: log_port = ksp->log_port; ! 1038: ksp->log_port = PORT_NULL; ! 1039: ! 1040: simple_unlock(&ksp->slock); ! 1041: splx(s); ! 1042: if (log_port == PORT_NULL) ! 1043: return; ! 1044: ! 1045: ASSERT((void *)ksp->log.base == (void *)round_page(ksp->log.base)); ! 1046: r = vm_read(ksp->kernel_port, (vm_address_t)ksp->log.base, ! 1047: size, &ldata, &ldata_count); ! 1048: ASSERT(r == KERN_SUCCESS); ! 1049: kern_serv_log_data(log_port, (log_entry_t *)ldata, ! 1050: ksp->log.ptr - ksp->log.base); ! 1051: ! 1052: port_deallocate(ksp->task_port, log_port); ! 1053: vm_deallocate(ksp->task_port, ldata, size); ! 1054: ! 1055: s = splhigh(); ! 1056: simple_lock(&ksp->slock); ! 1057: ! 1058: ksp->log.ptr = ksp->log.base; ! 1059: ! 1060: simple_unlock(&ksp->slock); ! 1061: splx(s); ! 1062: ! 1063: } ! 1064: ! 1065: /* ! 1066: * Ensure that the number of entries is rounded up to a page boundary. ! 1067: */ ! 1068: static void kern_serv_log_init ( // initialize server's log buffer ! 1069: log_t *log, // uninitialized log struct ! 1070: int num_entries) // size of log ! 1071: { ! 1072: vm_size_t size = round_page(sizeof(log_entry_t)*num_entries); ! 1073: num_entries = size / sizeof(log_entry_t); ! 1074: ! 1075: log->base = (log_entry_t *)kalloc(size); ! 1076: ! 1077: log->last = log->base + num_entries; ! 1078: log->ptr = log->base; ! 1079: #if DIAGNOSTIC ! 1080: printf("kern_serv_log_init: log 0x%x log.last 0x%x, log.base 0x%x\n", ! 1081: log, log->last, log->base); ! 1082: #endif ! 1083: } ! 1084: ! 1085: static void kern_serv_log_free (log_t *log) // deallocate log structure ! 1086: { ! 1087: kfree(log->base, round_page((char *)log->last - (char *)log->base)); ! 1088: log->base = log->last = log->ptr = 0; ! 1089: } ! 1090: ! 1091: kern_return_t kern_serv_callout ( ! 1092: kern_server_t *kspp, ! 1093: void (*proc)(void *arg), ! 1094: void * arg) ! 1095: { ! 1096: kern_server_t ksp = *kspp; ! 1097: struct msg_send_entry *msep; ! 1098: int s; ! 1099: ! 1100: /* ! 1101: * Just call this guy directly if the conditions are right. ! 1102: */ ! 1103: if ( ! 1104: curipl() == 0 ! 1105: && task_self() == ksp->task_port) { ! 1106: (*proc)(arg); ! 1107: return KERN_SUCCESS; ! 1108: } ! 1109: ! 1110: s = splhigh(); ! 1111: simple_lock(&ksp->slock); ! 1112: ! 1113: if (queue_empty(&ksp->msg_callout_fq)) { ! 1114: #if DIAGNOSTIC ! 1115: printf("kern_serv_callout: no free messages"); ! 1116: #endif ! 1117: simple_unlock(&ksp->slock); ! 1118: splx(s); ! 1119: return KERN_RESOURCE_SHORTAGE; ! 1120: } ! 1121: ! 1122: queue_remove_first(&ksp->msg_callout_fq, msep, struct msg_send_entry *, ! 1123: link); ! 1124: ks_log(("kern_serv_send: (queue) proc 0x%x\n", proc)); ! 1125: ! 1126: msep->func = proc; ! 1127: msep->arg = arg; ! 1128: queue_enter(&ksp->msg_callout_q, msep, struct msg_send_entry *, link); ! 1129: ! 1130: simple_unlock(&ksp->slock); ! 1131: splx(s); ! 1132: ! 1133: /* ! 1134: * Interrupt the server thread to that it'll look at this sucker. ! 1135: */ ! 1136: thread_call_func( ! 1137: (thread_call_func_t)kern_serv_interrupt_server, ! 1138: (thread_call_spec_t)ksp->server_thread, TRUE); ! 1139: ! 1140: return KERN_SUCCESS; ! 1141: } ! 1142: ! 1143: static void kern_serv_interrupt_server(thread_t thread) ! 1144: { ! 1145: /* ! 1146: * Sending the guy a message sounds like the best way to ensure ! 1147: * that he see's that there's something to do. ! 1148: */ ! 1149: send_notification(thread->task, NOTIFY_MSG_ACCEPTED, PORT_NULL); ! 1150: } ! 1151: ! 1152: /* ! 1153: * Structure access functions. ! 1154: */ ! 1155: port_t kern_serv_local_port(kern_server_t *ksp) ! 1156: { ! 1157: return (*ksp)->local_port; ! 1158: } ! 1159: ! 1160: port_t kern_serv_bootstrap_port(kern_server_t *ksp) ! 1161: { ! 1162: return (*ksp)->bootstrap_port; ! 1163: } ! 1164: ! 1165: port_t kern_serv_notify_port(kern_server_t *ksp) ! 1166: { ! 1167: return (*ksp)->notify_port; ! 1168: } ! 1169: ! 1170: port_set_name_t kern_serv_port_set(kern_server_t *ksp) ! 1171: { ! 1172: return (*ksp)->port_set; ! 1173: } ! 1174: ! 1175: /* Get the kernel task port. */ ! 1176: port_t kern_serv_kernel_task_port(void) ! 1177: { ! 1178: extern task_t kernel_task; // global kernel variable. ! 1179: port_t my_kernel_port; ! 1180: ! 1181: task_reference(kernel_task); ! 1182: my_kernel_port = convert_task_to_port(kernel_task); ! 1183: if (my_kernel_port == PORT_NULL) ! 1184: return PORT_NULL; ! 1185: ! 1186: object_copyout(current_task(), my_kernel_port, MSG_TYPE_PORT, ! 1187: &my_kernel_port); ! 1188: return my_kernel_port; ! 1189: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.