NetBSD/sys/compat/mach/mach_iokit.c
manu b5139de154 Enforce good santity checks with Mach messages sizes:
1) make sure Mach servers will not work on data beyond the end of the
   request message buffer.
2) make sure that on copying out the reply message buffer, we will not
   leak kernel data located after the buffer.
3) make sure that the server will not overwrite memory beyond the end
   of the reply message buffer. That check is the responsability of the
   server, there is just a DIAGNOSTIC test to check everything is in
   good shape. All currently implemented servers in NetBSD have been
   modified to check for this condition

While we are here, build the mach services table (formerly in mach_namemap.c)
and the services prototypes automatically from mach_services.master, just
as this is done for system calls.

The next step would be to fold the message formats in the mach_services.master
file, but this tends to be difficult, as some messages are quite long and
complex.
2003-11-13 13:40:39 +00:00

1372 lines
41 KiB
C

/* $NetBSD: mach_iokit.c,v 1.25 2003/11/13 13:40:39 manu Exp $ */
/*-
* Copyright (c) 2003 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Emmanuel Dreyfus.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "opt_compat_darwin.h"
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: mach_iokit.c,v 1.25 2003/11/13 13:40:39 manu Exp $");
#include <sys/types.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/signal.h>
#include <sys/mount.h>
#include <sys/proc.h>
#include <sys/device.h>
#include <uvm/uvm_extern.h>
#include <uvm/uvm_map.h>
#include <compat/mach/mach_types.h>
#include <compat/mach/mach_message.h>
#include <compat/mach/mach_port.h>
#include <compat/mach/mach_errno.h>
#include <compat/mach/mach_iokit.h>
#include <compat/mach/mach_services.h>
#ifdef COMPAT_DARWIN
#include <compat/darwin/darwin_iokit.h>
#endif
struct mach_iokit_devclass mach_ioroot_devclass = {
"(unknwon)",
{ NULL },
"<dict ID=\"0\"></dict>",
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
"Root",
NULL,
};
struct mach_iokit_devclass *mach_iokit_devclasses[] = {
&mach_ioroot_devclass,
#ifdef COMPAT_DARWIN
DARWIN_IOKIT_DEVCLASSES
#endif
NULL,
};
static int mach_fill_child_iterator(struct mach_device_iterator *, int, int,
struct mach_iokit_devclass *);
static int mach_fill_parent_iterator(struct mach_device_iterator *, int, int,
struct mach_iokit_devclass *);
int
mach_io_service_get_matching_services(args)
struct mach_trap_args *args;
{
mach_io_service_get_matching_services_request_t *req = args->smsg;
mach_io_service_get_matching_services_reply_t *rep = args->rmsg;
size_t *msglen = args->rsize;
struct lwp *l = args->l;
struct mach_port *mp;
struct mach_right *mr;
struct mach_iokit_devclass *mid;
struct mach_device_iterator *mdi;
size_t size;
int end_offset;
int i;
/* Sanity check req_size */
end_offset = req->req_size;
if (MACH_REQMSG_OVERFLOW(args, req->req_string[end_offset]))
return mach_msg_error(args, EINVAL);
mp = mach_port_get();
mp->mp_flags |= MACH_MP_INKERNEL;
mr = mach_right_get(mp, l, MACH_PORT_TYPE_SEND, 0);
mp->mp_data = NULL;
i = 0;
while ((mid = mach_iokit_devclasses[i++]) != NULL) {
if (memcmp(req->req_string, mid->mid_string,
req->req_size) == 0) {
mp->mp_datatype = MACH_MP_DEVICE_ITERATOR;
size = sizeof(*mdi)
+ sizeof(struct mach_device_iterator *);
mdi = malloc(size, M_EMULDATA, M_WAITOK);
mdi->mdi_devices[0] = mid;
mdi->mdi_devices[1] = NULL;
mdi->mdi_current = 0;
mp->mp_data = mdi;
break;
}
}
if (mp->mp_data == NULL)
return mach_iokit_error(args, MACH_IOKIT_ENOENT);
rep->rep_msgh.msgh_bits =
MACH_MSGH_REPLY_LOCAL_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE) |
MACH_MSGH_BITS_COMPLEX;
rep->rep_msgh.msgh_size = sizeof(*rep) - sizeof(rep->rep_trailer);
rep->rep_msgh.msgh_local_port = req->req_msgh.msgh_local_port;
rep->rep_msgh.msgh_id = req->req_msgh.msgh_id + 100;
rep->rep_body.msgh_descriptor_count = 1;
rep->rep_match.name = (mach_port_t)mr->mr_name;
rep->rep_match.disposition = 0x11; /* XXX */
rep->rep_trailer.msgh_trailer_size = 8;
*msglen = sizeof(*rep);
return 0;
}
int
mach_io_iterator_next(args)
struct mach_trap_args *args;
{
mach_io_iterator_next_request_t *req = args->smsg;
mach_io_iterator_next_reply_t *rep = args->rmsg;
size_t *msglen = args->rsize;
struct lwp *l = args->l;
struct mach_port *mp;
struct mach_right *mr;
struct mach_device_iterator *mdi;
mach_port_t mn;
mn = req->req_msgh.msgh_remote_port;
if ((mr = mach_right_check(mn, l, MACH_PORT_TYPE_ALL_RIGHTS)) == NULL)
return mach_iokit_error(args, MACH_IOKIT_EPERM);
if (mr->mr_port->mp_datatype != MACH_MP_DEVICE_ITERATOR)
return mach_iokit_error(args, MACH_IOKIT_EINVAL);
mdi = mr->mr_port->mp_data;
/* Is there something coming next? */
if (mdi->mdi_devices[mdi->mdi_current] == NULL)
return mach_iokit_error(args, MACH_IOKIT_EINVAL);
mp = mach_port_get();
mp->mp_flags |= MACH_MP_INKERNEL;
mp->mp_datatype = MACH_MP_IOKIT_DEVCLASS;
mp->mp_data = mdi->mdi_devices[mdi->mdi_current++];
mr = mach_right_get(mp, l, MACH_PORT_TYPE_SEND, 0);
rep->rep_msgh.msgh_bits =
MACH_MSGH_REPLY_LOCAL_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE) |
MACH_MSGH_BITS_COMPLEX;
rep->rep_msgh.msgh_size = sizeof(*rep) - sizeof(rep->rep_trailer);
rep->rep_msgh.msgh_local_port = req->req_msgh.msgh_local_port;
rep->rep_msgh.msgh_id = req->req_msgh.msgh_id + 100;
rep->rep_body.msgh_descriptor_count = 1;
rep->rep_object.name = (mach_port_t)mr->mr_name;
rep->rep_object.disposition = 0x11; /* XXX */
rep->rep_trailer.msgh_trailer_size = 8;
*msglen = sizeof(*rep);
return 0;
}
int
mach_io_service_open(args)
struct mach_trap_args *args;
{
mach_io_service_open_request_t *req = args->smsg;
mach_io_service_open_reply_t *rep = args->rmsg;
size_t *msglen = args->rsize;
struct lwp *l = args->l;
struct mach_port *mp;
struct mach_right *mr;
mach_port_t mn;
mn = req->req_msgh.msgh_remote_port;
if ((mr = mach_right_check(mn, l, MACH_PORT_TYPE_ALL_RIGHTS)) == NULL)
return mach_iokit_error(args, MACH_IOKIT_EPERM);
mp = mach_port_get();
mp->mp_flags |= MACH_MP_INKERNEL;
if (mr->mr_port->mp_datatype == MACH_MP_IOKIT_DEVCLASS) {
mp->mp_datatype = MACH_MP_IOKIT_DEVCLASS;
mp->mp_data = mr->mr_port->mp_data;
}
mr = mach_right_get(mp, l, MACH_PORT_TYPE_SEND, 0);
rep->rep_msgh.msgh_bits =
MACH_MSGH_REPLY_LOCAL_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE) |
MACH_MSGH_BITS_COMPLEX;
rep->rep_msgh.msgh_size = sizeof(*rep) - sizeof(rep->rep_trailer);
rep->rep_msgh.msgh_local_port = req->req_msgh.msgh_local_port;
rep->rep_msgh.msgh_id = req->req_msgh.msgh_id + 100;
rep->rep_body.msgh_descriptor_count = 1;
rep->rep_connect.name = (mach_port_t)mr->mr_name;
rep->rep_connect.disposition = 0x11; /* XXX */
rep->rep_trailer.msgh_trailer_size = 8;
*msglen = sizeof(*rep);
return 0;
}
int
mach_io_connect_method_scalari_scalaro(args)
struct mach_trap_args *args;
{
mach_io_connect_method_scalari_scalaro_request_t *req = args->smsg;
struct lwp *l = args->l;
mach_port_t mn;
struct mach_right *mr;
struct mach_iokit_devclass *mid;
int end_offset;
/*
* Sanity check req_incount
* the +1 gives us the last field of the message, req_outcount
*/
end_offset = req->req_incount +
(sizeof(req->req_outcount) / sizeof(req->req_in[0]));
if (MACH_REQMSG_OVERFLOW(args, req->req_in[end_offset]))
return mach_msg_error(args, EINVAL);
/* Sanity check req->req_outcount */
if (req->req_outcount > 16)
return mach_msg_error(args, EINVAL);
mn = req->req_msgh.msgh_remote_port;
if ((mr = mach_right_check(mn, l, MACH_PORT_TYPE_ALL_RIGHTS)) == NULL)
return mach_iokit_error(args, MACH_IOKIT_EPERM);
if (mr->mr_port->mp_datatype == MACH_MP_IOKIT_DEVCLASS) {
mid = mr->mr_port->mp_data;
if (mid->mid_connect_method_scalari_scalaro == NULL)
printf("no connect_method_scalari_scalaro method "
"for darwin_iokit_class %s\n", mid->mid_name);
else
return (mid->mid_connect_method_scalari_scalaro)(args);
}
return mach_iokit_error(args, MACH_IOKIT_ENODEV);
}
int
mach_io_connect_get_service(args)
struct mach_trap_args *args;
{
mach_io_connect_get_service_request_t *req = args->smsg;
mach_io_connect_get_service_reply_t *rep = args->rmsg;
size_t *msglen = args->rsize;
struct lwp *l = args->l;
struct mach_port *mp;
struct mach_right *mr;
mach_port_t mn;
mn = req->req_msgh.msgh_remote_port;
if ((mr = mach_right_check(mn, l, MACH_PORT_TYPE_ALL_RIGHTS)) == NULL)
return mach_iokit_error(args, MACH_IOKIT_EPERM);
mp = mach_port_get();
mp->mp_flags |= MACH_MP_INKERNEL;
if (mr->mr_port->mp_datatype == MACH_MP_IOKIT_DEVCLASS) {
mp->mp_datatype = MACH_MP_IOKIT_DEVCLASS;
mp->mp_data = mr->mr_port->mp_data;
}
mr = mach_right_get(mp, l, MACH_PORT_TYPE_SEND, 0);
/*
* XXX Bump the refcount to workaround an emulation bug
* that causes Windowserver to release the port too early.
*/
mr->mr_refcount++;
rep->rep_msgh.msgh_bits =
MACH_MSGH_REPLY_LOCAL_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE) |
MACH_MSGH_BITS_COMPLEX;
rep->rep_msgh.msgh_size = sizeof(*rep) - sizeof(rep->rep_trailer);
rep->rep_msgh.msgh_local_port = req->req_msgh.msgh_local_port;
rep->rep_msgh.msgh_id = req->req_msgh.msgh_id + 100;
rep->rep_body.msgh_descriptor_count = 1;
rep->rep_service.name = (mach_port_t)mr->mr_name;
rep->rep_service.disposition = 0x11; /* XXX */
rep->rep_trailer.msgh_trailer_size = 8;
*msglen = sizeof(*rep);
return 0;
}
int
mach_io_registry_entry_create_iterator(args)
struct mach_trap_args *args;
{
mach_io_registry_entry_create_iterator_request_t *req = args->smsg;
mach_io_registry_entry_create_iterator_reply_t *rep = args->rmsg;
size_t *msglen = args->rsize;
struct lwp *l = args->l;
struct mach_port *mp;
mach_port_t mn;
struct mach_right *mr;
struct mach_iokit_devclass *mid;
struct mach_device_iterator *mdi;
struct mach_iokit_devclass **midp;
int maxdev, index;
size_t size;
int end_offset;
/*
* req_planeoffset is not used.
* Sanity check req_planecount
*/
end_offset = req->req_planecount +
(sizeof(req->req_options) / sizeof(req->req_plane[0]));
if (MACH_REQMSG_OVERFLOW(args, req->req_plane[end_offset]))
return mach_msg_error(args, EINVAL);
mn = req->req_msgh.msgh_remote_port;
if ((mr = mach_right_check(mn, l, MACH_PORT_TYPE_ALL_RIGHTS)) == NULL)
return mach_iokit_error(args, MACH_IOKIT_EPERM);
if (mr->mr_port->mp_datatype != MACH_MP_IOKIT_DEVCLASS)
return mach_iokit_error(args, MACH_IOKIT_EINVAL);
mid = (struct mach_iokit_devclass *)mr->mr_port->mp_data;
mp = mach_port_get();
mp->mp_flags |= (MACH_MP_INKERNEL | MACH_MP_DATA_ALLOCATED);
mp->mp_datatype = MACH_MP_DEVICE_ITERATOR;
maxdev = sizeof(mach_iokit_devclasses);
size = sizeof(*mdi) + (maxdev * sizeof(struct mach_iokit_devclass *));
mdi = malloc(size, M_EMULDATA, M_WAITOK);
mp->mp_data = mdi;
if (req->req_options & MACH_IOKIT_PARENT_ITERATOR)
index = mach_fill_parent_iterator(mdi, maxdev, 0, mid);
else
index = mach_fill_child_iterator(mdi, maxdev, 0, mid);
/* XXX This is untested */
if (req->req_options & MACH_IOKIT_RECURSIVE_ITERATOR) {
for (midp = mdi->mdi_devices; *midp != NULL; midp++) {
if (req->req_options & MACH_IOKIT_PARENT_ITERATOR)
index = mach_fill_parent_iterator(mdi,
maxdev, index, *midp);
else
index = mach_fill_child_iterator(mdi,
maxdev, index, *midp);
}
}
mdi->mdi_current = 0;
mr = mach_right_get(mp, l, MACH_PORT_TYPE_SEND, 0);
#ifdef DEBUG_MACH
printf("io_registry_entry_create_iterator\n");
#endif
rep->rep_msgh.msgh_bits =
MACH_MSGH_REPLY_LOCAL_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE) |
MACH_MSGH_BITS_COMPLEX;
rep->rep_msgh.msgh_size = sizeof(*rep) - sizeof(rep->rep_trailer);
rep->rep_msgh.msgh_local_port = req->req_msgh.msgh_local_port;
rep->rep_msgh.msgh_id = req->req_msgh.msgh_id + 100;
rep->rep_body.msgh_descriptor_count = 1;
rep->rep_iterator.name = (mach_port_t)mr->mr_name;
rep->rep_iterator.disposition = 0x11; /* XXX */
rep->rep_trailer.msgh_trailer_size = 8;
*msglen = sizeof(*rep);
return 0;
}
int
mach_io_object_conforms_to(args)
struct mach_trap_args *args;
{
mach_io_object_conforms_to_request_t *req = args->smsg;
mach_io_object_conforms_to_reply_t *rep = args->rmsg;
size_t *msglen = args->rsize;
int end_offset;
/*
* req_classnameoffset is not used.
* Sanity check req_classnamecount.
*/
end_offset = req->req_classnamecount;
if (MACH_REQMSG_OVERFLOW(args, req->req_classname[end_offset]))
return mach_msg_error(args, EINVAL);
#ifdef DEBUG_DARWIN
uprintf("Unimplemented mach_io_object_conforms_to\n");
#endif
rep->rep_msgh.msgh_bits =
MACH_MSGH_REPLY_LOCAL_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE);
rep->rep_msgh.msgh_size = sizeof(*rep) - sizeof(rep->rep_trailer);
rep->rep_msgh.msgh_local_port = req->req_msgh.msgh_local_port;
rep->rep_msgh.msgh_id = req->req_msgh.msgh_id + 100;
rep->rep_conforms = 1; /* XXX */
rep->rep_trailer.msgh_trailer_size = 8;
*msglen = sizeof(*rep);
return 0;
}
int
mach_io_service_add_interest_notification(args)
struct mach_trap_args *args;
{
mach_io_service_add_interest_notification_request_t *req = args->smsg;
mach_io_service_add_interest_notification_reply_t *rep = args->rmsg;
size_t *msglen = args->rsize;
struct lwp *l = args->l;
struct mach_port *mp;
struct mach_right *mr;
int end_offset;
int item_size, refitem_size;
/*
* req_typeofinterestoffset is not used.
* Sanity check req_typeofinterestcount and req_refcount
*/
item_size = sizeof(req->req_typeofinterest[0]);
refitem_size = sizeof(req->req_ref[0]);
end_offset = req->req_typeofinterestcount +
(sizeof(req->req_refcount) / item_size) +
(req->req_refcount * refitem_size / item_size);
if (MACH_REQMSG_OVERFLOW(args, req->req_typeofinterest[end_offset]))
return mach_msg_error(args, EINVAL);
mp = mach_port_get();
mp->mp_flags |= MACH_MP_INKERNEL;
mr = mach_right_get(mp, l, MACH_PORT_TYPE_SEND, 0);
#ifdef DEBUG_DARWIN
uprintf("Unimplemented mach_io_service_add_interest_notification\n");
#endif
rep->rep_msgh.msgh_bits =
MACH_MSGH_REPLY_LOCAL_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE) |
MACH_MSGH_BITS_COMPLEX;
rep->rep_msgh.msgh_size = sizeof(*rep) - sizeof(rep->rep_trailer);
rep->rep_msgh.msgh_local_port = req->req_msgh.msgh_local_port;
rep->rep_msgh.msgh_id = req->req_msgh.msgh_id + 100;
rep->rep_body.msgh_descriptor_count = 1;
rep->rep_notification.name = (mach_port_t)mr->mr_name;
rep->rep_notification.disposition = 0x11; /* XXX */
rep->rep_trailer.msgh_trailer_size = 8;
*msglen = sizeof(*rep);
return 0;
}
int
mach_io_connect_set_notification_port(args)
struct mach_trap_args *args;
{
mach_io_connect_set_notification_port_request_t *req = args->smsg;
mach_io_connect_set_notification_port_reply_t *rep = args->rmsg;
struct lwp *l = args->l;
size_t *msglen = args->rsize;
mach_port_t mnn, mn;
struct mach_right *mrn;
struct mach_right *mr;
struct mach_iokit_devclass *mid;
#ifdef DEBUG_DARWIN
printf("mach_io_connect_set_notification_port\n");
#endif
mnn = req->req_port.name;
if ((mrn = mach_right_check(mnn, l, MACH_PORT_TYPE_ALL_RIGHTS)) == NULL)
return mach_msg_error(args, EINVAL);
mn = req->req_msgh.msgh_remote_port;
if ((mr = mach_right_check(mn, l, MACH_PORT_TYPE_ALL_RIGHTS)) == NULL)
return mach_msg_error(args, EINVAL);
if (mr->mr_port->mp_datatype != MACH_MP_IOKIT_DEVCLASS)
return mach_msg_error(args, EINVAL);
#ifdef DEBUG_DARWIN
printf("notification on right %p, name %x\n", mrn, mrn->mr_name);
#endif
mid = (struct mach_iokit_devclass *)mr->mr_port->mp_data;
mid->mid_notify = mrn;
rep->rep_msgh.msgh_bits =
MACH_MSGH_REPLY_LOCAL_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE);
rep->rep_msgh.msgh_size = sizeof(*rep) - sizeof(rep->rep_trailer);
rep->rep_msgh.msgh_local_port = req->req_msgh.msgh_local_port;
rep->rep_msgh.msgh_id = req->req_msgh.msgh_id + 100;
rep->rep_trailer.msgh_trailer_size = 8;
*msglen = sizeof(*rep);
return 0;
}
int
mach_io_registry_get_root_entry(args)
struct mach_trap_args *args;
{
mach_io_registry_get_root_entry_request_t *req = args->smsg;
mach_io_registry_get_root_entry_reply_t *rep = args->rmsg;
size_t *msglen = args->rsize;
struct lwp *l = args->l;
struct mach_port *mp;
struct mach_right *mr;
mp = mach_port_get();
mp->mp_flags |= MACH_MP_INKERNEL;
mp->mp_datatype = MACH_MP_IOKIT_DEVCLASS;
mp->mp_data = &mach_ioroot_devclass;
mr = mach_right_get(mp, l, MACH_PORT_TYPE_SEND, 0);
rep->rep_msgh.msgh_bits =
MACH_MSGH_REPLY_LOCAL_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE) |
MACH_MSGH_BITS_COMPLEX;
rep->rep_msgh.msgh_size = sizeof(*rep) - sizeof(rep->rep_trailer);
rep->rep_msgh.msgh_local_port = req->req_msgh.msgh_local_port;
rep->rep_msgh.msgh_id = req->req_msgh.msgh_id + 100;
rep->rep_body.msgh_descriptor_count = 1;
rep->rep_root.name = (mach_port_t)mr->mr_name;
rep->rep_root.disposition = 0x11; /* XXX */
rep->rep_trailer.msgh_trailer_size = 8;
*msglen = sizeof(*rep);
return 0;
}
int
mach_io_registry_entry_get_child_iterator(args)
struct mach_trap_args *args;
{
mach_io_registry_entry_get_child_iterator_request_t *req = args->smsg;
mach_io_registry_entry_get_child_iterator_reply_t *rep = args->rmsg;
size_t *msglen = args->rsize;
struct lwp *l = args->l;
struct mach_port *mp;
struct mach_right *mr;
mach_port_t mn;
struct mach_iokit_devclass *mid;
struct mach_device_iterator *mdi;
int maxdev;
size_t size;
int end_offset;
/*
* req_planeoffset is not used.
* Sanity check req_planecount.
*/
end_offset = req->req_planecount;
if (MACH_REQMSG_OVERFLOW(args, req->req_plane[end_offset]))
return mach_msg_error(args, EINVAL);
mn = req->req_msgh.msgh_remote_port;
if ((mr = mach_right_check(mn, l, MACH_PORT_TYPE_ALL_RIGHTS)) == NULL)
return mach_iokit_error(args, MACH_IOKIT_EPERM);
if (mr->mr_port->mp_datatype != MACH_MP_IOKIT_DEVCLASS)
return mach_iokit_error(args, MACH_IOKIT_EINVAL);
mid = (struct mach_iokit_devclass *)mr->mr_port->mp_data;
mp = mach_port_get();
mp->mp_flags |= (MACH_MP_INKERNEL | MACH_MP_DATA_ALLOCATED);
mp->mp_datatype = MACH_MP_DEVICE_ITERATOR;
maxdev = sizeof(mach_iokit_devclasses);
size = sizeof(*mdi) + (maxdev * sizeof(struct mach_iokit_devclass *));
mdi = malloc(size, M_EMULDATA, M_WAITOK);
mp->mp_data = mdi;
(void)mach_fill_child_iterator(mdi, maxdev, 0, mid);
mdi->mdi_current = 0;
mr = mach_right_get(mp, l, MACH_PORT_TYPE_SEND, 0);
rep->rep_msgh.msgh_bits =
MACH_MSGH_REPLY_LOCAL_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE) |
MACH_MSGH_BITS_COMPLEX;
rep->rep_msgh.msgh_size = sizeof(*rep) - sizeof(rep->rep_trailer);
rep->rep_msgh.msgh_local_port = req->req_msgh.msgh_local_port;
rep->rep_msgh.msgh_id = req->req_msgh.msgh_id + 100;
rep->rep_body.msgh_descriptor_count = 1;
rep->rep_iterator.name = (mach_port_t)mr->mr_name;
rep->rep_iterator.disposition = 0x11; /* XXX */
rep->rep_trailer.msgh_trailer_size = 8;
*msglen = sizeof(*rep);
return 0;
}
int
mach_io_registry_entry_get_name_in_plane(args)
struct mach_trap_args *args;
{
mach_io_registry_entry_get_name_in_plane_request_t *req = args->smsg;
mach_io_registry_entry_get_name_in_plane_reply_t *rep = args->rmsg;
size_t *msglen = args->rsize;
struct lwp *l = args->l;
struct mach_right *mr;
mach_port_t mn;
struct mach_iokit_devclass *mid;
int end_offset;
/*
* req_planeoffset is not used.
* Sanity check req_planecount.
*/
end_offset = req->req_planecount;
if (MACH_REQMSG_OVERFLOW(args, req->req_plane[end_offset]))
return mach_msg_error(args, EINVAL);
mn = req->req_msgh.msgh_remote_port;
if ((mr = mach_right_check(mn, l, MACH_PORT_TYPE_ALL_RIGHTS)) == NULL)
return mach_iokit_error(args, MACH_IOKIT_EPERM);
if (mr->mr_port->mp_datatype != MACH_MP_IOKIT_DEVCLASS)
return mach_iokit_error(args, MACH_IOKIT_EINVAL);
mid = mr->mr_port->mp_data;
rep->rep_msgh.msgh_bits =
MACH_MSGH_REPLY_LOCAL_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE);
rep->rep_msgh.msgh_size = sizeof(*rep) - sizeof(rep->rep_trailer);
rep->rep_msgh.msgh_local_port = req->req_msgh.msgh_local_port;
rep->rep_msgh.msgh_id = req->req_msgh.msgh_id + 100;
rep->rep_namecount = strlen(mid->mid_name);
if (rep->rep_namecount >= 128)
rep->rep_namecount = 128;
memcpy(&rep->rep_name, mid->mid_name, rep->rep_namecount);
rep->rep_trailer.msgh_trailer_size = 8;
*msglen = sizeof(*rep);
return 0;
}
int
mach_io_object_get_class(args)
struct mach_trap_args *args;
{
mach_io_object_get_class_request_t *req = args->smsg;
mach_io_object_get_class_reply_t *rep = args->rmsg;
size_t *msglen = args->rsize;
char classname[] = "unknownClass";
rep->rep_msgh.msgh_bits =
MACH_MSGH_REPLY_LOCAL_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE);
rep->rep_msgh.msgh_size = sizeof(*rep) - sizeof(rep->rep_trailer);
rep->rep_msgh.msgh_local_port = req->req_msgh.msgh_local_port;
rep->rep_msgh.msgh_id = req->req_msgh.msgh_id + 100;
/* XXX Just return a dummy name for now */
rep->rep_namecount = strlen(classname);
if (rep->rep_namecount >= 128)
rep->rep_namecount = 128;
memcpy(&rep->rep_name, classname, rep->rep_namecount);
rep->rep_trailer.msgh_trailer_size = 8;
*msglen = sizeof(*rep);
return 0;
}
int
mach_io_registry_entry_get_location_in_plane(args)
struct mach_trap_args *args;
{
mach_io_registry_entry_get_location_in_plane_request_t *req =
args->smsg;
mach_io_registry_entry_get_location_in_plane_reply_t *rep = args->rmsg;
size_t *msglen = args->rsize;
char location[] = "";
int end_offset;
/*
* req_nameoffset is not used.
* Sanity check req_namecount.
*/
end_offset = req->req_namecount;
if (MACH_REQMSG_OVERFLOW(args, req->req_plane[end_offset]))
return mach_msg_error(args, EINVAL);
rep->rep_msgh.msgh_bits =
MACH_MSGH_REPLY_LOCAL_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE);
rep->rep_msgh.msgh_size = sizeof(*rep) - sizeof(rep->rep_trailer);
rep->rep_msgh.msgh_local_port = req->req_msgh.msgh_local_port;
rep->rep_msgh.msgh_id = req->req_msgh.msgh_id + 100;
/* XXX Just return a dummy name for now */
rep->rep_locationcount = sizeof(location);
memcpy(&rep->rep_location, location, sizeof(location));
rep->rep_trailer.msgh_trailer_size = 8;
*msglen = sizeof(*rep);
return 0;
}
int
mach_io_registry_entry_get_properties(args)
struct mach_trap_args *args;
{
mach_io_registry_entry_get_properties_request_t *req = args->smsg;
mach_io_registry_entry_get_properties_reply_t *rep = args->rmsg;
size_t *msglen = args->rsize;
struct lwp *l = args->l;
int error;
vaddr_t va;
size_t size;
mach_port_t mn;
struct mach_right *mr;
struct mach_iokit_devclass *mid;
mn = req->req_msgh.msgh_remote_port;
if ((mr = mach_right_check(mn, l, MACH_PORT_TYPE_ALL_RIGHTS)) == NULL)
return mach_iokit_error(args, MACH_IOKIT_EPERM);
if (mr->mr_port->mp_datatype != MACH_MP_IOKIT_DEVCLASS)
return mach_iokit_error(args, MACH_IOKIT_EINVAL);
mid = mr->mr_port->mp_data;
if (mid->mid_properties == NULL)
return mach_iokit_error(args, MACH_IOKIT_EINVAL);
size = strlen(mid->mid_properties) + 1; /* Include trailing zero */
va = vm_map_min(&l->l_proc->p_vmspace->vm_map);
if ((error = uvm_map(&l->l_proc->p_vmspace->vm_map, &va,
round_page(size), NULL, UVM_UNKNOWN_OFFSET, 0,
UVM_MAPFLAG(UVM_PROT_RW, UVM_PROT_ALL,
UVM_INH_COPY, UVM_ADV_NORMAL, UVM_FLAG_COPYONW))) != 0)
return mach_msg_error(args, error);
#ifdef DEBUG_MACH
printf("pid %d.%d: copyout iokit properties at %p\n",
l->l_proc->p_pid, l->l_lid, (void *)va);
#endif
if ((error = copyout(mid->mid_properties, (void *)va, size)) != 0) {
#ifdef DEBUG_MACH
printf("pid %d.%d: copyout iokit properties failed\n",
l->l_proc->p_pid, l->l_lid);
#endif
}
rep->rep_msgh.msgh_bits =
MACH_MSGH_REPLY_LOCAL_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE) |
MACH_MSGH_BITS_COMPLEX;
rep->rep_msgh.msgh_size = sizeof(*rep) - sizeof(rep->rep_trailer);
rep->rep_msgh.msgh_local_port = req->req_msgh.msgh_local_port;
rep->rep_msgh.msgh_id = req->req_msgh.msgh_id + 100;
rep->rep_body.msgh_descriptor_count = 1;
rep->rep_properties.address = (void *)va;
rep->rep_properties.size = size;
rep->rep_properties.deallocate = 0; /* XXX */
rep->rep_properties.copy = 2; /* XXX */
rep->rep_properties.pad1 = 1; /* XXX */
rep->rep_properties.type = 1; /* XXX */
rep->rep_count = size;
rep->rep_trailer.msgh_trailer_size = 8;
*msglen = sizeof(*rep);
return 0;
}
int
mach_io_registry_entry_get_property(args)
struct mach_trap_args *args;
{
mach_io_registry_entry_get_property_request_t *req = args->smsg;
mach_io_registry_entry_get_property_reply_t *rep = args->rmsg;
size_t *msglen = args->rsize;
struct lwp *l = args->l;
int error;
vaddr_t va;
size_t size;
mach_port_t mn;
struct mach_right *mr;
struct mach_iokit_devclass *mid;
struct mach_iokit_property *mip;
int end_offset;
/*
* req_property_nameoffset is not used.
* Sanity check req_property_namecount.
*/
end_offset = req->req_property_namecount;
if (MACH_REQMSG_OVERFLOW(args, req->req_property_name[end_offset]))
return mach_iokit_error(args, MACH_IOKIT_EINVAL);
/* Find the port */
mn = req->req_msgh.msgh_remote_port;
if ((mr = mach_right_check(mn, l, MACH_PORT_TYPE_ALL_RIGHTS)) == NULL)
return mach_iokit_error(args, MACH_IOKIT_EPERM);
/* Find the devclass information */
if (mr->mr_port->mp_datatype != MACH_MP_IOKIT_DEVCLASS)
return mach_iokit_error(args, MACH_IOKIT_EINVAL);
mid = mr->mr_port->mp_data;
if (mid->mid_properties_array == NULL)
return mach_iokit_error(args, MACH_IOKIT_EINVAL);
/* Lookup the property name */
for (mip = mid->mid_properties_array; mip->mip_name; mip++)
if (memcmp(mip->mip_name, req->req_property_name,
req->req_property_namecount) == 0)
break;
if (mip->mip_value == NULL)
return mach_iokit_error(args, MACH_IOKIT_ENOENT);
/* And copyout its associated value */
va = vm_map_min(&l->l_proc->p_vmspace->vm_map);
size = strlen(mip->mip_value) + 1; /* Include trailing zero */
if ((error = uvm_map(&l->l_proc->p_vmspace->vm_map, &va,
round_page(size), NULL, UVM_UNKNOWN_OFFSET, 0,
UVM_MAPFLAG(UVM_PROT_RW, UVM_PROT_ALL,
UVM_INH_COPY, UVM_ADV_NORMAL, UVM_FLAG_COPYONW))) != 0)
return mach_msg_error(args, error);
#ifdef DEBUG_MACH
printf("pid %d.%d: copyout iokit property at %p\n",
l->l_proc->p_pid, l->l_lid, (void *)va);
#endif
if ((error = copyout(mip->mip_value, (void *)va, size)) != 0) {
#ifdef DEBUG_MACH
printf("pid %d.%d: copyout iokit property failed\n",
l->l_proc->p_pid, l->l_lid);
#endif
}
rep->rep_msgh.msgh_bits =
MACH_MSGH_REPLY_LOCAL_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE) |
MACH_MSGH_BITS_COMPLEX;
rep->rep_msgh.msgh_size = sizeof(*rep) - sizeof(rep->rep_trailer);
rep->rep_msgh.msgh_local_port = req->req_msgh.msgh_local_port;
rep->rep_msgh.msgh_id = req->req_msgh.msgh_id + 100;
rep->rep_body.msgh_descriptor_count = 1;
rep->rep_properties.address = (void *)va;
rep->rep_properties.size = size;
rep->rep_properties.deallocate = 0; /* XXX */
rep->rep_properties.copy = 2; /* XXX */
rep->rep_properties.pad1 = 0; /* XXX */
rep->rep_properties.type = 0; /* XXX */
rep->rep_properties_count = size;
rep->rep_trailer.msgh_trailer_size = 8;
*msglen = sizeof(*rep);
return 0;
}
int
mach_io_registry_entry_get_path(args)
struct mach_trap_args *args;
{
mach_io_registry_entry_get_path_request_t *req = args->smsg;
mach_io_registry_entry_get_path_reply_t *rep = args->rmsg;
size_t *msglen = args->rsize;
char location[] = ":/GossamerPE/pci@80000000/AppleGracklePCI/"
"ATY,264LT-G@11/.Display_Video_ATI_mach64-01018002/"
"display0/AppleBacklightDisplay";
char *cp;
size_t len, plen;
int end_offset;
/*
* req_offset is not used.
* Sanity check req_count.
*/
end_offset = req->req_count;
if (MACH_REQMSG_OVERFLOW(args, req->req_plane[end_offset]))
return mach_iokit_error(args, MACH_IOKIT_EINVAL);
/* XXX Just return a dummy name for now */
len = req->req_count + strlen(location) - 1;
/* Sanity check for len */
if (len > 512)
return mach_iokit_error(args, MACH_IOKIT_EINVAL);
plen = (len & ~0x3UL) + 4; /* Round to an int */
rep->rep_msgh.msgh_bits =
MACH_MSGH_REPLY_LOCAL_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE);
rep->rep_msgh.msgh_size = sizeof(*rep) +
(plen - 512) - sizeof(rep->rep_trailer);
rep->rep_msgh.msgh_local_port = req->req_msgh.msgh_local_port;
rep->rep_msgh.msgh_id = req->req_msgh.msgh_id + 100;
rep->rep_retval = 0;
rep->rep_count = len;
cp = &rep->rep_path[0];
memcpy(cp, &req->req_plane, req->req_count);
cp += (req->req_count - 1); /* overwrite trailing \0 */
memcpy(cp, location, strlen(location));
cp += strlen(location);
*cp = '\0';
rep->rep_path[plen + 7] = 8; /* Trailer */
*msglen = sizeof(*rep) + (plen - 512);
return 0;
}
int
mach_io_connect_map_memory(args)
struct mach_trap_args *args;
{
mach_io_connect_map_memory_request_t *req = args->smsg;
struct lwp *l = args->l;
mach_port_t mn;
struct mach_right *mr;
struct mach_iokit_devclass *mid;
mn = req->req_msgh.msgh_remote_port;
if ((mr = mach_right_check(mn, l, MACH_PORT_TYPE_ALL_RIGHTS)) == NULL)
return mach_iokit_error(args, MACH_IOKIT_EPERM);
if (mr->mr_port->mp_datatype == MACH_MP_IOKIT_DEVCLASS) {
mid = mr->mr_port->mp_data;
if (mid->mid_connect_map_memory == NULL)
printf("no connect_map_memory method "
"for darwin_iokit_class %s\n", mid->mid_name);
else
return (mid->mid_connect_map_memory)(args);
}
return mach_iokit_error(args, MACH_IOKIT_ENODEV);
}
int
mach_io_iterator_reset(args)
struct mach_trap_args *args;
{
mach_io_iterator_reset_request_t *req = args->smsg;
mach_io_iterator_reset_reply_t *rep = args->rmsg;
size_t *msglen = args->rsize;
struct lwp *l = args->l;
mach_port_t mn;
struct mach_right *mr;
struct mach_device_iterator *mdi;
mn = req->req_msgh.msgh_remote_port;
if ((mr = mach_right_check(mn, l, MACH_PORT_TYPE_ALL_RIGHTS)) == NULL)
return mach_iokit_error(args, MACH_IOKIT_EPERM);
if (mr->mr_port->mp_datatype != MACH_MP_DEVICE_ITERATOR)
return mach_iokit_error(args, MACH_IOKIT_EINVAL);
mdi = mr->mr_port->mp_data;
mdi->mdi_current = 0;
rep->rep_msgh.msgh_bits =
MACH_MSGH_REPLY_LOCAL_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE);
rep->rep_msgh.msgh_size = sizeof(*rep) - sizeof(rep->rep_trailer);
rep->rep_msgh.msgh_local_port = req->req_msgh.msgh_local_port;
rep->rep_msgh.msgh_id = req->req_msgh.msgh_id + 100;
rep->rep_retval = 0;
rep->rep_trailer.msgh_trailer_size = 8;
*msglen = sizeof(*rep);
return 0;
}
int
mach_io_connect_method_scalari_structo(args)
struct mach_trap_args *args;
{
mach_io_connect_method_scalari_structo_request_t *req = args->smsg;
struct lwp *l = args->l;
mach_port_t mn;
struct mach_right *mr;
struct mach_iokit_devclass *mid;
int end_offset;
/* Sanity check req_incount */
end_offset = req->req_incount +
(sizeof(req->req_outcount) / sizeof(req->req_in[0]));
if (MACH_REQMSG_OVERFLOW(args, req->req_in[end_offset]))
return mach_msg_error(args, EINVAL);
/* Sanity check req_outcount */
if (req->req_outcount > 4096)
return mach_msg_error(args, EINVAL);
mn = req->req_msgh.msgh_remote_port;
if ((mr = mach_right_check(mn, l, MACH_PORT_TYPE_ALL_RIGHTS)) == NULL)
return mach_iokit_error(args, MACH_IOKIT_EPERM);
if (mr->mr_port->mp_datatype == MACH_MP_IOKIT_DEVCLASS) {
mid = mr->mr_port->mp_data;
if (mid->mid_connect_method_scalari_structo == NULL)
printf("no connect_method_scalari_structo method "
"for darwin_iokit_class %s\n", mid->mid_name);
else
return (mid->mid_connect_method_scalari_structo)(args);
}
return mach_iokit_error(args, MACH_IOKIT_ENODEV);
}
int
mach_io_connect_method_structi_structo(args)
struct mach_trap_args *args;
{
mach_io_connect_method_structi_structo_request_t *req = args->smsg;
struct lwp *l = args->l;
mach_port_t mn;
struct mach_right *mr;
struct mach_iokit_devclass *mid;
int end_offset;
/* Sanity check req_incount */
end_offset = req->req_incount +
(sizeof(req->req_outcount) / sizeof(req->req_in[0]));
if (MACH_REQMSG_OVERFLOW(args, req->req_in[end_offset]))
return mach_msg_error(args, EINVAL);
/* Sanity check req_outcount */
if (req->req_outcount > 4096)
return mach_msg_error(args, EINVAL);
mn = req->req_msgh.msgh_remote_port;
if ((mr = mach_right_check(mn, l, MACH_PORT_TYPE_ALL_RIGHTS)) == NULL)
return mach_iokit_error(args, MACH_IOKIT_EPERM);
if (mr->mr_port->mp_datatype == MACH_MP_IOKIT_DEVCLASS) {
mid = mr->mr_port->mp_data;
if (mid->mid_connect_method_structi_structo == NULL)
printf("no connect_method_structi_structo method "
"for darwin_iokit_class %s\n", mid->mid_name);
else
return (mid->mid_connect_method_structi_structo)(args);
}
return mach_iokit_error(args, MACH_IOKIT_ENODEV);
}
int
mach_io_connect_set_properties(args)
struct mach_trap_args *args;
{
mach_io_connect_set_properties_request_t *req = args->smsg;
mach_io_connect_set_properties_reply_t *rep = args->rmsg;
size_t *msglen = args->rsize;
#ifdef DEBUG_MACH
uprintf("Unimplemented mach_io_connect_set_properties\n");
#endif
rep->rep_msgh.msgh_bits =
MACH_MSGH_REPLY_LOCAL_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE);
rep->rep_msgh.msgh_size = sizeof(*rep) - sizeof(rep->rep_trailer);
rep->rep_msgh.msgh_local_port = req->req_msgh.msgh_local_port;
rep->rep_msgh.msgh_id = req->req_msgh.msgh_id + 100;
rep->rep_trailer.msgh_trailer_size = 8;
*msglen = sizeof(*rep);
return 0;
}
int
mach_io_service_close(args)
struct mach_trap_args *args;
{
mach_io_service_close_request_t *req = args->smsg;
mach_io_service_close_reply_t *rep = args->rmsg;
size_t *msglen = args->rsize;
#ifdef DEBUG_MACH
uprintf("Unimplemented mach_io_service_close\n");
#endif
rep->rep_msgh.msgh_bits =
MACH_MSGH_REPLY_LOCAL_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE);
rep->rep_msgh.msgh_size = sizeof(*rep) - sizeof(rep->rep_trailer);
rep->rep_msgh.msgh_local_port = req->req_msgh.msgh_local_port;
rep->rep_msgh.msgh_id = req->req_msgh.msgh_id + 100;
rep->rep_retval = 0;
rep->rep_trailer.msgh_trailer_size = 8;
*msglen = sizeof(*rep);
return 0;
}
int
mach_io_connect_add_client(args)
struct mach_trap_args *args;
{
mach_io_connect_add_client_request_t *req = args->smsg;
mach_io_connect_add_client_reply_t *rep = args->rmsg;
size_t *msglen = args->rsize;
#ifdef DEBUG_MACH
uprintf("Unimplemented mach_io_connect_add_client\n");
#endif
rep->rep_msgh.msgh_bits =
MACH_MSGH_REPLY_LOCAL_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE);
rep->rep_msgh.msgh_size = sizeof(*rep) - sizeof(rep->rep_trailer);
rep->rep_msgh.msgh_local_port = req->req_msgh.msgh_local_port;
rep->rep_msgh.msgh_id = req->req_msgh.msgh_id + 100;
rep->rep_retval = 0;
rep->rep_trailer.msgh_trailer_size = 8;
*msglen = sizeof(*rep);
return 0;
}
int
mach_io_connect_method_scalari_structi(args)
struct mach_trap_args *args;
{
mach_io_connect_method_scalari_structi_request_t *req = args->smsg;
struct lwp *l = args->l;
mach_port_t mn;
struct mach_right *mr;
struct mach_iokit_devclass *mid;
int end_offset;
int scalar_size, struct_size;
/* Sanity check req_incount and req_instructcount */
scalar_size = sizeof(req->req_in[0]);
struct_size = sizeof(req->req_instruct[0]);
end_offset = req->req_incount +
(sizeof(req->req_instructcount) / scalar_size) +
(req->req_instructcount * struct_size / scalar_size);
if (MACH_REQMSG_OVERFLOW(args, req->req_in[end_offset]))
return mach_msg_error(args, EINVAL);
mn = req->req_msgh.msgh_remote_port;
if ((mr = mach_right_check(mn, l, MACH_PORT_TYPE_ALL_RIGHTS)) == NULL)
return mach_iokit_error(args, MACH_IOKIT_EPERM);
if (mr->mr_port->mp_datatype == MACH_MP_IOKIT_DEVCLASS) {
mid = mr->mr_port->mp_data;
if (mid->mid_connect_method_scalari_structi == NULL)
printf("no connect_method_scalari_structi method "
"for darwin_iokit_class %s\n", mid->mid_name);
else
return (mid->mid_connect_method_scalari_structi)(args);
}
return mach_iokit_error(args, MACH_IOKIT_ENODEV);
}
int
mach_io_registry_entry_from_path(args)
struct mach_trap_args *args;
{
mach_io_registry_entry_from_path_request_t *req = args->smsg;
mach_io_registry_entry_from_path_reply_t *rep = args->rmsg;
size_t *msglen = args->rsize;
struct lwp *l = args->l;
struct mach_port *mp;
struct mach_right *mr;
struct mach_iokit_devclass *mid;
int i, len;
int end_offset;
/*
* req_pathoffset is not used.
* Sanity check req_pathcount.
*/
end_offset = req->req_pathcount;
if (MACH_REQMSG_OVERFLOW(args, req->req_path[end_offset]))
return mach_msg_error(args, EINVAL);
#ifdef DEBUG_MACH
printf("mach_io_registry_entry_from_path: path = %s\n", req->req_path);
#endif
mp = mach_port_get();
mp->mp_flags |= MACH_MP_INKERNEL;
mr = mach_right_get(mp, l, MACH_PORT_TYPE_SEND, 0);
i = 0;
while ((mid = mach_iokit_devclasses[i++]) != NULL) {
len = strlen(mid->mid_name);
#ifdef DEBUG_MACH
printf("trying \"%s\" vs \"%s\"\n",
&req->req_path[req->req_pathcount - 1 - len],
mid->mid_name);
#endif
if (memcmp(&req->req_path[req->req_pathcount - 1 - len],
mid->mid_name, len) == 0) {
mp->mp_datatype = MACH_MP_IOKIT_DEVCLASS;
mp->mp_data = mid;
break;
}
}
rep->rep_msgh.msgh_bits =
MACH_MSGH_REPLY_LOCAL_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE) |
MACH_MSGH_BITS_COMPLEX;
rep->rep_msgh.msgh_size = sizeof(*rep) - sizeof(rep->rep_trailer);
rep->rep_msgh.msgh_local_port = req->req_msgh.msgh_local_port;
rep->rep_msgh.msgh_id = req->req_msgh.msgh_id + 100;
rep->rep_body.msgh_descriptor_count = 1;
rep->rep_entry.name = (mach_port_t)mr->mr_name;
rep->rep_entry.disposition = 0x11; /* XXX */
rep->rep_trailer.msgh_trailer_size = 8;
*msglen = sizeof(*rep);
return 0;
}
int
mach_io_registry_entry_get_parent_iterator(args)
struct mach_trap_args *args;
{
mach_io_registry_entry_get_parent_iterator_request_t *req = args->smsg;
mach_io_registry_entry_get_parent_iterator_reply_t *rep = args->rmsg;
size_t *msglen = args->rsize;
struct lwp *l = args->l;
struct mach_port *mp;
struct mach_right *mr;
struct mach_iokit_devclass *mid;
struct mach_device_iterator *mdi;
mach_port_t mn;
int maxdev;
size_t size;
int end_offset;
/*
* req_offset is unused
* Sanity check req_count
*/
end_offset = req->req_count;
if (MACH_REQMSG_OVERFLOW(args, req->req_plane[end_offset]))
return mach_msg_error(args, EINVAL);
#ifdef DEBUG_MACH
printf("mach_io_registry_entry_get_parent_iterator: plane = %s\n",
req->req_plane);
#endif
mn = req->req_msgh.msgh_remote_port;
if ((mr = mach_right_check(mn, l, MACH_PORT_TYPE_ALL_RIGHTS)) == NULL)
return mach_iokit_error(args, MACH_IOKIT_EPERM);
if (mr->mr_port->mp_datatype != MACH_MP_IOKIT_DEVCLASS)
return mach_iokit_error(args, MACH_IOKIT_EINVAL);
mid = mr->mr_port->mp_data;
mp = mach_port_get();
mp->mp_flags |= (MACH_MP_INKERNEL | MACH_MP_DATA_ALLOCATED);
mp->mp_datatype = MACH_MP_DEVICE_ITERATOR;
maxdev = sizeof(mach_iokit_devclasses);
size = sizeof(*mdi) + (maxdev * sizeof(struct mach_iokit_devclass *));
mdi = malloc(size, M_EMULDATA, M_WAITOK);
mp->mp_data = mdi;
(void)mach_fill_parent_iterator(mdi, maxdev, 0, mid);
mdi->mdi_current = 0;
mr = mach_right_get(mp, l, MACH_PORT_TYPE_SEND, 0);
rep->rep_msgh.msgh_bits =
MACH_MSGH_REPLY_LOCAL_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE) |
MACH_MSGH_BITS_COMPLEX;
rep->rep_msgh.msgh_size = sizeof(*rep) - sizeof(rep->rep_trailer);
rep->rep_msgh.msgh_local_port = req->req_msgh.msgh_local_port;
rep->rep_msgh.msgh_id = req->req_msgh.msgh_id + 100;
rep->rep_body.msgh_descriptor_count = 1;
rep->rep_iterator.name = (mach_port_t)mr->mr_name;
rep->rep_iterator.disposition = 0x11; /* XXX */
rep->rep_trailer.msgh_trailer_size = 8;
*msglen = sizeof(*rep);
return 0;
}
void
mach_iokit_cleanup_notify(mr)
struct mach_right *mr;
{
int i;
struct mach_iokit_devclass *mid;
i = 0;
while ((mid = mach_iokit_devclasses[i++]) != NULL)
if (mid->mid_notify == mr)
mid->mid_notify = NULL;
return;
}
static int
mach_fill_child_iterator(mdi, size, index, mid)
struct mach_device_iterator *mdi;
int size;
int index;
struct mach_iokit_devclass *mid;
{
struct mach_iokit_devclass **midp;
struct mach_iokit_devclass **midq;
for (midp = mach_iokit_devclasses; *midp != NULL; midp++) {
for (midq = (*midp)->mid_parent; *midq != NULL; midq++) {
if (*midq == mid) {
mdi->mdi_devices[index++] = *midp;
break;
}
}
#ifdef DIAGNOSTIC
if (index >= size) {
printf("mach_device_iterator overflow\n");
break;
}
#endif
}
mdi->mdi_devices[index] = NULL;
return index;
}
static int
mach_fill_parent_iterator(mdi, size, index, mid)
struct mach_device_iterator *mdi;
int size;
int index;
struct mach_iokit_devclass *mid;
{
struct mach_iokit_devclass **midp;
for (midp = mid->mid_parent; *midp != NULL; midp++) {
mdi->mdi_devices[index++] = *midp;
#ifdef DIAGNOSTIC
if (index >= size) {
printf("mach_device_iterator overflow\n");
break;
}
#endif
}
mdi->mdi_devices[index] = NULL;
return index;
}