aboutsummaryrefslogtreecommitdiff
path: root/kern/ipc_kobject.c
diff options
context:
space:
mode:
authorPasha <pasha@member.fsf.org>2024-02-20 18:49:50 +0000
committerPasha <pasha@member.fsf.org>2024-02-20 18:49:50 +0000
commit5e0b8d508ed51004bd836384293be00950ee62c9 (patch)
treee3f16b1aa8b7177032ce3ec429fbad2b1d92a876 /kern/ipc_kobject.c
downloadgnumach-riscv-5e0b8d508ed51004bd836384293be00950ee62c9.tar.gz
gnumach-riscv-5e0b8d508ed51004bd836384293be00950ee62c9.tar.bz2
init gnumach copy
Diffstat (limited to 'kern/ipc_kobject.c')
-rw-r--r--kern/ipc_kobject.c365
1 files changed, 365 insertions, 0 deletions
diff --git a/kern/ipc_kobject.c b/kern/ipc_kobject.c
new file mode 100644
index 0000000..0a81595
--- /dev/null
+++ b/kern/ipc_kobject.c
@@ -0,0 +1,365 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ */
+/*
+ * File: kern/ipc_kobject.c
+ * Author: Rich Draves
+ * Date: 1989
+ *
+ * Functions for letting a port represent a kernel object.
+ */
+
+#include <kern/debug.h>
+#include <kern/printf.h>
+#include <mach/port.h>
+#include <mach/kern_return.h>
+#include <mach/message.h>
+#include <mach/mig_errors.h>
+#include <mach/notify.h>
+#include <kern/ipc_kobject.h>
+#include <ipc/ipc_object.h>
+#include <ipc/ipc_kmsg.h>
+#include <ipc/ipc_port.h>
+#include <ipc/ipc_thread.h>
+#include <vm/vm_object.h>
+#include <vm/memory_object_proxy.h>
+#include <device/ds_routines.h>
+
+#include <kern/mach.server.h>
+#include <ipc/mach_port.server.h>
+#include <kern/mach_host.server.h>
+#include <device/device.server.h>
+#include <device/device_pager.server.h>
+#include <kern/mach4.server.h>
+#include <kern/gnumach.server.h>
+#include <kern/experimental.server.h>
+
+#if MACH_DEBUG
+#include <kern/mach_debug.server.h>
+#endif
+
+#if MACH_MACHINE_ROUTINES
+#include <machine/machine_routines.h>
+#include MACHINE_SERVER_HEADER
+#endif
+
+
+/*
+ * Routine: ipc_kobject_server
+ * Purpose:
+ * Handle a message sent to the kernel.
+ * Generates a reply message.
+ * Conditions:
+ * Nothing locked.
+ */
+
+ipc_kmsg_t
+ipc_kobject_server(ipc_kmsg_t request)
+{
+ mach_msg_size_t reply_size = ikm_less_overhead(8192);
+ ipc_kmsg_t reply;
+ kern_return_t kr;
+ mig_routine_t routine;
+ ipc_port_t *destp;
+
+ reply = ikm_alloc(reply_size);
+ if (reply == IKM_NULL) {
+ printf("ipc_kobject_server: dropping request\n");
+ ipc_kmsg_destroy(request);
+ return IKM_NULL;
+ }
+ ikm_init(reply, reply_size);
+
+ /*
+ * Initialize reply message.
+ */
+ {
+#define InP ((mach_msg_header_t *) &request->ikm_header)
+#define OutP ((mig_reply_header_t *) &reply->ikm_header)
+
+ static const mach_msg_type_t RetCodeType = {
+ .msgt_name = MACH_MSG_TYPE_INTEGER_32,
+ .msgt_size = 32,
+ .msgt_number = 1,
+ .msgt_inline = TRUE,
+ .msgt_longform = FALSE,
+ .msgt_deallocate = FALSE,
+ .msgt_unused = 0
+ };
+ OutP->Head.msgh_bits =
+ MACH_MSGH_BITS(MACH_MSGH_BITS_LOCAL(InP->msgh_bits), 0);
+ OutP->Head.msgh_size = sizeof(mig_reply_header_t);
+ OutP->Head.msgh_remote_port = InP->msgh_local_port;
+ OutP->Head.msgh_local_port = MACH_PORT_NULL;
+ OutP->Head.msgh_seqno = 0;
+ OutP->Head.msgh_id = InP->msgh_id + 100;
+#if 0
+ if (InP->msgh_id) {
+ static long _calls;
+ static struct { long id, count; } _counts[512];
+ int i, id;
+
+ id = InP->msgh_id;
+ for (i = 0; i < 511; i++) {
+ if (_counts[i].id == 0) {
+ _counts[i].id = id;
+ _counts[i].count++;
+ break;
+ }
+ if (_counts[i].id == id) {
+ _counts[i].count++;
+ break;
+ }
+ }
+ if (i == 511) {
+ _counts[i].id = id;
+ _counts[i].count++;
+ }
+ if ((++_calls & 0x7fff) == 0)
+ for (i = 0; i < 512; i++) {
+ if (_counts[i].id == 0)
+ break;
+ printf("%d: %d\n",
+ _counts[i].id, _counts[i].count);
+ }
+ }
+#endif
+
+ OutP->RetCodeType = RetCodeType;
+
+#undef InP
+#undef OutP
+ }
+
+ /*
+ * Find the server routine to call, and call it
+ * to perform the kernel function
+ */
+ {
+ check_simple_locks();
+ if ((routine = mach_server_routine(&request->ikm_header)) != 0
+ || (routine = mach_port_server_routine(&request->ikm_header)) != 0
+ || (routine = mach_host_server_routine(&request->ikm_header)) != 0
+ || (routine = device_server_routine(&request->ikm_header)) != 0
+ || (routine = device_pager_server_routine(&request->ikm_header)) != 0
+#if MACH_DEBUG
+ || (routine = mach_debug_server_routine(&request->ikm_header)) != 0
+#endif /* MACH_DEBUG */
+ || (routine = mach4_server_routine(&request->ikm_header)) != 0
+ || (routine = gnumach_server_routine(&request->ikm_header)) != 0
+ || (routine = experimental_server_routine(&request->ikm_header)) != 0
+#if MACH_MACHINE_ROUTINES
+ || (routine = MACHINE_SERVER_ROUTINE(&request->ikm_header)) != 0
+#endif /* MACH_MACHINE_ROUTINES */
+ ) {
+ (*routine)(&request->ikm_header, &reply->ikm_header);
+ kernel_task->messages_received++;
+ } else {
+ if (!ipc_kobject_notify(&request->ikm_header,
+ &reply->ikm_header)) {
+ ((mig_reply_header_t *) &reply->ikm_header)->RetCode
+ = MIG_BAD_ID;
+#if MACH_IPC_TEST
+ printf("ipc_kobject_server: bogus kernel message, id=%d\n",
+ request->ikm_header.msgh_id);
+#endif /* MACH_IPC_TEST */
+ } else {
+ kernel_task->messages_received++;
+ }
+ }
+ kernel_task->messages_sent++;
+ }
+ check_simple_locks();
+
+ /*
+ * Destroy destination. The following code differs from
+ * ipc_object_destroy in that we release the send-once
+ * right instead of generating a send-once notification
+ * (which would bring us here again, creating a loop).
+ * It also differs in that we only expect send or
+ * send-once rights, never receive rights.
+ *
+ * We set msgh_remote_port to IP_NULL so that the kmsg
+ * destroy routines don't try to destroy the port twice.
+ */
+ destp = (ipc_port_t *) &request->ikm_header.msgh_remote_port;
+ switch (MACH_MSGH_BITS_REMOTE(request->ikm_header.msgh_bits)) {
+ case MACH_MSG_TYPE_PORT_SEND:
+ ipc_port_release_send(*destp);
+ break;
+
+ case MACH_MSG_TYPE_PORT_SEND_ONCE:
+ ipc_port_release_sonce(*destp);
+ break;
+
+ default:
+#if MACH_ASSERT
+ assert(!"ipc_object_destroy: strange destination rights");
+#else
+ panic("ipc_object_destroy: strange destination rights");
+#endif
+ }
+ *destp = IP_NULL;
+
+ kr = ((mig_reply_header_t *) &reply->ikm_header)->RetCode;
+ if ((kr == KERN_SUCCESS) || (kr == MIG_NO_REPLY)) {
+ /*
+ * The server function is responsible for the contents
+ * of the message. The reply port right is moved
+ * to the reply message, and we have deallocated
+ * the destination port right, so we just need
+ * to free the kmsg.
+ */
+
+ /* like ipc_kmsg_put, but without the copyout */
+
+ ikm_check_initialized(request, request->ikm_size);
+ ikm_cache_free(request);
+ } else {
+ /*
+ * The message contents of the request are intact.
+ * Destroy everything except the reply port right,
+ * which is needed in the reply message.
+ */
+
+ request->ikm_header.msgh_local_port = MACH_PORT_NULL;
+ ipc_kmsg_destroy(request);
+ }
+
+ if (kr == MIG_NO_REPLY) {
+ /*
+ * The server function will send a reply message
+ * using the reply port right, which it has saved.
+ */
+
+ ikm_free(reply);
+ return IKM_NULL;
+ } else if (!IP_VALID((ipc_port_t)reply->ikm_header.msgh_remote_port)) {
+ /*
+ * Can't queue the reply message if the destination
+ * (the reply port) isn't valid.
+ */
+
+ ipc_kmsg_destroy(reply);
+ return IKM_NULL;
+ }
+
+ return reply;
+}
+
+/*
+ * Routine: ipc_kobject_set
+ * Purpose:
+ * Make a port represent a kernel object of the given type.
+ * The caller is responsible for handling refs for the
+ * kernel object, if necessary.
+ * Conditions:
+ * Nothing locked. The port must be active.
+ */
+
+void
+ipc_kobject_set(ipc_port_t port, ipc_kobject_t kobject, ipc_kobject_type_t type)
+{
+ ip_lock(port);
+ assert(ip_active(port));
+ port->ip_bits = (port->ip_bits &~ IO_BITS_KOTYPE) | type;
+ port->ip_kobject = kobject;
+ ip_unlock(port);
+}
+
+/*
+ * Routine: ipc_kobject_destroy
+ * Purpose:
+ * Release any kernel object resources associated
+ * with the port, which is being destroyed.
+ *
+ * This should only be needed when resources are
+ * associated with a user's port. In the normal case,
+ * when the kernel is the receiver, the code calling
+ * ipc_port_dealloc_kernel should clean up the resources.
+ * Conditions:
+ * The port is not locked, but it is dead.
+ */
+
+void
+ipc_kobject_destroy(
+ ipc_port_t port)
+{
+ switch (ip_kotype(port)) {
+ case IKOT_PAGER:
+ vm_object_destroy(port);
+ break;
+
+ case IKOT_PAGER_TERMINATING:
+ vm_object_pager_wakeup(port);
+ break;
+
+ default:
+#if MACH_ASSERT
+ printf("ipc_kobject_destroy: port 0x%p, kobj 0x%zd, type %d\n",
+ port, port->ip_kobject, ip_kotype(port));
+#endif /* MACH_ASSERT */
+ break;
+ }
+}
+
+/*
+ * Routine: ipc_kobject_notify
+ * Purpose:
+ * Deliver notifications to kobjects that care about them.
+ */
+
+boolean_t
+ipc_kobject_notify(mach_msg_header_t *request_header,
+ mach_msg_header_t *reply_header)
+{
+ ipc_port_t port = (ipc_port_t) request_header->msgh_remote_port;
+
+ ((mig_reply_header_t *) reply_header)->RetCode = MIG_NO_REPLY;
+ switch (request_header->msgh_id) {
+ case MACH_NOTIFY_PORT_DELETED:
+ case MACH_NOTIFY_MSG_ACCEPTED:
+ case MACH_NOTIFY_PORT_DESTROYED:
+ case MACH_NOTIFY_NO_SENDERS:
+ case MACH_NOTIFY_SEND_ONCE:
+ case MACH_NOTIFY_DEAD_NAME:
+ break;
+
+ default:
+ return FALSE;
+ }
+ switch (ip_kotype(port)) {
+ case IKOT_DEVICE:
+ return ds_notify(request_header);
+
+ case IKOT_PAGER_PROXY:
+ return memory_object_proxy_notify(request_header);
+
+ default:
+ return FALSE;
+ }
+}