Implement RPC

This commit is contained in:
Jan Schär 2022-03-30 20:12:19 +02:00
parent f2fb4d5d01
commit 14063e60be
15 changed files with 459 additions and 112 deletions

View File

@ -1323,7 +1323,7 @@ errors sfn NIC_ERR_{
failure IO "Error during card IO", failure IO "Error during card IO",
failure INTR "Interrupted system call", failure INTR "Interrupted system call",
failure NOSYS "Not implemented", failure NOSYS "Not implemented",
failure UNKNOWN "Uknown error", failure UNKNOWN "Unknown error",
failure TX_PKT "Error sending packet", failure TX_PKT "Error sending packet",
failure RX_PKT "Error receiving packet", failure RX_PKT "Error receiving packet",
failure RX_DISCARD "Error, packet needs to be discared", failure RX_DISCARD "Error, packet needs to be discared",
@ -1376,6 +1376,10 @@ errors vas VAS_ERR_ {
errors aos AOS_ERR_ { errors aos AOS_ERR_ {
failure LMP_SEND_FAILURE "Failure while sending AOS LMP message", failure LMP_SEND_FAILURE "Failure while sending AOS LMP message",
failure LMP_MSGTYPE_UNKNOWN "Unknown message type for AOS LMP implementation", failure LMP_MSGTYPE_UNKNOWN "Unknown message type for AOS LMP implementation",
failure RPC_UNEXPECTED_MSGTYPE "Received RPC message of unexpected type",
failure RPC_ARG_TOO_BIG "RPC argument is too big",
failure RPC_RET_TOO_BIG "RPC return value is too big",
failure RPC_UNKNOWN_MSG_TYPE "RPC with unknown message type",
}; };
// errors NIC driver // errors NIC driver

View File

@ -5,7 +5,7 @@
bootdriver /armv8/sbin/boot_armv8_generic bootdriver /armv8/sbin/boot_armv8_generic
cpudriver /armv8/sbin/cpu_a57_qemu loglevel=3 serial=0x9000000 logmask=128 cpudriver /armv8/sbin/cpu_a57_qemu loglevel=3 serial=0x9000000 logmask=128
module /armv8/sbin/init module /armv8/sbin/init
module /armv8/sbin/hello catch Aurel Jan Sandro module /armv8/sbin/hello Aurel Jan Sandro
module /armv8/sbin/memeater module /armv8/sbin/memeater
# End of file, this needs to have a certain length... # End of file, this needs to have a certain length...

View File

@ -5,5 +5,5 @@
bootdriver /armv8/sbin/boot_armv8_generic bootdriver /armv8/sbin/boot_armv8_generic
cpudriver /armv8/sbin/cpu_imx8x cpudriver /armv8/sbin/cpu_imx8x
module /armv8/sbin/init module /armv8/sbin/init
module /armv8/sbin/hello catch Aurel Jan Sandro module /armv8/sbin/hello Aurel Jan Sandro
module /armv8/sbin/memeater module /armv8/sbin/memeater

View File

@ -17,23 +17,34 @@
#include <aos/aos.h> #include <aos/aos.h>
#define RPC_SHARED_SIZE PAGE_SIZE
// define some message types // define some message types
#define RPC_MTYPE_CHILD_ENDPOINT 1UL enum rpc_mtype {
#define RPC_MTYPE_CHILD_ENDPOINT_OK 2UL RPC_MTYPE_CHILD_ENDPOINT,
#define RPC_MTYPE_GET_RAM_CAP 3UL RPC_MTYPE_SEND_NUMBER,
#define RPC_MTYPE_GET_RAM_CAP_OK 4UL RPC_MTYPE_SEND_STRING,
RPC_MTYPE_GET_RAM_CAP,
RPC_MTYPE_SERIAL_GETCHAR,
RPC_MTYPE_SERIAL_PUTCHAR,
RPC_MTYPE_PROCESS_SPAWN,
RPC_MTYPE_PROCESS_GET_NAME,
RPC_MTYPE_PROCESS_GET_ALL_PIDS,
RPC_MTYPE_COUNT // How many message types exist
};
/* An RPC binding, which may be transported over LMP or UMP. */ /* An RPC binding, which may be transported over LMP or UMP. */
struct aos_rpc { struct aos_rpc {
// TODO(M3): Add state
struct lmp_chan *chan; struct lmp_chan *chan;
struct waitset ws;
void *shared_mem;
}; };
/** /**
* \brief Initialize an aos_rpc struct. * \brief Initialize an aos_rpc struct.
*/ */
errval_t aos_rpc_init(struct aos_rpc *rpc); errval_t aos_rpc_init(struct aos_rpc *rpc, struct lmp_chan *chan, void *shared_mem);
/** /**

View File

@ -25,6 +25,7 @@ struct spawn_domain_params {
char *envp[MAX_ENVIRON_VARS + 1]; ///< Environment strings; +1 for NULL terminator char *envp[MAX_ENVIRON_VARS + 1]; ///< Environment strings; +1 for NULL terminator
void *vspace_buf; ///< Serialised vspace data void *vspace_buf; ///< Serialised vspace data
size_t vspace_buf_len; ///< Length of serialised vspace data size_t vspace_buf_len; ///< Length of serialised vspace data
void *rpc_shared_memory;
void *tls_init_base; ///< Address of initialised TLS data block void *tls_init_base; ///< Address of initialised TLS data block
size_t tls_init_len; ///< Length of initialised TLS data block size_t tls_init_len; ///< Length of initialised TLS data block
size_t tls_total_len; ///< Total (initialised + BSS) TLS data length size_t tls_total_len; ///< Total (initialised + BSS) TLS data length

View File

@ -0,0 +1,28 @@
#ifndef _RPC_SERVER_H_
#define _RPC_SERVER_H_
#include <aos/aos.h>
struct aos_rpc_server {
struct lmp_chan *chan;
struct waitset ws;
void *shared_mem;
struct capref ret_cap;
errval_t ret_err;
size_t ret_size;
uintptr_t ret0;
uintptr_t ret1;
};
/**
* Initialize an aos_rpc_server struct.
*/
void rpc_server_init(struct aos_rpc_server *rpc, struct lmp_chan *chan, void *shared_mem);
/**
* Start listening for RPCs.
*/
void rpc_server_register_recv(struct aos_rpc_server *rpc);
#endif /* _RPC_SERVER_H_ */

View File

@ -17,6 +17,7 @@
#include "aos/slot_alloc.h" #include "aos/slot_alloc.h"
#include "aos/paging.h" #include "aos/paging.h"
#include <spawn/rpc_server.h>
@ -34,7 +35,7 @@ struct spawninfo {
// when spawning a new dispatcher, // when spawning a new dispatcher,
// e.g. references to the child's // e.g. references to the child's
// capabilities or paging state // capabilities or paging state
//afeer: see script page 84/85 //afeer: see script page 84/85
struct cnoderef cspace_l1_cnode_info; struct cnoderef cspace_l1_cnode_info;
struct capref cspace_l1_cnode_cap; struct capref cspace_l1_cnode_cap;
@ -58,6 +59,8 @@ struct spawninfo {
struct capref vspace_cap_l0_pagetable; struct capref vspace_cap_l0_pagetable;
struct lmp_chan init_chan; struct lmp_chan init_chan;
struct capref rpc_shared_frame;
struct aos_rpc_server rpc_server;
}; };
// Start a child process using the multiboot command line. Fills in si. // Start a child process using the multiboot command line. Fills in si.

View File

@ -17,74 +17,171 @@
static void noop_callback(void *arg) {
}
static errval_t do_aos_rpc(
struct aos_rpc *rpc, uintptr_t msg_type,
struct capref arg_cap, size_t arg_size, uintptr_t arg0, uintptr_t arg1,
struct capref *ret_cap, size_t *ret_size, uintptr_t *ret0, uintptr_t *ret1
) {
errval_t err;
// Send call
while (true) {
err = lmp_chan_send4(rpc->chan, LMP_FLAG_YIELD | LMP_FLAG_SYNC, arg_cap, msg_type, arg_size, arg0, arg1);
if (!err_is_fail(err)) break;
if (!lmp_err_is_transient(err)) {
return err_push(err, AOS_ERR_LMP_SEND_FAILURE);
}
err = lmp_chan_register_send(rpc->chan, &rpc->ws, MKCLOSURE(noop_callback, NULL));
if (err_is_fail(err)) return err;
err = event_dispatch(&rpc->ws);
if (err_is_fail(err)) return err;
}
// Receive return value
struct lmp_recv_msg recv = LMP_RECV_MSG_INIT;
while (!lmp_endpoint_can_recv(rpc->chan->endpoint)) {
err = lmp_chan_register_recv(rpc->chan, &rpc->ws, MKCLOSURE(noop_callback, NULL));
if (err_is_fail(err)) return err;
err = event_dispatch(&rpc->ws);
if (err_is_fail(err)) return err;
}
err = lmp_chan_recv(rpc->chan, &recv, ret_cap);
assert(err_is_ok(err));
if (ret_size != NULL) *ret_size = recv.words[1];
if (ret0 != NULL) *ret0 = recv.words[2];
if (ret1 != NULL) *ret1 = recv.words[3];
return recv.words[0];
}
errval_t errval_t
aos_rpc_send_number(struct aos_rpc *rpc, uintptr_t num) { aos_rpc_send_number(struct aos_rpc *rpc, uintptr_t num) {
// TODO: implement functionality to send a number over the channel // Implement functionality to send a number over the channel
// given channel and wait until the ack gets returned. // given channel and wait until the ack gets returned.
return SYS_ERR_OK; return do_aos_rpc(
rpc, RPC_MTYPE_SEND_NUMBER,
NULL_CAP, 0, num, 0,
NULL, NULL, NULL, NULL);
} }
errval_t errval_t
aos_rpc_send_string(struct aos_rpc *rpc, const char *string) { aos_rpc_send_string(struct aos_rpc *rpc, const char *string) {
// TODO: implement functionality to send a string over the given channel // Implement functionality to send a string over the given channel
// and wait for a response. // and wait for a response.
return SYS_ERR_OK; size_t string_size = strlen(string) + 1;
if (string_size > RPC_SHARED_SIZE) return AOS_ERR_RPC_ARG_TOO_BIG;
memcpy(rpc->shared_mem, string, string_size);
return do_aos_rpc(
rpc, RPC_MTYPE_SEND_STRING,
NULL_CAP, string_size, 0, 0,
NULL, NULL, NULL, NULL
);
} }
errval_t errval_t
aos_rpc_get_ram_cap(struct aos_rpc *rpc, size_t bytes, size_t alignment, aos_rpc_get_ram_cap(struct aos_rpc *rpc, size_t bytes, size_t alignment,
struct capref *ret_cap, size_t *ret_bytes) { struct capref *ret_cap, size_t *ret_bytes) {
// TODO: implement functionality to request a RAM capability over the // Implement functionality to request a RAM capability over the
// given channel and wait until it is delivered. // given channel and wait until it is delivered.
return SYS_ERR_OK; return do_aos_rpc(
rpc, RPC_MTYPE_GET_RAM_CAP,
NULL_CAP, 0, bytes, alignment,
ret_cap, NULL, ret_bytes, NULL
);
} }
errval_t errval_t
aos_rpc_serial_getchar(struct aos_rpc *rpc, char *retc) { aos_rpc_serial_getchar(struct aos_rpc *rpc, char *retc) {
// TODO implement functionality to request a character from // Implement functionality to request a character from
// the serial driver. // the serial driver.
return SYS_ERR_OK; uintptr_t retval;
errval_t err = do_aos_rpc(
rpc, RPC_MTYPE_SERIAL_GETCHAR,
NULL_CAP, 0, 0, 0,
NULL, NULL, &retval, NULL);
*retc = retval;
return err;
} }
errval_t errval_t
aos_rpc_serial_putchar(struct aos_rpc *rpc, char c) { aos_rpc_serial_putchar(struct aos_rpc *rpc, char c) {
// TODO implement functionality to send a character to the // Implement functionality to send a character to the
// serial port. // serial port.
return SYS_ERR_OK; return do_aos_rpc(
rpc, RPC_MTYPE_SERIAL_PUTCHAR,
NULL_CAP, 0, c, 0,
NULL, NULL, NULL, NULL
);
} }
errval_t errval_t
aos_rpc_process_spawn(struct aos_rpc *rpc, char *cmdline, aos_rpc_process_spawn(struct aos_rpc *rpc, char *cmdline,
coreid_t core, domainid_t *newpid) { coreid_t core, domainid_t *newpid) {
// TODO (M5): implement spawn new process rpc // (M5): implement spawn new process rpc
return SYS_ERR_OK; size_t cmdline_size = strlen(cmdline) + 1;
if (cmdline_size > RPC_SHARED_SIZE) return AOS_ERR_RPC_ARG_TOO_BIG;
memcpy(rpc->shared_mem, cmdline, cmdline_size);
uintptr_t retval;
errval_t err = do_aos_rpc(
rpc, RPC_MTYPE_PROCESS_SPAWN,
NULL_CAP, cmdline_size, core, 0,
NULL, NULL, &retval, NULL
);
*newpid = retval;
return err;
} }
errval_t errval_t
aos_rpc_process_get_name(struct aos_rpc *rpc, domainid_t pid, char **name) { aos_rpc_process_get_name(struct aos_rpc *rpc, domainid_t pid, char **name) {
// TODO (M5): implement name lookup for process given a process id // (M5): implement name lookup for process given a process id
return SYS_ERR_OK; size_t name_len;
errval_t err = do_aos_rpc(
rpc, RPC_MTYPE_PROCESS_GET_NAME,
NULL_CAP, 0, pid, 0,
NULL, &name_len, NULL, NULL
);
if (err_is_fail(err)) return err;
*name = malloc(name_len);
if (*name == NULL) return LIB_ERR_MALLOC_FAIL;
memcpy(name, rpc->shared_mem, name_len);
return err;
} }
errval_t errval_t
aos_rpc_process_get_all_pids(struct aos_rpc *rpc, domainid_t **pids, aos_rpc_process_get_all_pids(struct aos_rpc *rpc, domainid_t **pids,
size_t *pid_count) { size_t *pid_count) {
// TODO (M5): implement process id discovery // (M5): implement process id discovery
return SYS_ERR_OK; size_t ret_len;
errval_t err = do_aos_rpc(
rpc, RPC_MTYPE_PROCESS_GET_NAME,
NULL_CAP, 0, 0, 0,
NULL, &ret_len, NULL, NULL
);
if (err_is_fail(err)) return err;
*pid_count = ret_len / sizeof(**pids);
*pids = malloc(ret_len);
if (*pids == NULL) return LIB_ERR_MALLOC_FAIL;
memcpy(pids, rpc->shared_mem, ret_len);
return err;
} }
// We are allowed to change the signature for this one // We are allowed to change the signature for this one
errval_t aos_rpc_init(struct aos_rpc *rpc) errval_t aos_rpc_init(struct aos_rpc *rpc, struct lmp_chan *chan, void *shared_mem)
{ {
// TODO! rpc->chan = chan;
rpc->shared_mem = shared_mem;
waitset_init(&rpc->ws);
return SYS_ERR_OK; return SYS_ERR_OK;
} }
@ -93,9 +190,8 @@ errval_t aos_rpc_init(struct aos_rpc *rpc)
*/ */
struct aos_rpc *aos_rpc_get_init_channel(void) struct aos_rpc *aos_rpc_get_init_channel(void)
{ {
//TODO: Return channel to talk to init process // Return channel to talk to init process
debug_printf("aos_rpc_get_init_channel NYI\n"); return get_init_rpc();
return NULL;
} }
/** /**
@ -103,10 +199,9 @@ struct aos_rpc *aos_rpc_get_init_channel(void)
*/ */
struct aos_rpc *aos_rpc_get_memory_channel(void) struct aos_rpc *aos_rpc_get_memory_channel(void)
{ {
//TODO: Return channel to talk to memory server process (or whoever // Return channel to talk to memory server process (or whoever
//implements memory server functionality) // implements memory server functionality)
debug_printf("aos_rpc_get_memory_channel NYI\n"); return get_init_rpc();
return NULL;
} }
/** /**
@ -114,10 +209,9 @@ struct aos_rpc *aos_rpc_get_memory_channel(void)
*/ */
struct aos_rpc *aos_rpc_get_process_channel(void) struct aos_rpc *aos_rpc_get_process_channel(void)
{ {
//TODO: Return channel to talk to process server process (or whoever // Return channel to talk to process server process (or whoever
//implements process server functionality) // implements process server functionality)
debug_printf("aos_rpc_get_process_channel NYI\n"); return get_init_rpc();
return NULL;
} }
/** /**
@ -125,9 +219,7 @@ struct aos_rpc *aos_rpc_get_process_channel(void)
*/ */
struct aos_rpc *aos_rpc_get_serial_channel(void) struct aos_rpc *aos_rpc_get_serial_channel(void)
{ {
//TODO: Return channel to talk to serial driver/terminal process (whoever // Return channel to talk to serial driver/terminal process (whoever
//implements print/read functionality) // implements print/read functionality)
debug_printf("aos_rpc_get_serial_channel NYI\n"); return get_init_rpc();
return NULL;
} }

View File

@ -83,7 +83,6 @@ static size_t dummy_terminal_read(char *buf, size_t len)
return 0; return 0;
} }
// TODO rueegges: putting it here for now. Not sure how to do rcp abstraction yet
static int event_init_dispatch_thread(void *arg) static int event_init_dispatch_thread(void *arg)
{ {
errval_t err; errval_t err;
@ -95,8 +94,6 @@ static int event_init_dispatch_thread(void *arg)
} }
} }
// TODO rueegges: putting it here for now. Not sure how to do rcp abstraction yet
// receive messages sent by the init
static void handle_init_recv(void *arg) static void handle_init_recv(void *arg)
{ {
errval_t err; errval_t err;
@ -106,31 +103,13 @@ static void handle_init_recv(void *arg)
struct capref cap; struct capref cap;
err = lmp_chan_recv(init_chan, &msg, &cap); err = lmp_chan_recv(init_chan, &msg, &cap);
if (err_is_fail(err)) { assert(err_is_ok(err));
if (lmp_err_is_transient(err)) {
err = lmp_endpoint_register(init_chan->endpoint, get_default_waitset(), MKCLOSURE(handle_init_recv, init_chan));
if (err_is_fail(err)) {
USER_PANIC_ERR(err, "Could not reregister after failed init_chan cap receive");
}
} else {
USER_PANIC_ERR(err, "Failure in child channel");
}
return;
}
switch(msg.words[0]){ if (msg.words[0] == SYS_ERR_OK) {
case RPC_MTYPE_CHILD_ENDPOINT_OK: debug_printf("Received child init OK\n");
debug_printf("Received child init OK\n"); init_chan_initialized = true;
init_chan_initialized = true; } else {
break; USER_PANIC("Child LMP initialization failed.");
default:
USER_PANIC("Unknown rpc message type.");
break;
}
err = lmp_endpoint_register(init_chan->endpoint, get_default_waitset(), MKCLOSURE(handle_init_recv, init_chan));
if (err_is_fail(err)) {
USER_PANIC_ERR(err, "[handle_init_recv]: Could not register endpoint after receiving message");
} }
} }
@ -207,6 +186,7 @@ errval_t barrelfish_init_onthread(struct spawn_domain_params *params)
// TODO MILESTONE 3: register ourselves with init // TODO MILESTONE 3: register ourselves with init
/* allocate lmp channel structure */ /* allocate lmp channel structure */
struct lmp_chan *init_chan = malloc(sizeof(struct lmp_chan)); struct lmp_chan *init_chan = malloc(sizeof(struct lmp_chan));
lmp_chan_init(init_chan);
/* create local endpoint */ /* create local endpoint */
err = endpoint_create(DEFAULT_LMP_BUF_WORDS, &init_chan->local_cap, &init_chan->endpoint); err = endpoint_create(DEFAULT_LMP_BUF_WORDS, &init_chan->local_cap, &init_chan->endpoint);
if (err_is_fail(err)) { if (err_is_fail(err)) {
@ -232,7 +212,7 @@ errval_t barrelfish_init_onthread(struct spawn_domain_params *params)
} }
/* initialize init RPC client with lmp channel */ /* initialize init RPC client with lmp channel */
struct aos_rpc *init_rpc = malloc(sizeof(struct aos_rpc)); struct aos_rpc *init_rpc = malloc(sizeof(struct aos_rpc));
err = aos_rpc_init(init_rpc); err = aos_rpc_init(init_rpc, init_chan, params->rpc_shared_memory);
if (err_is_fail(err)){ if (err_is_fail(err)){
return err_push(err, ERR_NOTIMP); return err_push(err, ERR_NOTIMP);
} }
@ -261,7 +241,7 @@ errval_t barrelfish_init_onthread(struct spawn_domain_params *params)
void barrelfish_init_disabled(dispatcher_handle_t handle, bool init_dom_arg); void barrelfish_init_disabled(dispatcher_handle_t handle, bool init_dom_arg);
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; init_domain = init_dom_arg;
disp_init_disabled(handle); disp_init_disabled(handle);
thread_init_disabled(handle, init_dom_arg); thread_init_disabled(handle, init_dom_arg);
} }

