merge shelly into main
This commit is contained in:
commit
8e0c0c13ed
@ -1445,3 +1445,10 @@ errors block BLOCK_ERR_ {
|
||||
failure OVERFLOW_BLOCK "Client tried to operate over block bounds",
|
||||
failure WRITE_BOOTSECTOR "Client tried to overwrite the boot sector",
|
||||
};
|
||||
|
||||
errors shelly SHELLY_ERR_ {
|
||||
failure BUFFER_OVERFLOW "Buffer limits reached",
|
||||
failure WRITE "String write failed",
|
||||
failure SPAWN_RPC "Spawn RPC failed",
|
||||
failure PS_RPC "ps RPC failed",
|
||||
};
|
||||
|
||||
41
include/aos/shelly_client.h
Normal file
41
include/aos/shelly_client.h
Normal file
@ -0,0 +1,41 @@
|
||||
#ifndef _SHELLY_CLIENT_H_
|
||||
#define _SHELLY_CLIENT_H_
|
||||
|
||||
#include <aos/aos.h>
|
||||
|
||||
// #define SHELLY_CLIENT_DEBUG_ON 1
|
||||
|
||||
#if defined(SHELLY_CLIENT_DEBUG_ON)
|
||||
#define SHELLY_CLIENT_DEBUG(x...) debug_printf("[SHELLY_CLIENT_DEBUG] " x);
|
||||
#else
|
||||
#define SHELLY_CLIENT_DEBUG(x, ...) ((void)0)
|
||||
#endif
|
||||
|
||||
|
||||
enum shelly_msg_type {
|
||||
SHELLY_MSG_PUTCHAR,
|
||||
SHELLY_MSG_GETCHAR,
|
||||
SHELLY_MSG_RESPONSE,
|
||||
};
|
||||
|
||||
struct shelly_header {
|
||||
enum shelly_msg_type type;
|
||||
char character;
|
||||
};
|
||||
|
||||
struct shelly_client_state {
|
||||
struct ump_send_chan *send_chan;
|
||||
struct ump_recv_chan *recv_chan;
|
||||
|
||||
struct capref shared_frame;
|
||||
bool request_ongoing;
|
||||
struct shelly_header * current_request;
|
||||
|
||||
char * buf;
|
||||
};
|
||||
|
||||
errval_t shelly_client_init(void);
|
||||
errval_t shelly_client_getchar(struct aos_rpc * rpc, char * ret);
|
||||
errval_t shelly_client_putchar(struct aos_rpc * rpc, char input);
|
||||
|
||||
#endif /* _SHELLY_CLIENT_H_ */
|
||||
@ -9,6 +9,7 @@ enum ump_server_id {
|
||||
UMP_SERVER_ECHO,
|
||||
UMP_SERVER_NET,
|
||||
UMP_SERVER_BLOCK_DRIVER,
|
||||
UMP_SERVER_SHELLY,
|
||||
UMP_SERVER_COUNT // How many servers exist
|
||||
};
|
||||
|
||||
|
||||
@ -53,6 +53,7 @@ struct spawninfo {
|
||||
struct capref cspace_cap_dispframe; // < A capability to the dispatcher frame, used to communicate between a process and the CPU driver.
|
||||
struct capref cspace_cap_argspage; // < A page containing a list of command line arguments.
|
||||
struct capref cspace_cap_vspace; // < The frame capability used to store the serialized vspace
|
||||
struct capref cspace_cap_irq; // < the irq capability for interrupts
|
||||
|
||||
struct capref vspace_cap_l0_pagetable;
|
||||
|
||||
|
||||
@ -53,6 +53,7 @@
|
||||
"sys_debug.c",
|
||||
"syscalls.c",
|
||||
"systime.c",
|
||||
"shelly_client.c",
|
||||
"thread_once.c",
|
||||
"thread_sync.c",
|
||||
"threads.c",
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
#include <aos/ump_binding.h>
|
||||
|
||||
#include <aos/dispatcher_arch.h>
|
||||
#include <aos/shelly_client.h>
|
||||
|
||||
static void noop_callback(void *arg) {
|
||||
}
|
||||
@ -166,14 +167,16 @@ aos_rpc_serial_getchar(struct aos_rpc *rpc, char *retc) {
|
||||
// Implement functionality to request a character from
|
||||
// the serial driver.
|
||||
errval_t err;
|
||||
uintptr_t retval;
|
||||
// uintptr_t retval;
|
||||
|
||||
err = do_aos_rpc(
|
||||
rpc, RPC_MTYPE_SERIAL_GETCHAR,
|
||||
NULL_CAP, 0, 0, 0,
|
||||
NULL, NULL, &retval, NULL);
|
||||
err = shelly_client_getchar(rpc, retc);
|
||||
|
||||
*retc = retval;
|
||||
// err = do_aos_rpc(
|
||||
// rpc, RPC_MTYPE_SERIAL_GETCHAR,
|
||||
// NULL_CAP, 0, 0, 0,
|
||||
// NULL, NULL, &retval, NULL);
|
||||
|
||||
// *retc = retval;
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -184,11 +187,13 @@ aos_rpc_serial_putchar(struct aos_rpc *rpc, char c) {
|
||||
// serial port.
|
||||
errval_t err;
|
||||
|
||||
err = do_aos_rpc(
|
||||
rpc, RPC_MTYPE_SERIAL_PUTCHAR,
|
||||
NULL_CAP, 0, c, 0,
|
||||
NULL, NULL, NULL, NULL
|
||||
);
|
||||
err = shelly_client_putchar(rpc, c);
|
||||
|
||||
// err = do_aos_rpc(
|
||||
// rpc, RPC_MTYPE_SERIAL_PUTCHAR,
|
||||
// NULL_CAP, 0, c, 0,
|
||||
// NULL, NULL, NULL, NULL
|
||||
// );
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -30,6 +30,8 @@
|
||||
#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;
|
||||
@ -103,6 +105,7 @@ static void handle_init_recv(void *arg)
|
||||
|
||||
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();
|
||||
@ -110,12 +113,18 @@ static size_t aos_terminal_write(const char *buf, size_t len)
|
||||
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 aos_rpc_serial_write(rpc, buf, len);
|
||||
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();
|
||||
@ -123,8 +132,15 @@ static size_t aos_terminal_read(char *buf, size_t len)
|
||||
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 aos_rpc_serial_read(rpc, buf, len);
|
||||
return SYS_ERR_OK;
|
||||
// return aos_rpc_serial_read(rpc, buf, len);
|
||||
}
|
||||
|
||||
/* Set libc function pointers */
|
||||
@ -243,7 +259,12 @@ errval_t barrelfish_init_onthread(struct spawn_domain_params *params)
|
||||
* 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;
|
||||
|
||||
132
lib/aos/shelly_client.c
Normal file
132
lib/aos/shelly_client.c
Normal file
@ -0,0 +1,132 @@
|
||||
#include <aos/ump_chan.h>
|
||||
#include <aos/ump_binding.h>
|
||||
#include <aos/aos_rpc.h>
|
||||
#include <aos/deferred.h>
|
||||
#include <aos/shelly_client.h>
|
||||
#include <aos/domain.h>
|
||||
|
||||
// use a waitset to make the calls blocking
|
||||
struct waitset ws;
|
||||
static struct shelly_client_state state;
|
||||
|
||||
errval_t shelly_client_init(void) {
|
||||
errval_t err;
|
||||
SHELLY_CLIENT_DEBUG("[shelly_client_init]\n");
|
||||
|
||||
waitset_init(&ws);
|
||||
|
||||
state.request_ongoing = false;
|
||||
state.buf = NULL;
|
||||
state.current_request = NULL;
|
||||
|
||||
//connect to shelly
|
||||
struct aos_rpc *rpc = aos_rpc_get_init_channel();
|
||||
// retry several times, waiting inbetween in case the server is still starting up
|
||||
for (int attempts = 0; attempts < 50; attempts++) {
|
||||
err = aos_rpc_ump_connect(rpc, UMP_SERVER_SHELLY, &state.shared_frame);
|
||||
if (err_no(err) != LIB_ERR_UMP_NOT_REGISTERED) break;
|
||||
barrelfish_usleep(100000);
|
||||
}
|
||||
if (err_is_fail(err)) return err;
|
||||
|
||||
//create the ump channel to the serial driver (a.k.a. shelly)
|
||||
err = ump_chan_init(UMP_ROLE_CLIENT, &state.send_chan, &state.recv_chan, sizeof(struct shelly_header), state.shared_frame, &ws);
|
||||
if (err_is_fail(err)) return err;
|
||||
|
||||
// set_shelly_rpc(rpc);
|
||||
|
||||
return SYS_ERR_OK;
|
||||
}
|
||||
|
||||
static void handle_payload(void *arg, size_t payload_size, void *payload) {
|
||||
state.request_ongoing = false;
|
||||
}
|
||||
|
||||
static void handle_response(void *arg, size_t header_size, void *header_buf, size_t payload_size) {
|
||||
struct shelly_header *header = header_buf;
|
||||
SHELLY_CLIENT_DEBUG("[handle_response]\n");
|
||||
|
||||
if (state.current_request->type == SHELLY_MSG_GETCHAR) {
|
||||
*state.buf = header->character;
|
||||
} else if (state.current_request->type == SHELLY_MSG_PUTCHAR) {
|
||||
//nothing to do
|
||||
} else {
|
||||
SHELLY_CLIENT_DEBUG("[handle_response] unexpected request type");
|
||||
}
|
||||
|
||||
ump_recv_payload(state.recv_chan, NULL, handle_payload, NULL);
|
||||
}
|
||||
|
||||
static void handle_send_completed(void *arg, struct ump_send_queue_entry *entry) {
|
||||
SHELLY_CLIENT_DEBUG("[handle_send_completed]\n");
|
||||
free((void *)entry->header);
|
||||
free((void *)entry->payload);
|
||||
free(entry);
|
||||
}
|
||||
|
||||
errval_t shelly_client_getchar(struct aos_rpc * rpc, char * ret) {
|
||||
errval_t err;
|
||||
SHELLY_CLIENT_DEBUG("[shelly_client_getchar]\n");
|
||||
|
||||
state.request_ongoing = true;
|
||||
state.buf = ret;
|
||||
|
||||
struct shelly_header * header = malloc(sizeof(struct shelly_header));
|
||||
if (header == NULL) return LIB_ERR_MALLOC_FAIL;
|
||||
state.current_request = header;
|
||||
struct ump_send_queue_entry *entry = malloc(sizeof(struct ump_send_queue_entry));
|
||||
if (entry == NULL) return LIB_ERR_MALLOC_FAIL;
|
||||
|
||||
header->type = SHELLY_MSG_GETCHAR;
|
||||
header->character = 0;
|
||||
|
||||
ump_send(state.send_chan, entry, sizeof(struct shelly_header), header, 0, NULL, handle_send_completed, NULL);
|
||||
|
||||
// register response handler
|
||||
ump_recv_header(state.recv_chan, handle_response, NULL);
|
||||
|
||||
// wait for the response
|
||||
while (state.request_ongoing) {
|
||||
err = event_dispatch(&ws);
|
||||
if (err_is_fail(err)) {
|
||||
DEBUG_ERR(err, "in event_dispatch");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
SHELLY_CLIENT_DEBUG("[shelly_client_getchar] done\n");
|
||||
|
||||
return SYS_ERR_OK;
|
||||
}
|
||||
|
||||
errval_t shelly_client_putchar(struct aos_rpc * rpc, char input) {
|
||||
errval_t err;
|
||||
SHELLY_CLIENT_DEBUG("[shelly_client_putchar]\n");
|
||||
|
||||
state.request_ongoing = true;
|
||||
|
||||
struct shelly_header * header = malloc(sizeof(struct shelly_header));
|
||||
if (header == NULL) return LIB_ERR_MALLOC_FAIL;
|
||||
state.current_request = header;
|
||||
struct ump_send_queue_entry *entry = malloc(sizeof(struct ump_send_queue_entry));
|
||||
if (entry == NULL) return LIB_ERR_MALLOC_FAIL;
|
||||
|
||||
header->type = SHELLY_MSG_PUTCHAR;
|
||||
header->character = input;
|
||||
|
||||
ump_send(state.send_chan, entry, sizeof(struct shelly_header), header, 0, NULL, handle_send_completed, NULL);
|
||||
|
||||
// register response handler
|
||||
ump_recv_header(state.recv_chan, handle_response, NULL);
|
||||
|
||||
// wait for the response
|
||||
while (state.request_ongoing) {
|
||||
err = event_dispatch(&ws);
|
||||
if (err_is_fail(err)) {
|
||||
DEBUG_ERR(err, "in event_dispatch");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
SHELLY_CLIENT_DEBUG("[shelly_client_getchar] done\n");
|
||||
|
||||
return SYS_ERR_OK;
|
||||
}
|
||||
@ -285,6 +285,7 @@ static void ump_worker_schedule(struct ump_worker_context *worker_context) {
|
||||
// this is supposed to be called single threaded and only upon event trigger
|
||||
// hence this cannot be a reregister and thus not fail
|
||||
assert(err_is_ok(err));
|
||||
thread_yield();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
#include <spawn/ump_binding_server.h>
|
||||
#include <grading.h>
|
||||
#include <spawn/spawn.h>
|
||||
#include <aos/shelly_client.h>
|
||||
|
||||
extern coreid_t my_core_id;
|
||||
rpc_handler_t rpc_handlers[RPC_MTYPE_COUNT];
|
||||
@ -189,34 +190,38 @@ static errval_t handle_rpc_get_ram_cap(
|
||||
return SYS_ERR_OK;
|
||||
}
|
||||
|
||||
static errval_t handle_rpc_serial_getchar(
|
||||
struct generic_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 errval_t handle_rpc_serial_getchar(
|
||||
// struct generic_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
|
||||
// ) {
|
||||
// errval_t err;
|
||||
|
||||
grading_rpc_handler_serial_getchar();
|
||||
// grading_rpc_handler_serial_getchar();
|
||||
// char c;
|
||||
// err = shelly_client_getchar(&c);
|
||||
// *ret1 = c;
|
||||
// if (err_is_fail(err)) return err;
|
||||
|
||||
// MARKER SHELL: Replace with UART call
|
||||
*ret0 = getchar();
|
||||
// return SYS_ERR_OK;
|
||||
// }
|
||||
|
||||
return SYS_ERR_OK;
|
||||
}
|
||||
// static errval_t handle_rpc_serial_putchar(
|
||||
// struct generic_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
|
||||
// ) {
|
||||
// errval_t err;
|
||||
|
||||
static errval_t handle_rpc_serial_putchar(
|
||||
struct generic_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;
|
||||
// char c = arg0;
|
||||
|
||||
grading_rpc_handler_serial_putchar(c);
|
||||
// grading_rpc_handler_serial_putchar(c);
|
||||
|
||||
// MARKER SHELL: Replace with UART call
|
||||
putchar(c);
|
||||
// err = shelly_client_putchar(c);
|
||||
// if (err_is_fail(err)) return err;
|
||||
|
||||
return SYS_ERR_OK;
|
||||
}
|
||||
// return SYS_ERR_OK;
|
||||
// }
|
||||
|
||||
static errval_t handle_rpc_serial_write(
|
||||
struct generic_rpc_server *rpc,
|
||||
@ -502,8 +507,8 @@ 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_SERIAL_GETCHAR] = handle_rpc_serial_getchar,
|
||||
// [RPC_MTYPE_SERIAL_PUTCHAR] = handle_rpc_serial_putchar,
|
||||
[RPC_MTYPE_SERIAL_WRITE] = handle_rpc_serial_write,
|
||||
[RPC_MTYPE_SERIAL_READ] = handle_rpc_serial_read,
|
||||
[RPC_MTYPE_PROCESS_SPAWN] = handle_rpc_process_spawn,
|
||||
|
||||
@ -15,6 +15,7 @@
|
||||
#include <spawn/argv.h>
|
||||
|
||||
#include <maps/imx8x_map.h>
|
||||
#include <maps/qemu_map.h>
|
||||
|
||||
extern struct bootinfo *bi;
|
||||
extern coreid_t my_core_id;
|
||||
@ -467,6 +468,9 @@ errval_t spawn_load_argv(int argc, char *argv[], struct spawninfo *si,
|
||||
si->cspace_cap_vspace.cnode = si->cspace_l2_cnode_taskcn;
|
||||
si->cspace_cap_vspace.slot = TASKCN_SLOT_VSPACE;
|
||||
|
||||
si->cspace_cap_irq.cnode = si->cspace_l2_cnode_taskcn;
|
||||
si->cspace_cap_irq.slot = TASKCN_SLOT_IRQ;
|
||||
|
||||
err = cnode_create_foreign_l2(si->cspace_l1_cnode_cap, ROOTCN_SLOT_SLOT_ALLOC0, &si->cspace_l2_cnode_slot_alloc_0);
|
||||
if (err_is_fail(err)) return err;
|
||||
err = cnode_create_foreign_l2(si->cspace_l1_cnode_cap, ROOTCN_SLOT_SLOT_ALLOC1, &si->cspace_l2_cnode_slot_alloc_1);
|
||||
@ -494,6 +498,9 @@ errval_t spawn_load_argv(int argc, char *argv[], struct spawninfo *si,
|
||||
err = cap_retype(si->cspace_cap_selfep, si->cspace_cap_dispatcher, 0, ObjType_EndPointLMP, 0, 1);
|
||||
if (err_is_fail(err)) return err_push(err, SPAWN_ERR_CREATE_SELFEP);
|
||||
|
||||
err = cap_copy(si->cspace_cap_irq, cap_irq);
|
||||
if (err_is_fail(err)) return err;
|
||||
|
||||
// give the child an endpoint to talk to init
|
||||
lmp_chan_init(&si->init_chan);
|
||||
err = endpoint_create(DEFAULT_LMP_BUF_WORDS, &si->init_chan.local_cap, &si->init_chan.endpoint);
|
||||
@ -505,15 +512,23 @@ errval_t spawn_load_argv(int argc, char *argv[], struct spawninfo *si,
|
||||
// Set up capability arguments. This would ideally be passed somehow as an argument to spawn instead.
|
||||
size_t arg0_base = 0;
|
||||
size_t arg0_size = 0;
|
||||
size_t arg1_base = 0;
|
||||
size_t arg1_size = 0;
|
||||
if (strcmp(argv[0], "enet") == 0) {
|
||||
arg0_base = IMX8X_ENET_BASE;
|
||||
arg0_size = IMX8X_ENET_SIZE;
|
||||
} else if (strcmp(argv[0], "shelly") == 0) {
|
||||
arg0_base = IMX8X_UART3_BASE;
|
||||
arg0_size = IMX8X_UART_SIZE;
|
||||
arg1_base = IMX8X_GIC_DIST_BASE;
|
||||
arg1_size = IMX8X_GIC_DIST_SIZE;
|
||||
}
|
||||
if (strcmp(argv[0], "block_driver_server") == 0) {
|
||||
arg0_base = IMX8X_SDHC2_BASE;
|
||||
arg0_size = IMX8X_SDHC_SIZE;
|
||||
}
|
||||
|
||||
//TODO: also map GIC (interrupt controller) for shelly
|
||||
si->cspace_l2_cnode_argcn = NULL_CNODE;
|
||||
if (arg0_base != 0) {
|
||||
err = cnode_create_foreign_l2(si->cspace_l1_cnode_cap, ROOTCN_SLOT_ARGCN, &si->cspace_l2_cnode_argcn);
|
||||
@ -522,10 +537,24 @@ errval_t spawn_load_argv(int argc, char *argv[], struct spawninfo *si,
|
||||
.cnode = si->cspace_l2_cnode_argcn,
|
||||
.slot = 0
|
||||
};
|
||||
// char buf[256];
|
||||
// debug_print_cap_at_capref(buf, 256, cap_io);
|
||||
// debug_printf(buf);
|
||||
// printf("\n");
|
||||
// debug_printf("offset=%x\n", arg0_base - IMX8X_START_DEV_RANGE);
|
||||
err = cap_retype(arg0_cap, cap_io, (arg0_base - IMX8X_START_DEV_RANGE), ObjType_DevFrame, arg0_size, 1);
|
||||
if (err_is_fail(err)) return err_push(err, LIB_ERR_CAP_RETYPE);
|
||||
}
|
||||
|
||||
if (arg1_base != 0) {
|
||||
struct capref arg1_cap = {
|
||||
.cnode = si->cspace_l2_cnode_argcn,
|
||||
.slot = 1
|
||||
};
|
||||
err = cap_retype(arg1_cap, cap_io, (arg1_base - IMX8X_START_DEV_RANGE), ObjType_DevFrame, arg1_size, 1);
|
||||
if (err_is_fail(err)) return err_push(err, LIB_ERR_CAP_RETYPE);
|
||||
}
|
||||
|
||||
// - Setup the child's vspace
|
||||
// afeer: create level 0 page table
|
||||
// the l0 page table is in the first slot (PAGECN_SLOT_VROOT) of the pagecn cnode.
|
||||
|
||||
@ -154,6 +154,14 @@ bsp_main(int argc, char *argv[]) {
|
||||
DEBUG_ERR(err, "when spawning block_driver_server");
|
||||
}
|
||||
|
||||
//spawn shell
|
||||
struct spawninfo shelly_si;
|
||||
domainid_t shelly_pid;
|
||||
err = spawn_load_by_name("shelly", &shelly_si, &shelly_pid);
|
||||
if (err_is_fail(err)) {
|
||||
DEBUG_ERR(err, "when spawning shelly");
|
||||
}
|
||||
|
||||
// Spawn enet driver
|
||||
struct spawninfo enet_si;
|
||||
domainid_t enet_pid;
|
||||
@ -327,14 +335,6 @@ app_main(int argc, char *argv[]) {
|
||||
// Grading
|
||||
grading_test_late();
|
||||
|
||||
//spawn shell
|
||||
struct spawninfo shelly_si;
|
||||
domainid_t shelly_pid;
|
||||
err = spawn_load_by_name("shelly", &shelly_si, &shelly_pid);
|
||||
if (err_is_fail(err)) {
|
||||
DEBUG_ERR(err, "when spawning shelly");
|
||||
}
|
||||
|
||||
debug_printf("Message handler loop\n");
|
||||
// Hang around
|
||||
struct waitset *default_ws = get_default_waitset();
|
||||
|
||||
@ -13,6 +13,7 @@
|
||||
[ build application
|
||||
{
|
||||
target = "shelly",
|
||||
cFiles = [ "shelly.c" ]
|
||||
cFiles = [ "shelly.c" ],
|
||||
addLibraries = [ "lpuart", "gic_dist" ]
|
||||
}
|
||||
]
|
||||
|
||||
@ -6,9 +6,282 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <drivers/lpuart.h>
|
||||
#include <drivers/gic_dist.h>
|
||||
#include <maps/imx8x_map.h>
|
||||
#include <maps/qemu_map.h>
|
||||
#include <aos/aos.h>
|
||||
#include <aos/inthandler.h>
|
||||
#include <aos/ump_binding.h>
|
||||
#include <aos/ump_chan.h>
|
||||
#include <aos/shelly_client.h>
|
||||
#include <aos/aos_rpc.h>
|
||||
|
||||
#include "shelly.h"
|
||||
|
||||
//state that is shared for all clients
|
||||
static struct shelly_st_global * global_state;
|
||||
|
||||
#include "shelly_cmd.c"
|
||||
|
||||
bool is_newline(char c) {
|
||||
return c == ASCII_NL || c == ASCII_EOF || c == ASCII_CR;
|
||||
}
|
||||
|
||||
//prints a null terminated string
|
||||
errval_t shelly_write_str(char * str) {
|
||||
errval_t err;
|
||||
for (size_t i = 0; str[i] != '\0'; ++i) {
|
||||
err = lpuart_putchar(global_state->uart_s, str[i]);
|
||||
if (err_is_fail(err)) return err_push(err, SHELLY_ERR_WRITE);
|
||||
}
|
||||
err = lpuart_putchar(global_state->uart_s, '\0');
|
||||
if (err_is_fail(err)) return err_push(err, SHELLY_ERR_WRITE);
|
||||
return SYS_ERR_OK;
|
||||
}
|
||||
|
||||
void shelly_reset_buffer(void) {
|
||||
global_state->buffer_i = 0;
|
||||
memset(global_state->buf, 0, SHELLY_BUF_SIZE);
|
||||
}
|
||||
|
||||
errval_t shelly_buffer_append(char c) {
|
||||
global_state->buf[global_state->buffer_i] = c;
|
||||
global_state->buffer_i += 1;
|
||||
|
||||
if (global_state->buffer_i == SHELLY_BUF_SIZE) {
|
||||
shelly_reset_buffer();
|
||||
return SHELLY_ERR_BUFFER_OVERFLOW;
|
||||
}
|
||||
|
||||
return SYS_ERR_OK;
|
||||
}
|
||||
|
||||
__attribute__((__used__))
|
||||
static void handle_lpuart_interrupt(void * arg) {
|
||||
errval_t err;
|
||||
assert(global_state);
|
||||
|
||||
char input_char;
|
||||
while (true) {
|
||||
err = lpuart_getchar(global_state->uart_s, &input_char);
|
||||
if (err == LPUART_ERR_NO_DATA) {
|
||||
break;
|
||||
} else if (err_is_fail(err)) {
|
||||
USER_PANIC_ERR(err, "while trying to get character");
|
||||
}
|
||||
|
||||
err = lpuart_putchar(global_state->uart_s, input_char);
|
||||
if (err_is_fail(err)) USER_PANIC_ERR(err, "while trying to put character");
|
||||
|
||||
if (is_newline(input_char)) {
|
||||
err = lpuart_putchar(global_state->uart_s, ASCII_CR);
|
||||
if (err_is_fail(err)) USER_PANIC_ERR(err, "while trying to put character");
|
||||
|
||||
global_state->buf[global_state->buffer_i] = '\0';
|
||||
global_state->buffer_i += 1;
|
||||
|
||||
err = shelly_write_str("\n\r");
|
||||
if (err_is_fail(err)) USER_PANIC_ERR(err, "while trying to write string");
|
||||
|
||||
err = handle_shelly_cmd(global_state->buf, global_state->buffer_i);
|
||||
if (err_is_fail(err)) DEBUG_ERR(err, "while running command");
|
||||
|
||||
shelly_reset_buffer();
|
||||
|
||||
err = shelly_write_str("\n\ryou@windows me > ");
|
||||
if (err_is_fail(err)) USER_PANIC_ERR(err, "while trying to write string");
|
||||
} else {
|
||||
err = shelly_buffer_append(input_char);
|
||||
if (err_is_fail(err)) {
|
||||
err = shelly_write_str("shelly buffer full! resetting...\n\r");
|
||||
if (err_is_fail(err)) USER_PANIC_ERR(err, "while trying to write string");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_send_completed(void *arg, struct ump_send_queue_entry *entry) {
|
||||
free((void *)entry->header);
|
||||
free((void *)entry->payload);
|
||||
free(entry);
|
||||
}
|
||||
|
||||
static void send_response(struct shelly_st_local * local_state, errval_t err, size_t payload_size, void *payload) {
|
||||
assert(local_state);
|
||||
|
||||
// SHELLY_DEBUG("[send_response]\n");
|
||||
struct shelly_header * header = malloc(sizeof(struct shelly_header));
|
||||
assert(header);
|
||||
header->type = SHELLY_MSG_RESPONSE;
|
||||
|
||||
struct ump_send_queue_entry *entry = malloc(sizeof(struct ump_send_queue_entry));
|
||||
if (entry == NULL) USER_PANIC("Ran out of memory");
|
||||
|
||||
ump_send(
|
||||
local_state->send_chan,
|
||||
entry,
|
||||
sizeof(struct shelly_header),
|
||||
header,
|
||||
payload_size,
|
||||
payload,
|
||||
handle_send_completed,
|
||||
NULL
|
||||
);
|
||||
// SHELLY_DEBUG("[send_response] done\n");
|
||||
}
|
||||
|
||||
static void handle_client_request(void *arg, size_t header_size, void *header_buf, size_t payload_size);
|
||||
static void handle_payload(void *arg, size_t payload_size, void *payload) {
|
||||
struct shelly_st_local * local_state = arg;
|
||||
assert(local_state);
|
||||
assert(global_state);
|
||||
|
||||
// listen for the next request on this channel
|
||||
ump_recv_header(local_state->recv_chan, handle_client_request, local_state);
|
||||
}
|
||||
|
||||
static void handle_client_request(void *arg, size_t header_size, void *header_buf, size_t payload_size) {
|
||||
errval_t err;
|
||||
struct shelly_st_local * local_state = arg;
|
||||
assert(local_state);
|
||||
assert(global_state);
|
||||
|
||||
// SHELLY_DEBUG("[handle_client_request] client_id=%d\n", local_state->client_id);
|
||||
|
||||
struct shelly_header * header = (struct shelly_header *) header_buf;
|
||||
|
||||
if (header->type == SHELLY_MSG_GETCHAR) {
|
||||
char input_char = '\0';
|
||||
err = lpuart_getchar(global_state->uart_s, &input_char);
|
||||
if (err_is_fail(err)) USER_PANIC_ERR(err, "while trying to get character");
|
||||
} else if (header->type == SHELLY_MSG_PUTCHAR) {
|
||||
err = lpuart_putchar(global_state->uart_s, header->character);
|
||||
if (err_is_fail(err)) USER_PANIC_ERR(err, "while trying to put character");
|
||||
if (is_newline(header->character)) {
|
||||
err = lpuart_putchar(global_state->uart_s, ASCII_CR);
|
||||
if (err_is_fail(err)) USER_PANIC_ERR(err, "while trying to put character");
|
||||
}
|
||||
}
|
||||
|
||||
send_response(local_state, SYS_ERR_OK, 0, NULL);
|
||||
|
||||
// skip payload
|
||||
ump_recv_payload(local_state->recv_chan, NULL, handle_payload, local_state);
|
||||
}
|
||||
|
||||
__attribute__((__used__))
|
||||
static errval_t connection_callback(void *arg, struct capref cap) {
|
||||
errval_t err;
|
||||
|
||||
SHELLY_DEBUG("incoming connection\n");
|
||||
assert(global_state);
|
||||
|
||||
//create a new local state
|
||||
struct shelly_st_local * local_state = calloc(sizeof(struct shelly_st_local), 1);
|
||||
assert(local_state);
|
||||
|
||||
local_state->client_id = global_state->num_clients;
|
||||
global_state->num_clients += 1;
|
||||
|
||||
// we can run the server on the default waitset since we are dispatching on
|
||||
// it for listening to connections anyways
|
||||
err = ump_chan_init(UMP_ROLE_SERVER, &local_state->send_chan, &local_state->recv_chan, sizeof(struct shelly_header), cap, global_state->ws);
|
||||
if (err_is_fail(err)) return err;
|
||||
// SHELLY_DEBUG("[connection_callback] local_state=%p\n", local_state);
|
||||
|
||||
ump_recv_header(local_state->recv_chan, handle_client_request, local_state);
|
||||
|
||||
SHELLY_DEBUG("connection ready to receive requests\n");
|
||||
|
||||
return SYS_ERR_OK;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
debug_printf("welcome to shelly!\n");
|
||||
errval_t err;
|
||||
|
||||
global_state = calloc(sizeof(struct shelly_st_global), 1);
|
||||
assert(global_state);
|
||||
|
||||
global_state->num_clients = 0;
|
||||
global_state->buffer_i = 0;
|
||||
global_state->ws = get_default_waitset();
|
||||
|
||||
//afeer: map lpuart registers
|
||||
struct capref cap_arg0 = {
|
||||
.cnode = cnode_arg,
|
||||
.slot = 0
|
||||
};
|
||||
err = paging_map_frame_attr(get_current_paging_state(),
|
||||
(void **) &global_state->lpuart_base, IMX8X_UART_SIZE,
|
||||
cap_arg0, VREGION_FLAGS_READ_WRITE_NOCACHE);
|
||||
if (err_is_fail(err)) USER_PANIC_ERR(err, "while mapping lpuart registers");
|
||||
|
||||
SHELLY_DEBUG("mapped lpuart\n");
|
||||
|
||||
//afeer: map gic registers
|
||||
struct capref cap_arg1 = {
|
||||
.cnode = cnode_arg,
|
||||
.slot = 1
|
||||
};
|
||||
err = paging_map_frame_attr(get_current_paging_state(),
|
||||
(void**) &global_state->gic_base, IMX8X_GIC_DIST_SIZE,
|
||||
cap_arg1, VREGION_FLAGS_READ_WRITE_NOCACHE);
|
||||
if (err_is_fail(err)) USER_PANIC_ERR(err, "while mapping gic registers");
|
||||
|
||||
SHELLY_DEBUG("mapped gic\n");
|
||||
|
||||
//afeer: init gic driver
|
||||
err = gic_dist_init(&global_state->gic_s, global_state->gic_base);
|
||||
if (err_is_fail(err)) USER_PANIC_ERR(err, "couln't init gic_dist interrupts");
|
||||
|
||||
SHELLY_DEBUG("initialized gic driver\n");
|
||||
|
||||
//afeer: init lpuart driver
|
||||
err = lpuart_init(&global_state->uart_s, global_state->lpuart_base);
|
||||
if (err_is_fail(err)) {
|
||||
USER_PANIC_ERR(err, "couldn't init lpuart");
|
||||
}
|
||||
|
||||
SHELLY_DEBUG("initialized lpuart driver\n");
|
||||
|
||||
struct capref inter_cap;
|
||||
err = inthandler_alloc_dest_irq_cap(IMX8X_UART3_INT, &inter_cap);
|
||||
if (err_is_fail(err)) USER_PANIC_ERR(err, "couln't alloc dest cap");
|
||||
|
||||
SHELLY_DEBUG("created interrupt cap\n");
|
||||
|
||||
err = inthandler_setup(inter_cap, global_state->ws, MKCLOSURE(handle_lpuart_interrupt, NULL));
|
||||
if (err_is_fail(err)) USER_PANIC_ERR(err, "couln't setup interrupt handler");
|
||||
|
||||
SHELLY_DEBUG("setup interrupt handler\n");
|
||||
|
||||
err = gic_dist_enable_interrupt(global_state->gic_s, IMX8X_UART3_INT, 0b11111111, 0);
|
||||
if (err_is_fail(err)) USER_PANIC_ERR(err, "couln't enable gic interrupts");
|
||||
|
||||
SHELLY_DEBUG("enabled gic interrupt\n");
|
||||
|
||||
err = lpuart_enable_interrupt(global_state->uart_s);
|
||||
if (err_is_fail(err)) USER_PANIC_ERR(err, "couln't enable lpuart interrupts");
|
||||
|
||||
SHELLY_DEBUG("enabled lpuart interrupt\n");
|
||||
|
||||
struct ump_binding_server server;
|
||||
err = ump_binding_register(&server, UMP_SERVER_SHELLY, connection_callback, NULL);
|
||||
if (err_is_fail(err)) USER_PANIC_ERR(err, "Failed to register UMP server");
|
||||
|
||||
SHELLY_DEBUG("registered as shelly server\n");
|
||||
|
||||
err = shelly_write_str("Welcome to Shelly(TM)(TM)!\n\r");
|
||||
if (err_is_fail(err)) USER_PANIC_ERR(err, "while trying to write welcome message");
|
||||
|
||||
while (true) {
|
||||
err = event_dispatch(global_state->ws);
|
||||
if (err_is_fail(err)) {
|
||||
DEBUG_ERR(err, "in event_dispatch");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
58
usr/shelly/shelly.h
Normal file
58
usr/shelly/shelly.h
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2019, ETH Zurich.
|
||||
* 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, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
|
||||
*/
|
||||
|
||||
#ifndef SHELLY_H_
|
||||
#define SHELLY_H_
|
||||
|
||||
#define SHELLY_DEBUG_ON 1
|
||||
|
||||
#if defined(SHELLY_DEBUG_ON)
|
||||
#define SHELLY_DEBUG(x...) debug_printf("[SHELLY_DEBUG] " x);
|
||||
#else
|
||||
#define SHELLY_DEBUG(x, ...) ((void)0)
|
||||
#endif
|
||||
|
||||
#include <drivers/lpuart.h>
|
||||
#include <drivers/gic_dist.h>
|
||||
#include <aos/ump_chan.h>
|
||||
|
||||
#define ASCII_NL 10 // < new line
|
||||
#define ASCII_CR 13 // < carriage return
|
||||
#define ASCII_EOF 4 // < end of file
|
||||
#define ASCII_EOT 3 // < end of text
|
||||
|
||||
#define SHELLY_BUF_SIZE 2048
|
||||
//state that is shared for all clients
|
||||
struct shelly_st_global {
|
||||
struct waitset * ws;
|
||||
|
||||
void * lpuart_base; // < virtual address of the lpuart device registers
|
||||
void * gic_base; // < virtual address of the gic device registers
|
||||
|
||||
struct lpuart_s * uart_s; // < state of the uart driver
|
||||
struct gic_dist_s * gic_s; // < state of the gic driver
|
||||
|
||||
u_int32_t num_clients;
|
||||
char buf[SHELLY_BUF_SIZE];
|
||||
size_t buffer_i;
|
||||
};
|
||||
|
||||
//state that different for each client
|
||||
struct shelly_st_local {
|
||||
uint32_t client_id;
|
||||
struct ump_recv_chan * recv_chan;
|
||||
struct ump_send_chan * send_chan;
|
||||
};
|
||||
|
||||
bool is_newline(char c);
|
||||
errval_t shelly_write_str(char * str);
|
||||
void shelly_reset_buffer(void);
|
||||
errval_t shelly_buffer_append(char c);
|
||||
|
||||
#endif // ndef SHELLY_H_
|
||||
109
usr/shelly/shelly_cmd.c
Normal file
109
usr/shelly/shelly_cmd.c
Normal file
@ -0,0 +1,109 @@
|
||||
#include <stdlib.h>
|
||||
#include "shelly.h"
|
||||
|
||||
__attribute__((__used__))
|
||||
static void parse_cmd_line(char * line, int * argc, char ** argv) {
|
||||
*argc = 0;
|
||||
char *token = strtok(line, " ");
|
||||
while (token != NULL) {
|
||||
argv[*argc] = token;
|
||||
token = strtok(NULL, " ");
|
||||
*argc += 1;
|
||||
}
|
||||
}
|
||||
|
||||
static errval_t shelly_cmd_help(char * line) {
|
||||
errval_t err;
|
||||
err = shelly_write_str("commands implemented:\n\r");
|
||||
if (err_is_fail(err)) return err;
|
||||
err = shelly_write_str("- echo [string]\n\r");
|
||||
if (err_is_fail(err)) return err;
|
||||
err = shelly_write_str("- run [core] [binary]\n\r");
|
||||
if (err_is_fail(err)) return err;
|
||||
err = shelly_write_str(" run a module from bootinfo\n\r");
|
||||
if (err_is_fail(err)) return err;
|
||||
err = shelly_write_str("- ps\n\r");
|
||||
if (err_is_fail(err)) return err;
|
||||
err = shelly_write_str("- help\n\r");
|
||||
if (err_is_fail(err)) return err;
|
||||
|
||||
return SYS_ERR_OK;
|
||||
}
|
||||
|
||||
static errval_t shelly_cmd_echo(char * line) {
|
||||
errval_t err;
|
||||
err = shelly_write_str(line);
|
||||
if (err_is_fail(err)) return err;
|
||||
return SYS_ERR_OK;
|
||||
}
|
||||
|
||||
static errval_t shelly_cmd_run(char * line) {
|
||||
errval_t err;
|
||||
|
||||
SHELLY_DEBUG("[shelly_cmd_run] line=%s\n", line);
|
||||
|
||||
char * module_line;
|
||||
long core_id = strtol(line, &module_line, 10);
|
||||
module_line += 1;
|
||||
// start process
|
||||
domainid_t pid;
|
||||
struct aos_rpc * rpc = aos_rpc_get_process_channel();
|
||||
err = aos_rpc_process_spawn(rpc, module_line, core_id, &pid);
|
||||
if (err == SPAWN_ERR_FIND_MODULE) {
|
||||
err = shelly_write_str("[run] couldn't find module:\n\r");
|
||||
if (err_is_fail(err)) return err;
|
||||
err = shelly_write_str(line);
|
||||
if (err_is_fail(err)) return err;
|
||||
err = shelly_write_str("\n\r");
|
||||
if (err_is_fail(err)) return err;
|
||||
} else if (err_is_fail(err)) return err_push(err, SHELLY_ERR_SPAWN_RPC);
|
||||
|
||||
return SYS_ERR_OK;
|
||||
}
|
||||
|
||||
static errval_t shelly_cmd_ps(char * line) {
|
||||
errval_t err;
|
||||
|
||||
domainid_t *pids;
|
||||
size_t pid_count;
|
||||
struct aos_rpc * rpc = aos_rpc_get_process_channel();
|
||||
err = aos_rpc_process_get_all_pids(rpc, &pids, &pid_count);
|
||||
if (err_is_fail(err)) return err_push(err, SHELLY_ERR_PS_RPC);
|
||||
shelly_write_str("PIDs:\n\r");
|
||||
char buf[256];
|
||||
for(size_t i = 0; i < pid_count; ++i) {
|
||||
snprintf(buf, 256, " %lu\n\r", pids[i]);
|
||||
shelly_write_str(buf);
|
||||
}
|
||||
return SYS_ERR_OK;
|
||||
}
|
||||
|
||||
static errval_t handle_shelly_cmd(char* line, size_t len) {
|
||||
// SHELLY_DEBUG("[handle_shelly_cmd] len=%d\n", len);
|
||||
if (len <= 1) {
|
||||
return SYS_ERR_OK;
|
||||
}
|
||||
|
||||
char * cmd = strtok(line, " ");
|
||||
|
||||
char * remaining_line = line + strlen(cmd) + 1;
|
||||
|
||||
// debug_printf("remaining_line = %s\n", remaining_line);
|
||||
|
||||
if (strcmp(cmd, "echo") == 0) {
|
||||
return shelly_cmd_echo(remaining_line);
|
||||
} else if (strcmp(cmd, "run") == 0) {
|
||||
return shelly_cmd_run(remaining_line);
|
||||
} else if (strcmp(cmd, "ps") == 0) {
|
||||
return shelly_cmd_ps(remaining_line);
|
||||
} else if (strcmp(cmd, "help") == 0) {
|
||||
return shelly_cmd_help(remaining_line);
|
||||
} else {
|
||||
char buf[256];
|
||||
snprintf(buf, 256, "unknown command \"%s\"\n\r", cmd);
|
||||
shelly_write_str(buf);
|
||||
}
|
||||
|
||||
return SYS_ERR_OK;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user