Skip to content
Snippets Groups Projects
runtime.cc 8.94 KiB
Newer Older
  • Learn to ignore specific revisions
  • /*
     * Copyright (C) 2013 Cloudius Systems, Ltd.
     *
     * This work is open source software, licensed under the terms of the
     * BSD license as described in the LICENSE file in the top-level directory.
     */
    
    
    #include "sched.hh"
    
    Avi Kivity's avatar
    Avi Kivity committed
    #include <cstdlib>
    #include <cstring>
    #include <string.h>
    #include <exception>
    #include <libintl.h>
    #include <cxxabi.h>
    #include <sys/mman.h>
    #include <unistd.h>
    #include <libunwind.h>
    #include <link.h>
    
    Avi Kivity's avatar
    Avi Kivity committed
    #include <stdio.h>
    #include <sys/poll.h>
    #include <sys/ioctl.h>
    #include <errno.h>
    #include <sys/uio.h>
    #include <wchar.h>
    #include <locale.h>
    #include <libintl.h>
    #include <ctype.h>
    #include <wctype.h>
    #include <langinfo.h>
    #include <stdarg.h>
    
    #include <xlocale.h>
    #include <cassert>
    
    Avi Kivity's avatar
    Avi Kivity committed
    #include <sys/sysinfo.h>
    
    #include "processor.hh"
    
    #include "debug.hh"
    
    Avi Kivity's avatar
    Avi Kivity committed
    #include <boost/format.hpp>
    
    #include "mempool.hh"
    
    Avi Kivity's avatar
    Avi Kivity committed
    #include <pwd.h>
    
    Avi Kivity's avatar
    Avi Kivity committed
    #include <fcntl.h>
    
    #include "barrier.hh"
    
    #include "bsd/sys/sys/sysctl.h"
    
    Nadav Har'El's avatar
    Nadav Har'El committed
    #include <osv/power.hh>
    
    Or Cohen's avatar
    Or Cohen committed
    #include <sys/time.h>
    
    #include "mmu.hh"
    #include "libc/libc.hh"
    
    Pekka Enberg's avatar
    Pekka Enberg committed
    #include <api/sys/times.h>
    
    #include <map>
    #include <boost/range/adaptor/reversed.hpp>
    
    #include "align.hh"
    #include <safe-ptr.hh>
    
    #define __LC_LAST 13
    
    Avi Kivity's avatar
    Avi Kivity committed
    
    typedef unsigned char __guard;
    
    Avi Kivity's avatar
    Avi Kivity committed
    
    
    Avi Kivity's avatar
    Avi Kivity committed
    #define __alias(x) __attribute__((alias(x)))
    
    
    Avi Kivity's avatar
    Avi Kivity committed
    extern "C" {
        void __cxa_pure_virtual(void);
        void abort(void);
        void _Unwind_Resume(void);
    
    Avi Kivity's avatar
    Avi Kivity committed
        void *malloc(size_t size);
        void free(void *);
        int tdep_get_elf_image(struct elf_image *ei, pid_t pid, unw_word_t ip,
                               unsigned long *segbase, unsigned long *mapoff,
                               char *path, size_t pathlen);
        int _Uelf64_get_proc_name(unw_addr_space_t as, int pid, unw_word_t ip,
                                  char *buf, size_t buf_len, unw_word_t *offp);
    
    Avi Kivity's avatar
    Avi Kivity committed
        void __stack_chk_fail(void);
        __locale_t __newlocale(int __category_mask, __const char *__locale,
    			   __locale_t __base) __THROW;
    
    Christoph Hellwig's avatar
    Christoph Hellwig committed
        int mallopt(int param, int value);
    
        FILE *popen(const char *command, const char *type);
        int pclose(FILE *stream);
    
    Avi Kivity's avatar
    Avi Kivity committed
    }
    
    
    Avi Kivity's avatar
    Avi Kivity committed
    void *__dso_handle;
    
    
    #define WARN(msg) do {					\
    
    Avi Kivity's avatar
    Avi Kivity committed
            static bool _x;					\
    	if (!_x) {					\
    	    _x = true;					\
    
    	    debug("WARNING: unimplemented " msg);	\
    
    Avi Kivity's avatar
    Avi Kivity committed
    	}						\
    
        } while (0)
    
    #define UNIMPLEMENTED(msg) do {				\
    
    	WARN(msg "\n");					\
    
    Avi Kivity's avatar
    Avi Kivity committed
    	abort();					\
    
    Avi Kivity's avatar
    Avi Kivity committed
        } while (0)
    
    
    
    Avi Kivity's avatar
    Avi Kivity committed
    #define UNIMPL(decl) decl { UNIMPLEMENTED(#decl); }
    
    #define IGN(decl) decl { WARN(#decl " (continuing)"); }
    
    Avi Kivity's avatar
    Avi Kivity committed
    
    
    static bool already_aborted = false;
    
    Avi Kivity's avatar
    Avi Kivity committed
    void abort()
    
    {
        abort("Aborted\n");
    }
    
    void abort(const char *msg)
    
    Avi Kivity's avatar
    Avi Kivity committed
    {
    
        if (!already_aborted) {
    
            already_aborted = true;
    
            debug_ll(msg);
    
    Nadav Har'El's avatar
    Nadav Har'El committed
        osv::halt();
    
    Avi Kivity's avatar
    Avi Kivity committed
    }
    
    
    // __cxa_atexit and __cxa_finalize:
    // Gcc implements static constructors and destructors in shared-objects (DSO)
    // in the following way: Static constructors are added to a list DT_INIT_ARRAY
    // in the object, and we run these functions after loading the object. Gcc's
    // code for each constructor calls a function __cxxabiv1::__cxa_atexit (which
    // we need to implement here) to register a destructor, linked to this DSO.
    // Gcc also adds a single finalization function to DT_FINI_ARRAY (which we
    // call when unloading the DSO), which calls __cxxabiv1::__cxa_finalize
    // (which we need to implement here) - this function is supposed to call all
    // the destructors previously registered for the given DSO.
    //
    // This implementation is greatly simplified by the assumption that the kernel
    // never exits, so our code doesn't need to work during early initialization,
    // nor does __cxa_finalize(0) need to work.
    typedef void (*destructor_t)(void *);
    static std::map<void *, std::vector<std::pair<destructor_t,void*>>> destructors;
    
    Avi Kivity's avatar
    Avi Kivity committed
    namespace __cxxabiv1 {
    
    int __cxa_atexit(destructor_t destructor, void *arg, void *dso)
    {
        // As explained above, don't remember the kernel's own destructors.
        if (dso == &__dso_handle)
            return 0;
        destructors[dso].push_back(std::make_pair(destructor, arg));
        return 0;
    }
    
    Avi Kivity's avatar
    Avi Kivity committed
    
    
    int __cxa_finalize(void *dso)
    {
        if (!dso || dso == &__dso_handle) {
            debug("__cxa_finalize() running kernel's destructors not supported\n");
            return 0;
    
    Avi Kivity's avatar
    Avi Kivity committed
        }
    
        for (auto d : boost::adaptors::reverse(destructors[dso])) {
            d.first(d.second);
    
    Avi Kivity's avatar
    Avi Kivity committed
        }
    
        destructors.erase(dso);
        return 0;
    }
    
    Avi Kivity's avatar
    Avi Kivity committed
    }
    
    int getpagesize()
    {
        return 4096;
    }
    
    int
    tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip,
    		    unsigned long *segbase, unsigned long *mapoff,
    		    char *path, size_t pathlen)
    {
        return 0;
    }
    
    
    Glauber Costa's avatar
    Glauber Costa committed
    int vfork()
    {
        debug("vfork stubbed\n");
        return -1;
    }
    
    int fork()
    {
        debug("fork stubbed\n");
        return -1;
    }
    
    
    Glauber Costa's avatar
    Glauber Costa committed
    int mlockall(int flags)
    {
        return 0;
    }
    
    int munlockall(void)
    {
        return 0;
    }
    
    
    Glauber Costa's avatar
    Glauber Costa committed
    int posix_fadvise(int fd, off_t offset, off_t len, int advice)
    {
        switch (advice) {
        case POSIX_FADV_NORMAL:
        case POSIX_FADV_SEQUENTIAL:
        case POSIX_FADV_RANDOM:
        case POSIX_FADV_NOREUSE:
        case POSIX_FADV_WILLNEED:
        case POSIX_FADV_DONTNEED:
            return 0;
        default:
    
            return EINVAL;
    
    Avi Kivity's avatar
    Avi Kivity committed
    int getpid()
    {
        return 0;
    }
    
    int mincore(void *addr, size_t length, unsigned char *vec)
    {
    
        if ((reinterpret_cast<intptr_t>(addr) & 4095)) {
            return libc_error(EINVAL);
        }
    
        if (!mmu::is_linear_mapped(addr, length) && !mmu::ismapped(addr, length)) {
    
            return libc_error(ENOMEM);
        }
    
        char *end = align_up((char *)addr + length, mmu::page_size);
        char tmp;
        for (char *p = (char *)addr; p < end; p += mmu::page_size) {
            if (safe_load(p, tmp)) {
                *vec++ = 0x01;
            } else {
                *vec++ = 0x00;
            }
        }
    
    Avi Kivity's avatar
    Avi Kivity committed
        return 0;
    }
    
    
    //    WCTDEF(alnum), WCTDEF(alpha), WCTDEF(blank), WCTDEF(cntrl),
    //    WCTDEF(digit), WCTDEF(graph), WCTDEF(lower), WCTDEF(print),
    //    WCTDEF(punct), WCTDEF(space), WCTDEF(upper), WCTDEF(xdigit),
    
    static unsigned short c_locale_array[384] = {
    #include "ctype-data.h"
    };
    
    static struct __locale_struct c_locale = {
        { }, // __locales_data
        c_locale_array + 128, // __ctype_b
    };
    
    
    Avi Kivity's avatar
    Avi Kivity committed
    UNIMPL(void __stack_chk_fail(void))
    
    
    namespace {
        bool all_categories(int category_mask)
        {
    	return (category_mask | (1 << LC_ALL)) == (1 << __LC_LAST) - 1;
        }
    }
    
    
    struct __locale_data {
        const void *values[0];
    
    #define _NL_ITEM(category, index)   (((category) << 16) | (index))
    #define _NL_ITEM_CATEGORY(item)     ((int) (item) >> 16)
    #define _NL_ITEM_INDEX(item)        ((int) (item) & 0xffff)
    
    #define _NL_CTYPE_CLASS  0
    #define _NL_CTYPE_TOUPPER 1
    #define _NL_CTYPE_TOLOWER 3
    
    
    __locale_t __newlocale(int category_mask, const char *locale, locale_t base)
        __THROW
    {
        if (category_mask == 1 << LC_ALL) {
    	category_mask = ((1 << __LC_LAST) - 1) & ~(1 << LC_ALL);
        }
        assert(locale);
        if (base == &c_locale) {
    	base = NULL;
        }
        if ((base == NULL || all_categories(category_mask))
    	&& (category_mask == 0 || strcmp(locale, "C") == 0)) {
    	return &c_locale;
        }
        struct __locale_struct result = base ? *base : c_locale;
        if (category_mask == 0) {
    	auto result_ptr = new __locale_struct;
    	*result_ptr = result;
    	auto ctypes = result_ptr->__locales[LC_CTYPE]->values;
    	result_ptr->__ctype_b = (const unsigned short *)
    
    	    ctypes[_NL_ITEM_INDEX(_NL_CTYPE_CLASS)] + 128;
    
    	result_ptr->__ctype_tolower = (const int *)
    
    	    ctypes[_NL_ITEM_INDEX(_NL_CTYPE_TOLOWER)] + 128;
    
    	result_ptr->__ctype_toupper = (const int *)
    
    	    ctypes[_NL_ITEM_INDEX(_NL_CTYPE_TOUPPER)] + 128;
    
    Avi Kivity's avatar
    Avi Kivity committed
    long sysconf(int name)
    {
        switch (name) {
        case _SC_CLK_TCK: return CLOCKS_PER_SEC;
        case _SC_PAGESIZE: return 4096; // FIXME
        case _SC_THREAD_PROCESS_SHARED: return true;
    
        case _SC_NPROCESSORS_ONLN: return sched::cpus.size();
        case _SC_NPROCESSORS_CONF: return sched::cpus.size();
    
        case _SC_PHYS_PAGES: return memory::phys_mem_size / memory::page_size;
    
    Avi Kivity's avatar
    Avi Kivity committed
        case _SC_GETPW_R_SIZE_MAX: return 1024;
    
        case _SC_IOV_MAX: return KERN_IOV_MAX;
    
        case _SC_THREAD_SAFE_FUNCTIONS: return 1;
    
        default:
            debug(fmt("sysconf(): stubbed for parameter %1%\n") % name);
            errno = EINVAL;
            return -1;
    
    Avi Kivity's avatar
    Avi Kivity committed
    size_t confstr(int name, char* buf, size_t len)
    {
    
    Avi Kivity's avatar
    Avi Kivity committed
        char tmp[1];
        if (!buf) {
            buf = tmp;
            len = 1;
        }
    
    Avi Kivity's avatar
    Avi Kivity committed
        auto set = [=] (const char* v) { return snprintf(buf, len, "%s", v); };
        switch (name) {
        case _CS_GNU_LIBC_VERSION: return set("glibc 2.16");
        case _CS_GNU_LIBPTHREAD_VERSION: return set("NPTL 2.16");
        }
    
    Avi Kivity's avatar
    Avi Kivity committed
        debug(fmt("confstr: unknown parameter %1%\n") % name);
    
    Avi Kivity's avatar
    Avi Kivity committed
        abort();
    }
    
    
    Christoph Hellwig's avatar
    Christoph Hellwig committed
    int mallopt(int param, int value)
    {
        return 0;
    }
    
    
    FILE *popen(const char *command, const char *type)
    {
    
        debug("popen not implemented\n");
    
        return NULL;
    }
    
    int pclose(FILE *stream)
    {
    	return 0;
    }
    
    
    Christoph Hellwig's avatar
    Christoph Hellwig committed
    void exit(int status)
    {
    
        debug(fmt("program exited with status %d\n") % status);
    
    Christoph Hellwig's avatar
    Christoph Hellwig committed
        abort();
    }
    
    int atexit(void (*func)())
    {
        // nothing to do
        return 0;
    }
    
    
    Avi Kivity's avatar
    Avi Kivity committed
    int get_nprocs()
    {
        return sysconf(_SC_NPROCESSORS_ONLN);
    }
    
    Or Cohen's avatar
    Or Cohen committed
    
    int utimes (const char *, const struct timeval [2])
    {
        // FIXME This is just a stub
        return 0;
    }
    
    Pekka Enberg's avatar
    Pekka Enberg committed
    
    clock_t times(struct tms *buffer)
    {
        debug("times not implemented\n");
        return 0;
    }