aos/lib/aos/init.c
2022-06-02 16:58:27 +02:00

288 lines
8.7 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>
#include <aos/shelly_client.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.");
}
}
static size_t aos_terminal_write(const char *buf, size_t len)
{
errval_t err;
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.");
}
for (int i = 0; i < len; ++i) {
err = aos_rpc_serial_putchar(rpc, buf[i]);
if (err_is_fail(err)) return err;
}
return SYS_ERR_OK;
// return aos_rpc_serial_write(rpc, buf, len);
}
static size_t aos_terminal_read(char *buf, size_t len)
{
errval_t err;
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.");
}
for (int i = 0; i < len; ++i) {
char in;
err = aos_rpc_serial_getchar(rpc, &in);
if (err_is_fail(err)) return err;
buf[i] = in;
}
return SYS_ERR_OK;
// 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: init should also print through the UART driver
if(init_domain) {
_libc_terminal_read_func = dummy_terminal_read;
_libc_terminal_write_func = dummy_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 */
static struct lmp_chan init_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 */
static struct aos_rpc init_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);
if (err_is_fail(err)) return err;
if (strcmp(params->argv[0], "shelly") != 0) {
err = shelly_client_init();
if (err_is_fail(err)) DEBUG_ERR(err, "when trying to init shelly client");
}
// 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);
}