aos/lib/aos/init.c
2022-03-31 17:50:05 +02:00

269 lines
8.2 KiB
C

/**
* \file
* \brief Barrelfish library initialization.
*/
/*
* Copyright (c) 2007-2019, ETH Zurich.
* Copyright (c) 2014, HP Labs.
* All rights reserved.
*
* This file is distributed under the terms in the attached LICENSE file.
* If you do not find this file, copies can be found by writing to:
* ETH Zurich D-INFK, CAB F.78, Universitaetstr. 6, CH-8092 Zurich,
* Attn: Systems Group.
*/
#include <stdio.h>
#include <aos/aos.h>
#include <aos/dispatch.h>
#include <aos/curdispatcher_arch.h>
#include <aos/dispatcher_arch.h>
#include <barrelfish_kpi/dispatcher_shared.h>
#include <aos/morecore.h>
#include <aos/paging.h>
#include <aos/systime.h>
#include <barrelfish_kpi/domain_params.h>
#include "threads_priv.h"
#include "init.h"
#include <aos/aos_rpc.h>
/// Are we the init domain (and thus need to take some special paths)?
static bool init_domain;
static bool init_chan_initialized;
extern size_t (*_libc_terminal_read_func)(char *, size_t);
extern size_t (*_libc_terminal_write_func)(const char *, size_t);
extern void (*_libc_exit_func)(int);
extern void (*_libc_assert_func)(const char *, const char *, const char *, int);
void libc_exit(int);
__weak_reference(libc_exit, _exit);
void libc_exit(int status)
{
debug_printf("libc exit NYI!\n");
thread_exit(status);
// If we're not dead by now, we wait
while (1) {}
}
static void libc_assert(const char *expression, const char *file,
const char *function, int line)
{
char buf[512];
size_t len;
/* Formatting as per suggestion in C99 spec 7.2.1.1 */
len = snprintf(buf, sizeof(buf), "Assertion failed on core %d in %.*s: %s,"
" function %s, file %s, line %d.\n",
disp_get_core_id(), DISP_NAME_LEN,
disp_name(), expression, function, file, line);
sys_print(buf, len < sizeof(buf) ? len : sizeof(buf));
}
__attribute__((__used__))
static size_t syscall_terminal_write(const char *buf, size_t len)
{
if(len) {
errval_t err = sys_print(buf, len);
if (err_is_fail(err)) {
return 0;
}
}
return len;
}
__attribute__((__used__))
static size_t dummy_terminal_read(char *buf, size_t len)
{
debug_printf("Terminal read NYI!\n");
return 0;
}
static void handle_init_recv(void *arg)
{
errval_t err;
struct lmp_chan *init_chan = (struct lmp_chan *)arg;
struct lmp_recv_msg msg = LMP_RECV_MSG_INIT;
err = lmp_chan_recv(init_chan, &msg, NULL);
assert(err_is_ok(err));
if (msg.words[0] == SYS_ERR_OK) {
debug_printf("Received child init OK\n");
init_chan_initialized = true;
} else {
USER_PANIC("Child LMP initialization failed.");
}
}
// TODO rueegges: allow partial write
static size_t aos_terminal_write(const char *buf, size_t len)
{
if(len == 0) return 0;
struct aos_rpc *rpc = aos_rpc_get_serial_channel();
if (rpc == NULL) {
debug_printf("[aos_terminal_write] RPC NOT YET INITIALIZED: %.*s\n", len, buf);
USER_PANIC("Make sure to initialize aos_rpc before barrelfish_libc_glue_init is called.");
}
return aos_rpc_serial_write(rpc, buf, len);
}
// TODO rueegges: make more efficient?
static size_t aos_terminal_read(char *buf, size_t len)
{
if(len == 0) return 0;
struct aos_rpc *rpc = aos_rpc_get_serial_channel();
if (rpc == NULL) {
debug_printf("[aos_terminal_read] RPC NOT YET INITIALIZED: %.*s\n", len, buf);
USER_PANIC("Make sure to initialize aos_rpc before barrelfish_libc_glue_init is called.");
}
return aos_rpc_serial_read(rpc, buf, len);
}
/* Set libc function pointers */
void barrelfish_libc_glue_init(void)
{
// XXX: FIXME: Check whether we can use the proper kernel serial, and
// what we need for that
// TODO: change these to use the user-space serial driver if possible
// TODO: set these functions
// MARKER SHELL: replace functions for init domain or UART driver with non-remote calls
if(init_domain) {
_libc_terminal_read_func = dummy_terminal_read;
_libc_terminal_write_func = syscall_terminal_write;
} else {
_libc_terminal_read_func = aos_terminal_read;
_libc_terminal_write_func = aos_terminal_write;
}
_libc_exit_func = libc_exit;
_libc_assert_func = libc_assert;
/* morecore func is setup by morecore_init() */
// XXX: set a static buffer for stdout
// this avoids an implicit call to malloc() on the first printf
static char buf[BUFSIZ];
setvbuf(stdout, buf, _IOLBF, sizeof(buf));
}
/** \brief Initialise libbarrelfish.
*
* This runs on a thread in every domain, after the dispatcher is setup but
* before main() runs.
*/
errval_t barrelfish_init_onthread(struct spawn_domain_params *params)
{
errval_t err;
// do we have an environment?
if (params != NULL && params->envp[0] != NULL) {
extern char **environ;
environ = params->envp;
}
// Init default waitset for this dispatcher
struct waitset *default_ws = get_default_waitset();
waitset_init(default_ws);
// Initialize ram_alloc state
ram_alloc_init();
/* All domains use smallcn to initialize */
err = ram_alloc_set(ram_alloc_fixed);
if (err_is_fail(err)) {
return err_push(err, LIB_ERR_RAM_ALLOC_SET);
}
err = paging_init_params(params);
if (err_is_fail(err)) {
return err_push(err, LIB_ERR_VSPACE_INIT);
}
err = slot_alloc_init();
if (err_is_fail(err)) {
return err_push(err, LIB_ERR_SLOT_ALLOC_INIT);
}
err = morecore_init(BASE_PAGE_SIZE);
if (err_is_fail(err)) {
return err_push(err, LIB_ERR_MORECORE_INIT);
}
lmp_endpoint_init();
// HINT: Use init_domain to check if we are the init domain.
// early exit for the init process
if(init_domain) {
return SYS_ERR_OK;
}
// TODO MILESTONE 3: register ourselves with init
/* allocate lmp channel structure */
struct lmp_chan *init_chan = malloc(sizeof(struct lmp_chan));
lmp_chan_init(init_chan);
/* create local endpoint */
err = endpoint_create(DEFAULT_LMP_BUF_WORDS, &init_chan->local_cap, &init_chan->endpoint);
if (err_is_fail(err)) {
return err_push(err, LIB_ERR_ENDPOINT_CREATE);
}
/* set remote endpoint to init's endpoint */
init_chan->remote_cap = cap_initep;
/* set receive handler */
init_chan_initialized = false;
err = lmp_chan_register_recv(init_chan, get_default_waitset(), MKCLOSURE(handle_init_recv, init_chan));
/* send local ep to init */
err = lmp_chan_send1(init_chan, LMP_FLAG_YIELD | LMP_FLAG_SYNC, init_chan->local_cap, RPC_MTYPE_CHILD_ENDPOINT);
if (err_is_fail(err)) {
// should never fail since init listens before invoking the dispatcher
return err_push(err, LIB_ERR_LMP_CHAN_SEND);
}
/* wait for init to acknowledge receiving the endpoint */
while(!init_chan_initialized) {
err = event_dispatch(get_default_waitset());
if (err_is_fail(err)) {
return err_push(err, LIB_ERR_EVENT_DISPATCH);
}
}
/* initialize init RPC client with lmp channel */
struct aos_rpc *init_rpc = malloc(sizeof(struct aos_rpc));
err = aos_rpc_init(init_rpc, init_chan, params->rpc_shared_memory);
if (err_is_fail(err)){
return err_push(err, ERR_NOTIMP);
}
/* set init RPC client in our program state */
set_init_rpc(init_rpc);
/* TODO MILESTONE 3: now we should have a channel with init set up and can
* use it for the ram allocator */
//afeer: script page 135, tell domain to use our memserver.
err = ram_alloc_set(NULL);
// right now we don't have the nameservice & don't need the terminal
// and domain spanning, so we return here
return SYS_ERR_OK;
}
/**
* \brief Initialise libbarrelfish, while disabled.
*
* This runs on the dispatcher's stack, while disabled, before the dispatcher is
* setup. We can't call anything that needs to be enabled (ie. cap invocations)
* or uses threads. This is called from crt0.
*/
void barrelfish_init_disabled(dispatcher_handle_t handle, bool init_dom_arg);
void barrelfish_init_disabled(dispatcher_handle_t handle, bool init_dom_arg)
{
init_domain = init_dom_arg;
disp_init_disabled(handle);
thread_init_disabled(handle, init_dom_arg);
}