Add CPU independent code for running 32-bits CloudABI executables.

Essentially, this is a literal copy of the code in sys/compat/cloudabi64,
except that it now makes use of 32-bits datatypes and limits. In
sys/conf/files, we now need to take care to build the code in
sys/compat/cloudabi if either COMPAT_CLOUDABI32 or COMPAT_CLOUDABI64 is
turned on.

This change does not yet include any of the CPU dependent bits. Right
now I have implementations for running i386 binaries both on i386 and
x86-64, which I will send out for review separately.
This commit is contained in:
ed 2016-08-21 16:01:30 +00:00
parent 258ff8a811
commit d46ddfcd43
10 changed files with 1044 additions and 11 deletions

View File

@ -0,0 +1,14 @@
# $FreeBSD$
all:
@echo "make sysent only"
sysent: cloudabi32_sysent.c cloudabi32_syscall.h cloudabi32_proto.h \
cloudabi32_syscalls.c cloudabi32_systrace_args.c
cloudabi32_sysent.c cloudabi32_syscall.h cloudabi32_proto.h \
cloudabi32_syscalls.c cloudabi32_systrace_args.c: \
../../kern/makesyscalls.sh ../../contrib/cloudabi/syscalls32.master \
syscalls.conf
sh ../../kern/makesyscalls.sh ../../contrib/cloudabi/syscalls32.master \
syscalls.conf

View File

@ -0,0 +1,145 @@
/*-
* Copyright (c) 2015 Nuxi, https://nuxi.nl/
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/limits.h>
#include <sys/malloc.h>
#include <sys/syscallsubr.h>
#include <sys/systm.h>
#include <sys/uio.h>
#include <contrib/cloudabi/cloudabi32_types.h>
#include <compat/cloudabi32/cloudabi32_proto.h>
#include <compat/cloudabi32/cloudabi32_util.h>
/* Copies in 32-bit iovec structures from userspace. */
static int
cloudabi32_copyinuio(const cloudabi32_iovec_t *iovp, size_t iovcnt,
struct uio **uiop)
{
cloudabi32_iovec_t iovobj;
struct uio *uio;
struct iovec *iov;
size_t i;
int error;
/* Allocate uio and iovecs. */
if (iovcnt > UIO_MAXIOV)
return (EINVAL);
uio = malloc(sizeof(struct uio) + iovcnt * sizeof(struct iovec),
M_IOV, M_WAITOK);
iov = (struct iovec *)(uio + 1);
/* Initialize uio. */
uio->uio_iov = iov;
uio->uio_iovcnt = iovcnt;
uio->uio_segflg = UIO_USERSPACE;
uio->uio_offset = -1;
uio->uio_resid = 0;
/* Copy in iovecs. */
for (i = 0; i < iovcnt; i++) {
error = copyin(&iovp[i], &iovobj, sizeof(iovobj));
if (error != 0) {
free(uio, M_IOV);
return (error);
}
iov[i].iov_base = TO_PTR(iovobj.iov_base);
iov[i].iov_len = iovobj.iov_len;
if (iov[i].iov_len > INT32_MAX - uio->uio_resid) {
free(uio, M_IOV);
return (EINVAL);
}
uio->uio_resid += iov[i].iov_len;
}
*uiop = uio;
return (0);
}
int
cloudabi32_sys_fd_pread(struct thread *td,
struct cloudabi32_sys_fd_pread_args *uap)
{
struct uio *uio;
int error;
error = cloudabi32_copyinuio(uap->iov, uap->iovcnt, &uio);
if (error != 0)
return (error);
error = kern_preadv(td, uap->fd, uio, uap->offset);
free(uio, M_IOV);
return (error);
}
int
cloudabi32_sys_fd_pwrite(struct thread *td,
struct cloudabi32_sys_fd_pwrite_args *uap)
{
struct uio *uio;
int error;
error = cloudabi32_copyinuio(TO_PTR(uap->iov), uap->iovcnt, &uio);
if (error != 0)
return (error);
error = kern_pwritev(td, uap->fd, uio, uap->offset);
free(uio, M_IOV);
return (error);
}
int
cloudabi32_sys_fd_read(struct thread *td,
struct cloudabi32_sys_fd_read_args *uap)
{
struct uio *uio;
int error;
error = cloudabi32_copyinuio(uap->iov, uap->iovcnt, &uio);
if (error != 0)
return (error);
error = kern_readv(td, uap->fd, uio);
free(uio, M_IOV);
return (error);
}
int
cloudabi32_sys_fd_write(struct thread *td,
struct cloudabi32_sys_fd_write_args *uap)
{
struct uio *uio;
int error;
error = cloudabi32_copyinuio(TO_PTR(uap->iov), uap->iovcnt, &uio);
if (error != 0)
return (error);
error = kern_writev(td, uap->fd, uio);
free(uio, M_IOV);
return (error);
}

