diff --git a/soc/runtime/Makefile b/soc/runtime/Makefile index 1b95bd727..a27e651f8 100644 --- a/soc/runtime/Makefile +++ b/soc/runtime/Makefile @@ -1,6 +1,6 @@ include $(MSCDIR)/software/common.mak -OBJECTS := isr.o flash_storage.o clock.o elf_loader.o services.o session.o log.o test_mode.o kloader.o mailbox.o ksupport_data.o main.o +OBJECTS := isr.o flash_storage.o clock.o elf_loader.o services.o session.o log.o test_mode.o kloader.o mailbox.o ksupport_data.o kserver.o main.o OBJECTS_KSUPPORT := ksupport.o exception_jmp.o exceptions.o mailbox.o bridge.o rtio.o dds.o CFLAGS += -Ilwip/src/include -Iliblwip diff --git a/soc/runtime/kserver.c b/soc/runtime/kserver.c new file mode 100644 index 000000000..4d75da8bc --- /dev/null +++ b/soc/runtime/kserver.c @@ -0,0 +1,215 @@ +#include + +#ifdef CSR_ETHMAC_BASE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "session.h" +#include "kserver.h" + +struct kserver_connstate { + int magic_recognized; + struct pbuf *rp; + int rp_offset; +}; + +static struct kserver_connstate *cs_new(void) +{ + struct kserver_connstate *cs; + + cs = (struct kserver_connstate *)mem_malloc(sizeof(struct kserver_connstate)); + if(!cs) + return NULL; + cs->magic_recognized = 0; + cs->rp = NULL; + cs->rp_offset = 0; + return cs; +} + +static void cs_free(struct kserver_connstate *cs) +{ + if(cs->rp) + pbuf_free(cs->rp); + mem_free(cs); +} + +static const char kserver_magic[] = "ARTIQ coredev\n"; + +static int magic_ok(struct kserver_connstate *cs) +{ + return cs->magic_recognized >= 14; +} + +static struct kserver_connstate *active_cs; +static struct tcp_pcb *active_pcb; + +static void kserver_close(struct kserver_connstate *cs, struct tcp_pcb *pcb) +{ + if(cs == active_cs) { + session_end(); + active_cs = NULL; + active_pcb = NULL; + } + + /* lwip loves to call back with broken pointers. Prevent that. */ + tcp_arg(pcb, NULL); + tcp_recv(pcb, NULL); + tcp_sent(pcb, NULL); + tcp_err(pcb, NULL); + + cs_free(cs); + tcp_close(pcb); +} + +static err_t kserver_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) +{ + struct kserver_connstate *cs; + + cs = (struct kserver_connstate *)arg; + if(p) { + if(cs->rp) + pbuf_cat(cs->rp, p); + else { + cs->rp = p; + cs->rp_offset = 0; + } + } else + kserver_close(cs, pcb); + return ERR_OK; +} + +static err_t kserver_sent(void *arg, struct tcp_pcb *pcb, u16_t len) +{ + session_ack_mem(len); + return ERR_OK; +} + +static void tcp_pcb_service(void *arg, struct tcp_pcb *pcb) +{ + struct kserver_connstate *cs; + int remaining_in_pbuf; + char *rpp; + struct pbuf *next; + int r; + + cs = (struct kserver_connstate *)arg; + + while(cs->rp) { + remaining_in_pbuf = cs->rp->len - cs->rp_offset; + rpp = (char *)cs->rp->payload; + while(remaining_in_pbuf > 0) { + if(cs == active_cs) { + r = session_input(&rpp[cs->rp_offset], remaining_in_pbuf); + if(r > 0) { + tcp_recved(pcb, r); + cs->rp_offset += r; + remaining_in_pbuf -= r; + } else if(r == 0) + return; + else + kserver_close(cs, pcb); + } else { + if(rpp[cs->rp_offset] == kserver_magic[cs->magic_recognized]) { + cs->magic_recognized++; + if(magic_ok(cs)) { + if(active_cs) + kserver_close(active_cs, active_pcb); + session_start(); + active_cs = cs; + active_pcb = pcb; + tcp_sent(pcb, kserver_sent); + } + } else { + kserver_close(cs, pcb); + return; + } + remaining_in_pbuf--; + cs->rp_offset++; + tcp_recved(pcb, 1); + } + } + next = cs->rp->next; + if(cs->rp->tot_len != cs->rp->len) { + pbuf_ref(next); + pbuf_free(cs->rp); + cs->rp = next; + cs->rp_offset = 0; + } else { + pbuf_free(cs->rp); + cs->rp = NULL; + } + } +} + +static void kserver_err(void *arg, err_t err) +{ + struct kserver_connstate *cs; + + cs = (struct kserver_connstate *)arg; + cs_free(cs); +} + +static struct tcp_pcb *listen_pcb; + +static err_t kserver_accept(void *arg, struct tcp_pcb *newpcb, err_t err) +{ + struct kserver_connstate *cs; + + cs = cs_new(); + if(!cs) + return ERR_MEM; + tcp_accepted(listen_pcb); + tcp_arg(newpcb, cs); + tcp_recv(newpcb, kserver_recv); + tcp_err(newpcb, kserver_err); + return ERR_OK; +} + +void kserver_init(void) +{ + listen_pcb = tcp_new(); + tcp_bind(listen_pcb, IP_ADDR_ANY, 1381); + listen_pcb = tcp_listen(listen_pcb); + tcp_accept(listen_pcb, kserver_accept); +} + +extern struct tcp_pcb *tcp_active_pcbs; + +void kserver_service(void) +{ + struct tcp_pcb *pcb; + void *data; + int len, sndbuf; + + /* Assume all active TCP PCBs with a non-NULL arg are our connections. */ + pcb = tcp_active_pcbs; + while(pcb) { + if(pcb->callback_arg) + tcp_pcb_service(pcb->callback_arg, pcb); + pcb = pcb->next; + } + + if(active_cs) { + session_poll(&data, &len); + if(len > 0) { + sndbuf = tcp_sndbuf(active_pcb); + if(len > sndbuf) + len = sndbuf; + tcp_write(active_pcb, data, len, 0); + session_ack_data(len); + } + if(len < 0) + kserver_close(active_cs, active_pcb); + } +} + +#endif /* CSR_ETHMAC_BASE */ diff --git a/soc/runtime/kserver.h b/soc/runtime/kserver.h new file mode 100644 index 000000000..28eb79ecc --- /dev/null +++ b/soc/runtime/kserver.h @@ -0,0 +1,7 @@ +#ifndef __KSERVER_H +#define __KSERVER_H + +void kserver_init(void); +void kserver_service(void); + +#endif /* __KSERVER_H */ diff --git a/soc/runtime/main.c b/soc/runtime/main.c index 29a4fc378..f6facbdd0 100644 --- a/soc/runtime/main.c +++ b/soc/runtime/main.c @@ -21,12 +21,13 @@ #include #endif +#include "flash_storage.h" #include "clock.h" #include "test_mode.h" +#include "kserver.h" #include "session.h" #ifdef CSR_ETHMAC_BASE -unsigned char macadr[6] = {0x10, 0xe2, 0xd5, 0x00, 0x00, 0x00}; u32_t sys_now(void) { @@ -44,15 +45,69 @@ static void lwip_service(void) } } +unsigned char macadr[6]; + +static int hex2nib(int c) +{ + if((c >= '0') && (c <= '9')) + return c - '0'; + if((c >= 'a') && (c <= 'f')) + return c - 'a' + 10; + if((c >= 'A') && (c <= 'F')) + return c - 'A' + 10; + return -1; +} + +static void init_macadr(void) +{ + static const unsigned char default_macadr[6] = {0x10, 0xe2, 0xd5, 0x32, 0x50, 0x00}; + char b[32]; + char fs_macadr[6]; + int i, r, s; + + memcpy(macadr, default_macadr, 6); + r = fs_read("mac", b, sizeof(b) - 1, NULL); + if(r <= 0) + return; + b[r] = 0; + for(i=0;i<6;i++) { + r = hex2nib(b[3*i]); + s = hex2nib(b[3*i + 1]); + if((r < 0) || (s < 0)) + return; + fs_macadr[i] = (r << 4) | s; + } + for(i=0;i<5;i++) + if(b[3*i + 2] != ':') + return; + memcpy(macadr, fs_macadr, 6); +} + +static void fsip_or_default(struct ip4_addr *d, char *key, int i1, int i2, int i3, int i4) +{ + int r; + char cp[32]; + + IP4_ADDR(d, i1, i2, i3, i4); + + r = fs_read(key, cp, sizeof(cp) - 1, NULL); + if(r <= 0) + return; + cp[r] = 0; + if(!ip4addr_aton(cp, d)) + return; +} + static void network_init(void) { struct ip4_addr local_ip; struct ip4_addr netmask; struct ip4_addr gateway_ip; - IP4_ADDR(&local_ip, 192, 168, 0, 42); - IP4_ADDR(&netmask, 255, 255, 255, 0); - IP4_ADDR(&gateway_ip, 192, 168, 0, 1); + init_macadr(); + fsip_or_default(&local_ip, "ip", 192, 168, 0, 42); + fsip_or_default(&netmask, "netmask", 255, 255, 255, 0); + fsip_or_default(&gateway_ip, "gateway", 192, 168, 0, 1); lwip_init(); @@ -62,204 +117,9 @@ static void network_init(void) netif_set_link_up(&netif); } -struct kserver_connstate { - int magic_recognized; - struct pbuf *rp; - int rp_offset; -}; - -static struct kserver_connstate *cs_new(void) -{ - struct kserver_connstate *cs; - - cs = (struct kserver_connstate *)mem_malloc(sizeof(struct kserver_connstate)); - if(!cs) - return NULL; - cs->magic_recognized = 0; - cs->rp = NULL; - cs->rp_offset = 0; - return cs; -} - -static void cs_free(struct kserver_connstate *cs) -{ - if(cs->rp) - pbuf_free(cs->rp); - mem_free(cs); -} - -static const char kserver_magic[] = "ARTIQ coredev\n"; - -static int magic_ok(struct kserver_connstate *cs) -{ - return cs->magic_recognized >= 14; -} - -static struct kserver_connstate *active_cs; -static struct tcp_pcb *active_pcb; - -static void kserver_close(struct kserver_connstate *cs, struct tcp_pcb *pcb) -{ - if(cs == active_cs) { - session_end(); - active_cs = NULL; - active_pcb = NULL; - } - - /* lwip loves to call back with broken pointers. Prevent that. */ - tcp_arg(pcb, NULL); - tcp_recv(pcb, NULL); - tcp_sent(pcb, NULL); - tcp_err(pcb, NULL); - - cs_free(cs); - tcp_close(pcb); -} - -static err_t kserver_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) -{ - struct kserver_connstate *cs; - - cs = (struct kserver_connstate *)arg; - if(p) { - if(cs->rp) - pbuf_cat(cs->rp, p); - else { - cs->rp = p; - cs->rp_offset = 0; - } - } else - kserver_close(cs, pcb); - return ERR_OK; -} - -static err_t kserver_sent(void *arg, struct tcp_pcb *pcb, u16_t len) -{ - session_ack_mem(len); - return ERR_OK; -} - -static void tcp_pcb_service(void *arg, struct tcp_pcb *pcb) -{ - struct kserver_connstate *cs; - int remaining_in_pbuf; - char *rpp; - struct pbuf *next; - int r; - - cs = (struct kserver_connstate *)arg; - - while(cs->rp) { - remaining_in_pbuf = cs->rp->len - cs->rp_offset; - rpp = (char *)cs->rp->payload; - while(remaining_in_pbuf > 0) { - if(cs == active_cs) { - r = session_input(&rpp[cs->rp_offset], remaining_in_pbuf); - if(r > 0) { - tcp_recved(pcb, r); - cs->rp_offset += r; - remaining_in_pbuf -= r; - } else if(r == 0) - return; - else - kserver_close(cs, pcb); - } else { - if(rpp[cs->rp_offset] == kserver_magic[cs->magic_recognized]) { - cs->magic_recognized++; - if(magic_ok(cs)) { - if(active_cs) - kserver_close(active_cs, active_pcb); - session_start(); - active_cs = cs; - active_pcb = pcb; - tcp_sent(pcb, kserver_sent); - } - } else { - kserver_close(cs, pcb); - return; - } - remaining_in_pbuf--; - cs->rp_offset++; - tcp_recved(pcb, 1); - } - } - next = cs->rp->next; - if(cs->rp->tot_len != cs->rp->len) { - pbuf_ref(next); - pbuf_free(cs->rp); - cs->rp = next; - cs->rp_offset = 0; - } else { - pbuf_free(cs->rp); - cs->rp = NULL; - } - } -} - -static void kserver_err(void *arg, err_t err) -{ - struct kserver_connstate *cs; - - cs = (struct kserver_connstate *)arg; - cs_free(cs); -} - -static struct tcp_pcb *listen_pcb; - -static err_t kserver_accept(void *arg, struct tcp_pcb *newpcb, err_t err) -{ - struct kserver_connstate *cs; - - cs = cs_new(); - if(!cs) - return ERR_MEM; - tcp_accepted(listen_pcb); - tcp_arg(newpcb, cs); - tcp_recv(newpcb, kserver_recv); - tcp_err(newpcb, kserver_err); - return ERR_OK; -} - -static void kserver_init(void) -{ - listen_pcb = tcp_new(); - tcp_bind(listen_pcb, IP_ADDR_ANY, 1381); - listen_pcb = tcp_listen(listen_pcb); - tcp_accept(listen_pcb, kserver_accept); -} - -extern struct tcp_pcb *tcp_active_pcbs; - -static void kserver_service(void) -{ - struct tcp_pcb *pcb; - void *data; - int len, sndbuf; - - /* Assume all active TCP PCBs with a non-NULL arg are our connections. */ - pcb = tcp_active_pcbs; - while(pcb) { - if(pcb->callback_arg) - tcp_pcb_service(pcb->callback_arg, pcb); - pcb = pcb->next; - } - - if(active_cs) { - session_poll(&data, &len); - if(len > 0) { - sndbuf = tcp_sndbuf(active_pcb); - if(len > sndbuf) - len = sndbuf; - tcp_write(active_pcb, data, len, 0); - session_ack_data(len); - } - if(len < 0) - kserver_close(active_cs, active_pcb); - } -} - static void regular_main(void) { + puts("Accepting sessions on Ethernet"); clock_init(); network_init(); kserver_init(); @@ -317,6 +177,7 @@ static void serial_service(void) static void regular_main(void) { + puts("Accepting sessions on serial link"); clock_init(); /* Open the session for the serial control. */ @@ -369,12 +230,6 @@ int main(void) puts("ARTIQ runtime built "__DATE__" "__TIME__"\n"); -#ifdef CSR_ETHMAC_BASE - puts("Accepting sessions on Ethernet"); -#else - puts("Accepting sessions on serial link"); -#endif - puts("Press 't' to enter test mode..."); blink_led();