diff --git a/Makefile.example b/Makefile.example index a4b633f7..fd93ee09 100644 --- a/Makefile.example +++ b/Makefile.example @@ -3,7 +3,7 @@ ARCH = x86 NAME = metalsvm LWIPDIRS = lwip/src/arch lwip/src/api lwip/src/core lwip/src/core/ipv4 lwip/src/netif DRIVERDIRS = drivers/net drivers/char -KERNDIRS = libkern kernel mm fs arch/$(ARCH)/kernel arch/$(ARCH)/mm arch/$(ARCH)/scc $(LWIPDIRS) $(DRIVERDIRS) +KERNDIRS = libkern kernel mm fs apps arch/$(ARCH)/kernel arch/$(ARCH)/mm arch/$(ARCH)/scc $(LWIPDIRS) $(DRIVERDIRS) SUBDIRS = $(KERNDIRS) CC_FOR_TARGET=gcc diff --git a/apps/Makefile b/apps/Makefile new file mode 100644 index 00000000..94912228 --- /dev/null +++ b/apps/Makefile @@ -0,0 +1,4 @@ +C_source := tests.c echo.c netio.c +MODULE := apps + +include $(TOPDIR)/Makefile.inc diff --git a/kernel/echo.c b/apps/echo.c similarity index 100% rename from kernel/echo.c rename to apps/echo.c diff --git a/kernel/netio.c b/apps/netio.c similarity index 64% rename from kernel/netio.c rename to apps/netio.c index 8bfe5e3b..39f24ef1 100644 --- a/kernel/netio.c +++ b/apps/netio.c @@ -24,8 +24,14 @@ #include #include +#ifdef CONFIG_ROCKCREEK +#include +#include +#include +#endif + /* - * This implements a netio server. + * This implements a netio server and client (only TCP version). * The client sends a command word (4 bytes) then a data length word (4 bytes). * If the command is "receive", the server is to consume "data length" bytes into * a circular buffer until the first byte is non-zero, then it is to consume @@ -40,7 +46,6 @@ #ifdef CONFIG_LWIP #include -#include typedef struct { @@ -57,9 +62,12 @@ typedef struct #define DEFAULTPORT 0x494F /* "IO" */ #define TMAXSIZE 65536 +static int tSizes[] = {1024, 2048, 4096, 8192, 16384, 32767}; +static size_t ntSizes = sizeof(tSizes) / sizeof(int); static int nPort = DEFAULTPORT; static const int sobufsize = 131072; static struct in_addr addr_local; +static struct in_addr addr_server; static int send_data(int socket, void *buffer, size_t size, int flags) { @@ -132,7 +140,7 @@ static int TCPServer(void* arg) if ((cBuffer = InitBuffer(TMAXSIZE)) == NULL) { kprintf("Netio: Not enough memory\n"); - return -EINVAL; + return -1; } if ((server = socket(PF_INET, SOCK_STREAM, 0)) < 0) { @@ -271,8 +279,6 @@ static int TCPServer(void* arg) closesocket(client); - stats_display(); - if (rc < 0) break; } @@ -283,10 +289,170 @@ static int TCPServer(void* arg) return 0; } +int TCP_Bench(void) +{ + char *cBuffer; + CONTROL ctl; + uint64_t nData; + int i; + struct sockaddr_in sa_server; + int server; + int rc, err; + int nByte; + uint64_t start, end; + uint32_t freq = get_cpu_frequency(); /* in MHz */ + + if ((cBuffer = InitBuffer(TMAXSIZE)) == NULL) + { + kprintf("Netio: Not enough memory\n"); + return -1; + } + + if ((server = socket(PF_INET, SOCK_STREAM, 0)) < 0) + { + kprintf("socket failed: %d\n", server); + kfree(cBuffer, TMAXSIZE); + return -2; + } + + setsockopt(server, SOL_SOCKET, SO_RCVBUF, (char *) &sobufsize, sizeof(sobufsize)); + setsockopt(server, SOL_SOCKET, SO_SNDBUF, (char *) &sobufsize, sizeof(sobufsize)); + + sa_server.sin_family = AF_INET; + sa_server.sin_port = htons(nPort); + sa_server.sin_addr = addr_server; + + if ((err = connect(server, (struct sockaddr *) &sa_server, sizeof(sa_server))) < 0) + { + kprintf("connect failed: %d\n", err); + closesocket(server); + kfree(cBuffer, TMAXSIZE); + return -2; + } + + kprintf("\nTCP connection established.\n"); + + for (i = 0; i < ntSizes; i++) + { + kprintf("Packet size %s bytes: ", PacketSize(tSizes[i])); + + /* tell the server we will send it data now */ + + ctl.cmd = htonl(CMD_C2S); + ctl.data = htonl(tSizes[i]); + + if (send_data(server, (void *) &ctl, CTLSIZE, 0)) + break; + + /* 1 - Tx test */ + + start = rdtsc(); + nData = 0; + cBuffer[0] = 0; + + do + { + //GenerateRandomData(cBuffer, tSizes[i]); + + for (nByte = 0; nByte < tSizes[i]; ) + { + rc = send(server, cBuffer + nByte, tSizes[i] - nByte, 0); + + if (rc < 0) + { + kprintf("send failed: %d\n", rc); + break; + } + + if (rc > 0) + nByte += rc; + } + + nData += tSizes[i]; + end = rdtsc(); + } while((end-start)/freq < 6000000ULL /* = 6s */); + + kprintf("%llu KBytes/s\n", (nData/1024ULL)/((end-start)/(1000000ULL*freq))); + + kprintf(" Tx, "); + + cBuffer[0] = 1; + + if (send_data(server, cBuffer, tSizes[i], 0)) + break; + + /* tell the server we expect him to send us data now */ + + ctl.cmd = htonl(CMD_S2C); + ctl.data = htonl(tSizes[i]); + + if (send_data(server, (void *) &ctl, CTLSIZE, 0)) + break; + + /* 2 - Rx test */ + + start = rdtsc(); + nData = 0; + cBuffer[0] = 0; + rc = 0; + + do + { + for (nByte = 0; nByte < tSizes[i]; ) + { + rc = recv(server, cBuffer + nByte, tSizes[i] - nByte, 0); + + if (rc < 0) + { + kprintf("recv failed: %d\n", rc); + break; + } + + if (rc > 0) + nByte += rc; + } + + nData += tSizes[i]; + } while (cBuffer[0] == 0 && rc > 0); + + end = rdtsc(); + kprintf("%llu KBytes/s\n", (nData/1024ULL)/((end-start)/(1000000ULL*freq))); + + kprintf(" Rx.\n"); + } + + ctl.cmd = htonl(CMD_QUIT); + ctl.data = 0; + + send_data(server, (void *) &ctl, CTLSIZE, 0); + + kprintf("Done.\n"); + + closesocket(server); + kfree(cBuffer, TMAXSIZE); + + return 0; +} + int netio_init(void) { - addr_local.s_addr = INADDR_ANY; + int err = 0; - return create_kernel_task(NULL, TCPServer, NULL, NORMAL_PRIO); + addr_local.s_addr = INADDR_ANY; + //addr_server.s_addr = inet_addr("192.168.28.254"); + addr_server.s_addr = inet_addr("192.168.0.2"); + +#ifdef CONFIG_ROCKCREEK + if (RCCE_ue() == 1) { + err = create_kernel_task(NULL, TCPServer, NULL, NORMAL_PRIO); + } else if (RCCE_ue() == 0) { + sleep(3); + err = TCP_Bench(); + } +#else + err = create_kernel_task(NULL, TCPServer, NULL, NORMAL_PRIO); +#endif + + return err; } #endif diff --git a/kernel/tests.c b/apps/tests.c similarity index 96% rename from kernel/tests.c rename to apps/tests.c index c01d806b..0ef511d2 100644 --- a/kernel/tests.c +++ b/apps/tests.c @@ -279,7 +279,7 @@ int test_init(void) // char* argv[] = {"/bin/mshell", NULL}; char* argv[] = {"/bin/tests", NULL}; char* server_argv[] = {"/bin/server", "6789", NULL}; -// char* client_argv[] = {"/bin/client", "127.0.0.1", "6789", NULL}; + char* client_argv[] = {"/bin/client", "192.168.0.1", "6789", NULL}; sem_init(&producing, 1); sem_init(&consuming, 0); @@ -297,9 +297,11 @@ int test_init(void) //create_user_task(NULL, "/bin/jacobi", argv); //create_user_task(NULL, "/bin/mshell", argv); //create_user_task(NULL, "/bin/jacobi", argv); - //create_user_task(NULL, "/bin/server", server_argv); - //sleep(5); - //create_user_task(NULL, "/bin/client", client_argv); + /*create_user_task(NULL, "/bin/server", server_argv); + if (RCCE_ue() != 0) { + sleep(5); + create_user_task(NULL, "/bin/client", client_argv); + }*/ return 0; } diff --git a/arch/x86/include/asm/kb.h b/arch/x86/include/asm/kb.h index 1b2dfb40..fcb55196 100644 --- a/arch/x86/include/asm/kb.h +++ b/arch/x86/include/asm/kb.h @@ -53,7 +53,9 @@ typedef struct extern kb_buffer_t kb_buffer; -void kb_flush(); +void kb_init(size_t size, tid_t tid); + +void kb_finish(void); #endif diff --git a/arch/x86/scc/scc_memcpy.h b/arch/x86/include/asm/scc_memcpy.h similarity index 100% rename from arch/x86/scc/scc_memcpy.h rename to arch/x86/include/asm/scc_memcpy.h diff --git a/arch/x86/kernel/kb.c b/arch/x86/kernel/kb.c index aabf040c..18a65ee7 100644 --- a/arch/x86/kernel/kb.c +++ b/arch/x86/kernel/kb.c @@ -36,7 +36,7 @@ void kb_init(size_t size, tid_t tid) { return; } -void kb_finish() { +void kb_finish(void) { kfree(kb_buffer.buffer, (kb_buffer.maxsize * sizeof(char))); kb_buffer.buffer = NULL; kb_buffer.size = 0; diff --git a/arch/x86/scc/RCCE_get.c b/arch/x86/scc/RCCE_get.c index 5e0ed7c0..d7abb19f 100644 --- a/arch/x86/scc/RCCE_get.c +++ b/arch/x86/scc/RCCE_get.c @@ -26,7 +26,7 @@ #ifdef CONFIG_ROCKCREEK -#include "scc_memcpy.h" +#include //-------------------------------------------------------------------------------------- // FUNCTION: RCCE_get diff --git a/arch/x86/scc/RCCE_put.c b/arch/x86/scc/RCCE_put.c index 44893895..289ec00e 100644 --- a/arch/x86/scc/RCCE_put.c +++ b/arch/x86/scc/RCCE_put.c @@ -26,7 +26,7 @@ #ifdef CONFIG_ROCKCREEK -#include "scc_memcpy.h" +#include //-------------------------------------------------------------------------------------- // FUNCTION: RCCE_put diff --git a/arch/x86/scc/RCCE_recv.c b/arch/x86/scc/RCCE_recv.c index 31aeac96..30331a5b 100644 --- a/arch/x86/scc/RCCE_recv.c +++ b/arch/x86/scc/RCCE_recv.c @@ -28,7 +28,7 @@ #ifdef CONFIG_ROCKCREEK #include -#include "scc_memcpy.h" +#include //-------------------------------------------------------------------------------------- // FUNCTION: RCCE_recv_general diff --git a/arch/x86/scc/RCCE_send.c b/arch/x86/scc/RCCE_send.c index 5c7c61e0..efbca6c3 100644 --- a/arch/x86/scc/RCCE_send.c +++ b/arch/x86/scc/RCCE_send.c @@ -28,7 +28,7 @@ #ifdef CONFIG_ROCKCREEK #include -#include "scc_memcpy.h" +#include //-------------------------------------------------------------------------------------- // FUNCTION: RCCE_send_general diff --git a/arch/x86/scc/iRCCE_get.c b/arch/x86/scc/iRCCE_get.c index 8859bfed..c03a6d37 100644 --- a/arch/x86/scc/iRCCE_get.c +++ b/arch/x86/scc/iRCCE_get.c @@ -36,7 +36,7 @@ #include #if defined(COPPERRIDGE) || defined(SCC) -#include "scc_memcpy.h" +#include #endif void* iRCCE_memcpy_get(void *dest, const void *src, size_t count) diff --git a/arch/x86/scc/iRCCE_put.c b/arch/x86/scc/iRCCE_put.c index 96060cae..f16204b0 100644 --- a/arch/x86/scc/iRCCE_put.c +++ b/arch/x86/scc/iRCCE_put.c @@ -36,7 +36,7 @@ #include #if defined(COPPERRIDGE) || defined(SCC) -#include "scc_memcpy.h" +#include #endif void* iRCCE_memcpy_put(void *dest, const void *src, size_t count) diff --git a/arch/x86/scc/icc.c b/arch/x86/scc/icc.c index 065c086f..b5ef9002 100644 --- a/arch/x86/scc/icc.c +++ b/arch/x86/scc/icc.c @@ -90,7 +90,7 @@ static void intr_handler(struct state *s) int tmp, z; #ifdef CONFIG_LWIP - //mmnif_irqhandler(); + mmnif_irqhandler(); #endif z = Z_PID(RC_COREID[my_ue]); diff --git a/drivers/net/mmnif.c b/drivers/net/mmnif.c index 3b1679be..540b4a07 100644 --- a/drivers/net/mmnif.c +++ b/drivers/net/mmnif.c @@ -1,1139 +1,1714 @@ -/* - * mmnif.c --- memmory mapped interface - * - * Virutal IP Interface for the concept processor SCC - * - * virutally tested under Windows 7 - * - * Carl-Benedikt Krüger 2011 - * - * - * EXPERIMENTAL VERSION - */ - - -#include "mmnif.h" /* definitions */ - -#include /* lwip netif */ -#include /* inteface stats */ -#include /* ethernet arp packets */ -#include /* struct iphdr*/ -#include /* tcpip_input()*/ -#if defined(CONFIG_LWIP) && defined(CONFIG_ROCKCREEK) - -#ifdef WIN32 - -#define kmalloc malloc -#define kfree(x,y) free(x) -#define RCCE_shfree(x) VirtualFree(x,NULL,NULL); -#define RCCE_shmalloc(x) VirtualAlloc((char*)0x41000000,x,MEM_COMMIT|MEM_RESERVE,PAGE_READWRITE); -#include "mailbox.h" /* mailbox_ptr_t */ -#define WIN32_LEAN_AND_MEAN -#include -#include -typedef bthread_sem_t sem_t; -typedef bthread_t tid_t; -/* "interrupt" of the other virutal network card*/ -extern HANDLE remote_process_event; -extern HANDLE remote_process_mutex; -extern HANDLE own_process_mutex; -/* HANDLE to the other Process (for WPM and RPM)*/ -extern HANDLE hProc; -#define DEBUGPRINTF(x,...) printf(x,__VA_ARGS__) - -#else - -#include /* mailbox_ptr_t */ - -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include - -#define DEBUGPRINTF(x,...) kprintf(x,##__VA_ARGS__) - -#endif - - - -#define DEBUG_MMNIF -//#define DEBUG_MMNIF_PACKET - -#ifdef DEBUG_MMNIF -#include "util.h" /* hex dump */ -#endif - -/* define constants - * regarding the driver & its configuration - */ - -#define MMNIF_TX_BUFFERLEN 1792 -#define MMNIF_TX_QUEUELEN 4 - -#define MMNIF_RX_BUFFERLEN 8192 -#define MMNIF_MAX_DESCRIPTORS 32 - -#define MMNIF_CORES 48 - -#define MMNIF_POLL_BUDGET 0x100000 - -#define MMNIF_STATUS_FREE 0x00 -#define MMNIF_STATUS_PENDING 0x01 -#define MMNIF_STATUS_RDY 0x02 -#define MMNIF_STATUS_INPROC 0x03 -#define MMNIF_STATUS_PROC 0x04 - - -/* decide whether it's polling mode or not - */ -static int no_irq = 0; - -/* this will be set by open() and close() and shows wether the driver is running or not -*/ -static int active = 0; - -/* decide wheter it's uses locking or not - */ -static int disable_locking = 0; - -/* decide whether deliver work to a worker thread or instantly process all packets - */ -static int instant_process = 1; - -/* IP address of the local core and the router core to get packets forwarded - */ -static unsigned int own_ip_address = 0xC0A80000; /* 192.168.0.0 */ - -static unsigned int router_ip_address = 0xC0A80001; /* 192.168.0.1 */ - -/* "message passing buffer" specific constants: - * - start address - * - size - */ -char* mpb_start_address = NULL; -unsigned int mpb_size = NULL; - -/* - * the memory mapped network device - */ -static struct netif* mmnif_dev = NULL; - -/* thread variables */ -static tid_t worker_thread; -static tid_t polling_thread; - -typedef struct mmnif_device_stats -{ - /* device stats (granularity in packets): - * - recieve errors - * - recieve successes - * - recieved bytes - * - transmit errors - * - transmit successes - * - transmitted bytes - */ - unsigned int rx_err; - unsigned int rx; - - unsigned int rx_bytes; - - unsigned int tx_err; - unsigned int tx; - - unsigned int tx_bytes; - - /* Heuristics : - * - how many times an budget overflow occured - * - how many times the polling thread polled without recieving a new message - * - how many messages are recieved via interrupt - * - how many messages are recieved via the polling thread - */ - unsigned int bdg_overflow; - unsigned int pll_empty; - unsigned int rx_intr; - unsigned int rx_poll; - -} mmnif_device_stats_t; - -/* receive descror structure */ -typedef struct rx_desc -{ - uint8_t stat; - uint16_t len; - uint32_t addr; - -} rx_desc_t; - -/* receive ring buffer structure */ -typedef struct mm_rx_buffer -{ - /* iv_intr: inform via interrupt - * states whether the interface wants to recieve an interrupt for - * incoming packet - */ - uint16_t iv_intr; - /* memory "pseudo-ring/heap" - * packets are always in one single chunk of memory - * head : head of allocated memory region - * tail : tail of allocated memory region - */ - uint16_t head; - uint16_t tail; - spinlock_t rlock; - /* descritpor queue - * desc_table : descriptor table - * dcount : descriptor's free in queue - * dread : next descriptor to read - * dwrite : next descriptor to write - * dlock : lock to protect these members - */ - rx_desc_t desc_table[MMNIF_MAX_DESCRIPTORS]; - uint8_t dcount; - uint8_t dread; - uint8_t dwrite; - spinlock_t dlock; -} mm_rx_buffer_t; - -typedef struct mmnif -{ - struct mmnif_device_stats stats; - - /* Interface constants: - * - ehternet address - * - local ip address - */ - struct eth_addr* ethaddr; - uint32_t ipaddr; - - /* memory interaction variables: - * - transmit queue - * - pointer to transmit buffer - * - pointer to recive buffer - */ - uint8_t tx_queue; - uint8_t* tx_buff[MMNIF_TX_QUEUELEN]; - mm_rx_buffer_t* rx_buff; - - /* lock to protect members - */ - spinlock_t lock; - - /* - */ - sem_t com_poll; - -}mmnif_t; - - -#ifdef WIN32 -__inline int RCCE_ue(void){ -#ifndef RECV - return 1; -#else - return 0; -#endif -} -#endif - -/* - * memory maped interface helper functions - */ -#ifdef WIN32 -#define __MEMCPY(x,y,z) memcpy(x,y,z) -#else -#define __MEMCPY(x,y,z) memcpy(x,y,z) -#endif - -/* mmnif_device_schedule() : - * if there is no interupt used to indicate new packets - * this creates a polling thread which looks for data - * itself - */ -__inline int mmnif_device_schedule() -{ -#ifdef WIN32 - bthread_create(&polling_thread,NULL,mmnif_poll,NULL); - return NULL; -#else - create_kernel_task(&polling_thread,mmnif_poll,NULL, NORMAL_PRIO); - return NULL; -#endif -} - -/* trigger an interrupt on the remote processor - * so he knows there is a packet to read - */ -__inline int mmnif_trigger_irq(dest_ip) -{ -#ifdef WIN32 - return SetEvent(remote_process_event); -#else - int tmp, x, y, z, addr; - - int ue = dest_ip -1; - - z = Z_PID(RC_COREID[ue]); - x = X_PID(RC_COREID[ue]); - y = Y_PID(RC_COREID[ue]); - addr = CRB_ADDR(x,y) + (z==0 ? GLCFG0 : GLCFG1); - - // send interrupt to ue - do { - NOP1; - tmp=ReadConfigReg(addr); - } while(tmp & 2); - tmp |= 2; - SetConfigReg(addr, tmp); - - return 0; -#endif -} - -/* mmnif_get_device_stats(): Returns a copy of the - * current device - */ -mmnif_device_stats_t mmnif_get_device_stats(void) -{ - mmnif_device_stats_t stats = {0}; - - if(!mmnif_dev) - DEBUGPRINTF("mmnif_get_device_stats(): the device is not initialized yet.\n"); - else - stats = ((mmnif_t*)mmnif_dev->state)->stats; - - return stats; -} - -/* mmnif_print_stats(): Print the devices stats of the - * current device - */ -void mmnif_print_stats(void) -{ - mmnif_t* mmnif; - - if (!mmnif_dev) - { - DEBUGPRINTF("mmnif_print_stats(): the device is not initialized yet.\n"); - return; - } - - mmnif = (mmnif_t*)mmnif_dev->state; - - DEBUGPRINTF("/dev/mmnif - stats:\n"); - DEBUGPRINTF("Received: %d packets successfull\n",mmnif->stats.rx); - DEBUGPRINTF("Received: %d bytes\n",mmnif->stats.rx_bytes); - DEBUGPRINTF("interrupts: %d\n",mmnif->stats.rx_intr); - DEBUGPRINTF("polling: %d\n",mmnif->stats.rx_poll); - DEBUGPRINTF("Received: %d packets containuing errors\n",mmnif->stats.rx_err); - DEBUGPRINTF("Transmitted: %d packests successfull\n",mmnif->stats.tx); - DEBUGPRINTF("Transmitted: %d bytes\n",mmnif->stats.tx_bytes); - DEBUGPRINTF("Transmitted: %d packests were dropped due to errors\n",mmnif->stats.tx_err); - -} - - -/* - * memory maped interface main functions - */ - -/* mmnif_get_destination(): low level transmid helper function - * this function deals with some HW details, it checks to wich core this packet - * should be routed and returns the destination - */ - -uint8_t mmnif_get_destination(struct netif* netif, struct pbuf* p) -{ - struct ip_hdr* iphdr; - uint8_t core; - uint8_t* ip4addr; - uint8_t addr[4]; - uint32_t netmask = 0xFFFFFF00; - - /* grab the destination ip address out of the ip header - * for internal routing the last ocet is interpreted as core ID. - */ - - iphdr = (struct ip_hdr*)(p->payload); - ip4addr = &iphdr->dest.addr; - - /* revert the address to host format */ - addr[3] = ip4addr[0]; addr[2] = ip4addr[1]; - addr[1] = ip4addr[2]; addr[0] = ip4addr[3]; - - /* check if the ip address is in the Local Area Network of the 48 cores */ - - /* if it's not the same network the router core is addressed - * Note: the router core is core 1 - */ - - if (!((netmask & *(uint32_t*)addr) == (netmask & own_ip_address) )) - return 1; - - core = addr[0]; - - /* check if the address is legitimata else return router core again */ - if ((core) < 1 || (core > MMNIF_CORES)) - core = 1; - - return core; -} - -/* mmnif_rxbuff_alloc(): - * this function allocates a continues chunk of memory - * right inside of the buffer which is used for communication - * with the remote end - */ -uint32_t mmnif_rxbuff_alloc(uint8_t dest,uint16_t len) -{ - mm_rx_buffer_t* rb = (mm_rx_buffer_t*)((char*)mpb_start_address + ( dest -1 ) * mpb_size); - char* memblock = (char*)rb + sizeof(mm_rx_buffer_t); - - uint32_t ret; - - spinlock_lock(&rb->dlock); - - if (rb->dcount) - { - if (rb->tail > rb->head) - { - if (MMNIF_RX_BUFFERLEN - rb->tail > len) - { - rb->desc_table[rb->dwrite].stat = MMNIF_STATUS_PENDING; - ret = memblock + rb->tail; - rb->desc_table[rb->dwrite].addr = ret; - rb->desc_table[rb->dwrite].len = len; - rb->dcount--; - rb->dwrite = (++rb->dwrite)%MMNIF_MAX_DESCRIPTORS; - - rb->tail = (rb->tail + len); - spinlock_unlock(&rb->dlock); - return ret; - } - else if (rb->head > len) - { - rb->desc_table[rb->dwrite].stat = MMNIF_STATUS_PENDING; - ret = memblock; - rb->desc_table[rb->dwrite].addr = ret; - rb->desc_table[rb->dwrite].len = len; - rb->dcount--; - rb->dwrite = (++rb->dwrite)%MMNIF_MAX_DESCRIPTORS; - - rb->tail = len; - spinlock_unlock(&rb->dlock); - return ret; - } - else - { - spinlock_unlock(&rb->dlock); - return NULL; - } - } - else - { - if (rb->head - rb->tail > len) - { - rb->desc_table[rb->dwrite].stat = MMNIF_STATUS_PENDING; - ret = memblock + rb->tail; - rb->desc_table[rb->dwrite].addr = ret; - rb->desc_table[rb->dwrite].len = len; - rb->dcount--; - rb->dwrite = (++rb->dwrite)%MMNIF_MAX_DESCRIPTORS; - - rb->tail = (rb->tail + len); - spinlock_unlock(&rb->dlock); - return ret; - } - else if (rb->tail == rb->head) - { - if (MMNIF_RX_BUFFERLEN - rb->tail < len) - { - rb->tail = 0; - if (rb->dread == rb->dwrite) - rb->head = 0; - } - - rb->desc_table[rb->dwrite].stat = MMNIF_STATUS_PENDING; - ret = memblock + rb->tail; - rb->desc_table[rb->dwrite].addr = ret; - rb->desc_table[rb->dwrite].len = len; - rb->dcount--; - rb->dwrite = (++rb->dwrite)%MMNIF_MAX_DESCRIPTORS; - - rb->tail = (rb->tail + len); - spinlock_unlock(&rb->dlock); - return ret; - } - else - { - spinlock_unlock(&rb->dlock); - return NULL; - } - } - } - else - { - spinlock_unlock(&rb->dlock); - return NULL; - } -} - -/* mmnif_commit_packet: this function set the state of the (in advance) - * allocated packet to RDY so the recieve queue knows that it can be - * processed further - */ -int mmnif_commit_packet(uint8_t dest,uint32_t addr) -{ - mm_rx_buffer_t* rb = (mm_rx_buffer_t*)((char*)mpb_start_address + ( dest -1 ) * mpb_size); - uint32_t i; - - for (i = 0; i < MMNIF_MAX_DESCRIPTORS; i++) - { - if (rb->desc_table[i].addr == addr && rb->desc_table[i].stat == MMNIF_STATUS_PENDING) - { - rb->desc_table[i].stat = MMNIF_STATUS_RDY; - return 0; - } - } - return -1; -} - -/* mmnif_rxbuff_free() : the opposite to mmnif_rxbuff_alloc() a from the receiver - * already processed chunk of memory is freed so that it can be allocated again - */ -void mmnif_rxbuff_free(void) -{ - mmnif_t* mmnif = mmnif_dev->state; - mm_rx_buffer_t* b = mmnif->rx_buff; - uint32_t i,j; - uint32_t rpos; - - spinlock_lock(&b->dlock); - - rpos = b->dread; - - for (i = 0, j = rpos; i < MMNIF_MAX_DESCRIPTORS; i++) - { - j = (j+i)%MMNIF_MAX_DESCRIPTORS; - - if (b->desc_table[j].stat == MMNIF_STATUS_PROC) - { - b->dcount++; - b->dread = (b->dread +1)%MMNIF_MAX_DESCRIPTORS; - b->desc_table[j].stat = MMNIF_STATUS_FREE; - - if (b->tail > b->head) - { - b->head += b->desc_table[j].len; - } - else - { - if ( (b->desc_table[(j+1)%MMNIF_MAX_DESCRIPTORS].stat != MMNIF_STATUS_FREE ) - && ( b->desc_table[j].addr > b->desc_table[(j+1)%MMNIF_MAX_DESCRIPTORS].addr)) - { - b->head = 0; - - } - else - { - b->head += b->desc_table[j].len; - } - } - } - else - break; - } - - spinlock_unlock(&b->dlock); -} -/* - * Transmid a packet (called by the lwip) - */ -err_t mmnif_tx(struct netif* netif, struct pbuf* p) -{ - mmnif_t* mmnif = netif->state; - uint8_t slot = mmnif->tx_queue; - - uint32_t write_address; - uint32_t i; - struct pbuf* q; /* interator */ - - uint8_t build_buff = TRUE; - uint32_t dest_ip = mmnif_get_destination(netif,p); - - mm_rx_buffer_t* rb = (mm_rx_buffer_t*)((char*)mpb_start_address + ( dest_ip -1 ) * mpb_size); - -#ifdef WIN32 - ReadProcessMemory(hProc, (char*)mpb_start_address + ( dest_ip -1 ) * mpb_size, (char*)mpb_start_address + ( dest_ip -1 ) * mpb_size,mpb_size,NULL); - WaitForSingleObject(remote_process_mutex,INFINITE); -#endif - - spinlock_lock(&mmnif->lock); - mmnif->tx_queue++; - spinlock_unlock(&mmnif->lock); - - - /* Perform serveral sanity checks on the packet and the buffers: - * - is the queue full? - * - is the output packet to big? - */ - - if (mmnif->tx_queue > MMNIF_TX_QUEUELEN) - { - DEBUGPRINTF("mmnif_tx(): too many packets at once for tx_queue\n"); - goto drop_packet; - } - - if (p->tot_len > MMNIF_TX_BUFFERLEN) - { - DEBUGPRINTF("mmnif_tx(): packet is longer than %d bytes\n",MMNIF_TX_BUFFERLEN); - goto drop_packet; - } - - /* check if the pbuf consists only of one element - * if that is the case it would be much overhead - * copying that packet again - */ - if (!p->next) - build_buff = FALSE; - - if (build_buff) - { - /* build the payload out of the p's - * ensure that the packet is in one memory chunk stored in the transmid buffer - */ - for (q = p, i = 0; q != 0; q = q->next) - { - memcpy(mmnif->tx_buff[slot] + i, q->payload, q->len); - i += q->len; - } - } - - /* allocate memory for the packet in the remote buffer */ - - write_address = mmnif_rxbuff_alloc(dest_ip,p->tot_len); - - if (!write_address) - goto drop_packet; - - /* write buffer to buffer & increment the queued packet count - * this can be safely done without locking because this place is - * reserved for us because it has the status "pending" - */ - if (build_buff) - memcpy(write_address,mmnif->tx_buff[slot],p->tot_len); - else - memcpy(write_address,p->payload,p->tot_len); - - - if (mmnif_commit_packet(dest_ip,write_address)) - { - DEBUGPRINTF("mmnif_tx(): packet somehow lost during commit\n"); - } - -#ifdef DEBUG_MMNIF_PACKET - DEBUGPRINTF("\n SEND 0x%.8X with length: %d\n",(char*)mpb_start_address + (dest_ip -1)*mpb_size + pos * 1792,p->tot_len +2); - hex_dump(p->tot_len, p->payload); -#endif - - /* release the tx_queue because it's finished */ - spinlock_lock(&mmnif->lock); - mmnif->tx_queue--; - spinlock_unlock(&mmnif->lock); - - /* just gather some stats */ - LINK_STATS_INC(link.xmit); - - mmnif->stats.tx++; - mmnif->stats.tx_bytes += p->tot_len; - -#ifdef WIN32 - WriteProcessMemory(hProc, (char*)mpb_start_address + ( dest_ip -1 ) * mpb_size, (char*)mpb_start_address + ( dest_ip -1 ) * mpb_size,mpb_size,NULL); - SetEvent(remote_process_event); - ReleaseMutex(remote_process_mutex); -#endif - - if (rb->iv_intr) - mmnif_trigger_irq(dest_ip); - - return ERR_OK; - -drop_packet: - /* drop packet for one or another reason - */ - spinlock_lock(&mmnif->lock); - mmnif->tx_queue--; - spinlock_unlock(&mmnif->lock); - - LINK_STATS_INC(link.drop); - mmnif->stats.tx_err++; - -#ifdef WIN32 - WriteProcessMemory(hProc, (char*)mpb_start_address + ( dest_ip -1 ) * mpb_size,(char*)mpb_start_address + ( dest_ip -1 ) * mpb_size,mpb_size,NULL); -#endif - - return ERR_IF; -} - -/* mmnif_link_layer(): wrapper function called by ip_output() - * adding all needed headers for the link layer - * because we have no link layer and everything is reliable we don't need - * to add anything so we just pass it to our tx function - */ -static void mmnif_link_layer(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr) -{ - netif->linkoutput(netif,q); -} - -/* - * Init the device (called from lwip) - * It's invoked in netif_add - */ -err_t mmnif_init(struct netif* netif) -{ - mmnif_t* mmnif; - uint32_t i; - int num = 0; - - /* Alloc and clear memory for the device struct - */ - mmnif = kmalloc(sizeof(mmnif_t)); - - if (!mmnif) - { - DEBUGPRINTF("mmnif init():out of memory\n"); - return ERR_MEM; - } - memset(mmnif, 0, sizeof(mmnif_t)); - - /* Alloc and clear shared memory for rx_buff - */ - mpb_size = (sizeof(mm_rx_buffer_t) + MMNIF_RX_BUFFERLEN); - // align mpb size to the granularity of a page size - mpb_size = (mpb_size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); - mpb_start_address = RCCE_shmalloc(mpb_size*MMNIF_CORES); - // map physical address in the virtual address space - mpb_start_address = map_region(0, mpb_start_address, mpb_size >> PAGE_SHIFT, MAP_KERNEL_SPACE|MAP_NO_CACHE); - - mmnif->rx_buff = mpb_start_address + (mpb_size) * (own_ip_address - router_ip_address); - if (!(mpb_start_address)) - { - DEBUGPRINTF("mmnif init(): allocating shared memory failed\n"); - return ERR_MEM; - } - memset(mmnif->rx_buff, 0, mpb_size); - - /* set initial values - */ - mmnif->rx_buff->dcount = MMNIF_MAX_DESCRIPTORS; - - /* init the lock's for the hdr - */ - - spinlock_init(&mmnif->rx_buff->rlock); - spinlock_init(&mmnif->rx_buff->dlock); - - spinlock_init(&mmnif->lock); - - /* init the sems for communication art - */ - sem_init(&mmnif->com_poll,1); - - /* since there is no possibilty to create a full semaphore we just block it manually - */ - sem_wait(&mmnif->com_poll,0); - - /* inform via interrupt should be the dafault - */ - if (!no_irq) - mmnif->rx_buff->iv_intr = TRUE; - - /* Alloc and clear internal memory for tx_buff - */ - mmnif->tx_buff[0] = kmalloc(MMNIF_TX_QUEUELEN * MMNIF_TX_BUFFERLEN); - - if (!(mmnif->tx_buff[0])) - { - DEBUGPRINTF("mmnif init: out of memory tx\n"); - return ERR_MEM; - } - mmnif->tx_queue = 0; - memset(mmnif->tx_buff[0], 0, MMNIF_TX_QUEUELEN * MMNIF_TX_BUFFERLEN); - - for (i = 0; i < MMNIF_TX_QUEUELEN -1 ; i++) - mmnif->tx_buff[i+1] = mmnif->tx_buff[i] + MMNIF_TX_BUFFERLEN; - - /* pass the device state to lwip */ - netif->state = mmnif; - mmnif_dev = netif; - - /* administrative details */ - netif->name[0] = 'e'; - netif->name[1] = 'n'; - netif->num = num; - num++; - /* downward functions */ - netif->output = mmnif_link_layer; - /* there is no special link layer just the ip layer */ - netif->linkoutput = mmnif_tx; - /* maximum transfer unit */ - netif->mtu = 1500; - /* broadcast capability, keep all default flags*/ - netif->flags |= NETIF_FLAG_BROADCAST | NETIF_FLAG_LINK_UP; - /* hardware address length */ - netif->hwaddr_len = 6; - - active = TRUE; - -#ifdef MMNIF_DEBUG - DEBUGPRINTF("mmnif init complete\n"); -#endif - - return NULL; -} - -/* - * Receive a packet : recieve, pack it up and pass over to higher levels - */ -static void mmnif_rx(struct netif* netif) -{ - mmnif_t* mmnif = netif->state; - mm_rx_buffer_t* b = mmnif->rx_buff; - - uint16_t length; - struct pbuf* p = NULL; - struct pbuf* q; - char* packet; - - uint32_t i,j; - uint8_t rdesc = 0xFF; - - err_t err = NULL; - -#ifdef WIN32 - ReadProcessMemory(hProc, (char*)mpb_start_address + ( !((own_ip_address && 0xFF)-1) ) * mpb_size, (char*)mpb_start_address + ( !((own_ip_address && 0xFF)-1) ) * mpb_size,mpb_size,NULL); - WaitForSingleObject(own_process_mutex,INFINITE); -#endif - - spinlock_lock(&b->rlock); - - /* check if this call to mmnif_rx makes any sense - */ - if (b->desc_table[b->dread].stat == MMNIF_STATUS_FREE) - { - spinlock_unlock(&b->rlock); -#ifdef WIN32 - WriteProcessMemory(hProc, (char*)mpb_start_address + ( !((own_ip_address && 0xFF)-1) ) * mpb_size, (char*)mpb_start_address + ( !((own_ip_address && 0xFF)-1) ) * mpb_size,mpb_size,NULL); -#endif - return; - } - - /* search the packet whose transmission is finished - */ - for (i = 0,j = b->dread; i < MMNIF_MAX_DESCRIPTORS; i++) - { - if (b->desc_table[(j + i)% MMNIF_MAX_DESCRIPTORS].stat == MMNIF_STATUS_RDY) - { - rdesc = (j + i)% MMNIF_MAX_DESCRIPTORS; - b->desc_table[rdesc].stat = MMNIF_STATUS_INPROC; - packet = (char*)b->desc_table[rdesc].addr; - length = b->desc_table[rdesc].len; - break; - } - } - - spinlock_unlock(&b->rlock); - - /* if there is no packet finished we encountered a random error - */ - if (rdesc == 0xFF) - { -#ifdef WIN32 - WriteProcessMemory(hProc, (char*)mpb_start_address + ( !((own_ip_address && 0xFF)-1) ) * mpb_size, (char*)mpb_start_address + ( !((own_ip_address && 0xFF)-1) ) * mpb_size,mpb_size,NULL); -#endif - return; - } - - /* If length is zero return silently - */ - if (length == 0) - { - DEBUGPRINTF("mmnif_rx(): empty packet error\n"); - return; - } - if (length < sizeof(struct ip_hdr) ||length > netif->mtu) - { - DEBUGPRINTF("mmnif_rx(): illegal packet length %d => drop the packet\n",length); - goto drop_packet; - } - - /* From now on there is a real packet and it - * has to be worked on - */ - - #ifdef DEBUG_MMNIF_PACKET - DEBUGPRINTF("\n RECIEVED - 0x%.8X with legth: %d\n",packet,length); - hex_dump(length,packet); - #endif - - /* Build the pbuf for the packet so the lwip - * and other higher layer can handle it - */ - p = pbuf_alloc(PBUF_RAW, length, PBUF_POOL); - if (!p) - { - DEBUGPRINTF("mmnif_rx(): low on mem - packet dropped\n"); - goto drop_packet; - } - - /* copy packet to pbuf structure going through linked list */ - for (q=p, i = 0; q!=NULL; q=q->next) - { - memcpy((uint8_t*)q->payload,&packet[i],q->len); - i +=q->len; - } - - /* indicate that the copy process is done and the packet can be freed - * note that we did not lock here because we are the only one editing this value - */ - mmnif->rx_buff->desc_table[rdesc].stat = MMNIF_STATUS_PROC; - - /* everything is copied to a new buffer so it's save to release - * the old one for new incoming packets - */ - - mmnif_rxbuff_free(); - - /* full packet send to tcpip_thread to process */ - if ((err = mmnif_dev->input(p, mmnif_dev)) != ERR_OK) - { - DEBUGPRINTF("mmnif_rx: IP input error\n"); - pbuf_free(p); - } - - /* gather some stats and leave the rx handler */ - LINK_STATS_INC(link.xmit); - mmnif->stats.rx++; - - mmnif->stats.rx_bytes += p->tot_len; - - if (mmnif->rx_buff->iv_intr) - mmnif->stats.rx_intr++; - else - mmnif->stats.rx_poll++; - -#ifdef WIN32 - WriteProcessMemory(hProc, (char*)mpb_start_address + ( !((own_ip_address && 0xFF)-1) ) * mpb_size, (char*)mpb_start_address + ( !((own_ip_address && 0xFF)-1) ) * mpb_size,mpb_size,NULL); - ReleaseMutex(own_process_mutex); -#endif - - return; - -drop_packet: - - spinlock_lock(&mmnif->rx_buff->rlock); - /*error handling*/ - spinlock_unlock(&mmnif->rx_buff->rlock); - - LINK_STATS_INC(link.drop); - mmnif->stats.rx_err++; - -#ifdef WIN32 - WriteProcessMemory(hProc, (char*)mpb_start_address + ( !((own_ip_address && 0xFF)-1) ) * mpb_size, (char*)mpb_start_address + ( !((own_ip_address && 0xFF)-1) ) * mpb_size,mpb_size,NULL); -#endif - return; -} -/* mmnif_irqhandler(): - * handles the incomint interrupts - */ -void mmnif_irqhandler(void) -{ - mmnif_t* mmnif; - - /* return if mmnif_dev is not yet initialized*/ - if (!mmnif_dev) - { - DEBUGPRINTF("mmnif_irqhandler(): the driver is not initialized yet\n"); - return; - } - - mmnif = (mmnif_t*) mmnif_dev->state; - - while (mmnif->rx_buff->dcount < MMNIF_MAX_DESCRIPTORS) - { - mmnif_rx(mmnif_dev); - -// if (instant_process) -// mmnif_wait(mmnif_dev,1,MMNIF_WORKER_BUDGET); - } -} -/* - * the poll function wich is used if no interrupt wake up our mmnif_rx functions - */ -int mmnif_poll(void* e) -{ - mmnif_t* mmnif; - - if (!mmnif_dev) - { - DEBUGPRINTF("mmnif_poll(): the driver is not initialized yet\n"); - return -1; - } - - mmnif = (mmnif_t*) mmnif_dev->state; - -#ifdef DEBUG_MMNIF - DEBUGPRINTF("mmnif_poll(): polling thread launched",mmnif->rx_buff); -#endif - - if (!no_irq) - { - sem_wait(&mmnif->com_poll,0); - } - - /*run while driver is up*/ - while (active) - { - while (!mmnif->rx_buff->dcount == MMNIF_MAX_DESCRIPTORS) - { - mmnif->stats.pll_empty++; - if (mmnif->stats.pll_empty >= MMNIF_POLL_BUDGET) - { - /* enable interrupts and suspend polling - * - */ - mmnif->rx_buff->iv_intr = TRUE; - mmnif->stats.pll_empty = 0; -#ifdef DEBUG_MMNIF - DEBUGPRINTF("mmnif_poll(): heuristical interrupts enabled\n"); -#endif - sem_wait(&mmnif->com_poll,0); - } - /* uncomment this to test only polling - */ - // mmnif->stats.pll_empty = 0; - } - - mmnif->stats.pll_empty=0; - mmnif_rx(mmnif_dev); - - } - - return NULL; -} -/* - * Open the interface should be called by kernel to use this network interface - */ -int mmnif_open(void) -{ - struct ip_addr ipaddr; - struct ip_addr netmask; - struct ip_addr gw; - - /* calculate my own ip address from core number - * Note: core 1 is the router core - */ - IP4_ADDR(&gw, 0,0,0,0); - IP4_ADDR(&ipaddr, 192,168,0,RCCE_ue() +1); - IP4_ADDR(&netmask, 255,255,255,0); - - own_ip_address+= RCCE_ue() +1; - - mmnif_dev = kmalloc(sizeof(struct netif)); - - /* register our Memory Mapped Virtual IP interface in the lwip stack - * and tell him how to use the interface: - * - mmnif_dev : the device data storage - * - ipaddr : the ip address wich should be used - * - gw : the gateway wicht should be used - * - mmnif_init : the initialization which has to be done in order to use our interface - * - ethernet_input : tells him that he should get ethernet input (inclusice ARP) - * - * Note: Ethernet Input will be removed because its NOT needed and will - * be replaced with ip_input - */ - if (!netif_add(mmnif_dev, &ipaddr, &netmask, &gw, NULL,(netif_init_fn)mmnif_init, tcpip_input)) - { - DEBUGPRINTF("mmnif_open() : unable to add network interface\n"); - return -1; - } - - /* set our network interface to the default interface for lwip*/ - //netif_set_default(mmnif_dev); - /* tell lwip all initialization is done and we want to set it ab*/ - netif_set_up(mmnif_dev); - - /* test if interface is really up */ - if (!netif_is_up(mmnif_dev)) - { - DEBUGPRINTF("mmnif_open(): network interface is not up\n"); - return -2; - } - - /* indicate that the driver is active now*/ - active = TRUE; - - /* If interrupts are not used we immediately add the polling function - * to the queue which would otherwise be done through the IRQ handler. - */ - mmnif_device_schedule(); - - /* Start the device worker thread wich actually processes the incoming - * packet's this is not done in the "interrupt handler" to shorten them up - */ -// if (!instant_process) -// mmnif_worker_schedule(); - - - // mmnif_retrigger_schedule(); - -#ifdef DEBUG_MMNIF - DEBUGPRINTF("mmnif_dev is open\n"); -#endif - - return 0; - -} - -/* - * close the interface should be called by kernel to close this interface and release resources - * Note: it's temporarly empty. Support will be added. - */ -int mmnif_close(void) -{ - size_t phyaddr; - - mmnif_t* mmnif; - - if (!mmnif_dev) - { - DEBUGPRINTF("mmnif_close(): you closed the device before it was properly opened -.-* \n"); - } - - mmnif = (mmnif_t*)mmnif_dev->state; - /* indicate that the driver is not active anymore - * - this will stop the polling thread i.e. - */ - - active = FALSE; - - kfree(mmnif->tx_buff[0],MMNIF_TX_QUEUELEN * MMNIF_TX_BUFFERLEN); - kfree(mmnif_dev,sizeof(mmnif_t)); - - // determine physical address - phyaddr = virt_to_phys(mpb_start_address); - // unmap shared memory regeion - unmap_region(mpb_start_address, mpb_size >> PAGE_SHIFT); - RCCE_shfree(phyaddr); - - return NULL; -} - -#endif +/* + * Copyright 2011 Carl-Benedikt Krueger, Chair for Operating Systems, + * RWTH Aachen University + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of MetalSVM. + * + * mmnif.c --- memmory mapped interface + * + * Virutal IP Interface for the concept processor SCC + * + */ + +#include + +#if defined(CONFIG_LWIP) && defined(CONFIG_ROCKCREEK) + +#include "mmnif.h" /* definitions */ + +#include /* lwip netif */ +#include /* inteface stats */ +#include /* ethernet arp packets */ +#include /* struct iphdr */ +#include /* tcpip_input() */ +#include + +//#include + +#include /* mailbox_ptr_t */ +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#define TRUE 1 +#define FALSE 0 + +#define DEBUGPRINTF(x,...) LWIP_DEBUGF(NETIF_DEBUG, (x, ##__VA_ARGS__)) + +#define DEBUG_MMNIF +//#define DEBUG_MMNIF_PACKET + +// set to 1 if you want to enable the L1 cache for the receive buffers +#define USE_CACHE 0 + +// set to 1 if you want to use the message passing buffer +#define MMNIF_USE_MPB 0 + +/* Cache line wrappers */ +#define CLINE_SHIFT 5 +#define CLINE_SIZE (1UL << CLINE_SHIFT) +#define CLINE_MASK (~(CLINE_SIZE - 1)) +#define CLINE_ALIGN(_x) (((_x) + CLINE_SIZE - 1) & CLINE_MASK) +//#define CLINE_ALIGN(_x) (_x) + +#define MMNIF_AUTO_SOCKET_TIMEOUT 500 + +#define MMNIF_FAST_SOCKET_BLOCK 1 + +#ifdef DEBUG_MMNIF +#include "util.h" /* hex dump */ +#endif + +/* define constants + * regarding the driver & its configuration + */ + +#define MMNIF_TX_BUFFERLEN 2048 +#define MMNIF_TX_QUEUELEN 4 + +#define MMNIF_RX_BUFFERLEN 7*1024 +#define MMNIF_MAX_DESCRIPTORS 64 + +#define MMNIF_CORES 2 + +#define MMNIF_POLL_BUDGET 0x100000 +#define MMNIF_INTR_BUDGET 0x10 + +#define MMNIF_STATUS_FREE 0x00 +#define MMNIF_STATUS_PENDING 0x01 +#define MMNIF_STATUS_RDY 0x02 +#define MMNIF_STATUS_INPROC 0x03 +#define MMNIF_STATUS_INPROC_BYPASS 0x04 +#define MMNIF_STATUS_PROC 0x05 + +#define MMNIF_MAX_ACCEPTORS 0x20 +#define MMNIF_ACC_STAT_CLOSED 0x00 +#define MMNIF_ACC_STAT_ACCEPTING 0x01 +#define MMNIF_ACC_STAT_ACCEPT_ME 0x02 +#define MMNIF_ACC_STAT_ACCEPTED 0x03 + +#define MMNIF_HASHTABLE_SIZE 0x20 + +#define MMNIF_PSEUDO_SOCKET_START 0x31337 + +static int npseudosocket = MMNIF_PSEUDO_SOCKET_START; +static spinlock_t pseudolock; + +/* IP address of the local core and the router core to get packets forwarded + */ +static unsigned int own_ip_address = 0xC0A80000; /* 192.168.0.0 */ +static unsigned int router_ip_address = 0xC0A80001; /* 192.168.0.1 */ +//static unsigned int budget_overflow_count = 0; + +/* "message passing buffer" specific constants: + * - start address + * - size + */ +static char* header_start_address = NULL; +static unsigned int header_size = 0; +static char* heap_start_address = NULL; +static unsigned int heap_size = 0; + +/* + * the memory mapped network device + */ +static struct netif* mmnif_dev = NULL; + +/* accept struct + */ +typedef struct acceptor { + /* stat: status of the acceptor + * src_ip: where did the connect request came from + * port: port on which the acceptor is listening + * alock : acceptor lock + * nsock : next pseudo socket which is used in further connection + * rsock : remote socket which has to be assosicated with the nsock + */ + uint8_t stat; + uint8_t src_ip; + uint16_t port; + spinlock_t alock; + int nsock; + int rsock; +} acceptor_t; + +/* bypass descriptor struct + */ +typedef struct bypass_rxdesc { + /* socket : hashtarget + * remote_socket: socket on the remote end + * cnt : atomic counter for the recv function + * dest_ip : associated destination ip/core + */ + int socket; + int remote_socket; + sem_t sem; + atomic_int32_t cnt; + uint8_t dest_ip; +} bypass_rxdesc_t; + +/* + */ +static bypass_rxdesc_t mmnif_hashtable[MMNIF_HASHTABLE_SIZE]; +typedef struct mmnif_device_stats { + /* device stats (granularity in packets): + * - recieve errors + * - recieve successes + * - recieved bytes + * - transmit errors + * - transmit successes + * - transmitted bytes + */ + unsigned int rx_err; + unsigned int rx; + unsigned int rx_bytes; + unsigned int tx_err; + unsigned int tx; + unsigned int tx_bytes; + + /* Heuristics : + * - how many times an budget overflow occured + * - how many times the polling thread polled without recieving a new message + */ + unsigned int bdg_overflow; + unsigned int pll_empty; +} mmnif_device_stats_t; + +/* receive descror structure */ +typedef struct rx_desc { + /* stat : status of the descriptor + * len : length of the packet + * addr : memory address of the packet + * fast_sock: (-1) if no socket is associated + * else the socket n of the fast socket + */ + uint8_t stat; + uint16_t len; + uint32_t addr; + uint32_t fast_sock; +} rx_desc_t; + +/* receive ring buffer structure */ +typedef struct mm_rx_buffer { + /* memory "pseudo-ring/heap" + * packets are always in one single chunk of memory + * head : head of allocated memory region + * tail : tail of allocated memory region + */ + uint16_t head; + uint16_t tail; + spinlock_t rlock; + + /* descritpor queue + * desc_table : descriptor table + * dcount : descriptor's free in queue + * dread : next descriptor to read + * dwrite : next descriptor to write + * dlock : lock to protect these members + */ + rx_desc_t desc_table[MMNIF_MAX_DESCRIPTORS]; + uint8_t dcount; + uint8_t dread; + uint8_t dwrite; + spinlock_t dlock; + + /* acceptors + * shared memory "hashtable" to realize + * fast socket accept/connect + */ + acceptor_t acceptors[MMNIF_MAX_ACCEPTORS]; +} mm_rx_buffer_t; + +typedef struct mmnif { + struct mmnif_device_stats stats; + + /* Interface constants: + * - ehternet address + * - local ip address + */ + struct eth_addr *ethaddr; + uint32_t ipaddr; + + // checks the TCPIP thread already the rx buffers? + uint8_t check_in_progress; + + /* memory interaction variables: + * - transmit queue + * - pointer to transmit buffer + * - pointer to recive buffer + */ + uint8_t tx_queue; + uint8_t *tx_buff[MMNIF_TX_QUEUELEN]; + mm_rx_buffer_t *rx_buff; + uint8_t *rx_heap; + + /* lock to protect members + */ + spinlock_t lock; + + /* semaphore to regulate polling vs. interrupts + */ + sem_t com_poll; +} mmnif_t; + +/* + * memory maped interface helper functions + */ + +/* trigger an interrupt on the remote processor + * so he knows there is a packet to read + */ +inline static int mmnif_trigger_irq(dest_ip) +{ + int tmp, x, y, z, addr; + int ue = dest_ip - 1; + z = Z_PID(RC_COREID[ue]); + x = X_PID(RC_COREID[ue]); + y = Y_PID(RC_COREID[ue]); + addr = CRB_ADDR(x, y) + (z == 0 ? GLCFG0 : GLCFG1); + + // send interrupt to ue + do { + NOP1; + tmp = ReadConfigReg(addr); + } + while (tmp & 2); + tmp |= 2; + SetConfigReg(addr, tmp); + return 0; +} + +/* mmnif_get_device_stats(): Returns a copy of the + * current device + */ +static mmnif_device_stats_t mmnif_get_device_stats(void) +{ + mmnif_device_stats_t stats = { 0 }; + + if (!mmnif_dev) + DEBUGPRINTF("mmnif_get_device_stats(): the device is not initialized yet.\n"); + else + stats = ((mmnif_t *) mmnif_dev->state)->stats; + + return stats; +} + +/* mmnif_print_stats(): Print the devices stats of the + * current device + */ +static void mmnif_print_stats(void) +{ + mmnif_t *mmnif; + + if (!mmnif_dev) + { + DEBUGPRINTF + ("mmnif_print_stats(): the device is not initialized yet.\n"); + return; + } + + mmnif = (mmnif_t *) mmnif_dev->state; + DEBUGPRINTF("/dev/mmnif - stats:\n"); + DEBUGPRINTF("Received: %d packets successfull\n", mmnif->stats.rx); + DEBUGPRINTF("Received: %d bytes\n", mmnif->stats.rx_bytes); + DEBUGPRINTF("Received: %d packets containuing errors\n", mmnif->stats.rx_err); + DEBUGPRINTF("Transmitted: %d packests successfull\n", mmnif->stats.tx); + DEBUGPRINTF("Transmitted: %d bytes\n", mmnif->stats.tx_bytes); + DEBUGPRINTF("Transmitted: %d packests were dropped due to errors\n", mmnif->stats.tx_err); +} + +/* mmnif_print_driver_status + * + */ +void mmnif_print_driver_status(void) +{ + mmnif_t *mmnif; + int i; + + if (!mmnif_dev) + { + DEBUGPRINTF("mmnif_print_driver_status(): the device is not initialized yet.\n"); + return; + } + + mmnif = (mmnif_t *) mmnif_dev->state; + DEBUGPRINTF("/dev/mmnif driver status: \n\n"); + DEBUGPRINTF("rx_buf: 0xp\n", mmnif->rx_buff); + DEBUGPRINTF("free descriptors : %d\n\n", mmnif->rx_buff->dcount); + DEBUGPRINTF("descriptor table: (only print descriptors in use)\n"); + DEBUGPRINTF("status\taddr\tsize\n"); + + for (i = 0; i < MMNIF_MAX_DESCRIPTORS; i++) + { + if (mmnif->rx_buff->desc_table[i].stat != 0) + DEBUGPRINTF("0x%.2X\t%p\t%X\t\n", + mmnif->rx_buff->desc_table[i].stat, + mmnif->rx_buff->desc_table[i].addr, + mmnif->rx_buff->desc_table[i].len); + } + + DEBUGPRINTF("ring heap start addr: %p\n", mmnif->rx_buff + sizeof(mm_rx_buffer_t)); + DEBUGPRINTF("head: 0x%X\ttail: 0x%X\n", mmnif->rx_buff->head, mmnif->rx_buff->tail); + mmnif_print_stats(); +} + +/* + * memory maped interface main functions + */ + +/* mmnif_get_destination(): low level transmid helper function + * this function deals with some HW details, it checks to wich core this packet + * should be routed and returns the destination + */ +static uint8_t mmnif_get_destination(struct netif *netif, struct pbuf *p) +{ + struct ip_hdr *iphdr; + uint8_t core; + uint8_t *ip4addr; + uint8_t addr[4]; + uint32_t netmask = 0xFFFFFF00; + + /* grab the destination ip address out of the ip header + * for internal routing the last ocet is interpreted as core ID. + */ + iphdr = (struct ip_hdr *)(p->payload); + ip4addr = (uint8_t*) &iphdr->dest.addr; + + /* revert the address to host format */ + addr[3] = ip4addr[0]; + addr[2] = ip4addr[1]; + addr[1] = ip4addr[2]; + addr[0] = ip4addr[3]; + + /* check if the ip address is in the Local Area Network of the 48 cores */ + + /* if it's not the same network the router core is addressed + * Note: the router core is core 1 + */ + if (!((netmask & *(uint32_t *) addr) == (netmask & own_ip_address))) + return 1; + core = addr[0]; + + /* check if the address is legitimata else return router core again */ + if ((core) < 1 || (core > MMNIF_CORES)) + core = 1; + return core; +} + +/* mmnif_rxbuff_alloc(): + * this function allocates a continues chunk of memory + * right inside of the buffer which is used for communication + * with the remote end + */ +static uint32_t mmnif_rxbuff_alloc(uint8_t dest, uint16_t len) +{ + uint32_t ret; + mm_rx_buffer_t *rb = (mm_rx_buffer_t *) ((char *)header_start_address + (dest - 1) * header_size); + +#if MMNIF_USE_MPB + char *memblock = (char *)heap_start_address + (dest - 1) * 0x2000; +#else + char *memblock = (char *)heap_start_address + (dest - 1) * heap_size; +#endif + +// if (rb->tail > rb->head) +// if ((MMNIF_RX_BUFFERLEN - rb->tail < len)&&(rb->head < len)) +// return NULL; +// else +// if ((rb->head - rb->tail < len)&&(rb->tail != rb->head)) +// return NULL; + + spinlock_lock(&rb->dlock); + if (rb->dcount) + { + if (rb->tail > rb->head) + { + if (MMNIF_RX_BUFFERLEN - rb->tail > len) + { + rb->desc_table[rb->dwrite].stat = MMNIF_STATUS_PENDING; + ret = (uint32_t) (memblock + rb->tail); + rb->desc_table[rb->dwrite].addr = ret; + rb->desc_table[rb->dwrite].len = len; + rb->dcount--; + rb->dwrite = (rb->dwrite + 1) % MMNIF_MAX_DESCRIPTORS; + rb->tail = (rb->tail + len); + spinlock_unlock(&rb->dlock); + return ret; + } else if (rb->head > len) { + rb->desc_table[rb->dwrite].stat = MMNIF_STATUS_PENDING; + ret = (uint32_t) memblock; + rb->desc_table[rb->dwrite].addr = ret; + rb->desc_table[rb->dwrite].len = len; + rb->dcount--; + rb->dwrite = (rb->dwrite + 1) % MMNIF_MAX_DESCRIPTORS; + rb->tail = len; + spinlock_unlock(&rb->dlock); + return ret; + } else { + spinlock_unlock(&rb->dlock); + return 0; + } + } else { + if (rb->head - rb->tail > len) + { + rb->desc_table[rb->dwrite].stat = MMNIF_STATUS_PENDING; + ret = (uint32_t) (memblock + rb->tail); + rb->desc_table[rb->dwrite].addr = ret; + rb->desc_table[rb->dwrite].len = len; + rb->dcount--; + rb->dwrite = (rb->dwrite + 1) % MMNIF_MAX_DESCRIPTORS; + rb->tail = (rb->tail + len); + spinlock_unlock(&rb->dlock); + return ret; + } else if (rb->tail == rb->head) { + if (MMNIF_RX_BUFFERLEN - rb->tail < len) + { + rb->tail = 0; + if (rb->dread == rb->dwrite) + rb->head = 0; + } + rb->desc_table[rb->dwrite].stat = MMNIF_STATUS_PENDING; + ret = (uint32_t) (memblock + rb->tail); + rb->desc_table[rb->dwrite].addr = ret; + rb->desc_table[rb->dwrite].len = len; + rb->dcount--; + rb->dwrite = (rb->dwrite + 1) % MMNIF_MAX_DESCRIPTORS; + rb->tail = (rb->tail + len); + spinlock_unlock(&rb->dlock); + return ret; + } else { + spinlock_unlock(&rb->dlock); + return 0; + } + } + } else { + spinlock_unlock(&rb->dlock); + return 0; + } +} + +/* mmnif_commit_packet: this function set the state of the (in advance) + * allocated packet to RDY so the recieve queue knows that it can be + * processed further + */ +static int mmnif_commit_packet(uint8_t dest, uint32_t addr) +{ + mm_rx_buffer_t *rb = (mm_rx_buffer_t *) ((char *)header_start_address + (dest - 1) * header_size); + uint32_t i; + + for (i = 0; i < MMNIF_MAX_DESCRIPTORS; i++) + { + if (rb->desc_table[i].addr == addr + && rb->desc_table[i].stat == MMNIF_STATUS_PENDING) + { + rb->desc_table[i].stat = MMNIF_STATUS_RDY; + rb->desc_table[i].fast_sock = -1; + return 0; + } + } + + return -1; +} + +/* mmnif_commit_packet: this function set the state of the (in advance) + * allocated packet to RDY so the recieve queue knows that it can be + * processed further + */ +static int mmnif_commit_packet_bypass(uint8_t dest, uint32_t addr, int dest_socket) +{ + mm_rx_buffer_t* rb = (mm_rx_buffer_t *) ((char *)header_start_address + (dest - 1) * header_size); + uint32_t i; + + for (i = 0; i < MMNIF_MAX_DESCRIPTORS; i++) + { + if (rb->desc_table[i].addr == addr + && rb->desc_table[i].stat == MMNIF_STATUS_PENDING) + { + rb->desc_table[i].stat = MMNIF_STATUS_RDY; + rb->desc_table[i].fast_sock = dest_socket; + return 0; + } + } + + return -1; +} + +/* mmnif_rxbuff_free() : the opposite to mmnif_rxbuff_alloc() a from the receiver + * already processed chunk of memory is freed so that it can be allocated again + */ +static void mmnif_rxbuff_free(void) +{ + mmnif_t *mmnif = mmnif_dev->state; + mm_rx_buffer_t *b = mmnif->rx_buff; + uint32_t i, j; + uint32_t rpos; + + spinlock_lock(&b->dlock); + rpos = b->dread; + + for (i = 0, j = rpos; i < MMNIF_MAX_DESCRIPTORS; i++) + { + j = (j + i) % MMNIF_MAX_DESCRIPTORS; + if (b->desc_table[j].stat == MMNIF_STATUS_PROC) + { + b->dcount++; + b->dread = (b->dread + 1) % MMNIF_MAX_DESCRIPTORS; + b->desc_table[j].stat = MMNIF_STATUS_FREE; + if (b->tail > b->head) + { + b->head += b->desc_table[j].len; + } else { + if ((b->desc_table[(j + 1) % MMNIF_MAX_DESCRIPTORS].stat != MMNIF_STATUS_FREE) + && (b->desc_table[j].addr > b->desc_table[(j + 1) % MMNIF_MAX_DESCRIPTORS].addr)) + { + b->head = 0; + } else { + b->head += b->desc_table[j].len; + } + } + } else + break; + } + spinlock_unlock(&b->dlock); +} + +/* + * Transmid a packet (called by the lwip) + */ +static err_t mmnif_tx(struct netif *netif, struct pbuf *p) +{ + mmnif_t *mmnif = netif->state; + uint8_t slot = mmnif->tx_queue; + uint32_t write_address; + uint32_t i; + struct pbuf *q; /* interator */ + uint8_t build_buff = TRUE; + uint32_t dest_ip = mmnif_get_destination(netif, p); + //uint8_t chances = 20; + //mm_rx_buffer_t *rb = (mm_rx_buffer_t *) ((char *)header_start_address + (dest_ip - 1) * header_size); + + spinlock_lock(&mmnif->lock); + mmnif->tx_queue++; + spinlock_unlock(&mmnif->lock); + + /* Perform serveral sanity checks on the packet and the buffers: + * - is the queue full? + * - is the output packet to big? + */ + if (mmnif->tx_queue > MMNIF_TX_QUEUELEN) + { + DEBUGPRINTF("mmnif_tx(): too many packets at once for tx_queue\n"); + goto drop_packet; + } + + if (p->tot_len > MMNIF_TX_BUFFERLEN) + { + DEBUGPRINTF("mmnif_tx(): packet is longer than %d bytes\n", MMNIF_TX_BUFFERLEN); + goto drop_packet; + } + + /* check if the pbuf consists only of one element + * if that is the case it would be much overhead + * copying that packet again + */ + if (!p->next) + build_buff = FALSE; + + if (build_buff) + { + + /* build the payload out of the p's + * ensure that the packet is in one memory chunk stored in the transmid buffer + */ + for (q = p, i = 0; q != 0; q = q->next) + { + memcpy(mmnif->tx_buff[slot] + i, q->payload, q->len); + i += q->len; + } + } + + /* allocate memory for the packet in the remote buffer */ +realloc: + write_address = mmnif_rxbuff_alloc(dest_ip, CLINE_ALIGN(p->tot_len)); + if (!write_address) + { + +// DEBUGPRINTF("mmnif_tx(): concurrency"); + +// if (!chances) +// goto drop_packet; + +// chances--; +// // udelay(exp_delay); +// // exp_delay << 1; +// // reschedule(); +// // NOP8;NOP8;NOP8;NOP8;NOP8;NOP8;NOP8;NOP8; +// udelay(20000); +// mmnif_trigger_irq(dest_ip); + goto realloc; + } + + if (!write_address) + goto drop_packet; + + /* write buffer to buffer & increment the queued packet count + * this can be safely done without locking because this place is + * reserved for us because it has the status "pending" + */ + +#if MMNIF_USE_MPB + asm volatile (".byte 0x0f; .byte 0x0a;\n"); + +#endif + if (build_buff) +#if MMNIF_USE_MPB + memcpy_put(write_address, mmnif->tx_buff[slot], CLINE_ALIGN(p->tot_len)); +#else + memcpy((void*)write_address, mmnif->tx_buff[slot], CLINE_ALIGN(p->tot_len)); +#endif + else +#if MMNIF_USE_MPB + memcpy_put(write_address, p->payload, CLINE_ALIGN(p->tot_len)); +#else + memcpy((void*)write_address, p->payload, CLINE_ALIGN(p->tot_len)); +#endif + + *((int *)RCCE_fool_write_combine_buffer) = 1; +#if USE_CACHE +#if MMNIF_USE_MPB + asm volatile (".byte 0x0f; .byte 0x0a;\n"); +#endif +#endif + if (mmnif_commit_packet(dest_ip, write_address)) + { + DEBUGPRINTF("mmnif_tx(): packet somehow lost during commit\n"); + } + +#ifdef DEBUG_MMNIF_PACKET +// DEBUGPRINTF("\n SEND %p with length: %d\n",(char*)heap_start_address + (dest_ip -1)*mpb_size + pos * 1792,p->tot_len +2); +// hex_dump(p->tot_len, p->payload); +#endif + + /* release the tx_queue because it's finished */ + spinlock_lock(&mmnif->lock); + mmnif->tx_queue--; + spinlock_unlock(&mmnif->lock); + + /* just gather some stats */ + LINK_STATS_INC(link.xmit); + mmnif->stats.tx++; + mmnif->stats.tx_bytes += p->tot_len; + mmnif_trigger_irq(dest_ip); + + return ERR_OK; + +drop_packet: + /* drop packet for one or another reason + */ +#ifdef DEBUG_MMNIF + DEBUGPRINTF("mmnif_tx(): packet dropped"); +#endif + + spinlock_lock(&mmnif->lock); + mmnif->tx_queue--; + spinlock_unlock(&mmnif->lock); + LINK_STATS_INC(link.drop); + mmnif->stats.tx_err++; + + return ERR_IF; +} + +/* mmnif_hashlookup(): looks up a bypass descriptor by + * the associated socket + */ +static bypass_rxdesc_t *mmnif_hashlookup(int s) +{ + int i; + bypass_rxdesc_t *p; + + for (i=0, p = &mmnif_hashtable[s % MMNIF_HASHTABLE_SIZE]; isocket == s) + return p; + p = &mmnif_hashtable[(s + i + 1) % MMNIF_HASHTABLE_SIZE]; + } + + return 0; +} + +/* mmnif_hashadd(): adds a entry to the hashtable + * by the socket + */ +static int mmnif_hashadd(int sock, int rsock, uint8_t dest_ip) +{ + bypass_rxdesc_t *p; + int i; + + p = mmnif_hashlookup(sock); + if (p != 0) + return -1; + + for (i = 0; i < MMNIF_HASHTABLE_SIZE; i++) + { + p = &mmnif_hashtable[(sock + i) % MMNIF_HASHTABLE_SIZE]; + if (p->socket == -1) + { + p->socket = sock; + p->remote_socket = rsock; + p->dest_ip = dest_ip; + return 0; + } + } + + return -1; +} + +/* mmnif_hashdelete(): deletes an entry from the + * hashtable + */ +static int mmnif_hashdelete(int sock) +{ + bypass_rxdesc_t *p; + int i; + + p = mmnif_hashlookup(sock); + if (p != 0) + return -1; + + for (i = 0; i < MMNIF_HASHTABLE_SIZE; i++) + { + p = &mmnif_hashtable[(sock + i) % MMNIF_HASHTABLE_SIZE]; + if (p->socket == sock) + { + p->socket = -1; + p->remote_socket = 0; + p->dest_ip = 0; + return 0; + } + } + + return -1; +} + +/* + * Transmid a packet (with insane speed) + */ +static err_t mmnif_tx_bypass(struct netif * netif, void *pbuff, uint16_t size, int s) +{ + mmnif_t *mmnif = netif->state; + uint32_t write_address; + bypass_rxdesc_t *dest = mmnif_hashlookup(s); + //uint32_t exp_delay = 2; + //mm_rx_buffer_t *rb = (mm_rx_buffer_t *) ((char *)header_start_address + (dest->dest_ip - 1) * header_size); + + /* Perform serveral sanity checks on the packet and the buffers: + * - is the output packet to big? + */ + +// if (size > MMNIF_TX_BUFFERLEN) +// { +// DEBUGPRINTF("mmnif_tx(): packet is longer than %d bytes\n",MMNIF_TX_BUFFERLEN); +// goto drop_packet; +// } + + /* allocate memory for the packet in the remote buffer */ +realloc: + write_address = mmnif_rxbuff_alloc(dest->dest_ip, CLINE_ALIGN(size)); + if (!write_address) + { + + // DEBUGPRINTF("mmnif_tx_bypass(): concurrency"); + // udelay(exp_delay); + // exp_delay << 1; + // reschedule(); + NOP8; + NOP8; + NOP8; + NOP8; + NOP8; + NOP8; + NOP8; + NOP8; + goto realloc; + } + + /* write buffer to buffer & increment the queued packet count + * this can be safely done without locking because this place is + * reserved for us because it has the status "pending" + */ + +#if MMNIF_USE_MPB + asm volatile (".byte 0x0f; .byte 0x0a;\n"); +#endif + +#if MMNIF_USE_MPB + memcpy_put(write_address, pbuff, CLINE_ALIGN(size)); +#else + memcpy((void*) write_address, pbuff, CLINE_ALIGN(size)); +#endif + *((int *)RCCE_fool_write_combine_buffer) = 1; + +#if USE_CACHE +#if MMNIF_USE_MPB + asm volatile (".byte 0x0f; .byte 0x0a;\n"); +#endif +#endif + if (mmnif_commit_packet_bypass(dest->dest_ip, write_address, dest->remote_socket)) + { + DEBUGPRINTF("mmnif_tx(): packet somehow lost during commit\n"); + } +#ifdef DEBUG_MMNIF_PACKET + // DEBUGPRINTF("\n SEND %p with length: %d\n",(char*)mpb_start_address + (dest_ip -1)*mpb_size + pos * 1792,p->tot_len +2); + // hex_dump(p->tot_len, p->payload); +#endif + + /* just gather some stats */ + LINK_STATS_INC(link.xmit); + mmnif->stats.tx++; + mmnif->stats.tx_bytes += size; + mmnif_trigger_irq(dest->dest_ip); + return ERR_OK; + +drop_packet: + /* drop packet for one or another reason + */ + LINK_STATS_INC(link.drop); + mmnif->stats.tx_err++; + return ERR_IF; +} + +/* mmnif_send(): is going to be used as replacement of + * lwip_send with fast_sockets + */ +int mmnif_send(int s, void *data, size_t size, int flags) +{ + bypass_rxdesc_t *p = mmnif_hashlookup(s); + uint32_t i, j, k, ret; + + if (p != 0) + { + if (size < ((MMNIF_RX_BUFFERLEN / 2) - 1)) + return mmnif_tx_bypass(mmnif_dev, data, size, s); + + else + { + j = size / (((MMNIF_RX_BUFFERLEN / 2) - 1)); + k = size - (j * (((MMNIF_RX_BUFFERLEN / 2) - 1))); + + for (i = 0; i < j; i++) + { + ret = mmnif_tx_bypass(mmnif_dev, data + i * ((MMNIF_RX_BUFFERLEN / 2) - 1), ((MMNIF_RX_BUFFERLEN / 2) - 1), s); + + if (ret < 0) + return ret; + } + ret = mmnif_tx_bypass(mmnif_dev, data + (j - 1) * ((MMNIF_RX_BUFFERLEN / 2) - 1), k, s); + return ret; + } + } + + return lwip_send(s, data, size, flags); +} + +/* mmnif_link_layer(): wrapper function called by ip_output() + * adding all needed headers for the link layer + * because we have no link layer and everything is reliable we don't need + * to add anything so we just pass it to our tx function + */ +static err_t +mmnif_link_layer(struct netif *netif, struct pbuf *q, ip_addr_t * ipaddr) +{ + return netif->linkoutput(netif, q); +} + +/* + * Init the device (called from lwip) + * It's invoked in netif_add + */ +err_t mmnif_init(struct netif *netif) +{ + mmnif_t *mmnif; + uint32_t i; + int num = 0; + //int tmp1, tmp2, n; + +#ifdef DEBUG_MMNIF + DEBUGPRINTF("mmnif init attempt\n"); +#endif + + mmnif_dev = netif; + own_ip_address += RCCE_ue() + 1; + + /* Alloc and clear memory for the device struct + */ + mmnif = kmalloc(sizeof(mmnif_t)); + if (!mmnif) + { + DEBUGPRINTF("mmnif init():out of memory\n"); + return ERR_MEM; + } + memset(mmnif, 0x00, sizeof(mmnif_t)); + + /* Alloc and clear shared memory for rx_buff + */ + header_size = (sizeof(mm_rx_buffer_t)); + DEBUGPRINTF("mmnif_init() : size of mm_rx_buffer_t : %d\n", sizeof(mm_rx_buffer_t)); + + // align mpb size to the granularity of a page size + header_size = (header_size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); + header_start_address = (void*) RCCE_shmalloc(header_size * MMNIF_CORES); + DEBUGPRINTF("RCCE_shmalloc : %p\n", header_start_address); + + // map physical address in the virtual address space + header_start_address = (void*) map_region(0, (size_t) header_start_address, (MMNIF_CORES * header_size) >> PAGE_SHIFT, MAP_KERNEL_SPACE | MAP_NO_CACHE); + DEBUGPRINTF("map_region : %p\n", header_start_address); + mmnif->rx_buff = (mm_rx_buffer_t *) (header_start_address + (header_size) * (own_ip_address - router_ip_address)); + + /* Alloc and clear shared memory for rx_buff + */ + heap_size = (MMNIF_RX_BUFFERLEN); + + // align mpb size to the granularity of a page size + heap_size = (heap_size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); + +#if MMNIF_USE_MPB + heap_start_address = RCCE_malloc(RCCE_LINE_SIZE); + DEBUGPRINTF("MessagePassingBuffer allocated @ : %p\n", heap_start_address); + for (i = heap_size / RCCE_LINE_SIZE; i > 0; i--) + { + if (!RCCE_malloc(RCCE_LINE_SIZE)) + { + //DEBUGPRINTF("mmnif init(): allocating shared memory failed\n"); + //return ERR_MEM; + } + } + +#else + heap_start_address = (void*) RCCE_shmalloc(heap_size * MMNIF_CORES); + DEBUGPRINTF("RCCE_shmalloc : %p\n", header_start_address); + + // map physical address in the virtual address space +#if USE_CACHE + //heap_start_address = map_region(0, heap_start_address, (MMNIF_CORES*heap_size) >> PAGE_SHIFT, MAP_KERNEL_SPACE|MAP_MPE); + heap_start_address = map_region(0, heap_start_address, (MMNIF_CORES * heap_size) >> PAGE_SHIFT, MAP_KERNEL_SPACE | MAP_NO_CACHE | MAP_MPE); + remap_region(heap_start_address + (heap_size) * (own_ip_address - router_ip_address), n + (heap_size) * (own_ip_address - router_ip_address), 1, MAP_KERNEL_SPACE | MAP_MPE); +#else + heap_start_address = (void*) map_region(0, (size_t) heap_start_address, (MMNIF_CORES * heap_size) >> PAGE_SHIFT, MAP_KERNEL_SPACE | MAP_NO_CACHE | MAP_MPE); +#endif // USE_CAHCE +#endif // MMNIF_USE_MPB + DEBUGPRINTF("map_region : %p\n", header_start_address); + +#if MMNIF_USE_MPB + mmnif->rx_heap = heap_start_address; + heap_start_address = heap_start_address - (own_ip_address - router_ip_address) * 0x2000; + DEBUGPRINTF("heap_start_address : %p\n", heap_start_address); + +// heap_start_address = 0xC0000000; +// mmnif->rx_heap = heap_start_address + (heap_size) * (own_ip_address - router_ip_address); +#else + mmnif->rx_heap = heap_start_address + (heap_size) * (own_ip_address - router_ip_address); +#endif + + if (!(heap_start_address)) + { + DEBUGPRINTF("mmnif init(): allocating shared memory failed\n"); + return ERR_MEM; + } + memset(mmnif->rx_buff, 0x00, header_size); + memset(mmnif->rx_heap, 0x00, heap_size); + + *((int *)RCCE_fool_write_combine_buffer) = 1; +#if USE_CACHE + asm volatile (".byte 0x0f; .byte 0x0a;\n"); +#endif + +#if 0 + if (own_ip_address == router_ip_address) + { + kprintf("Test0: MEMCPY 2048B"); + tmp1 = get_clock_tick(); + for (n = 0; n < 4096; n++) + { + memcpy(mmnif->rx_heap + heap_size, mmnif->rx_heap, 2048); + + *((int *)RCCE_fool_write_combine_buffer) = 1; +#if USE_CACHE + asm volatile (".byte 0x0f; .byte 0x0a;\n"); +#endif + memcpy(mmnif->rx_heap, mmnif->rx_heap, 2048); + } tmp2 = get_clock_tick(); + kprintf("memcpy'd' %d bytes in %d ticks\n", n * 2048, (tmp2 - tmp1)); + } +#endif + + /* set initial values + */ + mmnif->rx_buff->dcount = MMNIF_MAX_DESCRIPTORS; + + /* init the lock's for the hdr + */ + spinlock_init(&mmnif->rx_buff->rlock); + spinlock_init(&mmnif->rx_buff->dlock); + spinlock_init(&pseudolock); + spinlock_init(&mmnif->lock); + + /* init the sems for communication art + */ + sem_init(&mmnif->com_poll, 0); + + /* Alloc and clear internal memory for tx_buff + */ + mmnif->tx_buff[0] = kmalloc(MMNIF_TX_QUEUELEN * MMNIF_TX_BUFFERLEN); + if (!(mmnif->tx_buff[0])) + { + DEBUGPRINTF("mmnif init: out of memory tx\n"); + return ERR_MEM; + } + mmnif->tx_queue = 0; + memset(mmnif->tx_buff[0], 0x00, MMNIF_TX_QUEUELEN * MMNIF_TX_BUFFERLEN); + + for (i=0; itx_buff[i + 1] = mmnif->tx_buff[i] + MMNIF_TX_BUFFERLEN; + + for (i=0; irx_buff->acceptors[i].stat = MMNIF_ACC_STAT_CLOSED; + mmnif->rx_buff->acceptors[i].nsock = -1; + mmnif->rx_buff->acceptors[i].rsock = -1; + mmnif->rx_buff->acceptors[i].src_ip = 0; + mmnif->rx_buff->acceptors[i].port = 0; + spinlock_init(&mmnif->rx_buff->acceptors[i].alock); + spinlock_lock(&mmnif->rx_buff->acceptors[i].alock); + spinlock_unlock(&mmnif->rx_buff->acceptors[i].alock); + } + + /* pass the device state to lwip */ + netif->state = mmnif; + mmnif_dev = netif; + + /* administrative details */ + netif->name[0] = 'm'; + netif->name[1] = 'm'; + netif->num = num; + num++; + + /* downward functions */ + netif->output = mmnif_link_layer; + + /* there is no special link layer just the ip layer */ + netif->linkoutput = mmnif_tx; + + /* maximum transfer unit */ + netif->mtu = MMNIF_TX_BUFFERLEN; + + /* broadcast capability, keep all default flags */ + netif->flags |= NETIF_FLAG_BROADCAST; + + /* hardware address length */ + netif->hwaddr_len = 0; + +#ifdef DEBUG_MMNIF + DEBUGPRINTF("mmnif init complete\n"); +#endif + + return ERR_OK; +} + +/* + * Receive a packet : recieve, pack it up and pass over to higher levels + */ +static void mmnif_rx(struct netif *netif) +{ + mmnif_t *mmnif = netif->state; + mm_rx_buffer_t *b = mmnif->rx_buff; + uint16_t length = 0; + struct pbuf *p; + struct pbuf *q; + char *packet = NULL; + uint32_t i, j; + uint8_t rdesc; + err_t err = ERR_OK; + bypass_rxdesc_t *bp; + +anotherpacket: + rdesc = 0xFF; + spinlock_lock(&b->rlock); + + /* check if this call to mmnif_rx makes any sense + */ + if (b->desc_table[b->dread].stat == MMNIF_STATUS_FREE) + { + spinlock_unlock(&b->rlock); + goto out; + } + + /* search the packet whose transmission is finished + */ + for (i = 0, j = b->dread; i < MMNIF_MAX_DESCRIPTORS; i++) + { + if (b->desc_table[(j + i) % MMNIF_MAX_DESCRIPTORS].stat == MMNIF_STATUS_RDY) + { + rdesc = (j + i) % MMNIF_MAX_DESCRIPTORS; + if (b->desc_table[(j + i) % MMNIF_MAX_DESCRIPTORS].fast_sock == -1) + { + b->desc_table[rdesc].stat = MMNIF_STATUS_INPROC; + packet = (char *)b->desc_table[rdesc].addr; + length = b->desc_table[rdesc].len; + break; + } else { + bp = mmnif_hashlookup(b->desc_table[rdesc].fast_sock); + if (!bp) + { + DEBUGPRINTF("mmnif_rx(): no fast socket associated with %d", b->desc_table[rdesc].fast_sock); + mmnif->rx_buff->desc_table[rdesc].stat = MMNIF_STATUS_PROC; + mmnif_rxbuff_free(); + } else { + b->desc_table[rdesc].stat = MMNIF_STATUS_INPROC; +#if MMNIF_FAST_SOCKET_BLOCK + sem_post(&bp->sem); +#else + atomic_int32_inc(&bp->cnt); +#endif + } + spinlock_unlock(&b->rlock); + goto out; + } + } + + if (b->desc_table[(j + i) % MMNIF_MAX_DESCRIPTORS].stat == MMNIF_STATUS_FREE) + { + spinlock_unlock(&b->rlock); + goto out; + } + } + spinlock_unlock(&b->rlock); + + /* if there is no packet finished we encountered a random error + */ + if (rdesc == 0xFF) + goto out; + + /* If length is zero return silently + */ + if (length == 0) + { + DEBUGPRINTF("mmnif_rx(): empty packet error\n"); + goto out; + } + + if (length < sizeof(struct ip_hdr) || length > netif->mtu) + { + DEBUGPRINTF("mmnif_rx(): illegal packet length %d => drop the packet\n", length); + goto drop_packet; + } + + /* From now on there is a real packet and it + * has to be worked on + */ +#ifdef DEBUG_MMNIF_PACKET + DEBUGPRINTF("\n RECIEVED - %p with legth: %d\n", packet, length); + hex_dump(length, packet); +#endif + + /* Build the pbuf for the packet so the lwip + * and other higher layer can handle it + */ + p = pbuf_alloc(PBUF_RAW, length, PBUF_POOL); + if (!p) + { + DEBUGPRINTF("mmnif_rx(): low on mem - packet dropped\n"); + goto drop_packet; + } + +#if USE_CACHE + asm volatile (".byte 0x0f; .byte 0x0a;\n"); +#endif + + /* copy packet to pbuf structure going through linked list */ + for (q = p, i = 0; q != NULL; q = q->next) + { +#if MMNIF_USE_MPB + memcpy_get((uint8_t *) q->payload, &packet[i], q->len); +#else + memcpy((uint8_t *) q->payload, &packet[i], q->len); +#endif + i += q->len; + } + + /* indicate that the copy process is done and the packet can be freed + * note that we did not lock here because we are the only one editing this value + */ + mmnif->rx_buff->desc_table[rdesc].stat = MMNIF_STATUS_PROC; + + /* everything is copied to a new buffer so it's save to release + * the old one for new incoming packets + */ + mmnif_rxbuff_free(); + + /* + * This function is called in the context of the tcpip thread. + * Therefore, we are able to call directly the input functions. + */ + if ((err = ip_input(p, mmnif_dev)) != ERR_OK) + { + DEBUGPRINTF("mmnif_rx: IP input error\n"); + pbuf_free(p); + } + + /* gather some stats and leave the rx handler */ + LINK_STATS_INC(link.xmit); + mmnif->stats.rx++; + mmnif->stats.rx_bytes += p->tot_len; + goto anotherpacket; + +drop_packet: + spinlock_lock(&mmnif->rx_buff->rlock); + + /*error handling */ + spinlock_unlock(&mmnif->rx_buff->rlock); + LINK_STATS_INC(link.drop); + mmnif->stats.rx_err++; + +out: + mmnif->check_in_progress = 0; + return; +} + +/* mmnif_rx_bypass(): recieve packets + * with insane speed ;) + */ +static int mmnif_rx_bypass(struct netif *netif, int s, void *data, uint32_t len) +{ + mmnif_t *mmnif = netif->state; + mm_rx_buffer_t *b = mmnif->rx_buff; + uint16_t length; + char *packet; + uint32_t i, j; + uint8_t rdesc = 0xFF; + + // spinlock_lock(&b->rlock); + + /* check if this call to mmnif_rx makes any sense + */ + if (b->desc_table[b->dread].stat == MMNIF_STATUS_FREE) + { + + // spinlock_unlock(&b->rlock); + return -1; + } + + /* search the packet whose transmission is finished + */ + for (i = 0, j = b->dread; i < MMNIF_MAX_DESCRIPTORS; i++) + { + if (b->desc_table[(j + i) % MMNIF_MAX_DESCRIPTORS].stat == MMNIF_STATUS_INPROC + && b->desc_table[(j + i) % MMNIF_MAX_DESCRIPTORS].fast_sock != -1) + { + rdesc = (j + i) % MMNIF_MAX_DESCRIPTORS; + packet = (char *)b->desc_table[rdesc].addr; + length = b->desc_table[rdesc].len; + b->desc_table[rdesc].stat = MMNIF_STATUS_INPROC_BYPASS; + break; + } + } + + // spinlock_unlock(&b->rlock); + + /* if there is no packet finished we encountered a random error + */ + if (rdesc == 0xFF) + { + return -1; + } + + /* If length is zero return silently + */ + if (length == 0) + { + DEBUGPRINTF("mmnif_rx(): empty packet error\n"); + return -1; + } + + /* From now on there is a real packet and it + * has to be worked on + */ + +#ifdef DEBUG_MMNIF_PACKET + DEBUGPRINTF("\n RECIEVED - %p with legth: %d\n", packet, length); + hex_dump(length, packet); + +#endif /* */ + if (len >= length) + memcpy(data, (void*) mmnif->rx_buff->desc_table[rdesc].addr, mmnif->rx_buff->desc_table[rdesc].len); + + else + goto drop_packet; + + /* indicate that the copy process is done and the packet can be freed + * note that we did not lock here because we are the only one editing this value + */ + b->desc_table[rdesc].stat = MMNIF_STATUS_PROC; + + /* everything is copied to a new buffer so it's save to release + * the old one for new incoming packets + */ + mmnif_rxbuff_free(); + + /* gather some stats and leave the rx handler */ + LINK_STATS_INC(link.xmit); + mmnif->stats.rx++; + mmnif->stats.rx_bytes += length; + + return length; + +drop_packet: + spinlock_lock(&mmnif->rx_buff->rlock); + + /*error handling */ + spinlock_unlock(&mmnif->rx_buff->rlock); + LINK_STATS_INC(link.drop); + mmnif->stats.rx_err++; + + return -1; +} + +/* mmnif_recv(): replacement of lwip_recv + * for fast sockets + */ +int mmnif_recv(int s, void *data, uint32_t len, int flags) +{ + bypass_rxdesc_t *p = mmnif_hashlookup(s); + int ret; + + if (p == 0) + return lwip_recv(s, data, len, flags); + +#if MMNIF_FAST_SOCKET_BLOCK + sem_wait(&p->sem, 0); +#else + while (!atomic_int32_read(&p->cnt)) + { + + //reschedule(); + NOP8; + } + +#endif + + ret = mmnif_rx_bypass(mmnif_dev, s, data, len); + atomic_int32_dec(&p->cnt); + + return ret; +} + +/* mmnif_socket(): replacement of lwip_socket for + * fast sockets + */ +int mmnif_socket(int domain, int type, int protocol) +{ + int ret = 0; + + if (domain == AF_MMNIF_NET) + { + spinlock_lock(&pseudolock); + ret = npseudosocket++; + spinlock_unlock(&pseudolock); + return ret; + } + + return lwip_socket(domain, type, protocol); +} + +/* mmnif_accept(): replacement of lwip_accept for + * fast sockets + */ +int mmnif_accept(int s, struct sockaddr *addr, socklen_t * addrlen) +{ + struct sockaddr_in *bp = (struct sockaddr_in*)addr; + uint16_t port = bp->sin_port; + mm_rx_buffer_t *b = ((mmnif_t *) mmnif_dev->state)->rx_buff; + int i; + bypass_rxdesc_t *p; + int tmp1 = get_clock_tick(); + int tmp2 = 0; + if ((unsigned int)s >= MMNIF_PSEUDO_SOCKET_START) + { + for (i = 0; i < MMNIF_MAX_ACCEPTORS; i++) + { + if (b->acceptors[(i + port) % MMNIF_MAX_ACCEPTORS].stat == MMNIF_ACC_STAT_CLOSED) + { + spinlock_lock(&b->acceptors[(i + port) % MMNIF_MAX_ACCEPTORS].alock); + b->acceptors[(i + port) % MMNIF_MAX_ACCEPTORS].port = port; + b->acceptors[(i + port) % MMNIF_MAX_ACCEPTORS].stat = MMNIF_ACC_STAT_ACCEPTING; + spinlock_lock(&pseudolock); + mmnif_hashadd(npseudosocket, -1, 0); + b->acceptors[(i + port) % MMNIF_MAX_ACCEPTORS].nsock = npseudosocket++; + spinlock_unlock(&pseudolock); + spinlock_unlock(&b->acceptors[(i + port) % MMNIF_MAX_ACCEPTORS].alock); + + while (b->acceptors[(i + port) % MMNIF_MAX_ACCEPTORS].stat != MMNIF_ACC_STAT_ACCEPT_ME) + NOP8; + + p = mmnif_hashlookup(b->acceptors[(i + port) % MMNIF_MAX_ACCEPTORS].nsock); + p->dest_ip = b->acceptors[(i + port) % MMNIF_MAX_ACCEPTORS].src_ip; + p->remote_socket = b->acceptors[(i + port) % MMNIF_MAX_ACCEPTORS].rsock; + spinlock_lock(&b->acceptors[(i + port) % MMNIF_MAX_ACCEPTORS].alock); + b->acceptors[(i + port) % MMNIF_MAX_ACCEPTORS].stat = MMNIF_ACC_STAT_ACCEPTED; + i = b->acceptors[(i + port) % MMNIF_MAX_ACCEPTORS].nsock; + spinlock_unlock(&b->acceptors[(i + port) % MMNIF_MAX_ACCEPTORS].alock); + + return i; + } + } + return -1; + } + + else + { + for (i = 0; i < MMNIF_MAX_ACCEPTORS; i++) + { + if (b->acceptors[(i + port) % MMNIF_MAX_ACCEPTORS].stat == MMNIF_ACC_STAT_CLOSED) + { + spinlock_lock(&b->acceptors[(i + port) % MMNIF_MAX_ACCEPTORS].alock); + b->acceptors[(i + port) % MMNIF_MAX_ACCEPTORS].port = port; + b->acceptors[(i + port) % MMNIF_MAX_ACCEPTORS].stat = MMNIF_ACC_STAT_ACCEPTING; + spinlock_lock(&pseudolock); + mmnif_hashadd(npseudosocket, -1, 0); + b->acceptors[(i + port) % MMNIF_MAX_ACCEPTORS].nsock = npseudosocket++; + spinlock_unlock(&pseudolock); + spinlock_unlock(&b->acceptors[(i + port) % MMNIF_MAX_ACCEPTORS].alock); + + while (b->acceptors[(i + port) % MMNIF_MAX_ACCEPTORS].stat != MMNIF_ACC_STAT_ACCEPT_ME) + { + tmp2 = get_clock_tick(); + if (tmp2 - tmp1 > MMNIF_AUTO_SOCKET_TIMEOUT) + { + spinlock_lock(&b->acceptors[(i + port) % MMNIF_MAX_ACCEPTORS].alock); + if (b->acceptors[(i + port) % MMNIF_MAX_ACCEPTORS].stat == MMNIF_ACC_STAT_ACCEPT_ME) + { + spinlock_unlock(&b->acceptors[(i + port) % MMNIF_MAX_ACCEPTORS].alock); + break; + } +#ifdef DEBUG_MMNIF + DEBUGPRINTF("mmnif_accept(): Timout occoured, switching to normal accept()"); + +#endif + mmnif_hashdelete(b->acceptors[(i + port) % MMNIF_MAX_ACCEPTORS].nsock); + b->acceptors[(i + port) % MMNIF_MAX_ACCEPTORS].stat = MMNIF_ACC_STAT_CLOSED; + spinlock_unlock(&b->acceptors[(i + port) % MMNIF_MAX_ACCEPTORS].alock); + goto normalaccept; + } + NOP8; + } + + p = mmnif_hashlookup(b->acceptors[(i + port) % MMNIF_MAX_ACCEPTORS].nsock); + p->dest_ip = b->acceptors[(i + port) % MMNIF_MAX_ACCEPTORS].src_ip; + p->remote_socket = b->acceptors[(i + port) % MMNIF_MAX_ACCEPTORS].rsock; + spinlock_lock(&b->acceptors[(i + port) % MMNIF_MAX_ACCEPTORS].alock); + b->acceptors[(i + port) % MMNIF_MAX_ACCEPTORS].stat = MMNIF_ACC_STAT_ACCEPTED; + i = b->acceptors[(i + port) % MMNIF_MAX_ACCEPTORS].nsock; + spinlock_unlock(&b->acceptors[(i + port) % MMNIF_MAX_ACCEPTORS].alock); + + return i; + } + } + return -1; + } + +normalaccept: + return lwip_accept(s, addr, addrlen); +} + +/* mmnif_connect(): replacement of lwip_connect for + * fast sockets + */ +int mmnif_connect(int s, const struct sockaddr *name, socklen_t namelen) +{ + struct sockaddr_in *p = (struct sockaddr_in*) name; + uint16_t port = p->sin_port; + mm_rx_buffer_t *b; + int i; + //int tmp1 = get_clock_tick(); + //int tmp2 = 0; + uint8_t core; + uint8_t *ip4addr; + uint8_t addr[4]; + //uint32_t netmask = 0xFFFFFF00; + + /* grab the destination ip address out of the ip header + * for internal routing the last ocet is interpreted as core ID. + */ + ip4addr = (uint8_t*) &p->sin_addr.s_addr; + + /* revert the address to host format */ + addr[3] = ip4addr[0]; + addr[2] = ip4addr[1]; + addr[1] = ip4addr[2]; + addr[0] = ip4addr[3]; + + /* check if the ip address is in the Local Area Network of the 48 cores */ + // if (!((netmask & *(uint32_t*)addr) == (netmask & own_ip_address) )) + // return -1; + + core = addr[0]; + if ((core) < 1 || (core > MMNIF_CORES)) + return lwip_connect(s, name, namelen); + + b = (mm_rx_buffer_t *) ((char *)header_start_address + + (core - 1) * header_size); + for (i = 0; i < MMNIF_MAX_ACCEPTORS; i++) + { + if (b->acceptors[(i + port) % MMNIF_MAX_ACCEPTORS].stat == MMNIF_ACC_STAT_ACCEPTING + && b->acceptors[(i + port) % MMNIF_MAX_ACCEPTORS].port == port) + { + spinlock_lock(&b->acceptors[(i + port) % MMNIF_MAX_ACCEPTORS].alock); + b->acceptors[(i + port) % MMNIF_MAX_ACCEPTORS].stat = MMNIF_ACC_STAT_ACCEPT_ME; + b->acceptors[(i + port) % MMNIF_MAX_ACCEPTORS].rsock = s; + b->acceptors[(i + port) % MMNIF_MAX_ACCEPTORS].src_ip = own_ip_address & 0xFF; + mmnif_hashadd(s, + b->acceptors[(i + port) % MMNIF_MAX_ACCEPTORS].nsock, core); + spinlock_unlock(&b->acceptors[(i + port) % MMNIF_MAX_ACCEPTORS].alock); + while (b->acceptors[(i + port) % MMNIF_MAX_ACCEPTORS].stat != MMNIF_ACC_STAT_ACCEPTED) + { + +// tmp2 = get_clock_tick(); +// if (tmp2 - tmp1 > MMNIF_AUTO_SOCKET_TIMEOUT) +// { +//#ifdef DEBUG_MMNIF +// DEBUGPRINTF("mmnif_connect(): Timout occoured, switching to normal connect()"); +//#endif +// mmnif_hashdelete(s); +// goto normalsend; +// } + NOP8; + } + spinlock_lock(&b->acceptors[(i + port) % MMNIF_MAX_ACCEPTORS].alock); + b->acceptors[(i + port) % MMNIF_MAX_ACCEPTORS].stat = MMNIF_ACC_STAT_CLOSED; + spinlock_unlock(&b->acceptors[(i + port) % MMNIF_MAX_ACCEPTORS].alock); + return 0; + } + } + +#ifdef DEBUG_MMNIF + DEBUGPRINTF("mmnif_connect(): no acceptor found"); + +#endif + + return -1; +} + +int mmnif_listen(int s, int backlog) +{ + if ((unsigned int)s < MMNIF_PSEUDO_SOCKET_START) + return lwip_listen(s, backlog); + return 0; +} + +int mmnif_bind(int s, const struct sockaddr *name, socklen_t namelen) +{ + if ((unsigned int)s < MMNIF_PSEUDO_SOCKET_START) + return lwip_bind(s, name, namelen); + return 0; +} + +/* mmnif_closesocket(): replacement if lwip_close for + * fast_sockets + */ +int mmnif_closesocket(int s) +{ + bypass_rxdesc_t *p = mmnif_hashlookup(s); + + if (p == 0) + return -1; + + mmnif_hashdelete(s); + if ((unsigned int)s < MMNIF_PSEUDO_SOCKET_START) + return lwip_close(s); + + return 0; +} + +/* mmnif_irqhandler(): + * handles the incomint interrupts + */ +void mmnif_irqhandler(void) +{ + mmnif_t *mmnif; + + /* return if mmnif_dev is not yet initialized */ + if (!mmnif_dev) + { + DEBUGPRINTF("mmnif_irqhandler(): the driver is not initialized yet\n"); + return; + } + + mmnif = (mmnif_t *) mmnif_dev->state; + + if (!mmnif->check_in_progress) { + if (tcpip_callback_with_block(mmnif_rx, (void*) mmnif_dev, 0) == ERR_OK) { + mmnif->check_in_progress = 1; + } else { + DEBUGPRINTF("rckemacif_handler: unable to send a poll request to the tcpip thread\n"); + } + } +} + +/* + * close the interface should be called by kernel to close this interface and release resources + * Note: it's temporarly empty. Support will be added. + */ +err_t mmnif_shutdown(void) +{ + err_t err; + mmnif_t* mmnif; + + if (!mmnif_dev) { + DEBUGPRINTF("mmnif_shutdown(): you closed the device before it was properly initialized -.-* \n"); + return ERR_MEM; + } + mmnif = (mmnif_t *) mmnif_dev->state; + + err = netifapi_netif_set_down(mmnif_dev); + + kfree(mmnif->tx_buff[0], MMNIF_TX_QUEUELEN * MMNIF_TX_BUFFERLEN); + //RCCE_shfree(mpb_start_address); + mmnif_dev = NULL; + + return err; +} + +#endif diff --git a/drivers/net/mmnif.h b/drivers/net/mmnif.h index 012e8109..36e0ee8e 100644 --- a/drivers/net/mmnif.h +++ b/drivers/net/mmnif.h @@ -1,51 +1,51 @@ -/* - * Copyright 2011 Carl-Benedikt Krueger, Chair for Operating Systems, - * RWTH Aachen University - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * This file is part of MetalSVM. - */ - -#ifndef __MMNIF_H__ -#define __MMNIF_H__ - -#ifdef WIN32 - -typedef unsigned char uint8_t; -typedef unsigned short uint16_t; -typedef unsigned int uint32_t; - -typedef char int8_t; -typedef short int16_t; -typedef int int32_t; - -#else - -#define TRUE 1 -#define FALSE 0 - -#endif - -/* - * Initialize the network driver for mmn - */ -int mmnif_open(void); -int mmnif_close(void); - -int mmnif_poll(void* e); -int mmnif_worker(void* e); - -void mmnif_irqhandler(void); - -#endif +/* + * Copyright 2011 Carl-Benedikt Krueger, Chair for Operating Systems, + * RWTH Aachen University + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of MetalSVM. + */ + +#ifndef __MMNIF_H__ +#define __MMNIF_H__ + +#include +#ifdef CONFIG_LWIP +#include +#include /* lwip netif */ + +#define AF_MMNIF_NET 0x1337 + +#define MMNIF_AUTOACTIVATE_FAST_SOCKETS 0 + +#if MMNIF_AUTOACTIVATE_FAST_SOCKETS +#define accept(a,b,c) mmnif_accept(a,b,c) +#define closesocket(s) mmnif_closesocket(s) +#define connect(a,b,c) mmnif_connect(a,b,c) +#define recv(a,b,c,d) mmnif_recv(a,b,c,d) +#define send(a,b,c,d) mmnif_send(a,b,c,d) +#define socket(a,b,c) mmnif_socket(a,b,c) +#define bind(a,b,c) mmnif_bind(a,b,c) +#define listen(a,b) mmnif_listen(a,b) +#endif + +err_t mmnif_init(struct netif*); +err_t mmnif_shutdown(void); +int mmnif_worker(void *e); +void mmnif_irqhandler(void); +void mmnif_print_driver_status(); + +#endif + +#endif diff --git a/drivers/net/util.c b/drivers/net/util.c index 415d5fd0..449fa499 100644 --- a/drivers/net/util.c +++ b/drivers/net/util.c @@ -1,55 +1,52 @@ -/* - * Copyright 2011 Carl-Benedikt Krueger, Chair for Operating Systems, - * RWTH Aachen University - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * This file is part of MetalSVM. - */ - -#include -#include "util.h" - -inline int isprint(unsigned char e) -{ - if ((e < 0x30) || (e > 0x80)) - return 0; - return 1; -} - -// hex_dumb display network packets in a good way -void hex_dump(unsigned n, const unsigned char* buf) -{ - int on_this_line = 0; - - while (n-- > 0) - { - kprintf("%02X ", *buf++); - on_this_line += 1; - if (on_this_line == 16 || n == 0) - { - int i; - - kputs(" "); - - for (i = on_this_line; i < 16; i++) - kputs(" "); - - for (i = on_this_line; i > 0; i--) - kputchar(isprint(buf[-i]) ? buf[-i] : '.'); - - kputs("\n"); - on_this_line = 0; - } - } -} +/* + * Copyright 2011 Carl-Benedikt Krueger, Chair for Operating Systems, + * RWTH Aachen University + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of MetalSVM. + */ + +#include +#include "util.h" +inline int isprint(unsigned char e) +{ + if ((e < 0x30) || (e > 0x80)) + return 0; + return 1; +} + +// hex_dumb display network packets in a good way +void hex_dump(unsigned n, const unsigned char *buf) +{ + int on_this_line = 0; + + while (n-- > 0) + { + kprintf("%02X ", *buf++); + on_this_line += 1; + + if (on_this_line == 16 || n == 0) + { + int i; + + kputs(" "); + for (i = on_this_line; i < 16; i++) + kputs(" "); + for (i = on_this_line; i > 0; i--) + kputchar(isprint(buf[-i]) ? buf[-i] : '.'); + kputs("\n"); + on_this_line = 0; + } + } +} diff --git a/drivers/net/util.h b/drivers/net/util.h index f35b7428..c2c75c1d 100644 --- a/drivers/net/util.h +++ b/drivers/net/util.h @@ -1,26 +1,26 @@ -/* - * Copyright 2011 Carl-Benedikt Krueger, Chair for Operating Systems, - * RWTH Aachen University - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * This file is part of MetalSVM. - */ - -#ifndef __UTIL__ -#define __UTIL__ - -// hex_dumb display network packets in a good way -void hex_dump(unsigned n, const unsigned char* buf); - -#endif +/* + * Copyright 2011 Carl-Benedikt Krueger, Chair for Operating Systems, + * RWTH Aachen University + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of MetalSVM. + */ + +#ifndef __UTIL__ +#define __UTIL__ + +// hex_dumb display network packets in a good way +void hex_dump(unsigned n, const unsigned char *buf); + +#endif diff --git a/kernel/Makefile b/kernel/Makefile index fabfe28e..0e498e06 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -1,4 +1,4 @@ -C_source := main.c tasks.c syscall.c tests.c echo.c netio.c init.c +C_source := main.c tasks.c syscall.c init.c MODULE := kernel include $(TOPDIR)/Makefile.inc diff --git a/kernel/init.c b/kernel/init.c index 4d54b4d4..eea20644 100644 --- a/kernel/init.c +++ b/kernel/init.c @@ -71,6 +71,9 @@ int lowlevel_init(void) #if defined(CONFIG_LWIP) && (defined(CONFIG_PCI) || defined(CONFIG_ROCKCREEK)) static struct netif default_netif; +#ifdef CONFIG_ROCKCREEK +static struct netif mmnif_netif; +#endif static int init_netifs(void) { @@ -83,8 +86,9 @@ static int init_netifs(void) // Set up the lwIP network interface memset(&default_netif, 0x00, sizeof(struct netif)); - #ifdef CONFIG_ROCKCREEK + memset(&mmnif_netif, 0x00, sizeof(struct netif)); + /* Set network address variables */ IP4_ADDR(&gw, 192,168,28,254); IP4_ADDR(&ipaddr, 192,168,28,RCCE_ue()+1); @@ -92,12 +96,38 @@ static int init_netifs(void) /* Bring up the network interface */ if ((err = netifapi_netif_add(&default_netif, &ipaddr, &netmask, &gw, NULL, rckemacif_init, tcpip_input)) != ERR_OK) { - kprintf("Unable to add network interface: err = %d\n", err); + kprintf("Unable to add the network interface: err = %d\n", err); return -ENODEV; } netifapi_netif_set_default(&default_netif); netifapi_netif_set_up(&default_netif); + + /* Bring up the intra network interface */ + struct ip_addr intra_ipaddr; + struct ip_addr intra_netmask; + struct ip_addr intra_gw; + + IP4_ADDR(&intra_gw, 0,0,0,0); + IP4_ADDR(&intra_ipaddr, 192,168,0,RCCE_ue()+1); + IP4_ADDR(&intra_netmask, 255,255,255,0); + + /* register our Memory Mapped Virtual IP interface in the lwip stack + * and tell him how to use the interface: + * - mmnif_dev : the device data storage + * - ipaddr : the ip address wich should be used + * - gw : the gateway wicht should be used + * - mmnif_init : the initialization which has to be done in order to use our interface + * - ethernet_input : tells him that he should get ethernet input (inclusice ARP) + */ + if ((err = netifapi_netif_add(&mmnif_netif, &intra_ipaddr, &intra_netmask, &intra_gw, NULL, mmnif_init, tcpip_input)) != ERR_OK) + { + kprintf("Unable to add the intra network interface: err = %d\n", err); + return -ENODEV; + } + + /* tell lwip all initialization is done and we want to set it ab */ + netifapi_netif_set_up(&mmnif_netif); #else /* Clear network address because we use DHCP to get an ip address */ IP4_ADDR(&gw, 0,0,0,0); @@ -106,7 +136,7 @@ static int init_netifs(void) /* Bring up the network interface */ if ((err = netifapi_netif_add(&default_netif, &ipaddr, &netmask, &gw, NULL, rtl8139if_init, tcpip_input)) != ERR_OK) { - kprintf("Unable to add network interface: err = %d\n", err); + kprintf("Unable to add the network interface: err = %d\n", err); return -ENODEV; } @@ -144,11 +174,10 @@ static void tcpip_init_done(void* arg) static int network_shutdown(void) { #if defined(CONFIG_LWIP) && defined(CONFIG_ROCKCREEK) + mmnif_shutdown(); netifapi_netif_set_down(&default_netif); - memset(&default_netif, 0x00, sizeof(struct netif)); #elif defined(CONFIG_LWIP) && defined(CONFIG_PCI) netifapi_dhcp_stop(&default_netif); - memset(&default_netif, 0x00, sizeof(struct netif)); #endif return 0; @@ -209,6 +238,7 @@ int initd(void* arg) { #ifdef CONFIG_LWIP sys_sem_t sem; + tid_t id; char* argv[] = {"/bin/rlogind ", NULL}; // Initialize lwIP modules @@ -230,9 +260,10 @@ int initd(void* arg) #endif // start echo, netio and rlogind - echo_init(); - netio_init(); - create_user_task(NULL, "/bin/rlogind", argv); + //echo_init(); + create_user_task(&id, "/bin/rlogind", argv); + kprintf("Create rlogind with id %u\n", id); + //netio_init(); #endif list_root(); diff --git a/kernel/main.c b/kernel/main.c index c458c3aa..62753e41 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -60,6 +60,8 @@ int smp_main(void) int main(void) { + tid_t id; + lowlevel_init(); pushbg(COL_BLUE); @@ -91,7 +93,8 @@ int main(void) kprintf("Current available memory: %u MBytes\n", atomic_int32_read(&total_available_pages)/((1024*1024)/PAGE_SIZE)); sleep(5); - create_kernel_task(NULL, initd, NULL, NORMAL_PRIO); + create_kernel_task(&id, initd, NULL, NORMAL_PRIO); + kprintf("Create initd with id %u\n", id); reschedule(); while(1) { diff --git a/kernel/syscall.c b/kernel/syscall.c index f5329367..28b660ca 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -47,6 +47,11 @@ static int get_fildes(void) task_t* curr_task = per_core(current_task); int fd; + /* + * Seach the process specific file descriptor table for a free + * descriptor. The new descriptor returned by the call is the lowest + * numbered descriptor currently not in use by the process. + */ for (fd = 0; fd < NR_OPEN; fd++) { if (curr_task->fildes_table[fd] == NULL) { /* Init Filedescriptor */ @@ -60,32 +65,55 @@ static int get_fildes(void) return -EMFILE; } +static int sys_write(int fd, const char* buf, size_t len) +{ + task_t* curr_task = per_core(current_task); + + /* fd is negative or greater than the maximum allowable number */ + if (BUILTIN_EXPECT((fd >= NR_OPEN) || (fd < 0), 0)) + return -EBADF; + /* fd is not an active, valid file descriptor. */ + if (curr_task->fildes_table[fd] == NULL) + return -EBADF; + + return write_fs(curr_task->fildes_table[fd], (uint8_t*)buf, len); +} + static int sys_open(const char* name, int flags, int mode) { int fd, check; - fildes_t* file = NULL; + task_t* curr_task = per_core(current_task); + /* no name is given */ + if (name == NULL) + return -EINVAL; + + /* Get a free file descriptor */ fd = get_fildes(); - /* validate the fd */ - if (fd < 0) - return fd; - file = per_core(current_task)->fildes_table[fd]; - file->mode = mode; - file->flags = flags; - file->count = 1; - check = open_fs(file, (char*) name); + /* fd is negative or greater than the maximum allowable number */ + if (BUILTIN_EXPECT((fd >= NR_OPEN) || (fd < 0), 0)) + return fd; /* in this case fd = errno */ + + /* init the whole file descriptor structure */ + curr_task->fildes_table[fd]->mode = mode; + curr_task->fildes_table[fd]->flags = flags; + curr_task->fildes_table[fd]->count = 1; + check = open_fs(curr_task->fildes_table[fd], (char*) name); + + /* file doesn't exist! */ if (check < 0) { - /* file doesn't exist! */ - kfree(file, sizeof(fildes_t)); - file = NULL; + /* tidy up the fildescriptor */ + kfree(curr_task->fildes_table[fd], sizeof(fildes_t)); + curr_task->fildes_table[fd] = NULL; return check; } return fd; } -static int sys_stat(const char* name, struct stat* st) { +static int sys_stat(const char* name, struct stat* st) +{ vfs_node_t* node; node = findnode_fs(name); @@ -112,43 +140,102 @@ static int sys_stat(const char* name, struct stat* st) { return 0; } +static int sys_read(int fd, const char* buf, size_t len) +{ + task_t* curr_task = per_core(current_task); + + /* fd is negative or greater than the maximum allowable number */ + if (BUILTIN_EXPECT((fd >= NR_OPEN) || (fd < 0), 0)) + return -EBADF; + /* fd is not an active, valid file descriptor. */ + if (curr_task->fildes_table[fd] == NULL) + return -EBADF; + + return read_fs(curr_task->fildes_table[fd], (uint8_t*)buf, len); +} + + #if defined(CONFIG_LWIP) && LWIP_SOCKET static int sys_socket(int domain, int type, int protocol) { - int fd; - fildes_t* file = NULL; + int fd, sock; + task_t* curr_task = per_core(current_task); + /* Get a free file descriptor */ fd = get_fildes(); - /* validate the fd */ - if (fd < 0) - return fd; - file = per_core(current_task)->fildes_table[fd]; - file->offset = lwip_socket(domain, type, protocol); - file->node = findnode_fs("/dev/socket"); - file->count = 1; + /* validate the file descriptor */ + if (BUILTIN_EXPECT((fd >= NR_OPEN) || (fd < 0), 0)) + return fd; /* in this case fd = errno */ + + /* Get a valid lwip descriptor */ + sock = lwip_socket(domain, type, protocol); + + /* validate the file descriptor */ + if (BUILTIN_EXPECT(sock < 0, 0)) + return sock; /* in this case sock = errno */ + + /* + * init the whole file descriptor structure. + * We use the offset to save the lwip descriptor + * TODO: find another solution or change the name 'offset' + */ + curr_task->fildes_table[fd]->offset = sock; + curr_task->fildes_table[fd]->count = 1; + curr_task->fildes_table[fd]->node = findnode_fs("/dev/socket"); + + /* file doesn't exist! */ + if (curr_task->fildes_table[fd]->node == NULL) { + /* tidy up the fildescriptor */ + kfree(curr_task->fildes_table[fd], sizeof(fildes_t)); + curr_task->fildes_table[fd] = NULL; + return -ENOENT; + } return fd; } static int sys_accept(int s, struct sockaddr* addr, socklen_t* addrlen) { - int fd; - fildes_t* file = NULL; + int fd, sock2; + task_t* curr_task = per_core(current_task); - if (BUILTIN_EXPECT(s >= NR_OPEN, 0)) - return -EINVAL; + /* validate the 'socket'-filedescriptor */ + if (BUILTIN_EXPECT((s >= NR_OPEN) || (s < 0), 0)) + return -EBADF; + /* validate the 'socket'-file descriptor object */ + if (curr_task->fildes_table[s] == NULL) + return -EBADF; + /* Get a free file descriptor */ fd = get_fildes(); - /* validate the fd */ - if (fd < 0) - return fd; - file = per_core(current_task)->fildes_table[fd]; - file->offset = lwip_accept(s, addr, addrlen); - file->node = findnode_fs("/dev/socket"); - file->count = 1; + /* validate the file descriptor */ + if (BUILTIN_EXPECT((fd >= NR_OPEN) || (fd < 0), 0)) + return fd; /* in this case fd = errno */ + /* Get a valid lwip descriptor */ + sock2 = lwip_accept(s, addr, addrlen); + /* validate the file descriptor */ + if (BUILTIN_EXPECT(sock2 < 0, 0)) + return sock2; /* in this case sock = errno */ + + /* + * init the whole file descriptor structure. + * We use the offset to save the lwip descriptor + * TODO: find another solution or change the name 'offset' + */ + curr_task->fildes_table[fd]->offset = sock2; + curr_task->fildes_table[fd]->count = 1; + curr_task->fildes_table[fd]->node = findnode_fs("/dev/socket"); + /* file doesn't exist! */ + if (curr_task->fildes_table[fd]->node == NULL) { + /* tidy up the fildescriptor */ + kfree(curr_task->fildes_table[fd], sizeof(fildes_t)); + curr_task->fildes_table[fd] = NULL; + return -ENOENT; + } + return fd; } @@ -157,13 +244,26 @@ static int sys_accept(int s, struct sockaddr* addr, socklen_t* addrlen) static int sys_close(int fd) { + int check; task_t* curr_task = per_core(current_task); - - if (BUILTIN_EXPECT(fd >= NR_OPEN, 0)) - return -EINVAL; + /* fd is negative or greater than the maximum allowable number */ + if (BUILTIN_EXPECT((fd >= NR_OPEN) || (fd < 0), 0)) + return -EBADF; + /* fd is not an active, valid file descriptor. */ + if (curr_task->fildes_table[fd] == NULL) + return -EBADF; + + /* + * The close() call deletes a descriptor from the per-process object + * reference table. If this is the last reference to the underlying + * object, the object will be deactivated. + */ if (curr_task->fildes_table[fd]->count == 1) { - close_fs(curr_task->fildes_table[fd]); + check = close_fs(curr_task->fildes_table[fd]); + /* close command failed -> return check = errno */ + if (BUILTIN_EXPECT(check < 0, 0)) + return check; kfree(curr_task->fildes_table[fd], sizeof(fildes_t)); curr_task->fildes_table[fd] = NULL; } else { @@ -178,30 +278,42 @@ static int sys_close(int fd) static int sys_lseek(int fd, off_t pos, int origin) { int ret = -EINVAL; - fildes_t* file; + task_t* curr_task = per_core(current_task); - if (BUILTIN_EXPECT(fd >= NR_OPEN, 0)) - return -EINVAL; + /* fd is negative or greater than the maximum allowable number */ + if (BUILTIN_EXPECT((fd >= NR_OPEN) || (fd < 0), 0)) + return -EBADF; + /* fd is not an active, valid file descriptor. */ + if (curr_task->fildes_table[fd] == NULL) + return -EBADF; - file = per_core(current_task)->fildes_table[fd]; - - if (BUILTIN_EXPECT(!((file->node->type == FS_FILE) - || (file->node->type == FS_CHARDEVICE)), 0)) - return -EINVAL; + /* TODO: in case of Fildes is associated with a pipe, socket, or FIFO. return ESPIPE */ + /* TODO: The seek location is too large to be stored in an object of type off_t. return EOVERFLOW*/ switch(origin) - { + { case SEEK_SET: { /* set file offset to offset */ - file->offset = pos; + ret = pos; + /* The seek location is negative. */ + if (ret < 0) + return -EINVAL; + curr_task->fildes_table[fd]->offset = ret; ret = 0; break; } case SEEK_CUR: { /* set file offset to current plus offset */ - ret = pos + file->offset; + ret = pos + curr_task->fildes_table[fd]->offset; + /* The seek location is negative. */ + if (ret < 0) + return -EINVAL; break; } case SEEK_END: { /* set file offset to EOF plus offset */ - file->offset = pos + file->node->block_size; + ret = pos + curr_task->fildes_table[fd]->node->block_size; + /* The seek location is negative. */ + if (ret < 0) + return -EINVAL; + curr_task->fildes_table[fd]->offset = ret; ret = 0; break; } @@ -209,6 +321,7 @@ static int sys_lseek(int fd, off_t pos, int origin) ret = -EINVAL; break; } + return ret; } @@ -217,12 +330,19 @@ static int sys_dup(int fd) task_t* curr_task = per_core(current_task); int new_fd; + /* fd is negative or greater than the maximum allowable number */ if (BUILTIN_EXPECT((fd >= NR_OPEN) || (fd < 0), 0)) return -EBADF; + /* fd is not an active, valid file descriptor. */ if (curr_task->fildes_table[fd] == NULL) return -EBADF; + /* Get a free file descriptor */ new_fd = get_fildes(); + /* validate the file descriptor */ + if (BUILTIN_EXPECT((new_fd >= NR_OPEN) || (fd < 0), 0)) + return new_fd; /* in this case fd = errno */ + curr_task->fildes_table[new_fd] = curr_task->fildes_table[fd]; curr_task->fildes_table[fd]->count++; @@ -233,18 +353,26 @@ static int sys_dup2(int fd, int fd2) { task_t* curr_task = per_core(current_task); + /* fd and fd2 is negative or greater than the maximum allowable number */ if (BUILTIN_EXPECT((fd >= NR_OPEN) || (fd < 0), 0)) return -EBADF; if (BUILTIN_EXPECT((fd2 >= NR_OPEN) || (fd2 < 0), 0)) return -EBADF; + /* fd is not an active, valid file descriptor. */ if (curr_task->fildes_table[fd] == NULL) return -EBADF; - if (fd == fd2) + /* If fd and fd2 are equal, then dup2() just returns fd2 */ + if (fd == fd2) return fd2; + + /* + * if descriptor fd2 is already in use, it is first deallocated + * as if a close(2) call had been done first + */ if (curr_task->fildes_table[fd2] != NULL) sys_close(fd2); - + curr_task->fildes_table[fd2] = curr_task->fildes_table[fd]; curr_task->fildes_table[fd]->count++; @@ -296,9 +424,7 @@ int syscall_handler(uint32_t sys_nr, ...) int fd = va_arg(vl, int); const char* buf = va_arg(vl, const char*); size_t len = va_arg(vl, size_t); - if (fd >= 0) - ret = write_fs(per_core(current_task)->fildes_table[fd], - (uint8_t*)buf, len); + ret = sys_write(fd, buf, len); break; } case __NR_open: { @@ -310,8 +436,7 @@ int syscall_handler(uint32_t sys_nr, ...) } case __NR_close: { int fd = va_arg(vl, int); - if (fd >= 0) - ret = sys_close(fd); + ret = sys_close(fd); break; } case __NR_dup: { @@ -328,7 +453,6 @@ int syscall_handler(uint32_t sys_nr, ...) case __NR_stat: { const char* name = va_arg(vl, const char*); struct stat* st = va_arg(vl, struct stat*); - ret = sys_stat(name, st); break; } @@ -336,17 +460,14 @@ int syscall_handler(uint32_t sys_nr, ...) int fd = va_arg(vl, int); const char* buf = va_arg(vl, const char*); size_t len = va_arg(vl, size_t); - if (fd >= 0) - ret = read_fs(per_core(current_task)->fildes_table[fd], - (uint8_t*)buf, len); + ret = sys_read(fd, buf, len); break; } case __NR_lseek: { int fd = va_arg(vl, int); off_t pos = va_arg(vl, off_t); int origin = va_arg(vl, int); - if (fd >= 0) - ret = sys_lseek(fd, pos, origin); + ret = sys_lseek(fd, pos, origin); break; } case __NR_sbrk: {