diff --git a/errors/errno.fugu b/errors/errno.fugu index 72e926d..f3732b8 100755 --- a/errors/errno.fugu +++ b/errors/errno.fugu @@ -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", +}; diff --git a/include/aos/shelly_client.h b/include/aos/shelly_client.h new file mode 100644 index 0000000..4c382b0 --- /dev/null +++ b/include/aos/shelly_client.h @@ -0,0 +1,41 @@ +#ifndef _SHELLY_CLIENT_H_ +#define _SHELLY_CLIENT_H_ + +#include + +// #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_ */ \ No newline at end of file diff --git a/include/aos/ump_binding.h b/include/aos/ump_binding.h index 283a7dc..bea9ad6 100644 --- a/include/aos/ump_binding.h +++ b/include/aos/ump_binding.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 }; diff --git a/include/spawn/spawn.h b/include/spawn/spawn.h index 8258421..6c9c51d 100644 --- a/include/spawn/spawn.h +++ b/include/spawn/spawn.h @@ -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; diff --git a/lib/aos/Hakefile b/lib/aos/Hakefile index 909e0ea..1a2d3f8 100644 --- a/lib/aos/Hakefile +++ b/lib/aos/Hakefile @@ -53,6 +53,7 @@ "sys_debug.c", "syscalls.c", "systime.c", + "shelly_client.c", "thread_once.c", "thread_sync.c", "threads.c", diff --git a/lib/aos/aos_rpc.c b/lib/aos/aos_rpc.c index 1ae2361..436fa26 100644 --- a/lib/aos/aos_rpc.c +++ b/lib/aos/aos_rpc.c @@ -17,6 +17,7 @@ #include #include +#include static void noop_callback(void *arg) { } @@ -168,14 +169,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; } @@ -186,11 +189,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; } diff --git a/lib/aos/init.c b/lib/aos/init.c index 236180d..d3746bc 100644 --- a/lib/aos/init.c +++ b/lib/aos/init.c @@ -30,6 +30,8 @@ #include "init.h" #include +#include + /// 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; diff --git a/lib/aos/shelly_client.c b/lib/aos/shelly_client.c new file mode 100644 index 0000000..b3a1c57 --- /dev/null +++ b/lib/aos/shelly_client.c @@ -0,0 +1,132 @@ +#include +#include +#include +#include +#include +#include + +// 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; +} diff --git a/lib/aos/ump_chan.c b/lib/aos/ump_chan.c index 9668757..f5ed50e 100644 --- a/lib/aos/ump_chan.c +++ b/lib/aos/ump_chan.c @@ -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(); } /** diff --git a/lib/spawn/rpc_server.c b/lib/spawn/rpc_server.c index 5cfd525..725c80c 100644 --- a/lib/spawn/rpc_server.c +++ b/lib/spawn/rpc_server.c @@ -6,6 +6,7 @@ #include #include #include +#include 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, diff --git a/lib/spawn/spawn.c b/lib/spawn/spawn.c index 22b1855..eff36e5 100644 --- a/lib/spawn/spawn.c +++ b/lib/spawn/spawn.c @@ -15,6 +15,7 @@ #include #include +#include extern struct bootinfo *bi; extern coreid_t my_core_id; @@ -517,6 +518,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); @@ -544,6 +548,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); @@ -555,15 +562,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); @@ -572,10 +587,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. diff --git a/usr/init/main.c b/usr/init/main.c index 8208fb0..56a4454 100644 --- a/usr/init/main.c +++ b/usr/init/main.c @@ -264,6 +264,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; @@ -461,14 +469,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(); diff --git a/usr/shelly/Hakefile b/usr/shelly/Hakefile index 87f3d05..773fa4b 100644 --- a/usr/shelly/Hakefile +++ b/usr/shelly/Hakefile @@ -13,6 +13,7 @@ [ build application { target = "shelly", - cFiles = [ "shelly.c" ] + cFiles = [ "shelly.c" ], + addLibraries = [ "lpuart", "gic_dist", "fs" ] } ] diff --git a/usr/shelly/shelly.c b/usr/shelly/shelly.c index 1921974..cce9f67 100644 --- a/usr/shelly/shelly.c +++ b/usr/shelly/shelly.c @@ -6,9 +6,288 @@ #include #include +#include +#include +#include +#include #include +#include +#include +#include +#include +#include +#include + +#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 = filesystem_init(); + // if (err_is_fail(err)) DEBUG_ERR(err, "Failed to init filesystem"); + + // SHELLY_DEBUG("initialized filesystem\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(); + } + } } \ No newline at end of file diff --git a/usr/shelly/shelly.h b/usr/shelly/shelly.h new file mode 100644 index 0000000..a43e3d8 --- /dev/null +++ b/usr/shelly/shelly.h @@ -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 +#include +#include + +#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_ diff --git a/usr/shelly/shelly_cmd.c b/usr/shelly/shelly_cmd.c new file mode 100644 index 0000000..a27c264 --- /dev/null +++ b/usr/shelly/shelly_cmd.c @@ -0,0 +1,160 @@ +#include +#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("- ls\n\r"); + if (err_is_fail(err)) return err; + err = shelly_write_str("- cat\n\r"); + if (err_is_fail(err)) return err; + err = shelly_write_str(" ...meow\n\r"); + if (err_is_fail(err)) return err; + err = shelly_write_str("- mkdir\n\r"); + if (err_is_fail(err)) return err; + err = shelly_write_str("- rmdir\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_ls(char * line) { + // errval_t err; + + return SYS_ERR_OK; +} + +static errval_t shelly_cmd_cat(char * line) { + errval_t err; + + err = shelly_write_str(" /\\_/\\ ___\n\r"); + if (err_is_fail(err)) return err; + err = shelly_write_str(" = o_o =_______ \\ \\\n\r"); + if (err_is_fail(err)) return err; + err = shelly_write_str(" __^ __( \\.__) )\n\r"); + if (err_is_fail(err)) return err; + err = shelly_write_str("(@)<_____>__(_____)____/\n\r"); + if (err_is_fail(err)) return err; + + return SYS_ERR_OK; +} + +static errval_t shelly_cmd_mkdir(char * line) { + // errval_t err; + + return SYS_ERR_OK; +} + +static errval_t shelly_cmd_rmdir(char * line) { + // errval_t 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 if (strcmp(cmd, "ls") == 0) { + return shelly_cmd_ls(remaining_line); + } else if (strcmp(cmd, "cat") == 0) { + return shelly_cmd_cat(remaining_line); + } else if (strcmp(cmd, "mkdir") == 0) { + return shelly_cmd_mkdir(remaining_line); + } else if (strcmp(cmd, "rmdir") == 0) { + return shelly_cmd_rmdir(remaining_line); + } else { + char buf[256]; + snprintf(buf, 256, "unknown command \"%s\"\n\r", cmd); + shelly_write_str(buf); + } + + return SYS_ERR_OK; +} +