View File

@ -6,34 +6,42 @@
#include <grading.h> #include <grading.h>
void grading_rpc_handle_number(uintptr_t val) void grading_rpc_handle_number(uintptr_t val)
{ {
debug_printf("grading_rpc_handle_number(%"PRIuPTR")\n", val);
} }
void grading_rpc_handler_string(const char* string) void grading_rpc_handler_string(const char* string)
{ {
debug_printf("grading_rpc_handler_string(\"%s\")\n", string);
} }
void grading_rpc_handler_serial_getchar(void) void grading_rpc_handler_serial_getchar(void)
{ {
debug_printf("grading_rpc_handler_serial_getchar()\n");
} }
void grading_rpc_handler_serial_putchar(char c) void grading_rpc_handler_serial_putchar(char c)
{ {
debug_printf("grading_rpc_handler_serial_putchar(0x%"PRIx8")\n", c);
} }
void grading_rpc_handler_ram_cap(size_t bytes, size_t alignment) void grading_rpc_handler_ram_cap(size_t bytes, size_t alignment)
{ {
debug_printf("grading_rpc_handler_ram_cap(0x%"PRIxPTR", 0x%"PRIxPTR")\n", bytes, alignment);
} }
void grading_rpc_handler_process_spawn(char* cmdline, coreid_t core) void grading_rpc_handler_process_spawn(char* cmdline, coreid_t core)
{ {
debug_printf("grading_rpc_handler_process_spawn(\"%s\", %"PRIuCOREID")\n", cmdline, core);
} }
void grading_rpc_handler_process_get_name(domainid_t pid) void grading_rpc_handler_process_get_name(domainid_t pid)
{ {
debug_printf("grading_rpc_handler_process_get_name(%"PRIuDOMAINID")\n", pid);
} }
void grading_rpc_handler_process_get_all_pids(void) void grading_rpc_handler_process_get_all_pids(void)
{ {
debug_printf("grading_rpc_handler_process_get_all_pids()\n");
} }

