diff --git a/Pal/src/host/FreeBSD/Makefile b/Pal/src/host/FreeBSD/Makefile index 3d30534c..bfbe4b49 100644 --- a/Pal/src/host/FreeBSD/Makefile +++ b/Pal/src/host/FreeBSD/Makefile @@ -16,8 +16,8 @@ host_target = libpal-FreeBSD.a ../../pal-gdb defs = -DIN_PAL -DPAL_DIR="$(PAL_DIR)" objs = $(addprefix db_,files devices pipes sockets streams memory threading \ - semaphore mutex events process object main rtld misc ipc \ - exception) rfork_thread + mutex events process object main rtld misc ipc \ + exception2) rfork_thread graphene_lib = .lib/graphene-lib.a headers = $(wildcard *.h) $(wildcard ../../*.h) $(wildcard ../../../lib/*.h) diff --git a/Pal/src/host/FreeBSD/db_devices.c b/Pal/src/host/FreeBSD/db_devices.c index 214c26d3..d2056ffe 100644 --- a/Pal/src/host/FreeBSD/db_devices.c +++ b/Pal/src/host/FreeBSD/db_devices.c @@ -104,12 +104,12 @@ static int open_standard_term (PAL_HANDLE * handle, const char * param, hdl->dev.dev_type = device_type_term; if (!(access & PAL_ACCESS_WRONLY)) { - hdl->__in.flags |= RFD(0); + hdl->hdr.flags |= RFD(0); hdl->dev.fd_in = 0; } if (access & (PAL_ACCESS_WRONLY|PAL_ACCESS_RDWR)) { - hdl->__in.flags |= WFD(1); + hdl->hdr.flags |= WFD(1); hdl->dev.fd_out = 1; } diff --git a/Pal/src/host/FreeBSD/db_events.c b/Pal/src/host/FreeBSD/db_events.c index f7eb1338..cea539bc 100644 --- a/Pal/src/host/FreeBSD/db_events.c +++ b/Pal/src/host/FreeBSD/db_events.c @@ -78,7 +78,7 @@ int _DkEventSet (PAL_HANDLE event, int wakeup) return IS_ERR(ret) ? PAL_ERROR_TRYAGAIN : ret; } -int _DkEventWaitTimeout (PAL_HANDLE event, int timeout) +int _DkEventWaitTimeout (PAL_HANDLE event, uint64_t timeout) { int ret = 0; if (!event->event.isnotification || !atomic_read(&event->event.signaled)) { @@ -142,3 +142,21 @@ int _DkEventClear (PAL_HANDLE event) atomic_set(&event->event.signaled, 0); return 0; } + + +static int event_close (PAL_HANDLE handle) +{ + _DkEventSet(handle, -1); + return 0; +} + +static int event_wait (PAL_HANDLE handle, uint64_t timeout) +{ + return timeout == NO_TIMEOUT ? _DkEventWait(handle) : + _DkEventWaitTimeout(handle, timeout); +} + +struct handle_ops event_ops = { + .close = &event_close, + .wait = &event_wait, +}; diff --git a/Pal/src/host/FreeBSD/db_exception.c b/Pal/src/host/FreeBSD/db_exception.c index d4a00974..01f557b5 100644 --- a/Pal/src/host/FreeBSD/db_exception.c +++ b/Pal/src/host/FreeBSD/db_exception.c @@ -40,6 +40,8 @@ #include #include +typedef void (*PAL_UPCALL) (PAL_PTR, PAL_NUM, PAL_CONTEXT *); + int set_sighandler (int * sigs, int nsig, void * handler) { struct sigaction action; @@ -327,8 +329,7 @@ static struct pal_frame * get_frame (ucontext_t * uc) for (unsigned long ptr = rbp - sizeof(unsigned long) ; ptr > last_rbp ; ptr -= 8) { struct pal_frame * frame = (struct pal_frame *) ptr; - - if (frame->self == frame) + if (frame->identifier == PAL_FRAME_IDENTIFIER) return frame; } @@ -429,7 +430,6 @@ struct signal_ops { }; struct signal_ops on_signals[PAL_EVENT_NUM_BOUND] = { - /* reserved */ { .signum = { 0 }, .handler = NULL }, /* DivZero */ { .signum = { SIGFPE, 0 }, .handler = _DkGenericSighandler }, /* MemFault */ { .signum = { SIGSEGV, SIGBUS, 0 }, @@ -442,7 +442,6 @@ struct signal_ops on_signals[PAL_EVENT_NUM_BOUND] = { .handler = _DkTerminateSighandler }, /* Resume */ { .signum = { SIGCONT, 0 }, .handler = _DkGenericSighandler }, - /* Failure */ { .signum = { 0 }, .handler = NULL }, }; static int _DkPersistentSighandlerSetup (int event_num) @@ -571,7 +570,7 @@ err: init_fail(-ret, "cannot setup signal handlers"); } -void _DkExceptionReturn (const void * event) +void _DkExceptionReturn (void * event) { const struct exception_event * e = (const struct exception_event *) event; if (e->uc) { diff --git a/Pal/src/host/FreeBSD/db_exception2.c b/Pal/src/host/FreeBSD/db_exception2.c new file mode 100644 index 00000000..e18c6097 --- /dev/null +++ b/Pal/src/host/FreeBSD/db_exception2.c @@ -0,0 +1,465 @@ +/* -*- mode:c; c-file-style:"k&r"; c-basic-offset: 4; tab-width:4; indent-tabs-mode:nil; mode:auto-fill; fill-column:78; -*- */ +/* vim: set ts=4 sw=4 et tw=78 fo=cqt wm=0: */ + +/* Copyright (C) 2014 Stony Brook University + This file is part of Graphene Library OS. + + Graphene Library OS is free software: you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + Graphene Library OS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . */ + +/* + * db_signal.c + * + * This file contains APIs to set up handlers of exceptions issued by the + * host, and the methods to pass the exceptions to the upcalls. + */ + +#include "pal_defs.h" +#include "pal_freebsd_defs.h" +#include "pal.h" +#include "pal_internal.h" +#include "pal_freebsd.h" +#include "pal_error.h" +#include "pal_security.h" +#include "api.h" + +#include +#include +#include +#include + +#if !defined(__i386__) +/* In x86_64 kernels, sigaction is required to have a user-defined + * restorer. Also, they not yet support SA_INFO. The reference: + * http://lxr.linux.no/linux+v2.6.35/arch/x86/kernel/signal.c#L448 + * + * / * x86-64 should always use SA_RESTORER. * / + * if (ka->sa.sa_flags & SA_RESTORER) { + * put_user_ex(ka->sa.sa_restorer, &frame->pretcode); + * } else { + * / * could use a vstub here * / + * err |= -EFAULT; + * } + */ + +void restore_rt (void) asm ("__restore_rt"); + +#ifndef SA_RESTORER +#define SA_RESTORER 0x04000000 +#endif + +#define DEFINE_RESTORE_RT(syscall) DEFINE_RESTORE_RT2(syscall) +# define DEFINE_RESTORE_RT2(syscall) \ + asm ( \ + " nop\n" \ + ".align 16\n" \ + ".LSTART_restore_rt:\n" \ + " .type __restore_rt,@function\n" \ + "__restore_rt:\n" \ + " movq $" #syscall ", %rax\n" \ + " syscall\n"); + +#endif + +int set_sighandler (int * sigs, int nsig, void * handler) +{ + struct sigaction action; + + if (handler) { + action.sa_handler = (void (*)(int)) handler; + action.sa_flags = SA_SIGINFO; +#if !defined(__i386__) + //action.sa_flags |= SA_RESTORER; + //action.sa_restorer = restore_rt; +#endif + } else { + action.sa_handler = SIG_IGN; + } + +#ifdef DEBUG + if (!linux_state.in_gdb) +#endif + action.sa_flags |= SA_NOCLDWAIT; + + __sigemptyset((__sigset_t *) &action.sa_mask); + __sigaddset((__sigset_t *) &action.sa_mask, SIGCONT); + + for (int i = 0 ; i < nsig ; i++) { +#if defined(__i386__) + int ret = INLINE_SYSCALL(sigaction, 3, sigs[i], &action, NULL) +#else + int ret = INLINE_SYSCALL(sigaction, 4, sigs[i], &action, NULL, + sizeof(sigset_t)); +#endif + if (IS_ERR(ret)) + return -PAL_ERROR_DENIED; + } + + return 0; +} + +typedef struct { + PAL_IDX event_num; + PAL_CONTEXT context; + ucontext_t * uc; + PAL_PTR eframe; +} PAL_EVENT; + +#define SIGNAL_MASK_TIME 1000 + +#define save_return_point(ptr) \ + asm volatile ("leaq 0(%%rip), %%rax\r\n" \ + "movq %%rax, %0\r\n" \ + : "=b"(ptr) :: "memory", "rax") + +static int get_event_num (int signum) +{ + switch(signum) { + case SIGFPE: return PAL_EVENT_DIVZERO; + case SIGSEGV: case SIGBUS: return PAL_EVENT_MEMFAULT; + case SIGILL: case SIGSYS: return PAL_EVENT_ILLEGAL; + case SIGTERM: return PAL_EVENT_QUIT; + case SIGINT: return PAL_EVENT_SUSPEND; + case SIGCONT: return PAL_EVENT_RESUME; + default: return -1; + } +} + +void _DkGenericEventTrigger (PAL_IDX event_num, PAL_EVENT_HANDLER upcall, + PAL_NUM arg, struct pal_frame * frame, + ucontext_t * uc, void * eframe) +{ + PAL_EVENT event; + event.event_num = event_num; + + if (uc) { + event.context.r8 = uc->uc_mcontext.mc_r8; + event.context.r9 = uc->uc_mcontext.mc_r9; + event.context.r10 = uc->uc_mcontext.mc_r10; + event.context.r11 = uc->uc_mcontext.mc_r11; + event.context.r12 = uc->uc_mcontext.mc_r12; + event.context.r13 = uc->uc_mcontext.mc_r13; + event.context.r14 = uc->uc_mcontext.mc_r14; + event.context.r15 = uc->uc_mcontext.mc_r15; + event.context.rdi = uc->uc_mcontext.mc_rdi; + event.context.rsi = uc->uc_mcontext.mc_rsi; + event.context.rbp = uc->uc_mcontext.mc_rbp; + event.context.rbx = uc->uc_mcontext.mc_rbx; + event.context.rdx = uc->uc_mcontext.mc_rdx; + event.context.rax = uc->uc_mcontext.mc_rax; + event.context.rcx = uc->uc_mcontext.mc_rcx; + event.context.rsp = uc->uc_mcontext.mc_rsp; + event.context.rip = uc->uc_mcontext.mc_rip; + event.context.efl = uc->uc_mcontext.mc_flags; + event.context.err = uc->uc_mcontext.mc_err; + event.context.trapno = uc->uc_mcontext.mc_trapno; + event.context.csgsfs = 0; + event.context.oldmask = 0; + event.context.cr2 = 0; + } + + if (frame) { + event.context.r15 = frame->arch.r15; + event.context.r14 = frame->arch.r14; + event.context.r13 = frame->arch.r13; + event.context.r12 = frame->arch.r12; + event.context.rdi = frame->arch.rdi; + event.context.rsi = frame->arch.rsi; + event.context.rbx = frame->arch.rbx; + /* find last frame */ + event.context.rsp = frame->arch.rbp + sizeof(unsigned long) * 2; + event.context.rbp = ((unsigned long *) frame->arch.rbp)[0]; + event.context.rip = ((unsigned long *) frame->arch.rbp)[1]; + /* making rax = 0 to tell the caller that this PAL call failed */ + event.context.rax = 0; + } + + event.uc = uc; + event.eframe = eframe; + + (*upcall) ((PAL_PTR) &event, arg, &event.context); +} + +static bool _DkGenericSignalHandle (int event_num, siginfo_t * info, + struct pal_frame * frame, + ucontext_t * uc, void * eframe) +{ + PAL_EVENT_HANDLER upcall = _DkGetExceptionHandler(event_num); + + if (upcall) { + PAL_NUM arg = 0; + + if (event_num == PAL_EVENT_DIVZERO || + event_num == PAL_EVENT_MEMFAULT || + event_num == PAL_EVENT_ILLEGAL) + arg = (PAL_NUM) (info ? info->si_addr : 0); + + _DkGenericEventTrigger(event_num, upcall, arg, frame, uc, eframe); + return true; + } + + return false; +} + +#define ADDR_IN_PAL(addr) \ + ((void *) (addr) > TEXT_START && (void *) (addr) < TEXT_END) + +/* This function walks the stack to find the PAL_FRAME + * that was saved upon entry to the PAL, if an exception/interrupt + * comes in during a PAL call. This is needed to support the behavior that an + * exception in the PAL has Unix-style, EAGAIN semantics. + * + * The PAL_FRAME is supposed to be in the first PAL frame, and we look for + * it by matching a special magic number, that should only appear on the stack + * once. + * + * If an exception comes in while we are not in the PAL, this PAL_FRAME won't + * exist, and it is ok to return NULL. + */ +static struct pal_frame * get_frame (ucontext_t * uc) +{ + unsigned long rip = uc->uc_mcontext.mc_rip; + unsigned long rbp = uc->uc_mcontext.mc_rbp; + unsigned long last_rbp = rbp - 64; + + if (!ADDR_IN_PAL(rip)) + return NULL; + + while (ADDR_IN_PAL(((unsigned long *) rbp)[1])) { + last_rbp = rbp; + rbp = *(unsigned long *) rbp; + } + + /* search frame record in the top frame of PAL */ + for (unsigned long ptr = rbp - sizeof(unsigned long) ; + ptr > last_rbp ; ptr -= 8) { + struct pal_frame * frame = (struct pal_frame *) ptr; + if (frame->identifier == PAL_FRAME_IDENTIFIER) + return frame; + } + + return NULL; +} + +static void return_frame (struct pal_frame * frame, int err) +{ + if (err) + _DkRaiseFailure(err); + + __clear_frame(frame); + arch_restore_frame(&frame->arch); + + asm volatile ("xor %rax, %rax\r\n" + "leaveq\r\n" + "retq\r\n"); +} + +#if BLOCK_SIGFAULT == 1 +static char exception_msg[24] = "--- SIGSEGV --- [ ]\n"; +static volatile bool cont_exec = false; +#endif + +static void _DkGenericSighandler (int signum, siginfo_t * info, + struct ucontext * uc) +{ +#if BLOCK_SIGFUALT == 1 + /* reseurrect this code if signal handler if giving segmentation fault */ + if (signum == SIGSEGV) { + int pid = INLINE_SYSCALL(getpid, 0); + exception_msg[17] = '0' + pid / 10000; + exception_msg[18] = '0' + (pid / 1000) % 10; + exception_msg[19] = '0' + (pid / 100) % 10; + exception_msg[20] = '0' + (pid / 10) % 10; + exception_msg[21] = '0' + pid % 10; + INLINE_SYSCALL(write, 3, 1, exception_msg, 24); + while(!cont_exec); + } +#endif + + struct pal_frame * frame = get_frame(uc); + void * eframe; + + if (signum == SIGCONT && frame && frame->func == DkObjectsWaitAny) + return; + + asm volatile ("movq %%rbp, %0" : "=r"(eframe)); + + if (frame && frame->func != &_DkGenericSighandler && + signum != SIGCONT && + signum != SIGINT && + signum != SIGTERM) { + return_frame(frame, PAL_ERROR_BADADDR); + return; + } + + int event_num = get_event_num(signum); + if (event_num == -1) + return; + + _DkGenericSignalHandle(event_num, info, frame, uc, eframe); +} + +static void _DkTerminateSighandler (int signum, siginfo_t * info, + struct ucontext * uc) +{ + struct pal_frame * frame = get_frame(uc); + void * eframe; + + asm volatile ("movq %%rbp, %0" : "=r"(eframe)); + + int event_num = get_event_num(signum); + if (event_num == -1) + return; + + if (!_DkGenericSignalHandle(event_num, NULL, frame, uc, eframe)) + _DkThreadExit(); +} + +static void _DkPipeSighandler (int signum, siginfo_t * info, + struct ucontext * uc) +{ + return; +} + +void _DkRaiseFailure (int error) +{ + PAL_EVENT_HANDLER upcall = _DkGetExceptionHandler(PAL_EVENT_FAILURE); + + if (!upcall) + return; + + PAL_EVENT event; + event.event_num = PAL_EVENT_FAILURE; + event.uc = NULL; + event.eframe = NULL; + + (*upcall) ((PAL_PTR) &event, error, NULL); +} + +struct signal_ops { + int signum[3]; + void (*handler) (int signum, siginfo_t * info, ucontext_t * uc); +}; + +struct signal_ops on_signals[] = { + [PAL_EVENT_DIVZERO] = { .signum = { SIGFPE, 0 }, + .handler = _DkGenericSighandler }, + [PAL_EVENT_MEMFAULT] = { .signum = { SIGSEGV, SIGBUS, 0 }, + .handler = _DkGenericSighandler }, + [PAL_EVENT_ILLEGAL] = { .signum = { SIGILL, SIGSYS, 0 }, + .handler = _DkGenericSighandler }, + [PAL_EVENT_QUIT] = { .signum = { SIGTERM, 0, 0 }, + .handler = _DkTerminateSighandler }, + [PAL_EVENT_SUSPEND] = { .signum = { SIGINT, 0 }, + .handler = _DkTerminateSighandler }, + [PAL_EVENT_RESUME] = { .signum = { SIGCONT, 0 }, + .handler = _DkGenericSighandler }, + }; + +static int _DkPersistentSighandlerSetup (int event_num) +{ + int nsigs, * sigs = on_signals[event_num].signum; + for (nsigs = 0 ; sigs[nsigs] ; nsigs++); + + int ret = set_sighandler(sigs, nsigs, on_signals[event_num].handler); + if (ret < 0) + return ret; + + return 0; +} + +void signal_setup (void) +{ + int ret, sig = SIGCHLD; + +#ifdef DEBUG + if (!linux_state.in_gdb) +#endif + set_sighandler(&sig, 1, NULL); + + sig = SIGPIPE; + if ((ret = set_sighandler(&sig, 1, &_DkPipeSighandler)) < 0) + goto err; + + int events[] = { + PAL_EVENT_DIVZERO, + PAL_EVENT_MEMFAULT, + PAL_EVENT_ILLEGAL, + PAL_EVENT_QUIT, + PAL_EVENT_SUSPEND, + PAL_EVENT_RESUME, + }; + + for (int e = 0 ; e < sizeof(events) / sizeof(events[0]) ; e++) + if ((ret = _DkPersistentSighandlerSetup(events[e])) < 0) + goto err; + + return; +err: + init_fail(-ret, "cannot setup signal handlers"); +} + +void _DkExceptionReturn (void * event) +{ + PAL_EVENT * e = event; + + if (e->eframe) { + struct pal_frame * frame = (struct pal_frame *) e->eframe; + int err = 0; + + switch (e->event_num) { + case PAL_EVENT_MEMFAULT: + err = PAL_ERROR_BADADDR; + break; + case PAL_EVENT_QUIT: + case PAL_EVENT_SUSPEND: + case PAL_EVENT_RESUME: + err = PAL_ERROR_INTERRUPTED; + break; + } + + if (err) + _DkRaiseFailure(err); + + __clear_frame(frame); + } + + if (e->uc) { + /* copy the context back to ucontext */ + e->uc->uc_mcontext.mc_r8 = e->context.r8; + e->uc->uc_mcontext.mc_r9 = e->context.r9; + e->uc->uc_mcontext.mc_r10 = e->context.r10; + e->uc->uc_mcontext.mc_r11 = e->context.r11; + e->uc->uc_mcontext.mc_r12 = e->context.r12; + e->uc->uc_mcontext.mc_r13 = e->context.r13; + e->uc->uc_mcontext.mc_r14 = e->context.r14; + e->uc->uc_mcontext.mc_r15 = e->context.r15; + e->uc->uc_mcontext.mc_rdi = e->context.rdi; + e->uc->uc_mcontext.mc_rsi = e->context.rsi; + e->uc->uc_mcontext.mc_rbp = e->context.rbp; + e->uc->uc_mcontext.mc_rbx = e->context.rbx; + e->uc->uc_mcontext.mc_rdx = e->context.rdx; + e->uc->uc_mcontext.mc_rax = e->context.rax; + e->uc->uc_mcontext.mc_rcx = e->context.rcx; + e->uc->uc_mcontext.mc_rsp = e->context.rsp; + e->uc->uc_mcontext.mc_rip = e->context.rip; + e->uc->uc_mcontext.mc_flags = e->context.efl; + e->uc->uc_mcontext.mc_err = e->context.err; + e->uc->uc_mcontext.mc_trapno = e->context.trapno; + + /* return to the frame of exception handler */ + asm volatile ("movq %0, %%rbp\r\n" + "leaveq\r\n" + "retq\r\n" :: "r"(e->eframe) : "memory"); + } +} diff --git a/Pal/src/host/FreeBSD/db_files.c b/Pal/src/host/FreeBSD/db_files.c index eaa39d17..e530df16 100644 --- a/Pal/src/host/FreeBSD/db_files.c +++ b/Pal/src/host/FreeBSD/db_files.c @@ -58,7 +58,7 @@ static int file_open (PAL_HANDLE * handle, const char * type, const char * uri, int len = strlen(uri); PAL_HANDLE hdl = malloc(HANDLE_SIZE(file) + len + 1); SET_HANDLE_TYPE(hdl, file); - hdl->__in.flags |= RFD(0)|WFD(0)|WRITEABLE(0); + hdl->hdr.flags |= RFD(0)|WFD(0)|WRITEABLE(0); hdl->file.fd = ret; hdl->file.offset = 0; hdl->file.append = 0; @@ -243,7 +243,7 @@ static int file_attrquery (const char * type, const char * uri, static int file_attrquerybyhdl (PAL_HANDLE handle, PAL_STREAM_ATTR * attr) { - int fd = handle->__in.fds[0]; + int fd = handle->hdr.fds[0]; struct stat stat_buf; int ret = INLINE_SYSCALL(fstat, 2, fd, &stat_buf); @@ -258,7 +258,7 @@ static int file_attrquerybyhdl (PAL_HANDLE handle, static int file_attrsetbyhdl (PAL_HANDLE handle, PAL_STREAM_ATTR * attr) { - int fd = handle->__in.fds[0], ret; + int fd = handle->hdr.fds[0], ret; ret = INLINE_SYSCALL(fchmod, 2, fd, attr->share_flags); if (IS_ERR(ret)) @@ -341,7 +341,7 @@ static int dir_open (PAL_HANDLE * handle, const char * type, const char * uri, int len = strlen(uri); PAL_HANDLE hdl = malloc(HANDLE_SIZE(dir) + len + 1); SET_HANDLE_TYPE(hdl, dir); - hdl->__in.flags |= RFD(0); + hdl->hdr.flags |= RFD(0); hdl->dir.fd = ret; char * path = (void *) hdl + HANDLE_SIZE(dir); memcpy(path, uri, len + 1); diff --git a/Pal/src/host/FreeBSD/db_main.c b/Pal/src/host/FreeBSD/db_main.c index ff7d3053..fe2f6550 100644 --- a/Pal/src/host/FreeBSD/db_main.c +++ b/Pal/src/host/FreeBSD/db_main.c @@ -186,57 +186,6 @@ PAL_NUM _DkGetHostId (void) return 0; } -int create_domain_dir (void) -{ - int ret = 0; - const char * path; - - ret = INLINE_SYSCALL(mkdir, 2, (path = GRAPHENE_PIPEDIR), 0777); - - if (IS_ERR(ret) && ERRNO(ret) != EEXIST) { - if (ERRNO(ret) == ENOENT) { - ret = INLINE_SYSCALL(mkdir, 2, (path = GRAPHENE_TEMPDIR), 0777); - if (!IS_ERR(ret)) { - INLINE_SYSCALL(chmod, 2, GRAPHENE_TEMPDIR, 0777); - ret = INLINE_SYSCALL(mkdir, 2, (path = GRAPHENE_PIPEDIR), 0777); - } - } - - if (IS_ERR(ret)) { - printf("Cannot create directory %s, please check permission\n", - path); - return -PAL_ERROR_DENIED; - } - } - - if (!IS_ERR(ret)) - INLINE_SYSCALL(chmod, 2, GRAPHENE_PIPEDIR, 0777); - - char * pipedir = __alloca(sizeof(GRAPHENE_PIPEDIR) + 10); - unsigned int id; - - do { - if (!getrand(&id, sizeof(unsigned int))) { - printf("Unable to generate random numbers\n"); - return -PAL_ERROR_DENIED; - } - - snprintf(pipedir, sizeof(GRAPHENE_PIPEDIR) + 10, - GRAPHENE_PIPEDIR "/%08x", id); - - ret = INLINE_SYSCALL(mkdir, 2, pipedir, 0700); - - if (IS_ERR(ret) && ERRNO(ret) != -EEXIST) { - printf("Cannot create directory %s, please fix permission\n", - pipedir); - return -PAL_ERROR_DENIED; - } - } while (IS_ERR(ret)); - - pal_sec.domain_id = id; - return 0; -} - #include "dynamic_link.h" void setup_pal_map (struct link_map * map); @@ -271,6 +220,9 @@ void pal_bsd_main (void * args) bsd_state.pid = INLINE_SYSCALL(getpid, 0); bsd_state.uid = uid; bsd_state.gid = gid; + + if (!bsd_state.parent_pid) + bsd_state.parent_pid = bsd_state.pid; PAL_HANDLE first_thread = malloc(HANDLE_SIZE(thread)); SET_HANDLE_TYPE(first_thread, thread); @@ -288,7 +240,7 @@ void pal_bsd_main (void * args) int len = strlen(argv[0]); PAL_HANDLE file = malloc(HANDLE_SIZE(file) + len + 1); SET_HANDLE_TYPE(file, file); - file->__in.flags |= RFD(0)|WFD(0)|WRITEABLE(0); + file->hdr.flags |= RFD(0)|WFD(0)|WRITEABLE(0); file->file.fd = fd; char * path = (void *) file + HANDLE_SIZE(file); get_norm_path(argv[0], path, 0, len + 1); @@ -302,17 +254,15 @@ void pal_bsd_main (void * args) manifest = file; done_init: - /* Create domain directory for pipes */ - if(!pal_sec.domain_id){ - if ((ret = create_domain_dir()) < 0) - init_fail(-ret, "cannot create pipe directory"); + if (!parent && !exec && !manifest) { + printf("USAGE: %s [executable|manifest] args ...\n", pal_name); + _DkProcessExit(0); + return; } - signal_setup(); /* jump to main function */ - pal_main(pal_sec.domain_id, (void *) pal_map.l_addr, - pal_name, argc, argv, envp, parent, first_thread, exec, manifest); + pal_main(bsd_state.parent_pid, manifest, exec, NULL, parent, first_thread, argv, envp); } /* the following code is borrowed from CPUID */ diff --git a/Pal/src/host/FreeBSD/db_memory.c b/Pal/src/host/FreeBSD/db_memory.c index fe6f08ec..988194b3 100644 --- a/Pal/src/host/FreeBSD/db_memory.c +++ b/Pal/src/host/FreeBSD/db_memory.c @@ -40,7 +40,7 @@ bool _DkCheckMemoryMappable (const void * addr, int size) { return (addr <= DATA_END && addr + size >= TEXT_START); } -int _DkVirtualMemoryAlloc (void ** paddr, int size, int alloc_type, +int _DkVirtualMemoryAlloc (void ** paddr, uint64_t size, int alloc_type, int prot) { void * addr = *paddr, * mem = addr; @@ -59,14 +59,14 @@ int _DkVirtualMemoryAlloc (void ** paddr, int size, int alloc_type, return 0; } -int _DkVirtualMemoryFree (void * addr, int size) +int _DkVirtualMemoryFree (void * addr, uint64_t size) { int ret = INLINE_SYSCALL(munmap, 2, addr, size); return IS_ERR(ret) ? unix_to_pal_error(ERRNO(ret)) : 0; } -int _DkVirtualMemoryProtect (void * addr, int size, int prot) +int _DkVirtualMemoryProtect (void * addr, uint64_t size, int prot) { int ret = INLINE_SYSCALL(mprotect, 3, addr, size, HOST_PROT(prot)); diff --git a/Pal/src/host/FreeBSD/db_misc.c b/Pal/src/host/FreeBSD/db_misc.c index 896855c4..3f4296e0 100644 --- a/Pal/src/host/FreeBSD/db_misc.c +++ b/Pal/src/host/FreeBSD/db_misc.c @@ -200,7 +200,7 @@ static int init_randgen (void) return 0; } -void getrand (void * buffer, size_t size) +int getrand (void * buffer, size_t size) { unsigned long val; size_t bytes = 0; @@ -228,4 +228,11 @@ void getrand (void * buffer, size_t size) _DkInternalLock(&lock); randval = val; _DkInternalUnlock(&lock); + return 0; +} + +int _DkCpuIdRetrieve (unsigned int leaf, unsigned int subleaf, + unsigned int values[4]) +{ + return -PAL_ERROR_NOTIMPLEMENTED; } diff --git a/Pal/src/host/FreeBSD/db_mutex.c b/Pal/src/host/FreeBSD/db_mutex.c index 8907bc8e..7242a15f 100644 --- a/Pal/src/host/FreeBSD/db_mutex.c +++ b/Pal/src/host/FreeBSD/db_mutex.c @@ -35,7 +35,6 @@ #include #include -#include #include #include #include @@ -203,3 +202,32 @@ int _DkMutexUnlock (struct mutex_handle * mut) out: return ret; } + +int _DkMutexAcquireTimeout (PAL_HANDLE handle, int timeout) +{ + return _DkMutexLockTimeout(&handle->mutex.mut, timeout); +} + + +void _DkMutexRelease (PAL_HANDLE handle) +{ + _DkMutexUnlock(&handle->mutex.mut); + return; +} + +static int mutex_wait (PAL_HANDLE handle, uint64_t timeout) +{ + return _DkMutexAcquireTimeout(handle, timeout); +} + +struct handle_ops mutex_ops = { + .wait = &mutex_wait, +}; + +int _DkMutexCreate (PAL_HANDLE *handle, int count) { + PAL_HANDLE mut = malloc(HANDLE_SIZE(mutex)); + SET_HANDLE_TYPE(mut, mutex); + atomic_set(&mut->mutex.mut.value, 0); + *handle = mut; + return 0; +} diff --git a/Pal/src/host/FreeBSD/db_object.c b/Pal/src/host/FreeBSD/db_object.c index 474f2817..139011fa 100644 --- a/Pal/src/host/FreeBSD/db_object.c +++ b/Pal/src/host/FreeBSD/db_object.c @@ -36,7 +36,6 @@ #include #include #include -#include #include #define DEFAULT_QUANTUM 500 @@ -47,24 +46,24 @@ static int _DkObjectWaitOne (PAL_HANDLE handle, int timeout) { /* only for all these handle which has a file descriptor, or a eventfd. events and semaphores will skip this part */ - if (handle->__in.flags & HAS_FDS) { + if (handle->hdr.flags & HAS_FDS) { struct pollfd fds[MAX_FDS]; int off[MAX_FDS]; int nfds = 0; for (int i = 0 ; i < MAX_FDS ; i++) { int events = 0; - if ((handle->__in.flags & RFD(i)) && - !(handle->__in.flags & ERROR(i))) + if ((handle->hdr.flags & RFD(i)) && + !(handle->hdr.flags & ERROR(i))) events |= POLLIN; - if ((handle->__in.flags & WFD(i)) && - !(handle->__in.flags & WRITEABLE(i)) && - !(handle->__in.flags & ERROR(i))) + if ((handle->hdr.flags & WFD(i)) && + !(handle->hdr.flags & WRITEABLE(i)) && + !(handle->hdr.flags & ERROR(i))) events |= POLLOUT; if (events) { - fds[nfds].fd = handle->__in.fds[i]; + fds[nfds].fd = handle->hdr.fds[i]; fds[nfds].events = events|POLLHUP|POLLERR; fds[nfds].revents = 0; off[nfds] = i; @@ -93,9 +92,9 @@ static int _DkObjectWaitOne (PAL_HANDLE handle, int timeout) if (!fds[i].revents) continue; if (fds[i].revents & POLLOUT) - handle->__in.flags |= WRITEABLE(off[i]); + handle->hdr.flags |= WRITEABLE(off[i]); if (fds[i].revents & (POLLHUP|POLLERR)) - handle->__in.flags |= ERROR(off[i]); + handle->hdr.flags |= ERROR(off[i]); } return 0; @@ -111,7 +110,7 @@ static int _DkObjectWaitOne (PAL_HANDLE handle, int timeout) /* _DkObjectsWaitAny for internal use. The function wait for any of the handle in the handle array. timeout can be set for the wait. */ -int _DkObjectsWaitAny (int count, PAL_HANDLE * handleArray, int timeout, +int _DkObjectsWaitAny (int count, PAL_HANDLE * handleArray, uint64_t timeout, PAL_HANDLE * polled) { if (count <= 0) @@ -133,7 +132,7 @@ int _DkObjectsWaitAny (int count, PAL_HANDLE * handleArray, int timeout, if (!hdl) continue; - if (!(hdl->__in.flags & HAS_FDS)) + if (!(hdl->hdr.flags & HAS_FDS)) return -PAL_ERROR_NOTSUPPORT; /* eliminate repeated entries */ @@ -142,7 +141,7 @@ int _DkObjectsWaitAny (int count, PAL_HANDLE * handleArray, int timeout, break; if (j == i) { for (j = 0 ; j < MAX_FDS ; j++) - if (hdl->__in.flags & (RFD(j)|WFD(j))) + if (hdl->hdr.flags & (RFD(j)|WFD(j))) maxfds++; } } @@ -165,17 +164,17 @@ int _DkObjectsWaitAny (int count, PAL_HANDLE * handleArray, int timeout, for (j = 0 ; j < MAX_FDS ; j++) { int events = 0; - if ((hdl->__in.flags & RFD(j)) && - !(hdl->__in.flags & ERROR(j))) + if ((hdl->hdr.flags & RFD(j)) && + !(hdl->hdr.flags & ERROR(j))) events |= POLLIN; - if ((hdl->__in.flags & WFD(j)) && - !(hdl->__in.flags & WRITEABLE(j)) && - !(hdl->__in.flags & ERROR(j))) + if ((hdl->hdr.flags & WFD(j)) && + !(hdl->hdr.flags & WRITEABLE(j)) && + !(hdl->hdr.flags & ERROR(j))) events |= POLLOUT; - if (events && hdl->__in.fds[j] != PAL_IDX_POISON) { - fds[nfds].fd = hdl->__in.fds[j]; + if (events && hdl->hdr.fds[j] != PAL_IDX_POISON) { + fds[nfds].fd = hdl->hdr.fds[j]; fds[nfds].events = events|POLLHUP|POLLERR; fds[nfds].revents = 0; hdls[nfds] = hdl; @@ -216,17 +215,17 @@ int _DkObjectsWaitAny (int count, PAL_HANDLE * handleArray, int timeout, } for (j = 0 ; j < MAX_FDS ; j++) - if ((hdl->__in.flags & (RFD(j)|WFD(j))) && - hdl->__in.fds[j] == fds[i].fd) + if ((hdl->hdr.flags & (RFD(j)|WFD(j))) && + hdl->hdr.fds[j] == fds[i].fd) break; if (j == MAX_FDS) continue; if (fds[i].revents & POLLOUT) - hdl->__in.flags |= WRITEABLE(j); + hdl->hdr.flags |= WRITEABLE(j); if (fds[i].revents & (POLLHUP|POLLERR)) - hdl->__in.flags |= ERROR(j); + hdl->hdr.flags |= ERROR(j); } *polled = polled_hdl; diff --git a/Pal/src/host/FreeBSD/db_pipes.c b/Pal/src/host/FreeBSD/db_pipes.c index b7591892..493caf07 100644 --- a/Pal/src/host/FreeBSD/db_pipes.c +++ b/Pal/src/host/FreeBSD/db_pipes.c @@ -102,7 +102,7 @@ static int pipe_listen (PAL_HANDLE * handle, PAL_NUM pipeid, int options) PAL_HANDLE hdl = malloc(HANDLE_SIZE(pipe)); SET_HANDLE_TYPE(hdl, pipesrv); - hdl->__in.flags |= RFD(0); + hdl->hdr.flags |= RFD(0); hdl->pipe.fd = fd; hdl->pipe.pipeid = pipeid; hdl->pipe.nonblocking = options & O_NONBLOCK ? @@ -160,14 +160,14 @@ static int pipe_waitforclient (PAL_HANDLE handle, PAL_HANDLE * client) PAL_HANDLE clnt = malloc(HANDLE_SIZE(pipeprv)); SET_HANDLE_TYPE(clnt, pipeprv); - clnt->__in.flags |= RFD(0)|WFD(1)|WRITEABLE(1); + clnt->hdr.flags |= RFD(0)|WFD(1)|WRITEABLE(1); clnt->pipeprv.fds[0] = pipes[0]; clnt->pipeprv.fds[1] = pipes[1]; *client = clnt; #else PAL_HANDLE clnt = malloc(HANDLE_SIZE(pipe)); SET_HANDLE_TYPE(clnt, pipecli); - clnt->__in.flags |= RFD(0)|WFD(0)|WRITEABLE(0); + clnt->hdr.flags |= RFD(0)|WFD(0)|WRITEABLE(0); clnt->pipe.fd = newfd; clnt->pipe.nonblocking = PAL_FALSE; clnt->pipe.pipeid = handle->pipe.pipeid; @@ -254,7 +254,7 @@ static int pipe_connect (PAL_HANDLE * handle, PAL_NUM pipeid, int options) PAL_HANDLE hdl = malloc(HANDLE_SIZE(pipeprv)); SET_HANDLE_TYPE(hdl, pipeprv); - hdl->__in.flags |= RFD(0)|WFD(1)|WRITEABLE(1); + hdl->hdr.flags |= RFD(0)|WFD(1)|WRITEABLE(1); hdl->pipeprv.fds[0] = pipes[0]; hdl->pipeprv.fds[1] = pipes[1]; hdl->pipeprv.nonblocking = (options & O_NONBLOCK) ? @@ -262,7 +262,7 @@ static int pipe_connect (PAL_HANDLE * handle, PAL_NUM pipeid, int options) #else PAL_HANDLE hdl = malloc(HANDLE_SIZE(pipe)); SET_HANDLE_TYPE(hdl, pipe); - hdl->__in.flags |= RFD(0)|WFD(0)|WRITEABLE(0); + hdl->hdr.flags |= RFD(0)|WFD(0)|WRITEABLE(0); hdl->pipe.fd = fd; hdl->pipe.pipeid = pipeid; hdl->pipe.nonblocking = (options & O_NONBLOCK) ? @@ -290,7 +290,7 @@ static int pipe_private (PAL_HANDLE * handle, int options) PAL_HANDLE hdl = malloc(HANDLE_SIZE(pipeprv)); SET_HANDLE_TYPE(hdl, pipeprv); - hdl->__in.flags |= RFD(0)|WFD(1)|WRITEABLE(1); + hdl->hdr.flags |= RFD(0)|WFD(1)|WRITEABLE(1); hdl->pipeprv.fds[0] = fds[0]; hdl->pipeprv.fds[1] = fds[1]; hdl->pipeprv.nonblocking = (options & O_NONBLOCK) ? @@ -420,7 +420,7 @@ static int pipe_write (PAL_HANDLE handle, int offset, int len, if (IS_ERR(bytes)) switch(ERRNO(bytes)) { case EWOULDBLOCK: - handle->__in.flags &= ~writeable; + handle->hdr.flags &= ~writeable; return-PAL_ERROR_TRYAGAIN; case EINTR: return -PAL_ERROR_INTERRUPTED; @@ -429,9 +429,9 @@ static int pipe_write (PAL_HANDLE handle, int offset, int len, } if (bytes == len) - handle->__in.flags |= writeable; + handle->hdr.flags |= writeable; else - handle->__in.flags &= ~writeable; + handle->hdr.flags &= ~writeable; return bytes; } @@ -518,38 +518,38 @@ static int pipe_attrquerybyhdl (PAL_HANDLE handle, PAL_STREAM_ATTR * attr) { int ret, val; - if (handle->__in.fds[0] == PAL_IDX_POISON) + if (handle->hdr.fds[0] == PAL_IDX_POISON) return -PAL_ERROR_BADHANDLE; - ret = INLINE_SYSCALL(ioctl, 3, handle->__in.fds[0], FIONREAD, &val); + ret = INLINE_SYSCALL(ioctl, 3, handle->hdr.fds[0], FIONREAD, &val); if (IS_ERR(ret)) return unix_to_pal_error(ERRNO(ret)); attr->handle_type = pal_type_pipe; - attr->disconnected = handle->__in.flags & ERROR(0); - attr->nonblocking = (handle->__in.type == pal_type_pipeprv) ? + attr->disconnected = handle->hdr.flags & ERROR(0); + attr->nonblocking = (handle->hdr.type == pal_type_pipeprv) ? handle->pipeprv.nonblocking : handle->pipe.nonblocking; attr->readable = val > 0; if (PAL_GET_TYPE(handle) == pal_type_pipeprv) - attr->writeable = handle->__in.flags & WRITEABLE(1); + attr->writeable = handle->hdr.flags & WRITEABLE(1); else - attr->writeable = handle->__in.flags & WRITEABLE(0); + attr->writeable = handle->hdr.flags & WRITEABLE(0); attr->pending_size = val; return 0; } static int pipe_attrsetbyhdl (PAL_HANDLE handle, PAL_STREAM_ATTR * attr) { - if (handle->__in.fds[0] == PAL_IDX_POISON) + if (handle->hdr.fds[0] == PAL_IDX_POISON) return -PAL_ERROR_BADHANDLE; int ret; - PAL_BOL * nonblocking = (handle->__in.type == pal_type_pipeprv) ? + PAL_BOL * nonblocking = (handle->hdr.type == pal_type_pipeprv) ? &handle->pipeprv.nonblocking : &handle->pipe.nonblocking; if (attr->nonblocking != *nonblocking) { - ret = INLINE_SYSCALL(fcntl, 3, handle->__in.fds[0], F_SETFL, + ret = INLINE_SYSCALL(fcntl, 3, handle->hdr.fds[0], F_SETFL, *nonblocking ? O_NONBLOCK : 0); if (IS_ERR(ret)) diff --git a/Pal/src/host/FreeBSD/db_process.c b/Pal/src/host/FreeBSD/db_process.c index a8a07186..4996c50d 100644 --- a/Pal/src/host/FreeBSD/db_process.c +++ b/Pal/src/host/FreeBSD/db_process.c @@ -79,7 +79,7 @@ static inline int create_process_handle (PAL_HANDLE * parent, } SET_HANDLE_TYPE(phdl, process); - phdl->__in.flags |= RFD(0)|WFD(1)|RFD(2)|WFD(2)|WRITEABLE(1)|WRITEABLE(2); + phdl->hdr.flags |= RFD(0)|WFD(1)|RFD(2)|WFD(2)|WRITEABLE(1)|WRITEABLE(2); phdl->process.stream_in = proc_fds[0][0]; phdl->process.stream_out = proc_fds[0][1]; phdl->process.cargo = proc_fds[0][2]; @@ -93,7 +93,7 @@ static inline int create_process_handle (PAL_HANDLE * parent, } SET_HANDLE_TYPE(chdl, process); - chdl->__in.flags |= RFD(0)|WFD(1)|RFD(2)|WFD(2)|WRITEABLE(1)|WRITEABLE(2); + chdl->hdr.flags |= RFD(0)|WFD(1)|RFD(2)|WFD(2)|WRITEABLE(1)|WRITEABLE(2); chdl->process.stream_in = proc_fds[1][0]; chdl->process.stream_out = proc_fds[1][1]; chdl->process.cargo = proc_fds[1][2]; @@ -124,6 +124,7 @@ struct proc_param { }; struct proc_args { + PAL_NUM parent_process_id; struct pal_sec pal_sec; unsigned long memory_quota; unsigned int parent_data_size; @@ -220,6 +221,7 @@ int _DkProcessCreate (PAL_HANDLE * handle, struct proc_args * proc_args = __alloca(sizeof(struct proc_args) + datasz); + proc_args->parent_process_id = bsd_state.parent_pid; memcpy(&proc_args->pal_sec, &pal_sec, sizeof(struct pal_sec)); proc_args->pal_sec.r_debug_state = NULL; proc_args->pal_sec.r_debug = NULL; @@ -391,6 +393,10 @@ void _DkProcessExit (int exitcode) int _DkProcessSandboxCreate (const char * manifest, int flags) { + PAL_HANDLE handle = NULL; + _DkStreamOpen(&handle, manifest, PAL_ACCESS_RDONLY, 0, 0, 0); + pal_state.manifest_handle = handle; + pal_state.manifest = manifest; return -PAL_ERROR_NOTIMPLEMENTED; } @@ -422,7 +428,7 @@ static int proc_write (PAL_HANDLE handle, int offset, int count, if (IS_ERR(bytes)) switch(ERRNO(bytes)) { case EWOULDBLOCK: - handle->__in.flags &= ~WRITEABLE(1); + handle->hdr.flags &= ~WRITEABLE(1); return-PAL_ERROR_TRYAGAIN; case EINTR: return -PAL_ERROR_INTERRUPTED; @@ -431,9 +437,9 @@ static int proc_write (PAL_HANDLE handle, int offset, int count, } if (bytes == count) - handle->__in.flags |= WRITEABLE(1); + handle->hdr.flags |= WRITEABLE(1); else - handle->__in.flags &= ~WRITEABLE(1); + handle->hdr.flags &= ~WRITEABLE(1); return bytes; } @@ -506,9 +512,9 @@ static int proc_attrquerybyhdl (PAL_HANDLE handle, PAL_STREAM_ATTR * attr) attr->handle_type = pal_type_process; attr->nonblocking = handle->process.nonblocking; - attr->disconnected = handle->__in.flags & (ERROR(0)|ERROR(1)); + attr->disconnected = handle->hdr.flags & (ERROR(0)|ERROR(1)); attr->readable = !!val; - attr->writeable = handle->__in.flags & WRITEABLE(1); + attr->writeable = handle->hdr.flags & WRITEABLE(1); attr->runnable = PAL_FALSE; attr->pending_size = val; diff --git a/Pal/src/host/FreeBSD/db_rtld.c b/Pal/src/host/FreeBSD/db_rtld.c index d3da5faa..a3415d57 100644 --- a/Pal/src/host/FreeBSD/db_rtld.c +++ b/Pal/src/host/FreeBSD/db_rtld.c @@ -39,7 +39,7 @@ #include #include -#include +#include #include "elf-x86_64.h" diff --git a/Pal/src/host/FreeBSD/db_semaphore.c b/Pal/src/host/FreeBSD/db_semaphore.c deleted file mode 100644 index a8af4623..00000000 --- a/Pal/src/host/FreeBSD/db_semaphore.c +++ /dev/null @@ -1,264 +0,0 @@ -/* -*- mode:c; c-file-style:"k&r"; c-basic-offset: 4; tab-width:4; indent-tabs-mode:nil; mode:auto-fill; fill-column:78; -*- */ -/* vim: set ts=4 sw=4 et tw=78 fo=cqt wm=0: */ - -/* Copyright (C) 2014 Stony Brook University - This file is part of Graphene Library OS. - - Graphene Library OS is free software: you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public License - as published by the Free Software Foundation, either version 3 of the - License, or (at your option) any later version. - - Graphene Library OS is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program. If not, see . */ - -/* - * db_semaphore.c - * - * This file contains APIs that provides operations of semaphores. - */ - -#include "pal_defs.h" -#include "pal_freebsd_defs.h" -#include "pal.h" -#include "pal_internal.h" -#include "pal_freebsd.h" -#include "pal_error.h" -#include "api.h" - -#include -#include -#include -#include -#include - -static inline int atomic_dec_if_positive (struct atomic_int *v) -{ - int c, old, dec; - c = atomic_read(v); - for (;;) { - dec = c - 1; - if (unlikely(dec < 0)) - break; - old = atomic_cmpxchg((v), c, dec); - if (likely(old == c)) - break; - c = old; - } - return dec; -} - -int _DkSemaphoreCreate (PAL_HANDLE handle, int initialCount, int maxCount) -{ - /* - * 1. Allocate memory for db_sem (this includes a futex variable). - * 2. Pack it into a PAL_HANDLE - * 3. Set the semaphore object with the argument values (count, maxCount) - */ - - SET_HANDLE_TYPE(handle, semaphore); - atomic_set(&handle->semaphore.nwaiters, 0); - handle->semaphore.max_value = maxCount; - - /* optimization: if maxCount == 1, we make it into mutex */ - if (handle->semaphore.max_value == 1) { - atomic_set(&handle->semaphore.value.mut.value, 1 - initialCount); - } else { - atomic_set(&handle->semaphore.value.i, maxCount - initialCount); - } - - return 0; -} - -void _DkSemaphoreDestroy (PAL_HANDLE semaphoreHandle) -{ - free(semaphoreHandle); -} - -int _DkMutexLockTimeout (struct mutex_handle * mut, int timeout); - -int _DkSemaphoreAcquire (PAL_HANDLE sem, int count) -{ - /* optimization: use it as a mutex */ - if (sem->semaphore.max_value == 1) { - struct mutex_handle * mut = &sem->semaphore.value.mut; - _DkMutexLock(mut); - return 0; - } - - if (count > sem->semaphore.max_value) - return -PAL_ERROR_INVAL; - - struct atomic_int * value = &sem->semaphore.value.i; - int c = 0; - - if (!value) - return -PAL_ERROR_BADHANDLE; - - if (count == 1) - c = atomic_dec_and_test_nonnegative (value); - else - c = atomic_sub_and_test_nonnegative (count, value); - - if (c) - return 0; - - /* We didn't get the lock. Bump the count back up. */ - if (count == 1) - atomic_inc (value); - else - atomic_add (count, value); - - int ret = 0; - atomic_inc (&sem->semaphore.nwaiters); - - while (1) { - ret = INLINE_SYSCALL(_umtx_op, 5, value, UMTX_OP_WAIT, 0, - NULL, NULL); - - if (IS_ERR(ret)) { - if (ERRNO(ret) == EWOULDBLOCK) { - ret = 0; - } else { - ret = unix_to_pal_error(ERRNO(ret)); - break; - } - } - - if (count == 1) - c = atomic_dec_and_test_nonnegative (value); - else - c = atomic_sub_and_test_nonnegative (count, value); - - if (c) - break; - - /* We didn't get the lock. Bump the count back up. */ - if (count == 1) - atomic_inc (value); - else - atomic_add (count, value); - } - - atomic_dec (&sem->semaphore.nwaiters); - return ret; -} - -int _DkSemaphoreAcquireTimeout (PAL_HANDLE sem, int count, int timeout) -{ - /* Pass it up to the no-timeout version if no timeout requested */ - if (timeout == -1) - return _DkSemaphoreAcquire(sem, count); - - /* optimization: use it as a mutex */ - if (sem->semaphore.max_value == 1) { - struct mutex_handle * mut = & sem->semaphore.value.mut; - _DkMutexLockTimeout(mut, timeout); - return 0; - } - - if (count > sem->semaphore.max_value) - return -PAL_ERROR_INVAL; - - struct atomic_int * value = &sem->semaphore.value.i; - int c = 0; - - if (!value) - return -PAL_ERROR_BADHANDLE; - - if (count == 1) - c = atomic_dec_and_test_nonnegative (value); - else - c = atomic_sub_and_test_nonnegative (count, value); - - if (c) - return 0; - - /* We didn't get the lock. Bump the count back up. */ - if (count == 1) - atomic_inc (value); - else - atomic_add (count, value); - - if (!timeout) - return 0; - - struct timespec waittime; - long sec = timeout / 1000000; - long microsec = timeout - (sec * 1000000); - waittime.tv_sec = sec; - waittime.tv_nsec = microsec * 1000; - int ret = 0; - atomic_inc (&sem->semaphore.nwaiters); - - while (1) { - ret = INLINE_SYSCALL(_umtx_op, 5, value, UMTX_OP_WAIT_UINT, 0, - NULL, &waittime); - - if (ERRNO(ret) == EWOULDBLOCK) { - ret = 0; - } else { - ret = unix_to_pal_error(ERRNO(ret)); - break; - } - - if (count == 1) - c = atomic_dec_and_test_nonnegative (value); - else - c = atomic_sub_and_test_nonnegative (count, value); - - if (c) - break; - } - - /* We didn't get the lock. Bump the count back up. */ - if (count == 1) - atomic_inc (value); - else - atomic_add (count, value); - - atomic_dec (&sem->semaphore.nwaiters); - return ret; -} - -void _DkSemaphoreRelease (PAL_HANDLE sem, int count) -{ - /* optimization: use it as a mutex */ - if (sem->semaphore.max_value == 1) { - struct mutex_handle * mut = - &sem->semaphore.value.mut; - - _DkMutexUnlock(mut); - return; - } - - struct atomic_int * value = &sem->semaphore.value.i; - - if (count == 1) - atomic_inc (value); - else - atomic_add (count, value); - - int nwaiters = atomic_read (&sem->semaphore.nwaiters); - - if (nwaiters > 0) - INLINE_SYSCALL(_umtx_op, 5, value, UMTX_OP_WAKE, - nwaiters, NULL, NULL); -} - -int _DkSemaphoreGetCurrentCount (PAL_HANDLE sem) -{ - if (sem->semaphore.max_value == 1) { - struct mutex_handle * mut = - &sem->semaphore.value.mut; - return atomic_read(&mut->value); - } - - int c = atomic_read(&sem->semaphore.value.i); - return sem->semaphore.max_value - c; -} diff --git a/Pal/src/host/FreeBSD/db_sockets.c b/Pal/src/host/FreeBSD/db_sockets.c index 0803a3a3..92aa8f86 100644 --- a/Pal/src/host/FreeBSD/db_sockets.c +++ b/Pal/src/host/FreeBSD/db_sockets.c @@ -45,6 +45,10 @@ typedef __kernel_pid_t pid_t; #include #include +/* FreeBSD doesn't have addr_check_any. */ +#undef ALLOW_BIND_ANY +#define ALLOW_BIND_ANY 1 + /* 96 bytes is the minimal size of buffer to store a IPv4/IPv6 address */ #define PAL_SOCKADDR_SIZE 96 @@ -233,7 +237,7 @@ PAL_HANDLE socket_create_handle (int type, int fd, int options, memset(hdl, 0, sizeof(union pal_handle)); PAL_GET_TYPE(hdl) = type; - hdl->__in.flags |= RFD(0)|(type != pal_type_tcpsrv ? WFD(0) : 0); + hdl->hdr.flags |= RFD(0)|(type != pal_type_tcpsrv ? WFD(0) : 0); hdl->sock.fd = fd; void * addr = (void *) hdl + HANDLE_SIZE(sock); if (bind_addr) { @@ -351,7 +355,7 @@ static int tcp_listen (PAL_HANDLE * handle, char * uri, int options) options = HOST_SOCKET_OPTIONS(options); /* the socket need to have a binding address, a null address or an any address is not allowed */ - if (!bind_addr || addr_check_any(bind_addr) == 0) + if (!bind_addr == 0) return -PAL_ERROR_INVAL; fd = INLINE_SYSCALL(socket, 3, bind_addr->sa_family, @@ -619,16 +623,16 @@ static int tcp_write (PAL_HANDLE handle, int offset, int len, const void * buf) case EPIPE: return -PAL_ERROR_CONNFAILED; case EWOULDBLOCK: - handle->__in.flags &= ~WRITEABLE(0); + handle->hdr.flags &= ~WRITEABLE(0); return -PAL_ERROR_TRYAGAIN; default: return unix_to_pal_error(ERRNO(bytes)); } if (bytes == len) - handle->__in.flags |= WRITEABLE(0); + handle->hdr.flags |= WRITEABLE(0); else - handle->__in.flags &= ~WRITEABLE(0); + handle->hdr.flags &= ~WRITEABLE(0); return bytes; } @@ -882,7 +886,7 @@ static int udp_send (PAL_HANDLE handle, int offset, int len, const void * buf) if (IS_ERR(bytes)) switch(ERRNO(bytes)) { case EAGAIN: - handle->__in.flags &= ~WRITEABLE(0); + handle->hdr.flags &= ~WRITEABLE(0); return -PAL_ERROR_TRYAGAIN; case ECONNRESET: case EPIPE: @@ -892,9 +896,9 @@ static int udp_send (PAL_HANDLE handle, int offset, int len, const void * buf) } if (bytes == len) - handle->__in.flags |= WRITEABLE(0); + handle->hdr.flags |= WRITEABLE(0); else - handle->__in.flags &= ~WRITEABLE(0); + handle->hdr.flags &= ~WRITEABLE(0); return bytes; } @@ -943,15 +947,15 @@ static int udp_sendbyaddr (PAL_HANDLE handle, int offset, int len, case EPIPE: return -PAL_ERROR_CONNFAILED; case EAGAIN: - handle->__in.flags &= ~WRITEABLE(0); + handle->hdr.flags &= ~WRITEABLE(0); default: return unix_to_pal_error(ERRNO(bytes)); } if (bytes == len) - handle->__in.flags |= WRITEABLE(0); + handle->hdr.flags |= WRITEABLE(0); else - handle->__in.flags &= ~WRITEABLE(0); + handle->hdr.flags &= ~WRITEABLE(0); return bytes; } @@ -1022,10 +1026,10 @@ static int socket_attrquerybyhdl (PAL_HANDLE handle, PAL_STREAM_ATTR * attr) attr->readable = !attr->disconnected; } - attr->handle_type = handle->__in.type; - attr->disconnected = handle->__in.flags & ERROR(0); + attr->handle_type = handle->hdr.type; + attr->disconnected = handle->hdr.flags & ERROR(0); attr->nonblocking = handle->sock.nonblocking; - attr->writeable = handle->__in.flags & WRITEABLE(0); + attr->writeable = handle->hdr.flags & WRITEABLE(0); attr->socket.linger = handle->sock.linger; attr->socket.receivebuf = handle->sock.receivebuf; attr->socket.sendbuf = handle->sock.sendbuf; @@ -1275,7 +1279,7 @@ static int mcast_s (PAL_HANDLE handle, int port) if (IS_ERR(ret)) return -PAL_ERROR_DENIED; - handle->__in.flags |= WFD(1)|WRITEABLE(1); + handle->hdr.flags |= WFD(1)|WRITEABLE(1); handle->mcast.srv = fd; return 0; } @@ -1375,15 +1379,15 @@ static int mcast_send (PAL_HANDLE handle, int offset, int size, case EPIPE: return -PAL_ERROR_CONNFAILED; case EAGAIN: - handle->__in.flags &= ~WRITEABLE(1); + handle->hdr.flags &= ~WRITEABLE(1); default: return unix_to_pal_error(ERRNO(bytes)); } if (bytes == size) - handle->__in.flags |= WRITEABLE(1); + handle->hdr.flags |= WRITEABLE(1); else - handle->__in.flags &= ~WRITEABLE(1); + handle->hdr.flags &= ~WRITEABLE(1); return bytes; } @@ -1437,10 +1441,10 @@ static int mcast_attrquerybyhdl (PAL_HANDLE handle, PAL_STREAM_ATTR * attr) return unix_to_pal_error(ERRNO(ret)); attr->handle_type = pal_type_mcast; - attr->disconnected = handle->__in.flags & (ERROR(0)|ERROR(1)); + attr->disconnected = handle->hdr.flags & (ERROR(0)|ERROR(1)); attr->nonblocking = handle->mcast.nonblocking; attr->readable = !!val; - attr->writeable = handle->__in.flags & WRITEABLE(1); + attr->writeable = handle->hdr.flags & WRITEABLE(1); attr->runnable = PAL_FALSE; attr->pending_size = val; return 0; diff --git a/Pal/src/host/FreeBSD/db_streams.c b/Pal/src/host/FreeBSD/db_streams.c index 7c7eae0b..8b27a944 100644 --- a/Pal/src/host/FreeBSD/db_streams.c +++ b/Pal/src/host/FreeBSD/db_streams.c @@ -73,10 +73,10 @@ out: int handle_set_cloexec (PAL_HANDLE handle, bool enable) { for (int i = 0 ; i < MAX_FDS ; i++) - if (handle->__in.flags & (RFD(i)|WFD(i))) { + if (handle->hdr.flags & (RFD(i)|WFD(i))) { long flags = enable ? FD_CLOEXEC : 0; int ret = INLINE_SYSCALL(fcntl, 3, - handle->__in.fds[i], F_SETFD, + handle->hdr.fds[i], F_SETFD, flags); if (IS_ERR(ret) && ERRNO(ret) != EBADF) return -PAL_ERROR_DENIED; @@ -87,7 +87,7 @@ int handle_set_cloexec (PAL_HANDLE handle, bool enable) /* _DkStreamUnmap for internal use. Unmap stream at certain memory address. The memory is unmapped as a whole.*/ -int _DkStreamUnmap (void * addr, int size) +int _DkStreamUnmap (void * addr, uint64_t size) { /* Just let the kernel tell us if the mapping isn't good. */ int ret = INLINE_SYSCALL(munmap, 2, addr, size); @@ -289,9 +289,9 @@ int _DkSendHandle (PAL_HANDLE hdl, PAL_HANDLE cargo) int fds[MAX_FDS]; int nfds = 0; for (int i = 0 ; i < MAX_FDS ; i++) - if (cargo->__in.flags & (RFD(i)|WFD(1))) { + if (cargo->hdr.flags & (RFD(i)|WFD(1))) { hdl_hdr.fds |= 1U << i; - fds[nfds++] = cargo->__in.fds[i]; + fds[nfds++] = cargo->hdr.fds[i]; } // ~ Initialize common parameter formessage passing // Channel between parent and child @@ -434,9 +434,9 @@ int _DkReceiveHandle(PAL_HANDLE hdl, PAL_HANDLE * cargo) for (int i = 0 ; i < MAX_FDS ; i++) if (hdl_hdr.fds & (1U << i)) { if (n < total_fds) { - handle->__in.fds[i] = ((int *) CMSG_DATA(chdr))[n++]; + handle->hdr.fds[i] = ((int *) CMSG_DATA(chdr))[n++]; } else { - handle->__in.flags &= ~(RFD(i)|WFD(i)); + handle->hdr.flags &= ~(RFD(i)|WFD(i)); } } diff --git a/Pal/src/host/FreeBSD/pal_freebsd.h b/Pal/src/host/FreeBSD/pal_freebsd.h index c3b609fd..44c37534 100644 --- a/Pal/src/host/FreeBSD/pal_freebsd.h +++ b/Pal/src/host/FreeBSD/pal_freebsd.h @@ -47,7 +47,7 @@ typedef int __kernel_pid_t; #define ERRNO INTERNAL_SYSCALL_ERRNO #define ERRNO_P INTERNAL_SYSCALL_ERRNO_P -int getrand (void * buffer, int size); +int getrand (void * buffer, size_t size); struct timespec; struct timeval; @@ -58,10 +58,10 @@ extern struct pal_bsd_state { /* credentails */ unsigned int pid; unsigned int uid, gid; - + unsigned int parent_pid; /* currently enabled signals */ _sigset_t sigset; - + unsigned long memory_quota; } bsd_state; @@ -99,7 +99,7 @@ extern struct pal_bsd_state { static inline int HOST_FLAGS (int alloc_type, int prot) { - return ((alloc_type & PAL_ALLOC_RESERVE) ? MAP_NORESERVE : 0) | + return ((prot & PAL_PROT_WRITECOPY) ? MAP_PRIVATE : MAP_SHARED); } diff --git a/Pal/src/host/FreeBSD/pal_host.h b/Pal/src/host/FreeBSD/pal_host.h index 8d32b197..0c01b0c0 100644 --- a/Pal/src/host/FreeBSD/pal_host.h +++ b/Pal/src/host/FreeBSD/pal_host.h @@ -57,16 +57,20 @@ typedef union pal_handle * handle, also there is no need to allocate the internal * handles, so we hide the type name of these handles on purpose. */ + struct { + PAL_HDR hdr; + struct mutex_handle mut; + } mutex; struct { PAL_IDX type; PAL_FLG flags; PAL_REF ref; PAL_IDX fds[]; - } __in; + } hdr; struct { - PAL_HDR __in; + PAL_HDR hdr; PAL_IDX fd; PAL_NUM offset; PAL_BOL append; @@ -75,20 +79,20 @@ typedef union pal_handle } file; struct { - PAL_HDR __in; + PAL_HDR hdr; PAL_IDX fd; PAL_NUM pipeid; PAL_BOL nonblocking; } pipe; struct { - PAL_HDR __in; + PAL_HDR hdr; PAL_IDX fds[2]; PAL_BOL nonblocking; } pipeprv; struct { - PAL_HDR __in; + PAL_HDR hdr; PAL_IDX fd_in, fd_out; PAL_IDX dev_type; PAL_BOL destroy; @@ -96,7 +100,7 @@ typedef union pal_handle } dev; struct { - PAL_HDR __in; + PAL_HDR hdr; PAL_IDX fd; PAL_STR realpath; PAL_PTR buf; @@ -106,13 +110,13 @@ typedef union pal_handle } dir; struct { - PAL_HDR __in; + PAL_HDR hdr; PAL_IDX fd; PAL_NUM token; } gipc; struct { - PAL_HDR __in; + PAL_HDR hdr; PAL_IDX fd; PAL_PTR bind; PAL_PTR conn; @@ -129,7 +133,7 @@ typedef union pal_handle } sock; struct { - PAL_HDR __in; + PAL_HDR hdr; PAL_IDX stream_in, stream_out; PAL_IDX cargo; PAL_IDX pid; @@ -137,7 +141,7 @@ typedef union pal_handle } process; struct { - PAL_HDR __in; + PAL_HDR hdr; PAL_IDX cli; PAL_IDX srv; PAL_IDX port; @@ -145,12 +149,12 @@ typedef union pal_handle } mcast; struct { - PAL_HDR __in; + PAL_HDR hdr; PAL_IDX tid; } thread; struct { - PAL_HDR __in; + PAL_HDR hdr; struct atomic_int nwaiters; PAL_NUM max_value; union { @@ -160,7 +164,7 @@ typedef union pal_handle } semaphore; struct { - PAL_HDR __in; + PAL_HDR hdr; struct atomic_int signaled; struct atomic_int nwaiters; PAL_BOL isnotification; @@ -174,5 +178,115 @@ typedef union pal_handle #define MAX_FDS (3) #define HAS_FDS (00077) -#define HANDLE_TYPE(handle) ((handle)->__in.type) +#define HANDLE_TYPE(handle) ((handle)->hdr.type) +struct arch_frame { +#ifdef __x86_64__ + uint64_t rsp, rbp, rbx, rsi, rdi, r12, r13, r14, r15; +#else +# error "unsupported architecture" +#endif +}; + +#ifdef __x86_64__ +# define store_register(reg, var) \ + asm volatile ("movq %%" #reg ", %0" : "=a" (var) :: "memory"); + +# define store_register_in_frame(reg, f) store_register(reg, (f)->reg) + +# define arch_store_frame(f) \ + store_register_in_frame(rsp, f) \ + store_register_in_frame(rbp, f) \ + store_register_in_frame(rbx, f) \ + store_register_in_frame(rsi, f) \ + store_register_in_frame(rdi, f) \ + store_register_in_frame(r12, f) \ + store_register_in_frame(r13, f) \ + store_register_in_frame(r14, f) \ + store_register_in_frame(r15, f) + +# define restore_register(reg, var, clobber...) \ + asm volatile ("movq %0, %%" #reg :: "g" (var) : "memory", ##clobber); + +# define restore_register_in_frame(reg, f) \ + restore_register(reg, (f)->reg, \ + "r15", "r14", "r13", "r12", "rdi", "rsi", "rbx") + +# define arch_restore_frame(f) \ + restore_register_in_frame(r15, f) \ + restore_register_in_frame(r14, f) \ + restore_register_in_frame(r13, f) \ + restore_register_in_frame(r12, f) \ + restore_register_in_frame(rdi, f) \ + restore_register_in_frame(rsi, f) \ + restore_register_in_frame(rbx, f) \ + restore_register_in_frame(rbp, f) \ + restore_register_in_frame(rsp, f) +#else /* __x86_64__ */ +# error "unsupported architecture" +#endif + +#define PAL_FRAME_IDENTIFIER (0xdeaddeadbeefbeef) + +struct pal_frame { + volatile uint64_t identifier; + void * func; + const char * funcname; + struct arch_frame arch; +}; + +/* When a PAL call is issued, a special PAL_FRAME is placed on the stack. + * This stores both a magic identifier, debugging information, + * as well as callee-saved state. This is used as a way to deal + * with PAL-internal failures where the goal is to exit the PAL and return a + * failure. + * + * Arguably, an alternative is to unwind the stack and handle error cases at + * each stage. In general, this is probably more robust, but would take work + * in the short term. The one exception where the current strategy is + * probably better is when the PAL gets in a state where the code is + * unrecoverable, but ideally, this shouldn't happen. + */ + +/* DEP 12/25/17: This frame storage thing is important to mark volatile. + * The compiler should not optimize out any of these changes, and + * because some accesses can happen during an exception, these are not + * visible to the compiler in an otherwise stack-local variable (so the + * compiler will try to optimize out these assignments. + */ +static inline +void __store_frame (volatile struct pal_frame * frame, + void * func, const char * funcname) +{ + arch_store_frame(&frame->arch) + frame->func = func; + frame->funcname = funcname; + asm volatile ("nop" ::: "memory"); + frame->identifier = PAL_FRAME_IDENTIFIER; +} + +#define ENTER_PAL_CALL(name) \ + struct pal_frame frame; \ + __store_frame(&frame, &(name), #name) + + +static inline +void __clear_frame (volatile struct pal_frame * frame) +{ + if (frame->identifier == PAL_FRAME_IDENTIFIER) { + asm volatile ("nop" ::: "memory"); + frame->identifier = 0; + } +} + +#define LEAVE_PAL_CALL() \ + do { \ + __clear_frame(&frame); \ + } while (0) + +#define LEAVE_PAL_CALL_RETURN(retval) \ + do { \ + __clear_frame(&frame); \ + return (retval); \ +} while (0) + #endif /* PAL_HOST_H */