View File

@ -0,0 +1,167 @@
/*-
* Copyright (c) 2015 Nuxi, https://nuxi.nl/
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/imgact.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/proc.h>
#include <sys/smp.h>
#include <sys/sysctl.h>
#include <sys/sysent.h>
#include <sys/systm.h>
#include <contrib/cloudabi/cloudabi32_types.h>
#include <compat/cloudabi/cloudabi_util.h>
#include <compat/cloudabi32/cloudabi32_util.h>
extern char _binary_cloudabi32_vdso_o_start[];
extern char _binary_cloudabi32_vdso_o_end[];
register_t *
cloudabi32_copyout_strings(struct image_params *imgp)
{
struct image_args *args;
uintptr_t begin;
size_t len;
/* Copy out program arguments. */
args = imgp->args;
len = args->begin_envv - args->begin_argv;
begin = rounddown2(imgp->sysent->sv_usrstack - len, sizeof(register_t));
copyout(args->begin_argv, (void *)begin, len);
return ((register_t *)begin);
}
int
cloudabi32_fixup(register_t **stack_base, struct image_params *imgp)
{
char canarybuf[64];
Elf32_Auxargs *args;
struct thread *td;
void *argdata, *canary;
size_t argdatalen;
int error;
/*
* CloudABI executables do not store the FreeBSD OS release
* number in their header. Set the OS release number to the
* latest version of FreeBSD, so that system calls behave as if
* called natively.
*/
td = curthread;
td->td_proc->p_osrel = __FreeBSD_version;
/* Store canary for stack smashing protection. */
argdata = *stack_base;
arc4rand(canarybuf, sizeof(canarybuf), 0);
*stack_base -= howmany(sizeof(canarybuf), sizeof(register_t));
canary = *stack_base;
error = copyout(canarybuf, canary, sizeof(canarybuf));
if (error != 0)
return (error);
/*
* Compute length of program arguments. As the argument data is
* binary safe, we had to add a trailing null byte in
* exec_copyin_data_fds(). Undo this by reducing the length.
*/
args = (Elf32_Auxargs *)imgp->auxargs;
argdatalen = imgp->args->begin_envv - imgp->args->begin_argv;
if (argdatalen > 0)
--argdatalen;
/* Write out an auxiliary vector. */
cloudabi32_auxv_t auxv[] = {
#define VAL(type, val) { .a_type = (type), .a_val = (val) }
#define PTR(type, ptr) { .a_type = (type), .a_ptr = (uintptr_t)(ptr) }
PTR(CLOUDABI_AT_ARGDATA, argdata),
VAL(CLOUDABI_AT_ARGDATALEN, argdatalen),
VAL(CLOUDABI_AT_BASE, args->base),
PTR(CLOUDABI_AT_CANARY, canary),
VAL(CLOUDABI_AT_CANARYLEN, sizeof(canarybuf)),
VAL(CLOUDABI_AT_NCPUS, mp_ncpus),
VAL(CLOUDABI_AT_PAGESZ, args->pagesz),
PTR(CLOUDABI_AT_PHDR, args->phdr),
VAL(CLOUDABI_AT_PHNUM, args->phnum),
VAL(CLOUDABI_AT_TID, td->td_tid),
PTR(CLOUDABI_AT_SYSINFO_EHDR,
imgp->proc->p_sysent->sv_shared_page_base),
#undef VAL
#undef PTR
{ .a_type = CLOUDABI_AT_NULL },
};
*stack_base -= howmany(sizeof(auxv), sizeof(register_t));
error = copyout(auxv, *stack_base, sizeof(auxv));
if (error != 0)
return (error);
/* Reserve space for storing the TCB. */
*stack_base -= howmany(sizeof(cloudabi32_tcb_t), sizeof(register_t));
return (0);
}
static int
cloudabi32_modevent(module_t mod, int type, void *data)
{
switch (type) {
case MOD_LOAD:
cloudabi_vdso_init(cloudabi32_brand.sysvec,
_binary_cloudabi32_vdso_o_start,
_binary_cloudabi32_vdso_o_end);
if (elf32_insert_brand_entry(&cloudabi32_brand) < 0) {
printf("Failed to add CloudABI ELF brand handler\n");
return (EINVAL);
}
return (0);
case MOD_UNLOAD:
if (elf32_brand_inuse(&cloudabi32_brand))
return (EBUSY);
if (elf32_remove_brand_entry(&cloudabi32_brand) < 0) {
printf("Failed to remove CloudABI ELF brand handler\n");
return (EINVAL);
}
cloudabi_vdso_destroy(cloudabi32_brand.sysvec);
return (0);
default:
return (EOPNOTSUPP);
}
}
static moduledata_t cloudabi32_module = {
"cloudabi32",
cloudabi32_modevent,
NULL
};
DECLARE_MODULE_TIED(cloudabi32, cloudabi32_module, SI_SUB_EXEC, SI_ORDER_ANY);
MODULE_DEPEND(cloudabi32, cloudabi, 1, 1, 1);
FEATURE(cloudabi32, "CloudABI 32bit support");