View File

@ -3,7 +3,7 @@
#include <spawn/spawn.h> #include <spawn/spawn.h>
#include <time.h> #include <time.h>
#define PROCESS_COUNT 5 #define PROCESS_COUNT 1
void do_test_spawn(void) { void do_test_spawn(void) {
// spawn multiple processes // spawn multiple processes

View File

@ -7,13 +7,13 @@
-- ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group. -- ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
-- --
-- Hakefile for lib/spawn -- Hakefile for lib/spawn
-- --
-------------------------------------------------------------------------- --------------------------------------------------------------------------
[ [
build library { build library {
target = "spawn", target = "spawn",
cFiles = [ "spawn.c" ], cFiles = [ "spawn.c", "rpc_server.c" ],
addLibraries = [ "elf", "argv", "multiboot" ] addLibraries = [ "elf", "argv", "multiboot" ]
}, },
build library { build library {

219
lib/spawn/rpc_server.c Normal file
View File

@ -0,0 +1,219 @@
#include <aos/aos.h>
#include <aos/aos_rpc.h>
#include <spawn/rpc_server.h>
#include <grading.h>
typedef errval_t (*rpc_handler_t)(
struct aos_rpc_server *rpc,
struct capref arg_cap, size_t arg_size, uintptr_t arg0, uintptr_t arg1,
struct capref *ret_cap, size_t *ret_size, uintptr_t *ret0, uintptr_t *ret1
);
static rpc_handler_t rpc_handlers[RPC_MTYPE_COUNT];
static void rpc_server_handle_recv(void *arg);
static void rpc_server_send_reply(void *arg);
void rpc_server_init(struct aos_rpc_server *rpc, struct lmp_chan *chan, void *shared_mem) {
rpc->chan = chan;
rpc->shared_mem = shared_mem;
}
void rpc_server_register_recv(struct aos_rpc_server *rpc) {
errval_t err = lmp_chan_register_recv(rpc->chan, get_default_waitset(), MKCLOSURE(rpc_server_handle_recv, rpc));
if (err_is_fail(err)) {
DEBUG_ERR(err, "Could not register receive handler");
}
}
static void rpc_server_handle_recv(void *arg) {
errval_t err;
struct aos_rpc_server *rpc = (struct aos_rpc_server *)arg;
struct lmp_recv_msg msg = LMP_RECV_MSG_INIT;
struct capref arg_cap;
err = lmp_chan_recv(rpc->chan, &msg, &arg_cap);
assert(err_is_ok(err));
rpc->ret_cap = NULL_CAP;
rpc->ret_size = 0;
rpc->ret0 = 0;
rpc->ret1 = 0;
if (msg.words[0] >= RPC_MTYPE_COUNT) {
err = AOS_ERR_RPC_UNKNOWN_MSG_TYPE;
} else if (msg.words[1] > RPC_SHARED_SIZE) {
err = AOS_ERR_RPC_ARG_TOO_BIG;
} else {
rpc_handler_t handler = rpc_handlers[msg.words[0]];
if (handler == NULL) {
err = AOS_ERR_RPC_UNKNOWN_MSG_TYPE;
} else {
err = handler(
rpc,
arg_cap, msg.words[1], msg.words[2], msg.words[3],
&rpc->ret_cap, &rpc->ret_size, &rpc->ret0, &rpc->ret1
);
}
}
rpc->ret_err = err;
rpc_server_send_reply(rpc);
}
static void rpc_server_send_reply(void *arg) {
struct aos_rpc_server *rpc = (struct aos_rpc_server *)arg;
errval_t err;
err = lmp_chan_send4(
rpc->chan, LMP_FLAG_YIELD | LMP_FLAG_SYNC,
rpc->ret_cap, rpc->ret_err, rpc->ret_size, rpc->ret0, rpc->ret1
);
if (err_is_fail(err)) {
if (!lmp_err_is_transient(err)) {
DEBUG_ERR(err, "Could not send RPC reply");
return;
}
// Cannot send right now, try again later
err = lmp_chan_register_send(rpc->chan, &rpc->ws, MKCLOSURE(rpc_server_send_reply, arg));
if (err_is_fail(err)) {
DEBUG_ERR(err, "Could not register send handler");
return;
}
}
// Sent reply, wait for next RPC call
rpc_server_register_recv(rpc);
}
// RPC handlers
static errval_t handle_rpc_send_number(
struct aos_rpc_server *rpc,
struct capref arg_cap, size_t arg_size, uintptr_t arg0, uintptr_t arg1,
struct capref *ret_cap, size_t *ret_size, uintptr_t *ret0, uintptr_t *ret1
) {
uintptr_t num = arg0;
grading_rpc_handle_number(num);
return SYS_ERR_OK;
}
static errval_t handle_rpc_send_string(
struct aos_rpc_server *rpc,
struct capref arg_cap, size_t arg_size, uintptr_t arg0, uintptr_t arg1,
struct capref *ret_cap, size_t *ret_size, uintptr_t *ret0, uintptr_t *ret1
) {
const char* string = rpc->shared_mem;
if (arg_size == 0 || string[arg_size - 1] != '\0') {
return ERR_INVALID_ARGS;
}
grading_rpc_handler_string(string);
return SYS_ERR_OK;
}
static errval_t handle_rpc_get_ram_cap(
struct aos_rpc_server *rpc,
struct capref arg_cap, size_t arg_size, uintptr_t arg0, uintptr_t arg1,
struct capref *ret_cap, size_t *ret_size, uintptr_t *ret0, uintptr_t *ret1
) {
size_t bytes = arg0;
size_t alignment = arg1;
grading_rpc_handler_ram_cap(bytes, alignment);
// TODO
*ret0 = bytes;
return LIB_ERR_NOT_IMPLEMENTED;
}
static errval_t handle_rpc_serial_getchar(
struct aos_rpc_server *rpc,
struct capref arg_cap, size_t arg_size, uintptr_t arg0, uintptr_t arg1,
struct capref *ret_cap, size_t *ret_size, uintptr_t *ret0, uintptr_t *ret1
) {
grading_rpc_handler_serial_getchar();
// TODO
*ret0 = 'A';
return LIB_ERR_NOT_IMPLEMENTED;
}
static errval_t handle_rpc_serial_putchar(
struct aos_rpc_server *rpc,
struct capref arg_cap, size_t arg_size, uintptr_t arg0, uintptr_t arg1,
struct capref *ret_cap, size_t *ret_size, uintptr_t *ret0, uintptr_t *ret1
) {
char c = arg0;
grading_rpc_handler_serial_putchar(c);
// TODO
return LIB_ERR_NOT_IMPLEMENTED;
}
static errval_t handle_rpc_process_spawn(
struct aos_rpc_server *rpc,
struct capref arg_cap, size_t arg_size, uintptr_t arg0, uintptr_t arg1,
struct capref *ret_cap, size_t *ret_size, uintptr_t *ret0, uintptr_t *ret1
) {
char *cmdline = rpc->shared_mem;
coreid_t core = arg0;
if (arg_size == 0 || cmdline[arg_size - 1] != '\0') {
return ERR_INVALID_ARGS;
}
grading_rpc_handler_process_spawn(cmdline, core);
// TODO
*ret0 = 0;
return LIB_ERR_NOT_IMPLEMENTED;
}
static errval_t handle_rpc_process_get_name(
struct aos_rpc_server *rpc,
struct capref arg_cap, size_t arg_size, uintptr_t arg0, uintptr_t arg1,
struct capref *ret_cap, size_t *ret_size, uintptr_t *ret0, uintptr_t *ret1
) {
domainid_t pid = arg0;
grading_rpc_handler_process_get_name(pid);
// TODO
memcpy(rpc->shared_mem, "name", 5);
*ret_size = 5;
return LIB_ERR_NOT_IMPLEMENTED;
}
static errval_t handle_rpc_process_get_all_pids(
struct aos_rpc_server *rpc,
struct capref arg_cap, size_t arg_size, uintptr_t arg0, uintptr_t arg1,
struct capref *ret_cap, size_t *ret_size, uintptr_t *ret0, uintptr_t *ret1
) {
grading_rpc_handler_process_get_all_pids();
// TODO
return LIB_ERR_NOT_IMPLEMENTED;
}
static rpc_handler_t rpc_handlers[RPC_MTYPE_COUNT] = {
[RPC_MTYPE_SEND_NUMBER] = handle_rpc_send_number,
[RPC_MTYPE_SEND_STRING] = handle_rpc_send_string,
[RPC_MTYPE_GET_RAM_CAP] = handle_rpc_get_ram_cap,
[RPC_MTYPE_SERIAL_GETCHAR] = handle_rpc_serial_getchar,
[RPC_MTYPE_SERIAL_PUTCHAR] = handle_rpc_serial_putchar,
[RPC_MTYPE_PROCESS_SPAWN] = handle_rpc_process_spawn,
[RPC_MTYPE_PROCESS_GET_NAME] = handle_rpc_process_get_name,
[RPC_MTYPE_PROCESS_GET_ALL_PIDS] = handle_rpc_process_get_all_pids,
};

View File

@ -47,46 +47,23 @@ static void armv8_set_registers(void *arch_load_info,
disabled_area->regs[REG_OFFSET(PIC_REGISTER)] = got_base; disabled_area->regs[REG_OFFSET(PIC_REGISTER)] = got_base;
} }
// receive messages sent by the child
static void handle_child_recv(void *arg) { static void handle_child_recv(void *arg) {
errval_t err; errval_t err;
struct lmp_chan *init_chan = (struct lmp_chan *)arg; struct spawninfo *si = (struct spawninfo *)arg;
struct lmp_recv_msg msg = LMP_RECV_MSG_INIT; struct lmp_recv_msg msg = LMP_RECV_MSG_INIT;
struct capref cap; struct capref cap;
err = lmp_chan_recv(init_chan, &msg, &cap); err = lmp_chan_recv(&si->init_chan, &msg, &cap);
if (err_is_fail(err)) { assert(err_is_ok(err));
if (lmp_err_is_transient(err)) {
err = lmp_endpoint_register(init_chan->endpoint, get_default_waitset(), MKCLOSURE(handle_child_recv, init_chan));
if (err_is_fail(err)) {
USER_PANIC_ERR(err, "Could not reregister after failed init_chan cap receive");
}
} else {
USER_PANIC_ERR(err, "Failure in child channel");
}
return;
}
switch(msg.words[0]){ switch(msg.words[0]){
case RPC_MTYPE_CHILD_ENDPOINT: case RPC_MTYPE_CHILD_ENDPOINT:
debug_printf("SPAWN: Received child init_chan endpoint\n"); debug_printf("SPAWN: Received child init_chan endpoint\n");
init_chan->remote_cap = cap; si->init_chan.remote_cap = cap;
err = lmp_chan_send1(init_chan, LMP_FLAG_YIELD | LMP_FLAG_SYNC, NULL_CAP, RPC_MTYPE_CHILD_ENDPOINT_OK); err = lmp_chan_send1(&si->init_chan, LMP_FLAG_YIELD | LMP_FLAG_SYNC, NULL_CAP, SYS_ERR_OK);
if (err_is_fail(err)) { if (err_is_fail(err)) {
USER_PANIC_ERR(err, "Failed to send RPC_MTYPE_CHILD_ENDPOINT_OK"); USER_PANIC_ERR(err, "Failed to send reply");
}
break;
case RPC_MTYPE_GET_RAM_CAP:
debug_printf("[handle_init_recv]: RPC_MTYPE_GET_RAM_CAP\n");
size_t requested_size = msg.words[1];
struct capref new_ram_cap;
frame_alloc(&new_ram_cap, requested_size, NULL);
err = lmp_chan_send1(init_chan, LMP_FLAG_YIELD | LMP_FLAG_SYNC, NULL_CAP, RPC_MTYPE_GET_RAM_CAP_OK);
if (err_is_fail(err)) {
USER_PANIC_ERR(err, "Failed to send RPC_MTYPE_GET_RAM_CAP_OK");
} }
break; break;
default: default:
@ -94,10 +71,7 @@ static void handle_child_recv(void *arg) {
break; break;
} }
err = lmp_endpoint_register(init_chan->endpoint, get_default_waitset(), MKCLOSURE(handle_child_recv, init_chan)); rpc_server_register_recv(&si->rpc_server);
if (err_is_fail(err)) {
USER_PANIC_ERR(err, "Could not reregister after failed init_chan cap receive");
}
} }
struct temp_mapping { struct temp_mapping {
@ -594,6 +568,22 @@ errval_t spawn_load_argv(int argc, char *argv[], struct spawninfo *si,
return err_push(err, SPAWN_ERR_SERIALISE_VSPACE); return err_push(err, SPAWN_ERR_SERIALISE_VSPACE);
} }
// Create shared memory for RPC
err = frame_alloc(&si->rpc_shared_frame, RPC_SHARED_SIZE, NULL);
if (err_is_fail(err)) return err_push(err, LIB_ERR_FRAME_ALLOC);
void *rpc_shared_memory;
err = paging_map_frame_attr(
get_current_paging_state(), &rpc_shared_memory,
RPC_SHARED_SIZE, si->rpc_shared_frame, VREGION_FLAGS_READ_WRITE);
if (err_is_fail(err)) return err;
err = paging_map_frame_attr(
&child_paging_state, &domain_params->rpc_shared_memory,
RPC_SHARED_SIZE, si->rpc_shared_frame, VREGION_FLAGS_READ_WRITE);
if (err_is_fail(err)) return err;
// afeer: TODO: what do i put here? do we need to set these fields to some value? // afeer: TODO: what do i put here? do we need to set these fields to some value?
// domain_params->tls_init_base = NULL; // domain_params->tls_init_base = NULL;
// domain_params->tls_init_len = 0; // domain_params->tls_init_len = 0;
@ -624,9 +614,11 @@ errval_t spawn_load_argv(int argc, char *argv[], struct spawninfo *si,
err = paging_unmap(get_current_paging_state(), arguments_page_in_self); err = paging_unmap(get_current_paging_state(), arguments_page_in_self);
if (err_is_fail(err)) return err_push(err, LIB_ERR_PMAP_UNMAP); if (err_is_fail(err)) return err_push(err, LIB_ERR_PMAP_UNMAP);
rpc_server_init(&si->rpc_server, &si->init_chan, rpc_shared_memory);
// Receive the child's endpoint for the init channel // Receive the child's endpoint for the init channel
lmp_chan_alloc_recv_slot(&si->init_chan); lmp_chan_alloc_recv_slot(&si->init_chan);
err = lmp_endpoint_register(si->init_chan.endpoint, get_default_waitset(), MKCLOSURE(handle_child_recv, &si->init_chan)); err = lmp_chan_register_recv(&si->init_chan, get_default_waitset(), MKCLOSURE(handle_child_recv, si));
if (err_is_fail(err)) return err; if (err_is_fail(err)) return err;
// - Make the new dispatcher runnable // - Make the new dispatcher runnable

View File

@ -18,19 +18,28 @@
#include <string.h> #include <string.h>
#include <aos/aos.h> #include <aos/aos.h>
#include <aos/aos_rpc.h>
#include <aos/deferred.h> #include <aos/deferred.h>
#define HELLO_CATCH_COMMAND "catch" #define HELLO_CATCH_COMMAND "catch"
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
errval_t err;
printf("Hello, world!\n"); printf("Hello, world!\n");
printf("argv:\n"); printf("argv:\n");
for(int i = 0; i < argc; ++i) { for(int i = 0; i < argc; ++i) {
printf(" %d -> %s\n", i, argv[i]); printf(" %d -> %s\n", i, argv[i]);
} }
struct aos_rpc *rpc = aos_rpc_get_init_channel();
err = aos_rpc_send_number(rpc, 1234);
if (err_is_fail(err)) USER_PANIC_ERR(err, "Failed to send RPC");
err = aos_rpc_send_string(rpc, "Hello World via RPC!");
if (err_is_fail(err)) USER_PANIC_ERR(err, "Failed to send RPC");
// if we receive the catch command, RUN! // if we receive the catch command, RUN!
if (argc > 1 && !strncmp(argv[1], HELLO_CATCH_COMMAND, sizeof(HELLO_CATCH_COMMAND))) { if (argc > 1 && !strncmp(argv[1], HELLO_CATCH_COMMAND, sizeof(HELLO_CATCH_COMMAND))) {
int iter = 0; int iter = 0;