Added: Terminal RPC, Spawn RPC, small abstraction fixes, automatic recv slot allocation in aos_rpc

This commit is contained in:
Sparchatus 2022-03-31 07:59:00 +00:00
parent 14063e60be
commit 9750a752c3
10 changed files with 225 additions and 49 deletions

View File

@ -1380,6 +1380,7 @@ errors aos AOS_ERR_ {
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",
failure RPC_PROCESS_UNKNOWN_PID "Requested process name for an unknown PID",
};
// errors NIC driver

View File

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

View File

@ -27,6 +27,7 @@ enum rpc_mtype {
RPC_MTYPE_GET_RAM_CAP,
RPC_MTYPE_SERIAL_GETCHAR,
RPC_MTYPE_SERIAL_PUTCHAR,
RPC_MTYPE_SERIAL_WRITE,
RPC_MTYPE_PROCESS_SPAWN,
RPC_MTYPE_PROCESS_GET_NAME,
RPC_MTYPE_PROCESS_GET_ALL_PIDS,
@ -78,6 +79,12 @@ errval_t aos_rpc_serial_getchar(struct aos_rpc *chan, char *retc);
*/
errval_t aos_rpc_serial_putchar(struct aos_rpc *chan, char c);
/**
* \brief Send a list of characters to the serial port
*/
errval_t aos_rpc_serial_write(struct aos_rpc *chan, const char *buf,
size_t buf_len);
/**
* \brief Request that the process manager start a new process
* \arg cmdline the name of the process that needs to be spawned (without a

View File

@ -63,6 +63,11 @@ struct spawninfo {
struct aos_rpc_server rpc_server;
};
struct spawninfo *sawn_get_process_list(void);
// parse a commandline into arguments
void spawn_parse_cmd(char *cmdline, int *argc, char **argv);
// Start a child process using the multiboot command line. Fills in si.
errval_t spawn_load_by_name(char *binary_name, struct spawninfo * si,
domainid_t *pid);

View File

@ -27,6 +27,11 @@ static errval_t do_aos_rpc(
) {
errval_t err;
// allocate capability if we expect one and the recv slot is empty
if (ret_cap != NULL && rpc->chan->endpoint->k.recv_cptr == 0){
lmp_chan_alloc_recv_slot(rpc->chan);
}
// Send call
while (true) {
err = lmp_chan_send4(rpc->chan, LMP_FLAG_YIELD | LMP_FLAG_SYNC, arg_cap, msg_type, arg_size, arg0, arg1);
@ -121,6 +126,36 @@ aos_rpc_serial_putchar(struct aos_rpc *rpc, char c) {
);
}
// putchar for terminal printing is too slow so we send buffers instead
errval_t
aos_rpc_serial_write(struct aos_rpc *rpc, const char *buf, size_t buf_len) {
errval_t err;
// split the buffer into chunks for sending
while(buf_len > 0) {
size_t chunk_len = buf_len;
if (chunk_len > RPC_SHARED_SIZE) {
chunk_len = RPC_SHARED_SIZE;
}
memcpy(rpc->shared_mem, buf, chunk_len);
err = do_aos_rpc(
rpc, RPC_MTYPE_SERIAL_WRITE,
NULL_CAP, chunk_len, 0, 0,
NULL, NULL, NULL, NULL
);
if (err_is_fail(err)) {
return err;
}
buf += chunk_len;
buf_len -= chunk_len;
}
return SYS_ERR_OK;
}
errval_t
aos_rpc_process_spawn(struct aos_rpc *rpc, char *cmdline,
coreid_t core, domainid_t *newpid) {
@ -153,7 +188,8 @@ aos_rpc_process_get_name(struct aos_rpc *rpc, domainid_t pid, char **name) {
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);
memcpy(*name, rpc->shared_mem, name_len);
assert((*name)[name_len] == '\0');
return err;
}
@ -164,7 +200,7 @@ aos_rpc_process_get_all_pids(struct aos_rpc *rpc, domainid_t **pids,
// (M5): implement process id discovery
size_t ret_len;
errval_t err = do_aos_rpc(
rpc, RPC_MTYPE_PROCESS_GET_NAME,
rpc, RPC_MTYPE_PROCESS_GET_ALL_PIDS,
NULL_CAP, 0, 0, 0,
NULL, &ret_len, NULL, NULL
);
@ -172,7 +208,7 @@ aos_rpc_process_get_all_pids(struct aos_rpc *rpc, domainid_t **pids,
*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);
memcpy(*pids, rpc->shared_mem, ret_len);
return err;
}

View File

@ -100,9 +100,8 @@ static void handle_init_recv(void *arg)
struct lmp_chan *init_chan = (struct lmp_chan *)arg;
struct lmp_recv_msg msg = LMP_RECV_MSG_INIT;
struct capref cap;
err = lmp_chan_recv(init_chan, &msg, &cap);
err = lmp_chan_recv(init_chan, &msg, NULL);
assert(err_is_ok(err));
if (msg.words[0] == SYS_ERR_OK) {
@ -113,6 +112,32 @@ static void handle_init_recv(void *arg)
}
}
// TODO rueegges: allow partial write
static size_t aos_terminal_write(const char *buf, size_t len)
{
errval_t err;
struct aos_rpc *rpc = aos_rpc_get_serial_channel();
if (rpc == NULL) {
debug_printf("Attempted to printf before initializing rpc: %.*s\n", len, buf);
USER_PANIC("Make sure to initialize rpc before function barrelfish_libc_glue_init is called.");
return len;
}
err = aos_rpc_serial_write(rpc, buf, len);
assert(err_is_ok(err));
return len;
}
// TODO rueegges: make more efficient?
static size_t aos_terminal_read(char *buf, size_t len)
{
errval_t err;
struct aos_rpc *rpc = aos_rpc_get_serial_channel();
err = aos_rpc_serial_getchar(rpc, buf);
assert(err_is_ok(err));
return 1;
}
/* Set libc function pointers */
void barrelfish_libc_glue_init(void)
{
@ -120,8 +145,14 @@ void barrelfish_libc_glue_init(void)
// what we need for that
// TODO: change these to use the user-space serial driver if possible
// TODO: set these functions
_libc_terminal_read_func = dummy_terminal_read;
_libc_terminal_write_func = syscall_terminal_write;
// 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() */

View File

@ -16,19 +16,19 @@ void do_test_spawn(void) {
}
// wait for 10 seconds but handle events in the mean time
struct waitset *default_ws = get_default_waitset();
struct timespec tt;
clock_gettime(CLOCK_REALTIME, &tt);
long start = time_to_ms(tt);
do {
if(err_is_ok(check_for_event(default_ws))){
CHECK_ERR(event_dispatch(default_ws));
}
clock_gettime(CLOCK_REALTIME, &tt);
} while(time_to_ms(tt) - start < 10000);
// struct waitset *default_ws = get_default_waitset();
// struct timespec tt;
// clock_gettime(CLOCK_REALTIME, &tt);
// long start = time_to_ms(tt);
// do {
// if(err_is_ok(check_for_event(default_ws))){
// CHECK_ERR(event_dispatch(default_ws));
// }
// clock_gettime(CLOCK_REALTIME, &tt);
// } while(time_to_ms(tt) - start < 10000);
for(uint i = 0; i < PROCESS_COUNT; ++i) {
debug_printf("TEST_SPAWN: Killing %u\n", i);
CHECK_ERR(invoke_dispatcher_stop(si[i].dispatcher));
}
// for(uint i = 0; i < PROCESS_COUNT; ++i) {
// debug_printf("TEST_SPAWN: Killing %u\n", i);
// CHECK_ERR(invoke_dispatcher_stop(si[i].dispatcher));
// }
}

View File

@ -2,6 +2,7 @@
#include <aos/aos_rpc.h>
#include <spawn/rpc_server.h>
#include <grading.h>
#include <spawn/spawn.h>
typedef errval_t (*rpc_handler_t)(
struct aos_rpc_server *rpc,
@ -138,9 +139,9 @@ static errval_t handle_rpc_serial_getchar(
) {
grading_rpc_handler_serial_getchar();
// TODO
*ret0 = 'A';
// MARKER SHELL: Replace with UART call
*ret0 = getchar();
return LIB_ERR_NOT_IMPLEMENTED;
}
@ -154,9 +155,27 @@ static errval_t handle_rpc_serial_putchar(
grading_rpc_handler_serial_putchar(c);
// TODO
// MARKER SHELL: Replace with UART call
putchar(c);
return LIB_ERR_NOT_IMPLEMENTED;
return SYS_ERR_OK;
}
static errval_t handle_rpc_serial_write(
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
) {
if (arg_size == 0 ) {
return ERR_INVALID_ARGS;
}
// MARKER SHELL: Replace with UART call
for (size_t i = 0; i < arg_size; ++i){
putchar(((char *)rpc->shared_mem)[i]);
}
return SYS_ERR_OK;
}
static errval_t handle_rpc_process_spawn(
@ -172,10 +191,13 @@ static errval_t handle_rpc_process_spawn(
grading_rpc_handler_process_spawn(cmdline, core);
// TODO
*ret0 = 0;
struct spawninfo *si = malloc(sizeof(struct spawninfo));
return LIB_ERR_NOT_IMPLEMENTED;
char *argv[MAX_CMDLINE_ARGS];
int argc;
spawn_parse_cmd(cmdline, &argc, argv);
return spawn_load_argv(argc, argv, si, (domainid_t *)ret0);
}
static errval_t handle_rpc_process_get_name(
@ -187,11 +209,28 @@ static errval_t handle_rpc_process_get_name(
grading_rpc_handler_process_get_name(pid);
// TODO
memcpy(rpc->shared_mem, "name", 5);
*ret_size = 5;
// search for the pid
char *name = NULL;
for (struct spawninfo *si = sawn_get_process_list(); si != NULL; si = si->next) {
if (si->pid == pid) {
name = si->binary_name;
break;
}
}
return LIB_ERR_NOT_IMPLEMENTED;
if (name == NULL) {
return AOS_ERR_RPC_PROCESS_UNKNOWN_PID;
}
size_t name_len = strlen(name) + 1;
if(name_len > RPC_SHARED_SIZE) {
return AOS_ERR_RPC_RET_TOO_BIG;
}
memcpy(rpc->shared_mem, name, name_len);
*ret_size = name_len;
return SYS_ERR_OK;
}
static errval_t handle_rpc_process_get_all_pids(
@ -200,10 +239,25 @@ static errval_t handle_rpc_process_get_all_pids(
struct capref *ret_cap, size_t *ret_size, uintptr_t *ret0, uintptr_t *ret1
) {
grading_rpc_handler_process_get_all_pids();
// size in bytes
size_t list_size = 0;
domainid_t *buf = rpc->shared_mem;
// TODO
// get all PIDs that fit into the given space
for (struct spawninfo *si = sawn_get_process_list(); si != NULL; si = si->next) {
if (list_size + sizeof(domainid_t) > RPC_SHARED_SIZE) {
return AOS_ERR_RPC_RET_TOO_BIG;
}
return LIB_ERR_NOT_IMPLEMENTED;
*buf = si->pid;
++buf;
list_size += sizeof(domainid_t);
}
*ret_size = list_size;
return SYS_ERR_OK;
}
@ -213,6 +267,7 @@ static rpc_handler_t rpc_handlers[RPC_MTYPE_COUNT] = {
[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_SERIAL_WRITE] = handle_rpc_serial_write,
[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

@ -20,7 +20,9 @@ struct spawninfo *spawn_process_list = NULL;
// TODO: handle "freeing" of PIDs in case we learn how to detect stopped child processes
domainid_t spawn_last_pid = 1;
struct spawninfo *sawn_get_process_list(void) {
return spawn_process_list;
}
/**
* \brief Set the base address of the .got (Global Offset Table) section of the ELF binary
@ -334,6 +336,13 @@ errval_t spawn_load_argv(int argc, char *argv[], struct spawninfo *si,
// - Initialize the spawn_info struct
// TODO
// copy name to spawninfo struct
size_t binary_name_len = strlen(argv[0]);
si->binary_name = malloc(binary_name_len);
if (si->binary_name == NULL) {
return LIB_ERR_MALLOC_FAIL;
}
memcpy(si->binary_name, argv[0], binary_name_len);
// - Get the module from the multiboot image
// and map it (take a look at multiboot.c)
@ -633,9 +642,23 @@ errval_t spawn_load_argv(int argc, char *argv[], struct spawninfo *si,
si->pid = ++spawn_last_pid;
*pid = si->pid;
// add to process list
si->next = spawn_process_list;
spawn_process_list = si;
return SYS_ERR_OK;
}
void spawn_parse_cmd(char *cmdline, int *argc, char **argv){
*argc = 0;
char *token = strtok(cmdline, " ");
while (token != NULL) {
argv[*argc] = token;
token = strtok(NULL, " ");
*argc += 1;
}
}
/**
* (M2): Implement this function.
* \brief Spawn a new dispatcher executing 'binary_name'
@ -665,22 +688,13 @@ errval_t spawn_load_by_name(char *binary_name, struct spawninfo * si,
// printf("raw_arguments_str: %s\n", raw_arguments_str);
// afeer: explode the raw_arguments_str into argv
char * argv[MAX_CMDLINE_ARGS];
int argc = 0;
char * token = strtok(raw_arguments_str, " ");
while (token != NULL) {
argv[argc] = token;
token = strtok(NULL, " ");
argc += 1;
}
char *argv[MAX_CMDLINE_ARGS];
int argc;
spawn_parse_cmd(raw_arguments_str, &argc, argv);
// - Call spawn_load_argv
err = spawn_load_argv(argc, argv, si, pid);
if (err_is_fail(err)) return err;
// add to process list
si->next = spawn_process_list;
spawn_process_list = si;
return SYS_ERR_OK;
}

View File

@ -22,6 +22,7 @@
#include <aos/deferred.h>
#define HELLO_CATCH_COMMAND "catch"
#define HELLO_SPAWN_COMMAND "spawn"
int main(int argc, char *argv[])
{
@ -40,6 +41,32 @@ int main(int argc, char *argv[])
err = aos_rpc_send_string(rpc, "Hello World via RPC!");
if (err_is_fail(err)) USER_PANIC_ERR(err, "Failed to send RPC");
// try to spawn a child using rpc
if (argc > 1 && !strncmp(argv[1], HELLO_SPAWN_COMMAND, sizeof(HELLO_SPAWN_COMMAND))) {
// start process
domainid_t pid;
rpc = aos_rpc_get_process_channel();
err = aos_rpc_process_spawn(rpc, "hello Aurel Jan Sandro", 0, &pid);
if (err_is_fail(err)) USER_PANIC_ERR(err, "Failed to spawn process");
printf("Started a new process!\n");
// get process name
char *name;
err = aos_rpc_process_get_name(rpc, pid, &name);
if (err_is_fail(err)) USER_PANIC_ERR(err, "Failed to get process name");
printf("Process Name: %s\n", name);
// get all PIDs
domainid_t *pids;
size_t pid_count;
err = aos_rpc_process_get_all_pids(rpc, &pids, &pid_count);
if (err_is_fail(err)) USER_PANIC_ERR(err, "Failed to get all PIDs");
printf("PIDs:\n");
for(size_t i = 0; i < pid_count; ++i) {
printf(" %lu\n", pids[i]);
}
}
// if we receive the catch command, RUN!
if (argc > 1 && !strncmp(argv[1], HELLO_CATCH_COMMAND, sizeof(HELLO_CATCH_COMMAND))) {
int iter = 0;