View File

@ -0,0 +1,408 @@
/*-
* Copyright (c) 2015 Nuxi, https://nuxi.nl/
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/proc.h>
#include <sys/syscallsubr.h>
#include <contrib/cloudabi/cloudabi32_types.h>
#include <compat/cloudabi/cloudabi_util.h>
#include <compat/cloudabi32/cloudabi32_proto.h>
#include <compat/cloudabi32/cloudabi32_util.h>
/* Converts a FreeBSD signal number to a CloudABI signal number. */
static cloudabi_signal_t
convert_signal(int sig)
{
static const cloudabi_signal_t signals[] = {
[SIGABRT] = CLOUDABI_SIGABRT,
[SIGALRM] = CLOUDABI_SIGALRM,
[SIGBUS] = CLOUDABI_SIGBUS,
[SIGCHLD] = CLOUDABI_SIGCHLD,
[SIGCONT] = CLOUDABI_SIGCONT,
[SIGFPE] = CLOUDABI_SIGFPE,
[SIGHUP] = CLOUDABI_SIGHUP,
[SIGILL] = CLOUDABI_SIGILL,
[SIGINT] = CLOUDABI_SIGINT,
[SIGKILL] = CLOUDABI_SIGKILL,
[SIGPIPE] = CLOUDABI_SIGPIPE,
[SIGQUIT] = CLOUDABI_SIGQUIT,
[SIGSEGV] = CLOUDABI_SIGSEGV,
[SIGSTOP] = CLOUDABI_SIGSTOP,
[SIGSYS] = CLOUDABI_SIGSYS,
[SIGTERM] = CLOUDABI_SIGTERM,
[SIGTRAP] = CLOUDABI_SIGTRAP,
[SIGTSTP] = CLOUDABI_SIGTSTP,
[SIGTTIN] = CLOUDABI_SIGTTIN,
[SIGTTOU] = CLOUDABI_SIGTTOU,
[SIGURG] = CLOUDABI_SIGURG,
[SIGUSR1] = CLOUDABI_SIGUSR1,
[SIGUSR2] = CLOUDABI_SIGUSR2,
[SIGVTALRM] = CLOUDABI_SIGVTALRM,
[SIGXCPU] = CLOUDABI_SIGXCPU,
[SIGXFSZ] = CLOUDABI_SIGXFSZ,
};
/* Convert unknown signals to SIGABRT. */
if (sig < 0 || sig >= nitems(signals) || signals[sig] == 0)
return (SIGABRT);
return (signals[sig]);
}
struct cloudabi32_kevent_args {
const cloudabi32_subscription_t *in;
cloudabi32_event_t *out;
bool once;
};
/* Converts CloudABI's subscription objects to FreeBSD's struct kevent. */
static int
cloudabi32_kevent_copyin(void *arg, struct kevent *kevp, int count)
{
cloudabi32_subscription_t sub;
struct cloudabi32_kevent_args *args;
cloudabi_timestamp_t ts;
int error;
args = arg;
while (count-- > 0) {
/* TODO(ed): Copy in multiple entries at once. */
error = copyin(args->in++, &sub, sizeof(sub));
if (error != 0)
return (error);
memset(kevp, 0, sizeof(*kevp));
kevp->udata = TO_PTR(sub.userdata);
switch (sub.type) {
case CLOUDABI_EVENTTYPE_CLOCK:
kevp->filter = EVFILT_TIMER;
kevp->ident = sub.clock.identifier;
kevp->fflags = NOTE_NSECONDS;
if ((sub.clock.flags &
CLOUDABI_SUBSCRIPTION_CLOCK_ABSTIME) != 0 &&
sub.clock.timeout > 0) {
/* Convert absolute timestamp to a relative. */
error = cloudabi_clock_time_get(curthread,
sub.clock.clock_id, &ts);
if (error != 0)
return (error);
ts = ts > sub.clock.timeout ? 0 :
sub.clock.timeout - ts;
} else {
/* Relative timestamp. */
ts = sub.clock.timeout;
}
kevp->data = ts > INTPTR_MAX ? INTPTR_MAX : ts;
break;
case CLOUDABI_EVENTTYPE_FD_READ:
kevp->filter = EVFILT_READ;
kevp->ident = sub.fd_readwrite.fd;
if ((sub.fd_readwrite.flags &
CLOUDABI_SUBSCRIPTION_FD_READWRITE_POLL) != 0)
kevp->fflags = NOTE_FILE_POLL;
break;
case CLOUDABI_EVENTTYPE_FD_WRITE:
kevp->filter = EVFILT_WRITE;
kevp->ident = sub.fd_readwrite.fd;
break;
case CLOUDABI_EVENTTYPE_PROC_TERMINATE:
kevp->filter = EVFILT_PROCDESC;
kevp->ident = sub.proc_terminate.fd;
kevp->fflags = NOTE_EXIT;
break;
}
if (args->once) {
/* Ignore flags. Simply use oneshot mode. */
kevp->flags = EV_ADD | EV_ONESHOT;
} else {
/* Translate flags. */
if ((sub.flags & CLOUDABI_SUBSCRIPTION_ADD) != 0)
kevp->flags |= EV_ADD;
if ((sub.flags & CLOUDABI_SUBSCRIPTION_CLEAR) != 0)
kevp->flags |= EV_CLEAR;
if ((sub.flags & CLOUDABI_SUBSCRIPTION_DELETE) != 0)
kevp->flags |= EV_DELETE;
if ((sub.flags & CLOUDABI_SUBSCRIPTION_DISABLE) != 0)
kevp->flags |= EV_DISABLE;
if ((sub.flags & CLOUDABI_SUBSCRIPTION_ENABLE) != 0)
kevp->flags |= EV_ENABLE;
if ((sub.flags & CLOUDABI_SUBSCRIPTION_ONESHOT) != 0)
kevp->flags |= EV_ONESHOT;
}
++kevp;
}
return (0);
}
/* Converts FreeBSD's struct kevent to CloudABI's event objects. */
static int
cloudabi32_kevent_copyout(void *arg, struct kevent *kevp, int count)
{
cloudabi32_event_t ev;
struct cloudabi32_kevent_args *args;
int error;
args = arg;
while (count-- > 0) {
/* Convert fields that should always be present. */
memset(&ev, 0, sizeof(ev));
ev.userdata = (uintptr_t)kevp->udata;
switch (kevp->filter) {
case EVFILT_TIMER:
ev.type = CLOUDABI_EVENTTYPE_CLOCK;
ev.clock.identifier = kevp->ident;
break;
case EVFILT_READ:
ev.type = CLOUDABI_EVENTTYPE_FD_READ;
ev.fd_readwrite.fd = kevp->ident;
break;
case EVFILT_WRITE:
ev.type = CLOUDABI_EVENTTYPE_FD_WRITE;
ev.fd_readwrite.fd = kevp->ident;
break;
case EVFILT_PROCDESC:
ev.type = CLOUDABI_EVENTTYPE_PROC_TERMINATE;
ev.proc_terminate.fd = kevp->ident;
break;
}
if ((kevp->flags & EV_ERROR) == 0) {
/* Success. */
switch (kevp->filter) {
case EVFILT_READ:
case EVFILT_WRITE:
ev.fd_readwrite.nbytes = kevp->data;
if ((kevp->flags & EV_EOF) != 0) {
ev.fd_readwrite.flags |=
CLOUDABI_EVENT_FD_READWRITE_HANGUP;
}
break;
case EVFILT_PROCDESC:
if (WIFSIGNALED(kevp->data)) {
/* Process got signalled. */
ev.proc_terminate.signal =
convert_signal(WTERMSIG(kevp->data));
ev.proc_terminate.exitcode = 0;
} else {
/* Process exited. */
ev.proc_terminate.signal = 0;
ev.proc_terminate.exitcode =
WEXITSTATUS(kevp->data);
}
break;
}
} else {
/* Error. */
ev.error = cloudabi_convert_errno(kevp->data);
}
++kevp;
/* TODO(ed): Copy out multiple entries at once. */
error = copyout(&ev, args->out++, sizeof(ev));
if (error != 0)
return (error);
}
return (0);
}
int
cloudabi32_sys_poll(struct thread *td, struct cloudabi32_sys_poll_args *uap)
{
struct cloudabi32_kevent_args args = {
.in = uap->in,
.out = uap->out,
.once = true,
};
struct kevent_copyops copyops = {
.k_copyin = cloudabi32_kevent_copyin,
.k_copyout = cloudabi32_kevent_copyout,
.arg = &args,
};
/*
* Bandaid to support CloudABI futex constructs that are not
* implemented through FreeBSD's kqueue().
*/
if (uap->nsubscriptions == 1) {
cloudabi32_subscription_t sub;
cloudabi32_event_t ev = {};
int error;
error = copyin(uap->in, &sub, sizeof(sub));
if (error != 0)
return (error);
ev.userdata = sub.userdata;
ev.type = sub.type;
if (sub.type == CLOUDABI_EVENTTYPE_CONDVAR) {
/* Wait on a condition variable. */
ev.condvar.condvar = sub.condvar.condvar;
ev.error = cloudabi_convert_errno(
cloudabi_futex_condvar_wait(
td, TO_PTR(sub.condvar.condvar),
sub.condvar.condvar_scope,
TO_PTR(sub.condvar.lock),
sub.condvar.lock_scope,
CLOUDABI_CLOCK_MONOTONIC, UINT64_MAX, 0));
td->td_retval[0] = 1;
return (copyout(&ev, uap->out, sizeof(ev)));
} else if (sub.type == CLOUDABI_EVENTTYPE_LOCK_RDLOCK) {
/* Acquire a read lock. */
ev.lock.lock = sub.lock.lock;
ev.error = cloudabi_convert_errno(
cloudabi_futex_lock_rdlock(
td, TO_PTR(sub.lock.lock),
sub.lock.lock_scope, CLOUDABI_CLOCK_MONOTONIC,
UINT64_MAX, 0));
td->td_retval[0] = 1;
return (copyout(&ev, uap->out, sizeof(ev)));
} else if (sub.type == CLOUDABI_EVENTTYPE_LOCK_WRLOCK) {
/* Acquire a write lock. */
ev.lock.lock = sub.lock.lock;
ev.error = cloudabi_convert_errno(
cloudabi_futex_lock_wrlock(
td, TO_PTR(sub.lock.lock),
sub.lock.lock_scope, CLOUDABI_CLOCK_MONOTONIC,
UINT64_MAX, 0));
td->td_retval[0] = 1;
return (copyout(&ev, uap->out, sizeof(ev)));
}
} else if (uap->nsubscriptions == 2) {
cloudabi32_subscription_t sub[2];
cloudabi32_event_t ev[2] = {};
int error;
error = copyin(uap->in, &sub, sizeof(sub));
if (error != 0)
return (error);
ev[0].userdata = sub[0].userdata;
ev[0].type = sub[0].type;
ev[1].userdata = sub[1].userdata;
ev[1].type = sub[1].type;
if (sub[0].type == CLOUDABI_EVENTTYPE_CONDVAR &&
sub[1].type == CLOUDABI_EVENTTYPE_CLOCK &&
sub[1].clock.flags == CLOUDABI_SUBSCRIPTION_CLOCK_ABSTIME) {
/* Wait for a condition variable with timeout. */
ev[0].condvar.condvar = sub[0].condvar.condvar;
ev[1].clock.identifier = sub[1].clock.identifier;
error = cloudabi_futex_condvar_wait(
td, TO_PTR(sub[0].condvar.condvar),
sub[0].condvar.condvar_scope,
TO_PTR(sub[0].condvar.lock),
sub[0].condvar.lock_scope, sub[1].clock.clock_id,
sub[1].clock.timeout, sub[1].clock.precision);
if (error == ETIMEDOUT) {
td->td_retval[0] = 1;
return (copyout(&ev[1], uap->out,
sizeof(ev[1])));
}
ev[0].error = cloudabi_convert_errno(error);
td->td_retval[0] = 1;
return (copyout(&ev[0], uap->out, sizeof(ev[0])));
} else if (sub[0].type == CLOUDABI_EVENTTYPE_LOCK_RDLOCK &&
sub[1].type == CLOUDABI_EVENTTYPE_CLOCK &&
sub[1].clock.flags == CLOUDABI_SUBSCRIPTION_CLOCK_ABSTIME) {
/* Acquire a read lock with a timeout. */
ev[0].lock.lock = sub[0].lock.lock;
ev[1].clock.identifier = sub[1].clock.identifier;
error = cloudabi_futex_lock_rdlock(
td, TO_PTR(sub[0].lock.lock),
sub[0].lock.lock_scope, sub[1].clock.clock_id,
sub[1].clock.timeout, sub[1].clock.precision);
if (error == ETIMEDOUT) {
td->td_retval[0] = 1;
return (copyout(&ev[1], uap->out,
sizeof(ev[1])));
}
ev[0].error = cloudabi_convert_errno(error);
td->td_retval[0] = 1;
return (copyout(&ev[0], uap->out, sizeof(ev[0])));
} else if (sub[0].type == CLOUDABI_EVENTTYPE_LOCK_WRLOCK &&
sub[1].type == CLOUDABI_EVENTTYPE_CLOCK &&
sub[1].clock.flags == CLOUDABI_SUBSCRIPTION_CLOCK_ABSTIME) {
/* Acquire a write lock with a timeout. */
ev[0].lock.lock = sub[0].lock.lock;
ev[1].clock.identifier = sub[1].clock.identifier;
error = cloudabi_futex_lock_wrlock(
td, TO_PTR(sub[0].lock.lock),
sub[0].lock.lock_scope, sub[1].clock.clock_id,
sub[1].clock.timeout, sub[1].clock.precision);
if (error == ETIMEDOUT) {
td->td_retval[0] = 1;
return (copyout(&ev[1], uap->out,
sizeof(ev[1])));
}
ev[0].error = cloudabi_convert_errno(error);
td->td_retval[0] = 1;
return (copyout(&ev[0], uap->out, sizeof(ev[0])));
}
}
return (kern_kevent_anonymous(td, uap->nsubscriptions, &copyops));
}
int
cloudabi32_sys_poll_fd(struct thread *td,
struct cloudabi32_sys_poll_fd_args *uap)
{
struct cloudabi32_kevent_args args = {
.in = uap->in,
.out = uap->out,
.once = false,
};
struct kevent_copyops copyops = {
.k_copyin = cloudabi32_kevent_copyin,
.k_copyout = cloudabi32_kevent_copyout,
.arg = &args,
};
cloudabi32_subscription_t subtimo;
struct timespec timeout;
int error;
if (uap->timeout != NULL) {
/* Poll with a timeout. */
error = copyin(uap->timeout, &subtimo, sizeof(subtimo));
if (error != 0)
return (error);
if (subtimo.type != CLOUDABI_EVENTTYPE_CLOCK ||
subtimo.clock.flags != 0)
return (EINVAL);
timeout.tv_sec = subtimo.clock.timeout / 1000000000;
timeout.tv_nsec = subtimo.clock.timeout % 1000000000;
return (kern_kevent(td, uap->fd, uap->nin, uap->nout, &copyops,
&timeout));
} else {
/* Poll without a timeout. */
return (kern_kevent(td, uap->fd, uap->nin, uap->nout, &copyops,
NULL));
}
}

