181c78d482
This enforces the use of unsigned 64-bit values for time in the duration type, the timeout framework, the timer session, the userland timer-drivers, and the alarm framework on all platforms. The commit also adapts the code that uses these tools accross all basic repositories (base, base-*, os. gems, libports, ports, dde_*) to use unsigned 64-bit values for time as well as far as this does not imply profound modifications. Fixes #3208
373 lines
7.1 KiB
C++
373 lines
7.1 KiB
C++
/**
|
|
* \brief Rump hypercall-interface implementation
|
|
* \author Sebastian Sumpf
|
|
* \author Josef Soentgen
|
|
* \date 2013-12-06
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2013-2017 Genode Labs GmbH
|
|
*
|
|
* This file is part of the Genode OS framework, which is distributed
|
|
* under the terms of the GNU Affero General Public License version 3.
|
|
*/
|
|
|
|
#include "sched.h"
|
|
|
|
#include <base/log.h>
|
|
#include <base/sleep.h>
|
|
#include <rump/env.h>
|
|
#include <util/allocator_fap.h>
|
|
#include <util/random.h>
|
|
#include <util/string.h>
|
|
|
|
enum {
|
|
SUPPORTED_RUMP_VERSION = 17,
|
|
MAX_VIRTUAL_MEMORY = (sizeof(void *) == 4 ? 256UL : 4096UL) * 1024 * 1024
|
|
};
|
|
|
|
static bool verbose = false;
|
|
|
|
/* upcalls to rump kernel */
|
|
struct rumpuser_hyperup _rump_upcalls;
|
|
|
|
|
|
/*************
|
|
** Threads **
|
|
*************/
|
|
|
|
static Hard_context *main_context()
|
|
{
|
|
static Hard_context inst(0);
|
|
return &inst;
|
|
}
|
|
|
|
|
|
static Hard_context *myself()
|
|
{
|
|
Hard_context *h = Hard_context_registry::r().find(Genode::Thread::myself());
|
|
|
|
if (!h)
|
|
Genode::error("Hard context is nullptr (", Genode::Thread::myself(), ")");
|
|
|
|
return h;
|
|
}
|
|
|
|
|
|
Timer::Connection &Hard_context::timer()
|
|
{
|
|
static Timer::Connection _timer { Rump::env().env() };
|
|
return _timer;
|
|
}
|
|
|
|
|
|
void rumpuser_curlwpop(int enum_rumplwpop, struct lwp *l)
|
|
{
|
|
Hard_context *h = myself();
|
|
switch (enum_rumplwpop) {
|
|
case RUMPUSER_LWP_CREATE:
|
|
case RUMPUSER_LWP_DESTROY:
|
|
break;
|
|
case RUMPUSER_LWP_SET:
|
|
h->set_lwp(l);
|
|
break;
|
|
case RUMPUSER_LWP_CLEAR:
|
|
h->set_lwp(0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
struct lwp * rumpuser_curlwp(void)
|
|
{
|
|
return myself()->get_lwp();
|
|
}
|
|
|
|
|
|
int rumpuser_thread_create(func f, void *arg, const char *name,
|
|
int mustjoin, int priority, int cpui_dx, void **cookie)
|
|
{
|
|
static long count = 0;
|
|
|
|
if (mustjoin)
|
|
*cookie = (void *)++count;
|
|
|
|
new (Rump::env().heap()) Hard_context_thread(name, f, arg, mustjoin ? count : 0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
void rumpuser_thread_exit()
|
|
{
|
|
Genode::sleep_forever();
|
|
}
|
|
|
|
|
|
int errno;
|
|
void rumpuser_seterrno(int e) { errno = e; }
|
|
|
|
|
|
/********************
|
|
** Initialization **
|
|
********************/
|
|
|
|
int rumpuser_init(int version, const struct rumpuser_hyperup *hyp)
|
|
{
|
|
if (version != SUPPORTED_RUMP_VERSION) {
|
|
Genode::error("unsupported rump-kernel version (", version, ") - "
|
|
"supported is ", (int)SUPPORTED_RUMP_VERSION);
|
|
return -1;
|
|
}
|
|
|
|
_rump_upcalls = *hyp;
|
|
|
|
/* register context for main EP */
|
|
main_context()->thread(Genode::Thread::myself());
|
|
Hard_context_registry::r().insert(main_context());
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/*************************
|
|
** Parameter retrieval **
|
|
*************************/
|
|
|
|
static size_t _rump_memlimit = 0;
|
|
|
|
|
|
void rump_set_memlimit(Genode::size_t limit)
|
|
{
|
|
_rump_memlimit = limit;
|
|
}
|
|
|
|
|
|
int rumpuser_getparam(const char *name, void *buf, size_t buflen)
|
|
{
|
|
enum {
|
|
MIN_RESERVE_MEM = 1U << 20,
|
|
MIN_RUMP_MEM = 6U << 20,
|
|
};
|
|
|
|
/* support one cpu */
|
|
if (!Genode::strcmp(name, "_RUMPUSER_NCPU")) {
|
|
Genode::strncpy((char *)buf, "1", 2);
|
|
return 0;
|
|
}
|
|
|
|
/* return out cool host name */
|
|
if (!Genode::strcmp(name, "_RUMPUSER_HOSTNAME")) {
|
|
Genode::strncpy((char *)buf, "rump4genode", 12);
|
|
return 0;
|
|
}
|
|
|
|
if (!Genode::strcmp(name, "RUMP_MEMLIMIT")) {
|
|
|
|
if (!_rump_memlimit) {
|
|
Genode::error("no RAM limit set");
|
|
throw -1;
|
|
}
|
|
|
|
/*
|
|
* Set RAM limit and reserve a 10th or at least 1MiB for
|
|
* Genode meta-data.
|
|
*/
|
|
Genode::size_t rump_ram = _rump_memlimit;
|
|
size_t const reserve = Genode::max((size_t)MIN_RESERVE_MEM, rump_ram / 10);
|
|
|
|
if (reserve < MIN_RESERVE_MEM) {
|
|
Genode::error("could not reserve enough RAM for meta-data, need at least ",
|
|
(size_t)MIN_RESERVE_MEM >> 20, " MiB");
|
|
throw -1;
|
|
}
|
|
|
|
rump_ram -= reserve;
|
|
|
|
/* check RAM limit is enough... */
|
|
if (rump_ram < MIN_RUMP_MEM) {
|
|
Genode::error("RAM limit too small, need at least ",
|
|
(size_t)MIN_RUMP_MEM >> 20, " MiB");
|
|
throw -1;
|
|
}
|
|
|
|
/* ... and is in valid range (overflow) */
|
|
if (rump_ram >= _rump_memlimit) {
|
|
Genode::error("rump RAM limit invalid");
|
|
throw -1;
|
|
}
|
|
|
|
rump_ram = Genode::min((unsigned long)MAX_VIRTUAL_MEMORY, rump_ram);
|
|
|
|
/* convert to string */
|
|
Genode::snprintf((char *)buf, buflen, "%zu", rump_ram);
|
|
Genode::log("asserting rump kernel ", rump_ram / 1024, " KB of RAM");
|
|
return 0;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
/*************
|
|
** Console **
|
|
*************/
|
|
|
|
void rumpuser_putchar(int ch)
|
|
{
|
|
enum { BUF_SIZE = 256 };
|
|
static unsigned char buf[BUF_SIZE];
|
|
static int count = 0;
|
|
|
|
if (count < BUF_SIZE - 1 && ch != '\n')
|
|
buf[count++] = (unsigned char)ch;
|
|
|
|
if (ch == '\n' || count == BUF_SIZE - 1) {
|
|
buf[count] = 0;
|
|
int nlocks;
|
|
if (myself() != main_context())
|
|
rumpkern_unsched(&nlocks, 0);
|
|
|
|
Genode::log("rump: ", Genode::Cstring((char const *)buf));
|
|
|
|
if (myself() != main_context())
|
|
rumpkern_sched(nlocks, 0);
|
|
|
|
count = 0;
|
|
}
|
|
}
|
|
|
|
|
|
/************
|
|
** Memory **
|
|
************/
|
|
|
|
struct Allocator_policy
|
|
{
|
|
static int block()
|
|
{
|
|
int nlocks;
|
|
|
|
if (myself() != main_context())
|
|
rumpkern_unsched(&nlocks, 0);
|
|
return nlocks;
|
|
}
|
|
|
|
static void unblock(int nlocks)
|
|
{
|
|
if (myself() != main_context())
|
|
rumpkern_sched(nlocks, 0);
|
|
}
|
|
};
|
|
|
|
|
|
typedef Allocator::Fap<MAX_VIRTUAL_MEMORY, Allocator_policy> Rump_alloc;
|
|
|
|
static Genode::Lock & alloc_lock()
|
|
{
|
|
static Genode::Lock inst;
|
|
return inst;
|
|
}
|
|
|
|
|
|
static Rump_alloc* allocator()
|
|
{
|
|
static Rump_alloc _fap(true);
|
|
return &_fap;
|
|
}
|
|
|
|
|
|
int rumpuser_malloc(size_t len, int alignment, void **memp)
|
|
{
|
|
Genode::Lock::Guard guard(alloc_lock());
|
|
|
|
int align = alignment ? Genode::log2(alignment) : 0;
|
|
*memp = allocator()->alloc(len, align);
|
|
|
|
if (verbose)
|
|
Genode::log("ALLOC: p: ", *memp, ", s: ", len, ", a: ", align, " ", alignment);
|
|
|
|
|
|
return *memp ? 0 : -1;
|
|
}
|
|
|
|
|
|
void rumpuser_free(void *mem, size_t len)
|
|
{
|
|
Genode::Lock::Guard guard(alloc_lock());
|
|
|
|
allocator()->free(mem, len);
|
|
|
|
if (verbose)
|
|
Genode::warning("FREE: p: ", mem, ", s: ", len);
|
|
}
|
|
|
|
|
|
/************
|
|
** Clocks **
|
|
************/
|
|
|
|
int rumpuser_clock_gettime(int enum_rumpclock, int64_t *sec, long *nsec)
|
|
{
|
|
Hard_context *h = myself();
|
|
Genode::uint64_t t = h->timer().elapsed_ms();
|
|
*sec = (int64_t)t / 1000;
|
|
*nsec = (t % 1000) * 1000;
|
|
return 0;
|
|
}
|
|
|
|
|
|
int rumpuser_clock_sleep(int enum_rumpclock, int64_t sec, long nsec)
|
|
{
|
|
int nlocks;
|
|
Genode::uint64_t msec = 0;
|
|
|
|
Timer::Connection &timer = myself()->timer();
|
|
|
|
rumpkern_unsched(&nlocks, 0);
|
|
switch (enum_rumpclock) {
|
|
case RUMPUSER_CLOCK_RELWALL:
|
|
msec = (Genode::uint64_t)sec * 1000 + nsec / (1000*1000UL);
|
|
break;
|
|
case RUMPUSER_CLOCK_ABSMONO:
|
|
msec = timer.elapsed_ms();
|
|
msec = (((Genode::uint64_t)sec * 1000) + ((Genode::uint64_t)nsec / (1000 * 1000))) - msec;
|
|
break;
|
|
}
|
|
|
|
timer.msleep(msec);
|
|
rumpkern_sched(nlocks, 0);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*****************
|
|
** Random pool **
|
|
*****************/
|
|
|
|
int rumpuser_getrandom(void *buf, size_t buflen, int flags, size_t *retp)
|
|
{
|
|
/*
|
|
* Cast retp to Genode::size_t to prevent compiler error because
|
|
* the type of rump's size_t is int on 32 bit and long 64 bit archs.
|
|
*/
|
|
return rumpuser_getrandom_backend(buf, buflen, flags,
|
|
(Genode::size_t *)retp);
|
|
}
|
|
|
|
|
|
/**********
|
|
** Exit **
|
|
**********/
|
|
|
|
void genode_exit(int) __attribute__((noreturn));
|
|
|
|
void rumpuser_exit(int status)
|
|
{
|
|
if (status == RUMPUSER_PANIC)
|
|
Genode::error("Rump panic");
|
|
|
|
genode_exit(status);
|
|
}
|