#include <kern/telemetry.h>
#include <kern/waitq.h>
#include <kern/sched_prim.h>
+#include <kern/mpsc_queue.h>
#include <sys/mbuf.h>
#include <sys/domain.h>
#include <sys/vnode_internal.h>
/* for remote time api*/
#include <kern/remote_time.h>
+#include <os/log.h>
+#include <sys/log_data.h>
#if CONFIG_MACF
#include <security/mac_framework.h>
#endif
+/* for entitlement check */
+#include <IOKit/IOBSD.h>
+
/* XXX should be in a header file somewhere */
void evsofree(struct socket *);
void evpipefree(struct pipe *);
{
uio_t auio;
user_ssize_t bytecnt;
- long error = 0;
+ int error = 0;
char uio_buf[UIO_SIZEOF(1)];
if (nbyte > INT_MAX) {
auio = uio_createwithbuffer(1, offset, UIO_USERSPACE32, UIO_READ,
&uio_buf[0], sizeof(uio_buf));
}
- uio_addiov(auio, bufp, nbyte);
+ if (uio_addiov(auio, bufp, nbyte) != 0) {
+ *retval = 0;
+ return EINVAL;
+ }
bytecnt = nbyte;
user_ssize_t *retval)
{
uio_t auio;
- long error = 0;
+ int error = 0;
user_ssize_t bytecnt;
char uio_buf[UIO_SIZEOF(1)];
auio = uio_createwithbuffer(1, offset, UIO_USERSPACE32, UIO_WRITE,
&uio_buf[0], sizeof(uio_buf));
}
- uio_addiov(auio, bufp, nbyte);
+ if (uio_addiov(auio, bufp, nbyte) != 0) {
+ *retval = 0;
+ return EINVAL;
+ }
bytecnt = nbyte;
if ((error = fo_write(fp, auio, flags, ctx))) {
break;
}
if (fp->f_type == DTYPE_PIPE) {
- error = fo_ioctl(fp, (int)TIOCSPGRP, (caddr_t)&tmp, &context);
+ error = fo_ioctl(fp, TIOCSPGRP, (caddr_t)&tmp, &context);
break;
}
if (tmp <= 0) {
tmp = p1->p_pgrpid;
proc_rele(p1);
}
- error = fo_ioctl(fp, (int)TIOCSPGRP, (caddr_t)&tmp, &context);
+ error = fo_ioctl(fp, TIOCSPGRP, (caddr_t)&tmp, &context);
break;
case FIOGETOWN:
bits = iptr[i / NFDBITS];
while ((j = ffs(bits)) && (fd = i + --j) < nfd) {
- bits &= ~(1 << j);
+ bits &= ~(1U << j);
if (fd < fdp->fd_nfiles) {
fp = fdp->fd_ofiles[fd];
/* The select; set the bit, if true */
if (fp->f_ops && fp->f_type
&& fo_select(fp, flag[msk], rl_ptr, &context)) {
- optr[fd / NFDBITS] |= (1 << (fd % NFDBITS));
+ optr[fd / NFDBITS] |= (1U << (fd % NFDBITS));
n++;
}
if (sel_pass == SEL_FIRSTPASS) {
return 0;
}
-int poll_callback(struct kqueue *, struct kevent_internal_s *, void *);
-
-struct poll_continue_args {
- user_addr_t pca_fds;
- u_int pca_nfds;
- u_int pca_rfds;
-};
+static int poll_callback(struct kevent_qos_s *, kevent_ctx_t);
int
poll(struct proc *p, struct poll_args *uap, int32_t *retval)
int
poll_nocancel(struct proc *p, struct poll_nocancel_args *uap, int32_t *retval)
{
- struct poll_continue_args *cont;
- struct pollfd *fds;
- struct kqueue *kq;
- struct timeval atv;
+ struct pollfd *fds = NULL;
+ struct kqueue *kq = NULL;
int ncoll, error = 0;
u_int nfds = uap->nfds;
u_int rfds = 0;
- u_int i;
- size_t ni;
/*
* This is kinda bogus. We have fd limits, but that is not
return EINVAL;
}
- kq = kqueue_alloc(p, 0);
+ kq = kqueue_alloc(p);
if (kq == NULL) {
return EAGAIN;
}
- ni = nfds * sizeof(struct pollfd) + sizeof(struct poll_continue_args);
- MALLOC(cont, struct poll_continue_args *, ni, M_TEMP, M_WAITOK);
- if (NULL == cont) {
- error = EAGAIN;
- goto out;
- }
-
- fds = (struct pollfd *)&cont[1];
- error = copyin(uap->fds, fds, nfds * sizeof(struct pollfd));
- if (error) {
- goto out;
- }
-
- if (uap->timeout != -1) {
- struct timeval rtv;
+ if (nfds) {
+ size_t ni = nfds * sizeof(struct pollfd);
+ MALLOC(fds, struct pollfd *, ni, M_TEMP, M_WAITOK);
+ if (NULL == fds) {
+ error = EAGAIN;
+ goto out;
+ }
- atv.tv_sec = uap->timeout / 1000;
- atv.tv_usec = (uap->timeout % 1000) * 1000;
- if (itimerfix(&atv)) {
- error = EINVAL;
+ error = copyin(uap->fds, fds, nfds * sizeof(struct pollfd));
+ if (error) {
goto out;
}
- getmicrouptime(&rtv);
- timevaladd(&atv, &rtv);
- } else {
- atv.tv_sec = 0;
- atv.tv_usec = 0;
}
/* JMM - all this P_SELECT stuff is bogus */
ncoll = nselcoll;
OSBitOrAtomic(P_SELECT, &p->p_flag);
- for (i = 0; i < nfds; i++) {
+ for (u_int i = 0; i < nfds; i++) {
short events = fds[i].events;
- KNOTE_LOCK_CTX(knlc);
__assert_only int rc;
/* per spec, ignore fd values below zero */
}
/* convert the poll event into a kqueue kevent */
- struct kevent_internal_s kev = {
+ struct kevent_qos_s kev = {
.ident = fds[i].fd,
.flags = EV_ADD | EV_ONESHOT | EV_POLL,
.udata = CAST_USER_ADDR_T(&fds[i])
if (events & (POLLPRI | POLLRDBAND)) {
kev.flags |= EV_OOBAND;
}
- rc = kevent_register(kq, &kev, &knlc);
+ rc = kevent_register(kq, &kev, NULL);
assert((rc & FILTER_REGISTER_WAIT) == 0);
}
if ((kev.flags & EV_ERROR) == 0 &&
(events & (POLLOUT | POLLWRNORM | POLLWRBAND))) {
kev.filter = EVFILT_WRITE;
- rc = kevent_register(kq, &kev, &knlc);
+ rc = kevent_register(kq, &kev, NULL);
assert((rc & FILTER_REGISTER_WAIT) == 0);
}
if (events & POLLWRITE) {
kev.fflags |= NOTE_WRITE;
}
- rc = kevent_register(kq, &kev, &knlc);
+ rc = kevent_register(kq, &kev, NULL);
assert((rc & FILTER_REGISTER_WAIT) == 0);
}
goto done;
}
+ /* scan for, and possibly wait for, the kevents to trigger */
+ kevent_ctx_t kectx = kevent_get_context(current_thread());
+ *kectx = (struct kevent_ctx_s){
+ .kec_process_noutputs = rfds,
+ .kec_process_flags = KEVENT_FLAG_POLL,
+ .kec_deadline = 0, /* wait forever */
+ };
+
/*
* If any events have trouble registering, an event has fired and we
- * shouldn't wait for events in kqueue_scan -- use the current time as
- * the deadline.
+ * shouldn't wait for events in kqueue_scan.
*/
if (rfds) {
- getmicrouptime(&atv);
+ kectx->kec_process_flags |= KEVENT_FLAG_IMMEDIATE;
+ } else if (uap->timeout != -1) {
+ clock_interval_to_deadline(uap->timeout, NSEC_PER_MSEC,
+ &kectx->kec_deadline);
}
- /* scan for, and possibly wait for, the kevents to trigger */
- cont->pca_fds = uap->fds;
- cont->pca_nfds = nfds;
- cont->pca_rfds = rfds;
- error = kqueue_scan(kq, poll_callback, NULL, cont, NULL, &atv, p);
- rfds = cont->pca_rfds;
+ error = kqueue_scan(kq, kectx->kec_process_flags, kectx, poll_callback);
+ rfds = kectx->kec_process_noutputs;
done:
OSBitAndAtomic(~((uint32_t)P_SELECT), &p->p_flag);
if (error == ERESTART) {
error = EINTR;
}
- if (error == EWOULDBLOCK) {
- error = 0;
- }
if (error == 0) {
error = copyout(fds, uap->fds, nfds * sizeof(struct pollfd));
*retval = rfds;
}
out:
- if (NULL != cont) {
- FREE(cont, M_TEMP);
+ if (NULL != fds) {
+ FREE(fds, M_TEMP);
}
kqueue_dealloc(kq);
return error;
}
-int
-poll_callback(__unused struct kqueue *kq, struct kevent_internal_s *kevp, void *data)
+static int
+poll_callback(struct kevent_qos_s *kevp, kevent_ctx_t kectx)
{
- struct poll_continue_args *cont = (struct poll_continue_args *)data;
struct pollfd *fds = CAST_DOWN(struct pollfd *, kevp->udata);
short prev_revents = fds->revents;
short mask = 0;
}
if (fds->revents != 0 && prev_revents == 0) {
- cont->pca_rfds++;
+ kectx->kec_process_noutputs++;
}
return 0;
for (i = 0; i < nfd; i += NFDBITS) {
bits = iptr[i / NFDBITS];
while ((j = ffs(bits)) && (fd = i + --j) < nfd) {
- bits &= ~(1 << j);
+ bits &= ~(1U << j);
if (fd < fdp->fd_nfiles) {
fp = fdp->fd_ofiles[fd];
error = EBADF;
goto bad;
}
- fp->f_iocount++;
+ os_ref_retain_locked(&fp->f_iocount);
n++;
}
}
for (i = 0; i < nfd; i += NFDBITS) {
bits = iptr[i / NFDBITS];
while ((j = ffs(bits)) && (fd = i + --j) < nfd) {
- bits &= ~(1 << j);
+ bits &= ~(1U << j);
fp = fdp->fd_ofiles[fd];
/*
* If we've already dropped as many as were
continue;
}
- fp->f_iocount--;
- if (fp->f_iocount < 0) {
+ const os_ref_count_t refc = os_ref_release_locked(&fp->f_iocount);
+ if (0 == refc) {
panic("f_iocount overdecrement!");
}
- if (fp->f_iocount == 0) {
+ if (1 == refc) {
/*
* The last iocount is responsible for clearing
* selconfict flag - even if we didn't set it -
*
* Parameters: uuid_buf Pointer to buffer to receive UUID
* timeout Timespec for timout
- * spi SPI, skip sandbox check (temporary)
*
* Returns: 0 Success
* EWOULDBLOCK Timeout is too short
mach_timespec_t mach_ts; /* for IOKit call */
__darwin_uuid_t uuid_kern = {}; /* for IOKit call */
- if (!uap->spi) {
+ /* Check entitlement */
+ if (!IOTaskHasEntitlement(current_task(), "com.apple.private.getprivatesysid")) {
#if CONFIG_EMBEDDED
#if CONFIG_MACF
if ((error = mac_system_check_info(kauth_cred_get(), "hw.uuid")) != 0) {
return error;
}
+/*
+ * Logging
+ *
+ * Description: syscall to access kernel logging from userspace
+ *
+ * Args:
+ * tag - used for syncing with userspace on the version.
+ * flags - flags used by the syscall.
+ * buffer - userspace address of string to copy.
+ * size - size of buffer.
+ */
+int
+log_data(__unused struct proc *p, struct log_data_args *args, int *retval)
+{
+ unsigned int tag = args->tag;
+ unsigned int flags = args->flags;
+ user_addr_t buffer = args->buffer;
+ unsigned int size = args->size;
+ int ret = 0;
+ char *log_msg = NULL;
+ int error;
+ *retval = 0;
+
+ /*
+ * Tag synchronize the syscall version with userspace.
+ * Tag == 0 => flags == OS_LOG_TYPE
+ */
+ if (tag != 0) {
+ return EINVAL;
+ }
+
+ /*
+ * OS_LOG_TYPE are defined in libkern/os/log.h
+ * In userspace they are defined in libtrace/os/log.h
+ */
+ if (flags != OS_LOG_TYPE_DEFAULT &&
+ flags != OS_LOG_TYPE_INFO &&
+ flags != OS_LOG_TYPE_DEBUG &&
+ flags != OS_LOG_TYPE_ERROR &&
+ flags != OS_LOG_TYPE_FAULT) {
+ return EINVAL;
+ }
+
+ if (size == 0) {
+ return EINVAL;
+ }
+
+ /* truncate to OS_LOG_DATA_MAX_SIZE */
+ if (size > OS_LOG_DATA_MAX_SIZE) {
+ printf("%s: WARNING msg is going to be truncated from %u to %u\n", __func__, size, OS_LOG_DATA_MAX_SIZE);
+ size = OS_LOG_DATA_MAX_SIZE;
+ }
+
+ log_msg = kalloc(size);
+ if (!log_msg) {
+ return ENOMEM;
+ }
+
+ error = copyin(buffer, log_msg, size);
+ if (error) {
+ ret = EFAULT;
+ goto out;
+ }
+ log_msg[size - 1] = '\0';
+
+ /*
+ * This will log to dmesg and logd.
+ * The call will fail if the current
+ * process is not a driverKit process.
+ */
+ os_log_driverKit(&ret, OS_LOG_DEFAULT, flags, "%s", log_msg);
+
+out:
+ if (log_msg != NULL) {
+ kfree(log_msg, size);
+ }
+
+ return ret;
+}
+
#if DEVELOPMENT || DEBUG
#if CONFIG_WAITQ_DEBUG
static uint64_t g_wqset_num = 0;
0, 0, sysctl_waitq_set_nelem, "I", "ltable elementis currently used");
+static int
+sysctl_mpsc_test_pingpong SYSCTL_HANDLER_ARGS
+{
+#pragma unused(oidp, arg1, arg2)
+ uint64_t value = 0;
+ int error;
+
+ error = SYSCTL_IN(req, &value, sizeof(value));
+ if (error) {
+ return error;
+ }
+
+ if (error == 0 && req->newptr) {
+ error = mpsc_test_pingpong(value, &value);
+ if (error == 0) {
+ error = SYSCTL_OUT(req, &value, sizeof(value));
+ }
+ }
+
+ return error;
+}
+SYSCTL_PROC(_kern, OID_AUTO, mpsc_test_pingpong, CTLTYPE_QUAD | CTLFLAG_RW | CTLFLAG_LOCKED,
+ 0, 0, sysctl_mpsc_test_pingpong, "Q", "MPSC tests: pingpong");
+
#endif /* DEVELOPMENT || DEBUG */
/*Remote Time api*/
req->oldidx = sizeof(value);
return 0;
}
- if (bt_init_flag) {
+ if (os_atomic_load(&bt_init_flag, acquire)) {
if (req->newptr) {
int new_value = 0;
error = SYSCTL_IN(req, &new_value, sizeof(new_value));
#endif /* CONFIG_MACH_BRIDGE_RECV_TIME */
+#if DEVELOPMENT || DEBUG
+#endif /* DEVELOPMENT || DEBUG */
+
+extern uint32_t task_exc_guard_default;
+
+SYSCTL_INT(_kern, OID_AUTO, task_exc_guard_default,
+ CTLFLAG_RD | CTLFLAG_LOCKED, &task_exc_guard_default, 0, "");
static int
SYSCTL_PROC(_kern, OID_AUTO, sched_thread_set_no_smt,
CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED | CTLFLAG_ANYBODY,
0, 0, sysctl_kern_sched_thread_set_no_smt, "I", "");
-#endif
+#endif /* DEVELOPMENT || DEBUG */