View File

@ -0,0 +1,148 @@
/*-
* Copyright (c) 2015 Nuxi, https://nuxi.nl/
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/proc.h>
#include <sys/socket.h>
#include <sys/syscallsubr.h>
#include <sys/systm.h>
#include <sys/uio.h>
#include <contrib/cloudabi/cloudabi32_types.h>
#include <compat/cloudabi/cloudabi_util.h>
#include <compat/cloudabi32/cloudabi32_proto.h>
#include <compat/cloudabi32/cloudabi32_util.h>
static MALLOC_DEFINE(M_SOCKET, "socket", "CloudABI socket");
int
cloudabi32_sys_sock_recv(struct thread *td,
struct cloudabi32_sys_sock_recv_args *uap)
{
struct sockaddr_storage ss;
cloudabi32_recv_in_t ri;
cloudabi32_recv_out_t ro = {};
cloudabi32_iovec_t iovobj;
struct msghdr msghdr = {};
const cloudabi32_iovec_t *user_iov;
size_t i;
int error;
error = copyin(uap->in, &ri, sizeof(ri));
if (error != 0)
return (error);
/* Convert results in cloudabi_recv_in_t to struct msghdr. */
if (ri.ri_datalen > UIO_MAXIOV)
return (EINVAL);
msghdr.msg_iovlen = ri.ri_datalen;
msghdr.msg_iov = malloc(msghdr.msg_iovlen * sizeof(struct iovec),
M_SOCKET, M_WAITOK);
user_iov = TO_PTR(ri.ri_data);
for (i = 0; i < msghdr.msg_iovlen; i++) {
error = copyin(&user_iov[i], &iovobj, sizeof(iovobj));
if (error != 0) {
free(msghdr.msg_iov, M_SOCKET);
return (error);
}
msghdr.msg_iov[i].iov_base = TO_PTR(iovobj.iov_base);
msghdr.msg_iov[i].iov_len = iovobj.iov_len;
}
msghdr.msg_name = &ss;
msghdr.msg_namelen = sizeof(ss);
if (ri.ri_flags & CLOUDABI_MSG_PEEK)
msghdr.msg_flags |= MSG_PEEK;
if (ri.ri_flags & CLOUDABI_MSG_WAITALL)
msghdr.msg_flags |= MSG_WAITALL;
/* TODO(ed): Add file descriptor passing. */
error = kern_recvit(td, uap->sock, &msghdr, UIO_SYSSPACE, NULL);
free(msghdr.msg_iov, M_SOCKET);
if (error != 0)
return (error);
/* Convert results in msghdr to cloudabi_recv_out_t. */
ro.ro_datalen = td->td_retval[0];
cloudabi_convert_sockaddr((struct sockaddr *)&ss,
MIN(msghdr.msg_namelen, sizeof(ss)), &ro.ro_peername);
td->td_retval[0] = 0;
return (copyout(&ro, uap->out, sizeof(ro)));
}
int
cloudabi32_sys_sock_send(struct thread *td,
struct cloudabi32_sys_sock_send_args *uap)
{
cloudabi32_send_in_t si;
cloudabi32_send_out_t so = {};
cloudabi32_ciovec_t iovobj;
struct msghdr msghdr = {};
const cloudabi32_ciovec_t *user_iov;
size_t i;
int error, flags;
error = copyin(uap->in, &si, sizeof(si));
if (error != 0)
return (error);
/* Convert results in cloudabi_send_in_t to struct msghdr. */
if (si.si_datalen > UIO_MAXIOV)
return (EINVAL);
msghdr.msg_iovlen = si.si_datalen;
msghdr.msg_iov = malloc(msghdr.msg_iovlen * sizeof(struct iovec),
M_SOCKET, M_WAITOK);
user_iov = TO_PTR(si.si_data);
for (i = 0; i < msghdr.msg_iovlen; i++) {
error = copyin(&user_iov[i], &iovobj, sizeof(iovobj));
if (error != 0) {
free(msghdr.msg_iov, M_SOCKET);
return (error);
}
msghdr.msg_iov[i].iov_base = TO_PTR(iovobj.iov_base);
msghdr.msg_iov[i].iov_len = iovobj.iov_len;
}
flags = MSG_NOSIGNAL;
if (si.si_flags & CLOUDABI_MSG_EOR)
flags |= MSG_EOR;
/* TODO(ed): Add file descriptor passing. */
error = kern_sendit(td, uap->sock, &msghdr, flags, NULL, UIO_USERSPACE);
free(msghdr.msg_iov, M_SOCKET);
if (error != 0)
return (error);
/* Convert results in msghdr to cloudabi_send_out_t. */
so.so_datalen = td->td_retval[0];
td->td_retval[0] = 0;
return (copyout(&so, uap->out, sizeof(so)));
}

