aboutsummaryrefslogtreecommitdiff
path: root/kern/ipc_mig.c
diff options
context:
space:
mode:
Diffstat (limited to 'kern/ipc_mig.c')
-rw-r--r--kern/ipc_mig.c984
1 files changed, 984 insertions, 0 deletions
diff --git a/kern/ipc_mig.c b/kern/ipc_mig.c
new file mode 100644
index 0000000..d26d2c6
--- /dev/null
+++ b/kern/ipc_mig.c
@@ -0,0 +1,984 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 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.
+ */
+
+#include <mach/boolean.h>
+#include <mach/port.h>
+#include <mach/message.h>
+#include <mach/mig_support.h>
+#include <mach/thread_status.h>
+#include <machine/locore.h>
+#include <machine/copy_user.h>
+#include <kern/ast.h>
+#include <kern/debug.h>
+#include <kern/ipc_tt.h>
+#include <kern/syscall_subr.h>
+#include <kern/thread.h>
+#include <kern/task.h>
+#include <kern/ipc_kobject.h>
+#include <kern/ipc_tt.h>
+#include <kern/ipc_mig.h>
+#include <vm/vm_map.h>
+#include <vm/vm_user.h>
+#include <ipc/port.h>
+#include <ipc/ipc_kmsg.h>
+#include <ipc/ipc_entry.h>
+#include <ipc/ipc_object.h>
+#include <ipc/ipc_mqueue.h>
+#include <ipc/ipc_space.h>
+#include <ipc/ipc_port.h>
+#include <ipc/ipc_pset.h>
+#include <ipc/ipc_thread.h>
+#include <ipc/mach_port.server.h>
+#include <device/dev_hdr.h>
+#include <device/device_types.h>
+#include <device/ds_routines.h>
+
+/*
+ * Routine: mach_msg_send_from_kernel
+ * Purpose:
+ * Send a message from the kernel.
+ *
+ * This is used by the client side of KernelUser interfaces
+ * to implement SimpleRoutines. Currently, this includes
+ * device_reply and memory_object messages.
+ * Conditions:
+ * Nothing locked.
+ * Returns:
+ * MACH_MSG_SUCCESS Sent the message.
+ * MACH_SEND_INVALID_DATA Bad destination port.
+ */
+
+mach_msg_return_t
+mach_msg_send_from_kernel(
+ mach_msg_header_t *msg,
+ mach_msg_size_t send_size)
+{
+ ipc_kmsg_t kmsg;
+ mach_msg_return_t mr;
+
+ if (!MACH_PORT_VALID(msg->msgh_remote_port))
+ return MACH_SEND_INVALID_DEST;
+
+ mr = ipc_kmsg_get_from_kernel(msg, send_size, &kmsg);
+ if (mr != MACH_MSG_SUCCESS)
+ panic("mach_msg_send_from_kernel");
+
+ ipc_kmsg_copyin_from_kernel(kmsg);
+ ipc_mqueue_send_always(kmsg);
+
+ return MACH_MSG_SUCCESS;
+}
+
+mach_msg_return_t
+mach_msg_rpc_from_kernel(const mach_msg_header_t *msg,
+ mach_msg_size_t send_size,
+ mach_msg_size_t reply_size)
+{
+ panic("mach_msg_rpc_from_kernel"); /*XXX*/
+}
+
+/*
+ * Routine: mach_msg_abort_rpc
+ * Purpose:
+ * Destroy the thread's ith_rpc_reply port.
+ * This will interrupt a mach_msg_rpc_from_kernel
+ * with a MACH_RCV_PORT_DIED return code.
+ * Conditions:
+ * Nothing locked.
+ */
+
+void
+mach_msg_abort_rpc(ipc_thread_t thread)
+{
+ ipc_port_t reply = IP_NULL;
+
+ ith_lock(thread);
+ if (thread->ith_self != IP_NULL) {
+ reply = thread->ith_rpc_reply;
+ thread->ith_rpc_reply = IP_NULL;
+ }
+ ith_unlock(thread);
+
+ if (reply != IP_NULL)
+ ipc_port_dealloc_reply(reply);
+}
+
+/*
+ * Routine: mach_msg
+ * Purpose:
+ * Like mach_msg_trap except that message buffers
+ * live in kernel space. Doesn't handle any options.
+ *
+ * This is used by in-kernel server threads to make
+ * kernel calls, to receive request messages, and
+ * to send reply messages.
+ * Conditions:
+ * Nothing locked.
+ * Returns:
+ */
+
+mach_msg_return_t
+mach_msg(
+ mach_msg_header_t *msg,
+ mach_msg_option_t option,
+ mach_msg_size_t send_size,
+ mach_msg_size_t rcv_size,
+ mach_port_name_t rcv_name,
+ mach_msg_timeout_t time_out,
+ mach_port_name_t notify)
+{
+ ipc_space_t space = current_space();
+ vm_map_t map = current_map();
+ ipc_kmsg_t kmsg;
+ mach_port_seqno_t seqno;
+ mach_msg_return_t mr;
+
+ if (option & MACH_SEND_MSG) {
+ mr = ipc_kmsg_get_from_kernel(msg, send_size, &kmsg);
+ if (mr != MACH_MSG_SUCCESS)
+ panic("mach_msg");
+
+ mr = ipc_kmsg_copyin(kmsg, space, map, MACH_PORT_NULL);
+ if (mr != MACH_MSG_SUCCESS) {
+ ikm_free(kmsg);
+ return mr;
+ }
+
+ do
+ mr = ipc_mqueue_send(kmsg, MACH_MSG_OPTION_NONE,
+ MACH_MSG_TIMEOUT_NONE);
+ while (mr == MACH_SEND_INTERRUPTED);
+ assert(mr == MACH_MSG_SUCCESS);
+ }
+
+ if (option & MACH_RCV_MSG) {
+ do {
+ ipc_object_t object;
+ ipc_mqueue_t mqueue;
+
+ mr = ipc_mqueue_copyin(space, rcv_name,
+ &mqueue, &object);
+ if (mr != MACH_MSG_SUCCESS)
+ return mr;
+ /* hold ref for object; mqueue is locked */
+
+ mr = ipc_mqueue_receive(mqueue, MACH_MSG_OPTION_NONE,
+ MACH_MSG_SIZE_MAX,
+ MACH_MSG_TIMEOUT_NONE,
+ FALSE, IMQ_NULL_CONTINUE,
+ &kmsg, &seqno);
+ /* mqueue is unlocked */
+ ipc_object_release(object);
+ } while (mr == MACH_RCV_INTERRUPTED);
+ if (mr != MACH_MSG_SUCCESS)
+ return mr;
+
+ kmsg->ikm_header.msgh_seqno = seqno;
+
+ if (rcv_size < msg_usize(&kmsg->ikm_header)) {
+ ipc_kmsg_copyout_dest(kmsg, space);
+ ipc_kmsg_put_to_kernel(msg, kmsg, sizeof *msg);
+ return MACH_RCV_TOO_LARGE;
+ }
+
+ mr = ipc_kmsg_copyout(kmsg, space, map, MACH_PORT_NULL);
+ if (mr != MACH_MSG_SUCCESS) {
+ if ((mr &~ MACH_MSG_MASK) == MACH_RCV_BODY_ERROR) {
+ ipc_kmsg_put_to_kernel(msg, kmsg,
+ kmsg->ikm_header.msgh_size);
+ } else {
+ ipc_kmsg_copyout_dest(kmsg, space);
+ ipc_kmsg_put_to_kernel(msg, kmsg, sizeof *msg);
+ }
+
+ return mr;
+ }
+
+ ipc_kmsg_put_to_kernel(msg, kmsg, kmsg->ikm_header.msgh_size);
+ }
+
+ return MACH_MSG_SUCCESS;
+}
+
+/*
+ * Routine: mig_get_reply_port
+ * Purpose:
+ * Called by client side interfaces living in the kernel
+ * to get a reply port. This port is used for
+ * mach_msg() calls which are kernel calls.
+ */
+
+mach_port_name_t
+mig_get_reply_port(void)
+{
+ ipc_thread_t self = current_thread();
+
+ if (self->ith_mig_reply == MACH_PORT_NULL)
+ self->ith_mig_reply = mach_reply_port();
+
+ return self->ith_mig_reply;
+}
+
+/*
+ * Routine: mig_dealloc_reply_port
+ * Purpose:
+ * Called by client side interfaces to get rid of a reply port.
+ * Shouldn't ever be called inside the kernel, because
+ * kernel calls shouldn't prompt Mig to call it.
+ */
+
+void
+mig_dealloc_reply_port(
+ mach_port_t reply_port)
+{
+ panic("mig_dealloc_reply_port");
+}
+
+/*
+ * Routine: mig_put_reply_port
+ * Purpose:
+ * Called by client side interfaces after each RPC to
+ * let the client recycle the reply port if it wishes.
+ */
+void
+mig_put_reply_port(
+ mach_port_t reply_port)
+{
+}
+
+/*
+ * mig_strncpy.c - by Joshua Block
+ *
+ * mig_strncpy -- Bounded string copy. Does what the library routine
+ * strncpy does: Copies the (null terminated) string in src into dest,
+ * a buffer of length len. Returns the length of the destination
+ * string excluding the terminating null.
+ *
+ * Parameters:
+ *
+ * dest - Pointer to destination buffer.
+ *
+ * src - Pointer to source string.
+ *
+ * len - Length of destination buffer.
+ */
+vm_size_t
+mig_strncpy(char *dest, const char *src, vm_size_t len)
+{
+ char *dest_ = dest;
+ int i;
+
+ if (len <= 0)
+ return 0;
+
+ for (i = 0; i < len; i++) {
+ if (! (*dest = *src))
+ break;
+ dest++;
+ src++;
+ }
+
+ return dest - dest_;
+}
+
+/* Called by MiG to deallocate memory, which in this case happens
+ * to be kernel memory. */
+void
+mig_deallocate(vm_address_t addr, vm_size_t size)
+{
+ (void) size;
+ /* We do the same thing as in ipc_kmsg_clean_body. */
+ vm_map_copy_discard((vm_map_copy_t) addr);
+}
+
+#define fast_send_right_lookup(name, port, abort) \
+MACRO_BEGIN \
+ ipc_space_t space = current_space(); \
+ ipc_entry_t entry; \
+ \
+ is_read_lock(space); \
+ assert(space->is_active); \
+ \
+ entry = ipc_entry_lookup (space, name); \
+ if (entry == IE_NULL) { \
+ is_read_unlock (space); \
+ abort; \
+ } \
+ \
+ if (IE_BITS_TYPE (entry->ie_bits) != MACH_PORT_TYPE_SEND) { \
+ is_read_unlock (space); \
+ abort; \
+ } \
+ \
+ port = (ipc_port_t) entry->ie_object; \
+ assert(port != IP_NULL); \
+ \
+ ip_lock(port); \
+ /* can safely unlock space now that port is locked */ \
+ is_read_unlock(space); \
+MACRO_END
+
+static device_t
+port_name_to_device(mach_port_name_t name)
+{
+ ipc_port_t port;
+ device_t device;
+
+ fast_send_right_lookup(name, port, goto abort);
+ /* port is locked */
+
+ /*
+ * Now map the port object to a device object.
+ * This is an inline version of dev_port_lookup().
+ */
+ if (ip_active(port) && (ip_kotype(port) == IKOT_DEVICE)) {
+ device = (device_t) port->ip_kobject;
+ device_reference(device);
+ ip_unlock(port);
+ return device;
+ }
+
+ ip_unlock(port);
+ return DEVICE_NULL;
+
+ /*
+ * The slow case. The port wasn't easily accessible.
+ */
+ abort: {
+ ipc_port_t kern_port;
+ kern_return_t kr;
+
+ kr = ipc_object_copyin(current_space(), name,
+ MACH_MSG_TYPE_COPY_SEND,
+ (ipc_object_t *) &kern_port);
+ if (kr != KERN_SUCCESS)
+ return DEVICE_NULL;
+
+ device = dev_port_lookup(kern_port);
+ if (IP_VALID(kern_port))
+ ipc_port_release_send(kern_port);
+ return device;
+ }
+}
+
+static thread_t
+port_name_to_thread(mach_port_name_t name)
+{
+ ipc_port_t port;
+
+ fast_send_right_lookup(name, port, goto abort);
+ /* port is locked */
+
+ if (ip_active(port) &&
+ (ip_kotype(port) == IKOT_THREAD)) {
+ thread_t thread;
+
+ thread = (thread_t) port->ip_kobject;
+ assert(thread != THREAD_NULL);
+
+ /* thread referencing is a bit complicated,
+ so don't bother to expand inline */
+ thread_reference(thread);
+ ip_unlock(port);
+
+ return thread;
+ }
+
+ ip_unlock(port);
+ return THREAD_NULL;
+
+ abort: {
+ thread_t thread;
+ ipc_port_t kern_port;
+ kern_return_t kr;
+
+ kr = ipc_object_copyin(current_space(), name,
+ MACH_MSG_TYPE_COPY_SEND,
+ (ipc_object_t *) &kern_port);
+ if (kr != KERN_SUCCESS)
+ return THREAD_NULL;
+
+ thread = convert_port_to_thread(kern_port);
+ if (IP_VALID(kern_port))
+ ipc_port_release_send(kern_port);
+
+ return thread;
+ }
+}
+
+static task_t
+port_name_to_task(mach_port_name_t name)
+{
+ ipc_port_t port;
+
+ fast_send_right_lookup(name, port, goto abort);
+ /* port is locked */
+
+ if (ip_active(port) &&
+ (ip_kotype(port) == IKOT_TASK)) {
+ task_t task;
+
+ task = (task_t) port->ip_kobject;
+ assert(task != TASK_NULL);
+
+ task_lock(task);
+ /* can safely unlock port now that task is locked */
+ ip_unlock(port);
+
+ task->ref_count++;
+ task_unlock(task);
+
+ return task;
+ }
+
+ ip_unlock(port);
+ return TASK_NULL;
+
+ abort: {
+ task_t task;
+ ipc_port_t kern_port;
+ kern_return_t kr;
+
+ kr = ipc_object_copyin(current_space(), name,
+ MACH_MSG_TYPE_COPY_SEND,
+ (ipc_object_t *) &kern_port);
+ if (kr != KERN_SUCCESS)
+ return TASK_NULL;
+
+ task = convert_port_to_task(kern_port);
+ if (IP_VALID(kern_port))
+ ipc_port_release_send(kern_port);
+
+ return task;
+ }
+}
+
+static vm_map_t
+port_name_to_map(
+ mach_port_name_t name)
+{
+ ipc_port_t port;
+
+ fast_send_right_lookup(name, port, goto abort);
+ /* port is locked */
+
+ if (ip_active(port) &&
+ (ip_kotype(port) == IKOT_TASK)) {
+ vm_map_t map;
+
+ map = ((task_t) port->ip_kobject)->map;
+ assert(map != VM_MAP_NULL);
+
+ simple_lock(&map->ref_lock);
+ /* can safely unlock port now that map is locked */
+ ip_unlock(port);
+
+ map->ref_count++;
+ simple_unlock(&map->ref_lock);
+
+ return map;
+ }
+
+ ip_unlock(port);
+ return VM_MAP_NULL;
+
+ abort: {
+ vm_map_t map;
+ ipc_port_t kern_port;
+ kern_return_t kr;
+
+ kr = ipc_object_copyin(current_space(), name,
+ MACH_MSG_TYPE_COPY_SEND,
+ (ipc_object_t *) &kern_port);
+ if (kr != KERN_SUCCESS)
+ return VM_MAP_NULL;
+
+ map = convert_port_to_map(kern_port);
+ if (IP_VALID(kern_port))
+ ipc_port_release_send(kern_port);
+
+ return map;
+ }
+}
+
+static ipc_space_t
+port_name_to_space(mach_port_name_t name)
+{
+ ipc_port_t port;
+
+ fast_send_right_lookup(name, port, goto abort);
+ /* port is locked */
+
+ if (ip_active(port) &&
+ (ip_kotype(port) == IKOT_TASK)) {
+ ipc_space_t space;
+
+ space = ((task_t) port->ip_kobject)->itk_space;
+ assert(space != IS_NULL);
+
+ simple_lock(&space->is_ref_lock_data);
+ /* can safely unlock port now that space is locked */
+ ip_unlock(port);
+
+ space->is_references++;
+ simple_unlock(&space->is_ref_lock_data);
+
+ return space;
+ }
+
+ ip_unlock(port);
+ return IS_NULL;
+
+ abort: {
+ ipc_space_t space;
+ ipc_port_t kern_port;
+ kern_return_t kr;
+
+ kr = ipc_object_copyin(current_space(), name,
+ MACH_MSG_TYPE_COPY_SEND,
+ (ipc_object_t *) &kern_port);
+ if (kr != KERN_SUCCESS)
+ return IS_NULL;
+
+ space = convert_port_to_space(kern_port);
+ if (IP_VALID(kern_port))
+ ipc_port_release_send(kern_port);
+
+ return space;
+ }
+}
+
+/*
+ * Things to keep in mind:
+ *
+ * The idea here is to duplicate the semantics of the true kernel RPC.
+ * The destination port/object should be checked first, before anything
+ * that the user might notice (like ipc_object_copyin). Return
+ * MACH_SEND_INTERRUPTED if it isn't correct, so that the user stub
+ * knows to fall back on an RPC. For other return values, it won't
+ * retry with an RPC. The retry might get a different (incorrect) rc.
+ * Return values are only set (and should only be set, with copyout)
+ * on successful calls.
+ */
+
+kern_return_t
+syscall_vm_map(
+ mach_port_name_t target_map,
+ rpc_vm_offset_t *address,
+ rpc_vm_size_t size,
+ rpc_vm_offset_t mask,
+ boolean_t anywhere,
+ mach_port_name_t memory_object,
+ rpc_vm_offset_t offset,
+ boolean_t copy,
+ vm_prot_t cur_protection,
+ vm_prot_t max_protection,
+ vm_inherit_t inheritance)
+{
+ vm_map_t map;
+ ipc_port_t port;
+ vm_offset_t addr;
+ kern_return_t result;
+
+ map = port_name_to_map(target_map);
+ if (map == VM_MAP_NULL)
+ return MACH_SEND_INTERRUPTED;
+
+ if (MACH_PORT_NAME_VALID(memory_object)) {
+ result = ipc_object_copyin(current_space(), memory_object,
+ MACH_MSG_TYPE_COPY_SEND,
+ (ipc_object_t *) &port);
+ if (result != KERN_SUCCESS) {
+ vm_map_deallocate(map);
+ return result;
+ }
+ } else
+ port = (ipc_port_t)invalid_name_to_port(memory_object);
+
+ copyin_address(address, &addr);
+ result = vm_map(map, &addr, size, mask, anywhere,
+ port, offset, copy,
+ cur_protection, max_protection, inheritance);
+ if (result == KERN_SUCCESS)
+ copyout_address(&addr, address);
+ if (IP_VALID(port))
+ ipc_port_release_send(port);
+ vm_map_deallocate(map);
+
+ return result;
+}
+
+kern_return_t syscall_vm_allocate(
+ mach_port_name_t target_map,
+ rpc_vm_offset_t *address,
+ rpc_vm_size_t size,
+ boolean_t anywhere)
+{
+ vm_map_t map;
+ vm_offset_t addr;
+ kern_return_t result;
+
+ map = port_name_to_map(target_map);
+ if (map == VM_MAP_NULL)
+ return MACH_SEND_INTERRUPTED;
+
+ copyin_address(address, &addr);
+ result = vm_allocate(map, &addr, size, anywhere);
+ if (result == KERN_SUCCESS)
+ copyout_address(&addr, address);
+ vm_map_deallocate(map);
+
+ return result;
+}
+
+kern_return_t syscall_vm_deallocate(
+ mach_port_name_t target_map,
+ rpc_vm_offset_t start,
+ rpc_vm_size_t size)
+{
+ vm_map_t map;
+ kern_return_t result;
+
+ map = port_name_to_map(target_map);
+ if (map == VM_MAP_NULL)
+ return MACH_SEND_INTERRUPTED;
+
+ result = vm_deallocate(map, start, size);
+ vm_map_deallocate(map);
+
+ return result;
+}
+
+kern_return_t syscall_task_create(
+ mach_port_name_t parent_task,
+ boolean_t inherit_memory,
+ mach_port_name_t *child_task) /* OUT */
+{
+ task_t t, c;
+ ipc_port_t port;
+ mach_port_name_t name;
+ kern_return_t result;
+
+ t = port_name_to_task(parent_task);
+ if (t == TASK_NULL)
+ return MACH_SEND_INTERRUPTED;
+
+ result = task_create(t, inherit_memory, &c);
+ if (result == KERN_SUCCESS) {
+ port = (ipc_port_t) convert_task_to_port(c);
+ /* always returns a name, even for non-success return codes */
+ (void) ipc_kmsg_copyout_object(current_space(),
+ (ipc_object_t) port,
+ MACH_MSG_TYPE_PORT_SEND, &name);
+ copyout(&name, child_task, sizeof(mach_port_name_t));
+ }
+ task_deallocate(t);
+
+ return result;
+}
+
+kern_return_t syscall_task_terminate(mach_port_name_t task)
+{
+ task_t t;
+ kern_return_t result;
+
+ t = port_name_to_task(task);
+ if (t == TASK_NULL)
+ return MACH_SEND_INTERRUPTED;
+
+ result = task_terminate(t);
+ task_deallocate(t);
+
+ return result;
+}
+
+kern_return_t syscall_task_suspend(mach_port_name_t task)
+{
+ task_t t;
+ kern_return_t result;
+
+ t = port_name_to_task(task);
+ if (t == TASK_NULL)
+ return MACH_SEND_INTERRUPTED;
+
+ result = task_suspend(t);
+ task_deallocate(t);
+
+ return result;
+}
+
+kern_return_t syscall_task_set_special_port(
+ mach_port_name_t task,
+ int which_port,
+ mach_port_name_t port_name)
+{
+ task_t t;
+ ipc_port_t port;
+ kern_return_t result;
+
+ t = port_name_to_task(task);
+ if (t == TASK_NULL)
+ return MACH_SEND_INTERRUPTED;
+
+ if (MACH_PORT_NAME_VALID(port_name)) {
+ result = ipc_object_copyin(current_space(), port_name,
+ MACH_MSG_TYPE_COPY_SEND,
+ (ipc_object_t *) &port);
+ if (result != KERN_SUCCESS) {
+ task_deallocate(t);
+ return result;
+ }
+ } else
+ port = (ipc_port_t)invalid_name_to_port(port_name);
+
+ result = task_set_special_port(t, which_port, port);
+ if ((result != KERN_SUCCESS) && IP_VALID(port))
+ ipc_port_release_send(port);
+ task_deallocate(t);
+
+ return result;
+}
+
+kern_return_t
+syscall_mach_port_allocate(
+ mach_port_name_t task,
+ mach_port_right_t right,
+ mach_port_name_t *namep)
+{
+ ipc_space_t space;
+ mach_port_name_t name;
+ kern_return_t kr;
+
+ space = port_name_to_space(task);
+ if (space == IS_NULL)
+ return MACH_SEND_INTERRUPTED;
+
+ kr = mach_port_allocate(space, right, &name);
+ if (kr == KERN_SUCCESS)
+ {
+ copyout(&name, namep, sizeof(mach_port_name_t));
+ }
+ is_release(space);
+
+ return kr;
+}
+
+kern_return_t
+syscall_mach_port_allocate_name(
+ mach_port_name_t task,
+ mach_port_right_t right,
+ mach_port_name_t name)
+{
+ ipc_space_t space;
+ kern_return_t kr;
+
+ space = port_name_to_space(task);
+ if (space == IS_NULL)
+ return MACH_SEND_INTERRUPTED;
+
+ kr = mach_port_allocate_name(space, right, name);
+ is_release(space);
+
+ return kr;
+}
+
+kern_return_t
+syscall_mach_port_deallocate(
+ mach_port_name_t task,
+ mach_port_name_t name)
+{
+ ipc_space_t space;
+ kern_return_t kr;
+
+ space = port_name_to_space(task);
+ if (space == IS_NULL)
+ return MACH_SEND_INTERRUPTED;
+
+ kr = mach_port_deallocate(space, name);
+ is_release(space);
+
+ return kr;
+}
+
+kern_return_t
+syscall_mach_port_insert_right(
+ mach_port_name_t task,
+ mach_port_name_t name,
+ mach_port_name_t right,
+ mach_msg_type_name_t rightType)
+{
+ ipc_space_t space;
+ ipc_object_t object;
+ mach_msg_type_name_t newtype;
+ kern_return_t kr;
+
+ space = port_name_to_space(task);
+ if (space == IS_NULL)
+ return MACH_SEND_INTERRUPTED;
+
+ if (!MACH_MSG_TYPE_PORT_ANY(rightType)) {
+ is_release(space);
+ return KERN_INVALID_VALUE;
+ }
+
+ if (MACH_PORT_NAME_VALID(right)) {
+ kr = ipc_object_copyin(current_space(), right, rightType,
+ &object);
+ if (kr != KERN_SUCCESS) {
+ is_release(space);
+ return kr;
+ }
+ } else
+ object = (ipc_object_t)invalid_name_to_port(right);
+ newtype = ipc_object_copyin_type(rightType);
+
+ kr = mach_port_insert_right(space, name, (ipc_port_t) object, newtype);
+ if ((kr != KERN_SUCCESS) && IO_VALID(object))
+ ipc_object_destroy(object, newtype);
+ is_release(space);
+
+ return kr;
+}
+
+kern_return_t syscall_thread_depress_abort(mach_port_name_t thread)
+{
+ thread_t t;
+ kern_return_t result;
+
+ t = port_name_to_thread(thread);
+ if (t == THREAD_NULL)
+ return MACH_SEND_INTERRUPTED;
+
+ result = thread_depress_abort(t);
+ thread_deallocate(t);
+
+ return result;
+}
+
+/*
+ * Device traps -- these are way experimental.
+ */
+io_return_t
+syscall_device_write_request(mach_port_name_t device_name,
+ mach_port_name_t reply_name,
+ dev_mode_t mode,
+ rpc_recnum_t recnum,
+ rpc_vm_offset_t data,
+ rpc_vm_size_t data_count)
+{
+ device_t dev;
+ /*ipc_port_t reply_port;*/
+ io_return_t res;
+
+ /*
+ * First try to translate the device name.
+ *
+ * If this fails, return KERN_INVALID_CAPABILITY.
+ * Caller knows that this most likely means that
+ * device is not local to node and IPC should be used.
+ *
+ * If kernel doesn't do device traps, kern_invalid()
+ * will be called instead of this function which will
+ * return KERN_INVALID_ARGUMENT.
+ */
+ dev = port_name_to_device(device_name);
+ if (dev == DEVICE_NULL)
+ return KERN_INVALID_CAPABILITY;
+
+ /*
+ * Translate reply port.
+ */
+ /*if (reply_name == MACH_PORT_NULL)
+ reply_port = IP_NULL;
+ */
+ if (reply_name != MACH_PORT_NULL) {
+ /* Homey don't play that. */
+ device_deallocate(dev);
+ return KERN_INVALID_RIGHT;
+ }
+
+ /* note: doesn't take reply_port arg yet. */
+ res = ds_device_write_trap(dev, /*reply_port,*/
+ mode, recnum,
+ data, data_count);
+
+ /*
+ * Give up reference from port_name_to_device.
+ */
+ device_deallocate(dev);
+ return res;
+}
+
+io_return_t
+syscall_device_writev_request(mach_port_name_t device_name,
+ mach_port_name_t reply_name,
+ dev_mode_t mode,
+ rpc_recnum_t recnum,
+ rpc_io_buf_vec_t *iovec,
+ rpc_vm_size_t iocount)
+{
+ device_t dev;
+ /*ipc_port_t reply_port;*/
+ io_return_t res;
+
+ /*
+ * First try to translate the device name.
+ *
+ * If this fails, return KERN_INVALID_CAPABILITY.
+ * Caller knows that this most likely means that
+ * device is not local to node and IPC should be used.
+ *
+ * If kernel doesn't do device traps, kern_invalid()
+ * will be called instead of this function which will
+ * return KERN_INVALID_ARGUMENT.
+ */
+ dev = port_name_to_device(device_name);
+ if (dev == DEVICE_NULL)
+ return KERN_INVALID_CAPABILITY;
+
+ /*
+ * Translate reply port.
+ */
+ /*if (reply_name == MACH_PORT_NULL)
+ reply_port = IP_NULL;
+ */
+ if (reply_name != MACH_PORT_NULL) {
+ /* Homey don't play that. */
+ device_deallocate(dev);
+ return KERN_INVALID_RIGHT;
+ }
+
+ /* note: doesn't take reply_port arg yet. */
+ res = ds_device_writev_trap(dev, /*reply_port,*/
+ mode, recnum,
+ iovec, iocount);
+
+ /*
+ * Give up reference from port_name_to_device.
+ */
+ device_deallocate(dev);
+ return res;
+}