diff options
author | Pasha <pasha@member.fsf.org> | 2024-02-20 18:49:50 +0000 |
---|---|---|
committer | Pasha <pasha@member.fsf.org> | 2024-02-20 18:49:50 +0000 |
commit | 5e0b8d508ed51004bd836384293be00950ee62c9 (patch) | |
tree | e3f16b1aa8b7177032ce3ec429fbad2b1d92a876 /kern/ipc_kobject.c | |
download | gnumach-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.c | 365 |
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; + } +} |