View File

@ -0,0 +1,77 @@
/*-
* Copyright (c) 2015 Nuxi, https://nuxi.nl/
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/proc.h>
#include <sys/systm.h>
#include <contrib/cloudabi/cloudabi32_types.h>
#include <compat/cloudabi32/cloudabi32_proto.h>
#include <compat/cloudabi32/cloudabi32_util.h>
struct thread_create_args {
cloudabi32_threadattr_t attr;
uint32_t tcb;
lwpid_t tid;
};
static int
initialize_thread(struct thread *td, void *thunk)
{
struct thread_create_args *args = thunk;
/* Save the thread ID, so it can be returned. */
args->tid = td->td_tid;
/* Set up initial register contents. */
return (cloudabi32_thread_setregs(td, &args->attr, args->tcb));
}
int
cloudabi32_sys_thread_create(struct thread *td,
struct cloudabi32_sys_thread_create_args *uap)
{
struct thread_create_args args;
int error;
error = copyin(uap->attr, &args.attr, sizeof(args.attr));
if (error != 0)
return (error);
/* Remove some space on the top of the stack for the TCB. */
args.tcb = rounddown(args.attr.stack + args.attr.stack_size -
sizeof(cloudabi32_tcb_t), _Alignof(cloudabi32_tcb_t));
args.attr.stack_size = args.tcb - args.attr.stack;
error = thread_create(td, NULL, initialize_thread, &args);
if (error != 0)
return (error);
td->td_retval[0] = args.tid;
return (0);
}

