diff --git a/include/aos/ump_binding.h b/include/aos/ump_binding.h index 6e4029a..f19f823 100644 --- a/include/aos/ump_binding.h +++ b/include/aos/ump_binding.h @@ -8,6 +8,7 @@ enum ump_server_id { UMP_SERVER_ECHO, UMP_SERVER_NET, + UMP_SERVER_SHELLY, UMP_SERVER_COUNT // How many servers exist }; 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 12ac19e..8481355 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) { } @@ -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; } diff --git a/lib/aos/init.c b/lib/aos/init.c index 236180d..3092cf8 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,28 +105,45 @@ 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(); - if (rpc == NULL) { - debug_printf("[aos_terminal_write] RPC NOT YET INITIALIZED: %.*s\n", len, buf); - USER_PANIC("Make sure to initialize aos_rpc before barrelfish_libc_glue_init is called."); + for (int i = 0; i < len; ++i) { + err = aos_rpc_serial_putchar(rpc, buf[i]); + if (err_is_fail(err)) return err; } - return aos_rpc_serial_write(rpc, buf, len); + return SYS_ERR_OK; + // if (rpc == NULL) { + // debug_printf("[aos_terminal_write] RPC NOT YET INITIALIZED: %.*s\n", len, buf); + // USER_PANIC("Make sure to initialize aos_rpc before barrelfish_libc_glue_init is called."); + // } + + // return aos_rpc_serial_write(rpc, buf, len); } static size_t aos_terminal_read(char *buf, size_t len) { + errval_t err; if(len == 0) return 0; struct aos_rpc *rpc = aos_rpc_get_serial_channel(); - if (rpc == NULL) { - debug_printf("[aos_terminal_read] RPC NOT YET INITIALIZED: %.*s\n", len, buf); - USER_PANIC("Make sure to initialize aos_rpc before barrelfish_libc_glue_init is called."); + for (int i = 0; i < len; ++i) { + char in; + err = aos_rpc_serial_getchar(rpc, &in); + if (err_is_fail(err)) return err; + buf[i] = in; } - return aos_rpc_serial_read(rpc, buf, len); + return SYS_ERR_OK; + + // if (rpc == NULL) { + // debug_printf("[aos_terminal_read] RPC NOT YET INITIALIZED: %.*s\n", len, buf); + // USER_PANIC("Make sure to initialize aos_rpc before barrelfish_libc_glue_init is called."); + // } + + // return aos_rpc_serial_read(rpc, buf, len); } /* Set libc function pointers */ @@ -243,7 +262,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/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/usr/shelly/shelly.c b/usr/shelly/shelly.c index e97872f..3c13ef2 100644 --- a/usr/shelly/shelly.c +++ b/usr/shelly/shelly.c @@ -12,29 +12,125 @@ #include #include #include + +#include +#include +#include + #include "shelly.h" +//state that is shared for all clients +static struct shelly_st_global * global_state; + __attribute__((__used__)) static void shelly_interrupt_handler(void * arg) { errval_t err; - struct shelly_st * shelly_s = (struct shelly_st *) arg; - // SHELLY_DEBUG("[shelly_interrupt_handler]\n"); + SHELLY_DEBUG("[shelly_interrupt_handler]\n"); + assert(global_state); char input_char; - err = lpuart_getchar(shelly_s->uart_s, &input_char); + err = lpuart_getchar(global_state->uart_s, &input_char); if (err_is_fail(err)) USER_PANIC_ERR(err, "while trying to get character"); - err = lpuart_putchar(shelly_s->uart_s, input_char); + err = lpuart_putchar(global_state->uart_s, input_char); if (err_is_fail(err)) USER_PANIC_ERR(err, "while trying to put character"); } +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); + + 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 + ); +} + +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); + // SHELLY_DEBUG("[handle_payload] client_id=%d\n", local_state->client_id); + // 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); + + 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"); + } + + send_response(local_state, SYS_ERR_OK, 0, NULL); + + // skip payload + ump_recv_payload(local_state->recv_chan, NULL, handle_payload, local_state); +} + +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, get_default_waitset()); + 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[]) { errval_t err; debug_printf("welcome to shelly!\n"); - struct shelly_st * shelly_s = calloc(sizeof(struct shelly_st), 1); - assert(shelly_s); + global_state = calloc(sizeof(struct shelly_st_global), 1); + assert(global_state); //afeer: map lpuart registers struct capref cap_arg0 = { @@ -42,7 +138,7 @@ int main(int argc, char *argv[]) .slot = 0 }; err = paging_map_frame_attr(get_current_paging_state(), - (void **) &shelly_s->lpuart_base, IMX8X_UART_SIZE, + (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"); @@ -54,20 +150,20 @@ int main(int argc, char *argv[]) .slot = 1 }; err = paging_map_frame_attr(get_current_paging_state(), - (void**) &shelly_s->gic_base, IMX8X_GIC_DIST_SIZE, + (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(&shelly_s->gic_s, shelly_s->gic_base); + 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(&shelly_s->uart_s, shelly_s->lpuart_base); + err = lpuart_init(&global_state->uart_s, global_state->lpuart_base); if (err_is_fail(err)) { USER_PANIC_ERR(err, "couldn't init lpuart"); } @@ -84,21 +180,26 @@ int main(int argc, char *argv[]) debug_printf(buf); struct waitset * ws = get_default_waitset(); - err = inthandler_setup(inter_cap, ws, MKCLOSURE(shelly_interrupt_handler, (void *) shelly_s)); + err = inthandler_setup(inter_cap, ws, MKCLOSURE(shelly_interrupt_handler, 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(shelly_s->gic_s, IMX8X_UART3_INT, 0b11111111, 0); + 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(shelly_s->uart_s); + 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"); + SHELLY_DEBUG("registering as shelly server\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"); + while (true) { err = event_dispatch(ws); if (err_is_fail(err)) { diff --git a/usr/shelly/shelly.h b/usr/shelly/shelly.h index 33497fa..11c3440 100644 --- a/usr/shelly/shelly.h +++ b/usr/shelly/shelly.h @@ -10,7 +10,7 @@ #ifndef SHELLY_H_ #define SHELLY_H_ -#define SHELLY_DEBUG_ON 1 +// #define SHELLY_DEBUG_ON 1 #if defined(SHELLY_DEBUG_ON) #define SHELLY_DEBUG(x...) debug_printf("[SHELLY_DEBUG] " x); @@ -20,13 +20,26 @@ #include #include +#include -struct shelly_st { - void * lpuart_base; // < virtual address of the lpuart device registers - void * gic_base; // < virtual address of the gic device registers +#define SHELLY_BUF_SIZE 2048 +//state that is shared for all clients +struct shelly_st_global { + 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 + 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]; +}; + +//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; }; #endif // ndef SHELLY_H_