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