View File

@ -0,0 +1,51 @@
/*-
* Copyright (c) 2015 Nuxi, https://nuxi.nl/
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
*
* $FreeBSD$
*/
#ifndef _CLOUDABI32_UTIL_H_
#define _CLOUDABI32_UTIL_H_
#include <sys/types.h>
#define __ELF_WORD_SIZE 32
#include <sys/imgact_elf.h>
#include <contrib/cloudabi/cloudabi32_types.h>
struct image_params;
struct thread;
extern Elf32_Brandinfo cloudabi32_brand;
#define TO_PTR(x) ((void *)(uintptr_t)(x))
/* Stack initialization during process execution. */
register_t *cloudabi32_copyout_strings(struct image_params *);
int cloudabi32_fixup(register_t **, struct image_params *);
int cloudabi32_thread_setregs(struct thread *,
const cloudabi32_threadattr_t *, uint32_t);
#endif

View File

@ -0,0 +1,15 @@
# $FreeBSD$
sysnames="cloudabi32_syscalls.c"
sysproto="cloudabi32_proto.h"
sysproto_h=_CLOUDABI32_SYSPROTO_H_
syshdr="cloudabi32_syscall.h"
syssw="cloudabi32_sysent.c"
sysmk="/dev/null"
syscallprefix="CLOUDABI32_SYS_"
switchname="cloudabi32_sysent"
namesname="cloudabi32_syscallnames"
systrace="cloudabi32_systrace_args.c"
# Allow all system calls in capabilities mode. Extract the names of the
# system calls from syscalls.master.
capenabled=`sed -n -e 's/.*\<\(cloudabi[0-9]*_sys_[a-z0-9_]*\)\>.*/\1/p' $1 | tr '\n' ','`

View File

@ -274,17 +274,24 @@ cddl/dev/fbt/fbt.c optional dtrace_fbt | dtraceall compile-with "${FBT_C}
cddl/dev/systrace/systrace.c optional dtrace_systrace | dtraceall compile-with "${CDDL_C}"
cddl/dev/prototype.c optional dtrace_prototype | dtraceall compile-with "${CDDL_C}"
fs/nfsclient/nfs_clkdtrace.c optional dtnfscl nfscl | dtraceall nfscl compile-with "${CDDL_C}"
compat/cloudabi/cloudabi_clock.c optional compat_cloudabi64
compat/cloudabi/cloudabi_errno.c optional compat_cloudabi64
compat/cloudabi/cloudabi_fd.c optional compat_cloudabi64
compat/cloudabi/cloudabi_file.c optional compat_cloudabi64
compat/cloudabi/cloudabi_futex.c optional compat_cloudabi64
compat/cloudabi/cloudabi_mem.c optional compat_cloudabi64
compat/cloudabi/cloudabi_proc.c optional compat_cloudabi64
compat/cloudabi/cloudabi_random.c optional compat_cloudabi64
compat/cloudabi/cloudabi_sock.c optional compat_cloudabi64
compat/cloudabi/cloudabi_thread.c optional compat_cloudabi64
compat/cloudabi/cloudabi_vdso.c optional compat_cloudabi64
compat/cloudabi/cloudabi_clock.c optional compat_cloudabi32 | compat_cloudabi64
compat/cloudabi/cloudabi_errno.c optional compat_cloudabi32 | compat_cloudabi64
compat/cloudabi/cloudabi_fd.c optional compat_cloudabi32 | compat_cloudabi64
compat/cloudabi/cloudabi_file.c optional compat_cloudabi32 | compat_cloudabi64
compat/cloudabi/cloudabi_futex.c optional compat_cloudabi32 | compat_cloudabi64
compat/cloudabi/cloudabi_mem.c optional compat_cloudabi32 | compat_cloudabi64
compat/cloudabi/cloudabi_proc.c optional compat_cloudabi32 | compat_cloudabi64
compat/cloudabi/cloudabi_random.c optional compat_cloudabi32 | compat_cloudabi64
compat/cloudabi/cloudabi_sock.c optional compat_cloudabi32 | compat_cloudabi64
compat/cloudabi/cloudabi_thread.c optional compat_cloudabi32 | compat_cloudabi64
compat/cloudabi/cloudabi_vdso.c optional compat_cloudabi32 | compat_cloudabi64
compat/cloudabi32/cloudabi32_fd.c optional compat_cloudabi32
compat/cloudabi32/cloudabi32_module.c optional compat_cloudabi32
compat/cloudabi32/cloudabi32_poll.c optional compat_cloudabi32
compat/cloudabi32/cloudabi32_sock.c optional compat_cloudabi32
compat/cloudabi32/cloudabi32_syscalls.c optional compat_cloudabi32
compat/cloudabi32/cloudabi32_sysent.c optional compat_cloudabi32
compat/cloudabi32/cloudabi32_thread.c optional compat_cloudabi32
compat/cloudabi64/cloudabi64_fd.c optional compat_cloudabi64
compat/cloudabi64/cloudabi64_module.c optional compat_cloudabi64
compat/cloudabi64/cloudabi64_poll.c optional compat_cloudabi64

View File

@ -86,6 +86,7 @@ COMPAT_FREEBSD6 opt_compat.h
COMPAT_FREEBSD7 opt_compat.h
COMPAT_FREEBSD9 opt_compat.h
COMPAT_FREEBSD10 opt_compat.h
COMPAT_CLOUDABI32 opt_dontuse.h
COMPAT_CLOUDABI64 opt_dontuse.h
COMPAT_LINUXKPI opt_compat.h
COMPILING_LINT opt_global.h