diff --git a/Doxyfile b/Doxyfile index 352ee44e..6ea4977f 100644 --- a/Doxyfile +++ b/Doxyfile @@ -42,7 +42,7 @@ PROJECT_BRIEF = "A Bare-Metal Hypervisor for Non-Coherent Memory-Couple # exceed 55 pixels and the maximum width should not exceed 200 pixels. # Doxygen will copy the logo to the output directory. -PROJECT_LOGO = +PROJECT_LOGO = documentation/img/lfbs_logo.gif # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. @@ -536,7 +536,7 @@ FILE_VERSION_FILTER = # You can optionally specify a file name after the option, if omitted # DoxygenLayout.xml will be used as the name of the layout file. -LAYOUT_FILE = +LAYOUT_FILE = documentation/tmpl/layout.xml #--------------------------------------------------------------------------- # configuration options related to warning and progress messages @@ -599,14 +599,14 @@ WARN_LOGFILE = # with spaces. INPUT = ./fs \ - ./include \ - ./kernel \ - ./drivers \ - ./arch \ - ./libkern \ - ./mm \ - ./tools \ - ./documentation/doxy_mainpage.h + ./include \ + ./kernel \ + ./drivers \ + ./arch \ + ./libkern \ + ./mm \ + ./tools \ + ./documentation/text # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is @@ -624,7 +624,11 @@ INPUT_ENCODING = UTF-8 # *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py # *.f90 *.f *.for *.vhd *.vhdl -FILE_PATTERNS = +FILE_PATTERNS += *.c +FILE_PATTERNS += *.h +FILE_PATTERNS += *.asm +FILE_PATTERNS += *.S +FILE_PATTERNS += *.dox # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. @@ -913,17 +917,17 @@ DOCSET_FEEDNAME = "Doxygen generated docs" # reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen # will append .docset to the name. -DOCSET_BUNDLE_ID = org.doxygen.Project +DOCSET_BUNDLE_ID = de.rwth-aachen.lfbs # When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify # the documentation publisher. This should be a reverse domain-name style # string, e.g. com.mycompany.MyDocSet.documentation. -DOCSET_PUBLISHER_ID = org.doxygen.Publisher +DOCSET_PUBLISHER_ID = de.rwth-aachen.lfbs # The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. -DOCSET_PUBLISHER_NAME = Publisher +DOCSET_PUBLISHER_NAME = LfBS # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the diff --git a/apps/Makefile b/apps/Makefile index 94912228..e45d1a38 100644 --- a/apps/Makefile +++ b/apps/Makefile @@ -1,4 +1,4 @@ -C_source := tests.c echo.c netio.c +C_source := tests.c echo.c netio.c laplace.c gfx_client.c gfx_generic.c MODULE := apps include $(TOPDIR)/Makefile.inc diff --git a/apps/gfx_client.c b/apps/gfx_client.c new file mode 100644 index 00000000..5614849d --- /dev/null +++ b/apps/gfx_client.c @@ -0,0 +1,146 @@ +/* + * Copyright 2011 Sarah Fischer, Nicolas Berr, Pablo Reble + * 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 + +#ifdef CONFIG_LWIP + +#include "gfx_client.h" +#include + +static int myrank; +static int sockfd; + +#ifndef SINGLE_CONNECT +#define SINGLE_CONNECT 1 +#endif +#define SINGLE_CONNECT_RANK 0 +#define USE_GETHOSTBYNAME 0 + +//int gfx_init(int* pargc, char*** pargv, int rank){ +int gfx_init(char* ip_str, char* port_str, int rank) { + char* hostname; + int port; + struct sockaddr_in serveraddr; + struct hostent *server; + + //*pargc -=2; + myrank = rank; + +#if SINGLE_CONNECT + // currently only rank 0 will connect to the gfx-server + if (rank != SINGLE_CONNECT_RANK) { + return 0; + } +#endif + + /* hostname und port aus den parametern ermitteln) */ + //kprintf("pargc: %d\n", *pargc); + + hostname = ip_str; //(*pargv)[(*pargc)]; + port = atoi(port_str); //atoi((*pargv)[(*pargc)+1]); + + kprintf("gfx-client connecting to host: %s, port: %d\n", hostname, port); + + /* socket erzeugen */ + sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (sockfd < 0) + return -1; + +#if 1 + /* Disable the Nagle (TCP No Delay) algorithm */ + int flag = 1; + if (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(flag)) < 0) { + kprintf("Couldn't setsockopt(TCP_NODELAY)\n"); + return -1; + } +#endif + +#if USE_GETHOSTBYNAME + /* dns eintrag vom server ermitteln */ + serveraddr = gethostbyname(hostname); + if (server == NULL){ + fprintf(stderr, "%s: no such host\n", hostname); + return -2; + } +#endif + + /* adresse vom server ermitteln */ + memset((char *) &serveraddr, 0x00, sizeof(serveraddr)); + serveraddr.sin_family = AF_INET; +#if USE_GETHOSTBYNAME + bcopy((char *)server->h_addr, (char *)&serveraddr.sin_addr.s_addr, server->h_length); +#else + serveraddr.sin_addr.s_addr = inet_addr(hostname); +#endif + serveraddr.sin_port = htons(port); + + /* verbindung herstellen */ + if (connect(sockfd, (const struct sockaddr *) &serveraddr, sizeof(serveraddr)) < 0) + return -3; + + return 0; +} + +int gfx_send(char* buf, int size, int tag){ + int ret, pos = 0; + uint32_t u32size, u32tag; + +#if SINGLE_CONNECT + if (myrank != SINGLE_CONNECT_RANK) + return 0; +#endif + + u32size = size; + u32tag = tag; + +// printf("sending stuff...."); +// printf("tag: %d, size: %d\n", tag, size); +// fflush(stdout); + + ret = write(sockfd, &u32tag, sizeof(u32tag)); + if (ret != sizeof(tag)) + return -1; + ret = write(sockfd, &u32size, sizeof(u32size)); + if (ret != sizeof(size)) + return -2; + + + do{ + ret = write(sockfd, &buf[pos], size-pos); + pos += ret; + } while (pos < size); + + + return 0; +} + +int gfx_finalize(){ + // uint32_t u32tag = (uint32_t)(-1); + uint32_t u32tag = 1111; +#if SINGLE_CONNECT + if (myrank == SINGLE_CONNECT_RANK) { + write(sockfd, &u32tag, sizeof(u32tag)); + close(sockfd); + } +#endif + return 0; +} + +#endif diff --git a/apps/gfx_client.h b/apps/gfx_client.h new file mode 100644 index 00000000..c36743c7 --- /dev/null +++ b/apps/gfx_client.h @@ -0,0 +1,50 @@ +/* + * Copyright 2011 Sarah Fischer, Nicolas Berr, Pablo Reble + * 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 __GFX_CLIENT_H__ +#define __GFX_CLIENT_H__ + +#include +#include +#include + +#ifdef CONFIG_LWIP + +#define BUFSIZE 1024 + +/* + * grafik initialisieren, letzte beide argumente, ip und port, werden entfernt + * verbindung zu server aufbauen, kollektiver aufruf, erstmal nur rank 0 connecten +*/ +//int gfx_init(int* pargc, char*** pargv, int rank); +int gfx_init(char* ip_str, char* port_str, int rank); + +/* + * paket mit der geg. laenge wird an den server gesehendet, das tag soll auch uebertragen werden +*/ +int gfx_send(char* buf, int size, int tag); + +/* + * kollektiver aufruf, vorhandene verbindungen kontrolliert beenden +*/ +int gfx_finalize(); + +#endif + +#endif diff --git a/apps/gfx_generic.c b/apps/gfx_generic.c new file mode 100644 index 00000000..63b6e570 --- /dev/null +++ b/apps/gfx_generic.c @@ -0,0 +1,138 @@ +/* + * Copyright 2011 Sarah Fischer, Nicolas Berr, Pablo Reble + * 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 "gfx_client.h" +#include "gfx_generic.h" + +#ifdef CONFIG_LWIP + +int GFX_init(int* pargc, char*** pargv, int rank) +{ + return gfx_init(pargc, pargv, rank); +} + +int GFX_send(char* buf, int size, int tag) +{ + return gfx_send(buf, size, tag); +} + +int GFX_finalize() +{ + return gfx_finalize(); +} + +int GFX_update() +{ + return gfx_send(NULL, 0, GFX_UPDATE); +} + +int GFX_usleep(int sleep_time) +{ + int buf[1]; + buf[0] = sleep_time; + return gfx_send((char*)buf, sizeof(int), GFX_USLEEP); +} + +int GFX_set_rgb(int index, int r, int g, int b) +{ + int buf[4]; + buf[0] = index; + buf[1] = r; + buf[2] = g; + buf[3] = b; + return gfx_send((char*)buf, 4*sizeof(int), GFX_SET_RGB); +} + +int GFX_set_xy(int x, int y) +{ + int buf[2]; + buf[0] = x; + buf[1] = y; + return gfx_send((char*)buf, 2*sizeof(int), GFX_SET_XY); +} + +int GFX_set_hd(int height, int direction) +{ + int buf[2]; + buf[0] = height; + buf[1] = direction; + return gfx_send((char*)buf, 2*sizeof(int), GFX_SET_HD); +} + + +int GFX_draw_data(char *buf, int len) +{ + return gfx_send(buf, len, GFX_DRAW_DATA); +} + +int GFX_draw_pixel(int x, int y, int color) +{ + int buf[3]; + buf[0] = x; + buf[1] = y; + buf[2] = color; + return gfx_send((char*)buf, 3*sizeof(int), GFX_DRAW_PIXEL); +} + +int GFX_draw_line(int x1, int y1, int x2, int y2, int color) +{ + int buf[5]; + buf[0] = x1; + buf[1] = y1; + buf[2] = x2; + buf[3] = y2; + buf[4] = color; + return gfx_send((char*)buf, 5*sizeof(int), GFX_DRAW_LINE); +} + +int GFX_draw_box(int x, int y, int height, int width, int color) +{ + int buf[5]; + buf[0] = x; + buf[1] = y; + buf[2] = height; + buf[3] = width; + buf[4] = color; + return gfx_send((char*)buf, 5*sizeof(int), GFX_DRAW_BOX); +} + +int GFX_draw_text(int x, int y, int color, char *text) +{ + int buf[32]; + buf[0] = x; + buf[1] = y; + buf[2] = color; + strcpy((char*)&(buf[3]), text); + + return gfx_send((char*)buf, 32*sizeof(int), GFX_DRAW_TEXT); +} + +int GFX_draw_points(int* points, int num) +{ + return gfx_send((char*)points, num*3*sizeof(int), GFX_DRAW_POINTS); +} + +int GFX_draw_poly(int* points, int num, int color) +{ + int i; + for(i=0; i +#include +#include +#include + +#ifdef CONFIG_ROCKCREEK + +#include +#include + +#define _LAPLACE_SHMEM_ +//#define _USE_GFX + +#ifdef _LAPLACE_SHMEM_ +#define SINGLE_CONNECT 1 +#else +#define SINGLE_CONNECT 0 +#endif + +#ifdef _USE_GFX +#include "gfx_generic.h" +#include "gfx_client.h" +#endif + +#define ABS(a) (((a) < 0) ? -(a) : (a)) +#define MAX(a,b) (((a) < (b)) ? (b) : (a)) + +#define N 1022 +#define M 510 + +#define TMAX (100*50) + +//#define DATA unsigned int +#define DATA double +//#define FIX 1024 +#define FIX 1 + +#define USE_STRONG 1 +#define USE_LAZYRELEASE 0 + +#if USE_STRONG && USE_LAZYRELEASE +#error Please, use only one memory model +#endif + +static inline double pow(double a, int b) +{ + double base = a; + int i; + + for (i = 1; i < b; ++i) + a *= base; + + return a; +} + +int laplace(void *arg) +{ + //char* argv[] = {"/bin/laplace", "192.168.4.254", "12301", NULL}; + //int argc = 3; + uint32_t flags; +#ifdef _USE_GFX + uint32_t ret; +#endif + int t; + + int i, I, j, J; + int my_rank; + int num_ranks; + + int n; + int m; + + volatile DATA **NewValues; + volatile DATA **OldValues; + + volatile DATA **tmp; + + volatile char **BufValues; + + uint64_t start, end; + + flags = irq_nested_disable(); + my_rank = RCCE_ue(); + num_ranks = RCCE_num_ues(); + irq_nested_enable(flags); + +#ifdef _USE_GFX + kprintf("Laplace calls gfx_init\n"); + ret = gfx_init("192.168.4.254" /*&argc */ , "5000" /*&argv */ , my_rank); + kprintf("gfx_init: %d\n", ret); +#endif + + m = M; + J = 0; + + n = N / num_ranks; + I = n * my_rank; + + if (my_rank == num_ranks - 1) + n += N % num_ranks; + + kprintf("(%d) %d x %d / offsets: %d, %d / (%d x %d)\n", my_rank, N, M, I, J, n, m); + +#ifdef _USE_GFX + if (my_rank == 0) { + for (i = 0; i < 256; i++) { +//set color index, r, g, b + if (i < 64) + GFX_set_rgb(i, 0, i * 256 / 64, 255); + else if (i < 128) + GFX_set_rgb(i, 0, 255, 255 - ((i - 64) * 256 / 64)); + else if (i < 192) + GFX_set_rgb(i, (i - 128) * 256 / 64, 255, 0); + else if (i < 256) + GFX_set_rgb(i, 255, 255 - ((i - 192) * 256 / 64), 0); + } +// TODO: move draw area to center + //GFX_set_xy(150, 150); + GFX_set_hd(N, 0); + } +#endif + + NewValues = (volatile DATA **)kmalloc((N + 2) * sizeof(DATA *)); +#if USE_STRONG + NewValues[0] = (DATA *) svmmalloc((N + 2) * (M + 2) * sizeof(DATA), SVM_STRONG); +#elif USE_LAZYRELEASE + NewValues[0] = (DATA *) svmmalloc((N + 2) * (M + 2) * sizeof(DATA), SVM_LAZYRELEASE); +#else + NewValues[0] = (DATA *) kmalloc((N + 2) * (M + 2) * sizeof(DATA)); +#endif + + OldValues = (volatile DATA **)kmalloc((N + 2) * sizeof(DATA *)); +#if USE_STRONG + OldValues[0] = (DATA *) svmmalloc((N + 2) * (M + 2) * sizeof(DATA), SVM_STRONG); +#elif USE_LAZYRELEASE + OldValues[0] = (DATA *) svmmalloc((N + 2) * (M + 2) * sizeof(DATA), SVM_LAZYRELEASE); +#else + OldValues[0] = (DATA *) kmalloc((N + 2) * (M + 2) * sizeof(DATA)); +#endif + + for (i = 1; i < N + 2; i++) { + NewValues[i] = NewValues[i - 1] + (M + 2); + OldValues[i] = OldValues[i - 1] + (M + 2); + } + + BufValues = (volatile char **)kmalloc((N) * sizeof(char *)); + BufValues[0] = (char *)kmalloc((N) * (M) * sizeof(char)); + + for (i = 1; i < N; i++) { + BufValues[i] = BufValues[i - 1] + (M); + } + + RCCE_barrier(&RCCE_COMM_WORLD); + + kprintf("(%d) Memory allocated!\n", my_rank); + + //while (1) + { + int height = N + 2; + int width = M + 2; + + /*if (my_rank == 0) { + for (i = 0; i < N + 2; i++) { + for (j = 0; j < M + 2; j++) {*/ + { + for (i = I; i < I + n + 2; i++) { + for (j = 0; j < M + 2; j++) { + + double X = (((double)j / (double)width) * 5.0) - 2.5; + double Y = (((double)i / (double)height) * 5.0) - 2.5; + double Z = 0.0; + + Z = pow((4 - (X + 1) * (X + 1) - 4 * Y * Y), 2) + pow(1.2 * (1 - X), 3) - 10; + + if (Z < 0.0) + Z = 1.0; + else if (Z > 0.0) + Z = 0.0; + + OldValues[i][j] = NewValues[i][j] = (DATA) ((Z) * 255.0) * FIX; + + //if(NewValues[i][j] < 0) NewValues[i][j] = 0; + } + } + } + +#if USE_LAZYRELEASE + svm_flush(); + svm_invalidate(); +#endif + RCCE_barrier(&RCCE_COMM_WORLD); + + kprintf("(%d) Arrays initialized!\n", my_rank); + + start = rdtsc(); + start = rdtsc(); + +// START ITERATIONS LOOP + for (t = 0; t < TMAX; t++) { + + //kprintf("(%d): o:%u n:%u \n",my_rank,(unsigned int)(OldValues[I+1][J+1]), (unsigned int)(NewValues[I+1][J+1]) ); + +// over all collumns + for (i = 1; i < n + 1; i++) { +// over all rows + for (j = 1; j < m + 1; j++) { + NewValues[I + i][J + j] = + (OldValues[I + i - 1][J + j] + + OldValues[I + i + 1][J + j] + + OldValues[I + i][J + j - 1] + + OldValues[I + i][J + j + 1]) / 4; + } + } +#if USE_LAZYRELEASE + svm_flush(); + svm_invalidate(); +#endif + + tmp = NewValues; + NewValues = OldValues; + OldValues = tmp; + + RCCE_barrier(&RCCE_COMM_WORLD); + +#ifdef _USE_GFX + if ((my_rank == 0) && (t % 50 == 0)) { + int diff, res = 0; + + for (i = 1; i < N + 1; i++) { + for (j = 1; j < M + 1; j++) { + + diff = ABS(NewValues[i][j] - OldValues[i][j]); + if (diff > res) + res = diff; + + BufValues[i - 1][j - 1] = (unsigned char)(NewValues[i][j] / FIX); + //GFX_draw_pixel(150+j, 150+my_rank*n+i, (unsigned char)NewValues[i+1][j+1]); + //GFX_update(); + } + } + + kprintf("Graphic UPDATE! (t=%d) residual:%u \n", t, res); + GFX_draw_data((char *)(BufValues[0]), (N) * (M)); + GFX_update(); + } + + RCCE_barrier(&RCCE_COMM_WORLD); +#endif +// END ITERATIONS LOOP + } + + RCCE_barrier(&RCCE_COMM_WORLD); + + end = rdtsc(); + + kprintf("Calculation time: %llu ms (%llu ticks)\n", (end-start)/(1000ULL*get_cpu_frequency()), end-start); + +#if USE_STRONG || USE_LAZYRELEASE + svm_statistics(); +#endif + } + + kprintf("(%d) Algorithm completed!\n", my_rank); + + // TODO: Freeing memory regions + +#ifdef _USE_GFX + gfx_finalize(); +#endif + + return 0; +} + +#endif diff --git a/apps/netio.c b/apps/netio.c index 4469cd1a..9a6c374c 100644 --- a/apps/netio.c +++ b/apps/netio.c @@ -30,6 +30,8 @@ #include #endif +#define USE_SOCKET_BYPASSING 1 + /* * 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). @@ -45,7 +47,24 @@ /* See http://www.nwlab.net/art/netio/netio.html to get the netio tool */ #ifdef CONFIG_LWIP +#ifdef CONFIG_ROCKCREEK +#if USE_SOCKET_BYPASSING // for socket bypassing +#include +#undef LWIP_COMPAT_SOCKETS +#endif +#endif + #include +#include +#include + +#ifdef CONFIG_ROCKCREEK +#if USE_SOCKET_BYPASSING // for socket bypassing +#include +#undef AF_INET +#define AF_INET AF_MMNIF_NET +#endif +#endif typedef struct { @@ -59,7 +78,7 @@ typedef struct #define CMD_RES 3 #define CTLSIZE sizeof(CONTROL) -#define DEFAULTPORT 0x494F /* "IO" */ +#define DEFAULTPORT 0x494F #define TMAXSIZE 65536 static int tSizes[] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32767}; @@ -75,7 +94,7 @@ static int send_data(int socket, void *buffer, size_t size, int flags) if (rc < 0) { - kprintf("send failed: %d\n", rc); + kprintf("send failed: %d\n", errno); return -1; } @@ -90,7 +109,7 @@ static int recv_data(int socket, void *buffer, size_t size, int flags) size_t rc = recv(socket, buffer, size, flags); if (rc < 0) { - kprintf("recv failed: %d\n", rc); + kprintf("recv failed: %d\n", errno); return -1; } @@ -152,13 +171,14 @@ static int TCPServer(void* arg) setsockopt(server, SOL_SOCKET, SO_RCVBUF, (char *) &sobufsize, sizeof(sobufsize)); setsockopt(server, SOL_SOCKET, SO_SNDBUF, (char *) &sobufsize, sizeof(sobufsize)); + memset((char *) &sa_server, 0x00, sizeof(sa_server)); sa_server.sin_family = AF_INET; sa_server.sin_port = htons(nPort); sa_server.sin_addr = addr_local; if ((err = bind(server, (struct sockaddr *) &sa_server, sizeof(sa_server))) < 0) { - kprintf("bind failed: %d\n", err); + kprintf("bind failed: %d\n", errno); closesocket(server); kfree(cBuffer, TMAXSIZE); return -1; @@ -166,7 +186,7 @@ static int TCPServer(void* arg) if ((err = listen(server, 2)) != 0) { - kprintf("listen failed: %d\n", err); + kprintf("listen failed: %d\n", errno); closesocket(server); kfree(cBuffer, TMAXSIZE); return -1; @@ -176,6 +196,7 @@ static int TCPServer(void* arg) { kprintf("TCP server listening.\n"); +#if !USE_SOCKET_BYPASSING FD_ZERO(&fds); FD_SET(server, &fds); tv.tv_sec = 3600; @@ -183,16 +204,22 @@ static int TCPServer(void* arg) if ((rc = select(FD_SETSIZE, &fds, 0, 0, &tv)) < 0) { - kprintf("select failed: %d\n", rc); + kprintf("select failed: %d\n", errno); break; } if (rc == 0 || FD_ISSET(server, &fds) == 0) continue; - +#endif length = sizeof(sa_client); - if ((client = accept(server, (struct sockaddr *) &sa_client, &length)) == -1) +#if USE_SOCKET_BYPASSING + // TODO: Bug, not compatible with BSD sockets + memcpy(&sa_client, &sa_server, length); +#endif + if ((client = accept(server, (struct sockaddr *) &sa_client, &length)) < 0) { + kprintf("accept faild: %d\n", errno); continue; + } setsockopt(client, SOL_SOCKET, SO_RCVBUF, (char *) &sobufsize, sizeof(sobufsize)); setsockopt(client, SOL_SOCKET, SO_SNDBUF, (char *) &sobufsize, sizeof(sobufsize)); @@ -214,7 +241,7 @@ static int TCPServer(void* arg) kprintf("\nReceiving from client, packet size %s ... \n", PacketSize(ctl.data)); cBuffer[0] = 0; nData = 0; - + do { for (nByte = 0; nByte < ctl.data; ) { @@ -222,7 +249,7 @@ static int TCPServer(void* arg) if (rc < 0) { - kprintf("recv failed: %d\n", rc); + kprintf("recv failed: %d\n", errno); break; } @@ -252,7 +279,7 @@ static int TCPServer(void* arg) if (rc < 0) { - kprintf("send failed: %d\n", rc); + kprintf("send failed: %d\n", errno); break; } @@ -310,7 +337,7 @@ int TCP_Bench(void) if ((server = socket(PF_INET, SOCK_STREAM, 0)) < 0) { - kprintf("socket failed: %d\n", server); + kprintf("socket failed: %d\n", errno); kfree(cBuffer, TMAXSIZE); return -2; } @@ -324,7 +351,7 @@ int TCP_Bench(void) if ((err = connect(server, (struct sockaddr *) &sa_server, sizeof(sa_server))) < 0) { - kprintf("connect failed: %d\n", err); + kprintf("connect failed: %d\n", errno); closesocket(server); kfree(cBuffer, TMAXSIZE); return -2; @@ -360,8 +387,8 @@ int TCP_Bench(void) if (rc < 0) { - kprintf("send failed: %d\n", rc); - break; + kprintf("send failed: %d\n", errno); + return -1; } if (rc > 0) @@ -404,8 +431,8 @@ int TCP_Bench(void) if (rc < 0) { - kprintf("recv failed: %d\n", rc); - break; + kprintf("recv failed: %d\n", errno); + return -1; } if (rc > 0) @@ -448,6 +475,7 @@ int netio_init(void) } else if (RCCE_ue() == 0) { sleep(3); err = TCP_Bench(); + stats_display(); } #else err = create_kernel_task(NULL, TCPServer, NULL, NORMAL_PRIO); diff --git a/apps/scc_bootinfo.asm b/apps/scc_bootinfo.asm new file mode 100644 index 00000000..e69de29b diff --git a/apps/tests.c b/apps/tests.c index e6bd093b..d6b8a5eb 100644 --- a/apps/tests.c +++ b/apps/tests.c @@ -40,6 +40,8 @@ static sem_t consuming, producing; static mailbox_int32_t mbox; static int val = 0; +int laplace(void* arg); + static int consumer(void* arg) { int i, m = 0; @@ -318,6 +320,7 @@ int test_init(void) //create_kernel_task(NULL, mail_noise, NULL, NORMAL_PRIO); //create_kernel_task(NULL, svm_test, NULL, NORMAL_PRIO); //create_kernel_task(NULL, pi, NULL, NORMAL_PRIO); + //create_kernel_task(NULL, laplace, NULL, NORMAL_PRIO); //create_user_task(NULL, "/bin/hello", argv); create_user_task(NULL, "/bin/tests", argv); //create_user_task(NULL, "/bin/jacobi", argv); diff --git a/arch/x86/include/asm/RCCE.h b/arch/x86/include/asm/RCCE.h index 128ba664..d88e5723 100644 --- a/arch/x86/include/asm/RCCE.h +++ b/arch/x86/include/asm/RCCE.h @@ -190,6 +190,7 @@ int RCCE_comm_size(RCCE_COMM, int *); int RCCE_comm_rank(RCCE_COMM, int *); void RCCE_fence(void); int RCCE_barrier(RCCE_COMM *); +int RCCE_TNS_barrier(RCCE_COMM* comm); int RCCE_error_string(int, char *, int *); int RCCE_debug_set(int); int RCCE_debug_unset(int); diff --git a/arch/x86/include/asm/tasks.h b/arch/x86/include/asm/tasks.h index 206f5ad2..9f45b691 100644 --- a/arch/x86/include/asm/tasks.h +++ b/arch/x86/include/asm/tasks.h @@ -50,7 +50,7 @@ int dump_scheduling_statistics(void); */ int arch_fork(task_t* task); -/** @brieff Switch to new task +/** @brief Switch to new task * @param id Task Id */ void switch_task(uint32_t id); diff --git a/arch/x86/mm/svm.c b/arch/x86/mm/svm.c index a757bc2c..6a0449b2 100644 --- a/arch/x86/mm/svm.c +++ b/arch/x86/mm/svm.c @@ -49,7 +49,6 @@ static volatile uint8_t* page_owner = NULL; // helper array to convert a physical to a virtual address static size_t phys2virt[SHARED_PAGES] = {[0 ... SHARED_PAGES-1] = 0}; static size_t shmbegin = 0; -static int my_ue = 0; static uint32_t emit[RCCE_MAXNP] = {[0 ... RCCE_MAXNP-1] = 0}; static uint32_t request[RCCE_MAXNP] = {[0 ... RCCE_MAXNP-1] = 0}; static uint32_t forward[RCCE_MAXNP] = {[0 ... RCCE_MAXNP-1] = 0}; @@ -61,7 +60,6 @@ int svm_init(void) // iRCCE is not thread save => disable interrupts flags = irq_nested_disable(); - my_ue = RCCE_ue(); shmbegin = (size_t)RC_SHM_BUFFER_START(); phyaddr = (size_t) RCCE_shmalloc(OWNER_SIZE); irq_nested_enable(flags); @@ -84,7 +82,7 @@ int svm_init(void) } // per default is core 0 owner - if (!my_ue) + if (!RCCE_IAM) memset((void*)page_owner, 0x00, OWNER_SIZE); // iRCCE is not thread save => disable interrupts @@ -112,32 +110,29 @@ int svm_access_request(size_t addr) return -EINVAL; pageid = (phyaddr-shmbegin) >> PAGE_SHIFT; - //svm_flush(); - if (page_owner[pageid] == my_ue) + if (page_owner[pageid] == RCCE_IAM) return 0; remote_rank = page_owner[pageid]; - ((size_t*) payload)[0] = my_ue; + ((size_t*) payload)[0] = RCCE_IAM; ((size_t*) payload)[1] = phyaddr; - //kprintf("send access request to %d of 0x%x\n", remote_rank, phyaddr); /* send ping request */ iRCCE_mail_send(2*sizeof(size_t), SVM_REQUEST, 0, payload, remote_rank); request[remote_rank]++; - NOP8; icc_send_gic_irq(remote_rank); - /* check for incoming messages */ - icc_mail_check(); - - while (page_owner[pageid] != my_ue) { - check_workqueues(); + while (page_owner[pageid] != RCCE_IAM) { + icc_mail_check(); + NOP8; } return change_page_permissions(addr, addr+PAGE_SIZE, VMA_READ|VMA_WRITE|VMA_CACHEABLE); } +static atomic_int32_t size_counter = ATOMIC_INIT(0); + void* svmmalloc(size_t size, uint32_t consistency) { size_t phyaddr, viraddr, i; @@ -153,11 +148,61 @@ void* svmmalloc(size_t size, uint32_t consistency) // currently, we allocate memory in page size granulation size = (size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); +#if 0 // Workaround for our MARC paper + // iRCCE is not thread save => disable interrupts + flags = irq_nested_disable(); + + kprintf("Entering shmmalloc: size 0x%x, owner_size 0x%x\n", size, OWNER_SIZE); + if (RCCE_IAM && (consistency & SVM_STRONG)) + map_flags |= MAP_NO_ACCESS; + + viraddr = vm_alloc(size >> PAGE_SHIFT, map_flags); + kprintf("vm_alloc returns 0x%x\n", viraddr); + + static uint32_t last = 0; + // get memory on MC0 + if (last) + phyaddr = last + size/4; + else + last = phyaddr = (size_t) RCCE_shmalloc(size/4); + map_region(viraddr, phyaddr, (size/4) >> PAGE_SHIFT, map_flags|MAP_REMAP); + for(i=0; i> PAGE_SHIFT] = viraddr + i; + kprintf("svmmalloc on MC0: phyaddr 0x%x, viraddr 0x%x, size 0x%x\n", phyaddr, viraddr, size); + + // get memory on MC1 + phyaddr = shmbegin + 0x1000000 + atomic_int32_read(&size_counter); + map_region(viraddr + size/4, phyaddr, (size/4) >> PAGE_SHIFT, map_flags|MAP_REMAP); + for(i=0; i> PAGE_SHIFT] = viraddr + size/4 + i; + kprintf("svmmalloc on MC1: phyaddr 0x%x, viraddr 0x%x, size 0x%x\n", phyaddr, viraddr+size/4, size); + + // get memory on MC2 + phyaddr = shmbegin + 0x2000000 + atomic_int32_read(&size_counter); + map_region(viraddr + 2 * size/4, phyaddr, (size/4) >> PAGE_SHIFT, map_flags|MAP_REMAP); + for(i=0; i> PAGE_SHIFT] = viraddr + 2 * size/4 + i; + kprintf("svmmalloc on MC2: phyaddr 0x%x, viraddr 0x%x, size 0x%x\n", phyaddr, viraddr+2*size/4, size); + + // get memory on MC3 + phyaddr = shmbegin + 0x3000000 + atomic_int32_read(&size_counter); + map_region(viraddr + 3 * size/4, phyaddr, (size/4) >> PAGE_SHIFT, map_flags|MAP_REMAP); + for(i=0; i> PAGE_SHIFT] = viraddr + 3 * size/4 + i; + kprintf("svmmalloc on MC3: phyaddr 0x%x, viraddr 0x%x, size 0x%x\n", phyaddr, viraddr+3*size/4, size); + + atomic_int32_add(&size_counter, size/4); + irq_nested_enable(flags); + + kprintf("shmmalloc returns 0x%x\n", viraddr); + + return (void*) viraddr; +#else // iRCCE is not thread save => disable interrupts flags = irq_nested_disable(); phyaddr = (size_t) RCCE_shmalloc(size); - if (RCCE_ue() && (consistency & SVM_STRONG)) + if (RCCE_IAM && (consistency & SVM_STRONG)) map_flags |= MAP_NO_ACCESS; irq_nested_enable(flags); @@ -175,6 +220,7 @@ void* svmmalloc(size_t size, uint32_t consistency) kprintf("svmmalloc: phyaddr 0x%x, viraddr 0x%x, size 0x%x\n", phyaddr, viraddr, size); return (void*) viraddr; +#endif } void svmfree(void* addr, size_t size) @@ -218,12 +264,12 @@ int svm_emit_page(size_t phyaddr, int ue) return -EINVAL; pageid = (phyaddr-shmbegin) >> PAGE_SHIFT; - if (page_owner[pageid] != my_ue) { + if (page_owner[pageid] != RCCE_IAM) { // Core is nor owner => forward request to new owner int remote_rank; uint8_t payload[iRCCE_MAIL_HEADER_PAYLOAD]; - kprintf("Ups, core %d is not owner of page 0x%x\n", my_ue, phyaddr); + kprintf("Ups, core %d is not owner of page 0x%x\n", RCCE_IAM, phyaddr); remote_rank = page_owner[pageid]; ((size_t*) payload)[0] = ue; @@ -258,6 +304,7 @@ void svm_flush(void) *(int *)RCCE_fool_write_combine_buffer = 1; flush_cache(); +#error Currently not supported #if 0 // try to flush L2 cache z = Z_PID(RC_COREID[my_ue]); diff --git a/arch/x86/scc/RCCE_admin.c b/arch/x86/scc/RCCE_admin.c index 78b26b21..09e70166 100644 --- a/arch/x86/scc/RCCE_admin.c +++ b/arch/x86/scc/RCCE_admin.c @@ -48,6 +48,8 @@ // En-/ or disable debug prints... #define DEBUG 0 +#define Test_and_Set(a) ((*(virtual_lockaddress[a])) & 0x01) + //...................................................................................... // GLOBAL VARIABLES USED BY THE LIBRARY //...................................................................................... @@ -105,6 +107,38 @@ void RC_cache_invalidate() { return; } +int RCCE_TNS_barrier(RCCE_COMM* comm) { + +// two roundtrips to realize a barrier using a T&S Register for each core. + +// 1. search first free T&S Register to spin +// 2. last waiter wakes up first waiter and continues local wait +// 3. first waiter wakes up second waiter by releasing its lock ... +// At least every used T&S Register is 0 and no UE can overtake a barrier. + + int num = comm->size; + int step = 0; + //fprintf(stderr,"%d:\t enter barrier \n",id); + + while( !Test_and_Set(step) ) ++step; + // only one UE runs until T&S # num-1 + + //fprintf(stderr,"%d:\t step %d\n",id,step); + + if(step == num-1) { + //fprintf(stderr,"%d:\t I am the last one\n",id); + *(virtual_lockaddress[0]) = 0x0; + while(!Test_and_Set(step)) ; + *(virtual_lockaddress[step]) = 0x0; + } else { + while(!Test_and_Set(step)) ; + *(virtual_lockaddress[step]) = 0x0; + *(virtual_lockaddress[step+1]) = 0x0; + } + //fprintf(stderr,"released barrier! step: %d\n", step); + return RCCE_SUCCESS; +} + //-------------------------------------------------------------------------------------- // FUNCTION: RC_COMM_BUFFER_SIZE //-------------------------------------------------------------------------------------- diff --git a/arch/x86/scc/iRCCE_mailbox.c b/arch/x86/scc/iRCCE_mailbox.c index b311970d..1ca67c1f 100644 --- a/arch/x86/scc/iRCCE_mailbox.c +++ b/arch/x86/scc/iRCCE_mailbox.c @@ -27,7 +27,8 @@ /** * - * @file contains implementation of the mailbox system + * @file iRCCE_mailbox.c + * @brief contains implementation of the mailbox system * @author Simon Pickartz * * @@ -40,15 +41,6 @@ #include #include -/** - * - * @file contains implementation of the mailbox system - * @author Simon Pickartz - * - * - */ - - // forward declaration static int iRCCE_mailbox_close_one(int rank, int check); @@ -167,10 +159,10 @@ static int iRCCE_mail_fetch( * write out the data. */ //------------------------------------------------------------------------------ -iRCCE_MAIL_HEADER dummy_header = {0, 0, 0, NULL, 0, 0, 0, {[0 ... iRCCE_MAIL_HEADER_PAYLOAD-1] = 0} }; +static iRCCE_MAIL_HEADER dummy_header = {0, 0, 0, NULL, 0, 0, 0, {[0 ... iRCCE_MAIL_HEADER_PAYLOAD-1] = 0} }; -static int iRCCE_mailbox_check() { +static int iRCCE_mailbox_check(void) { int i,j; uint32_t flags; diff --git a/arch/x86/scc/icc.c b/arch/x86/scc/icc.c index 81258250..97796658 100644 --- a/arch/x86/scc/icc.c +++ b/arch/x86/scc/icc.c @@ -161,7 +161,7 @@ static void icc_handler(struct state *s) /* empty mail queue */ while( iRCCE_mail_recv(&header) == iRCCE_SUCCESS ) { icc_mail_check_tag(header); - iRCCE_mail_release( &header ); + iRCCE_mail_release(&header); NOP8; NOP8; NOP8; @@ -331,7 +331,7 @@ int icc_mail_ping(void) /* leave function if not participating in pingpong */ if( (RCCE_IAM != CORE_A) && (RCCE_IAM != CORE_B) ) return -1; - kprintf( "my_ue = %d\n", RCCE_IAM); + kprintf( "my rank = %d\n", RCCE_IAM); kprintf( "Hello from mail_ping ... \n" ); kprintf( "rounds = %d\n", ROUNDS ); @@ -401,7 +401,7 @@ int icc_mail_ping_irq(void) int res; iRCCE_MAIL_HEADER* recv_header = NULL; - kprintf( "my_rank = %d\n", RCCE_IAM ); + kprintf( "my rank = %d\n", RCCE_IAM ); kprintf( "rem_rank = %d\n", CORE_B ); kprintf( "rounds = %d\n", ROUNDS ); @@ -503,9 +503,6 @@ void icc_mail_check(void) iRCCE_mail_check(iRCCE_MAILBOX_ALL); - /* enable interrupts */ - irq_nested_enable(flags); - /* empty mail queue */ while( iRCCE_mail_recv(&header) == iRCCE_SUCCESS ) { icc_mail_check_tag(header); @@ -514,6 +511,9 @@ void icc_mail_check(void) NOP8; NOP8; } + + /* enable interrupts */ + irq_nested_enable(flags); } #endif diff --git a/documentation/img/reset.png b/documentation/img/reset.png new file mode 100644 index 00000000..caab6a7f Binary files /dev/null and b/documentation/img/reset.png differ diff --git a/documentation/img/sccGui.png b/documentation/img/sccGui.png new file mode 100644 index 00000000..8335e70b Binary files /dev/null and b/documentation/img/sccGui.png differ diff --git a/documentation/img/uart.png b/documentation/img/uart.png new file mode 100644 index 00000000..a183d9a2 Binary files /dev/null and b/documentation/img/uart.png differ diff --git a/documentation/text/.gitignore b/documentation/text/.gitignore new file mode 100644 index 00000000..424c745c --- /dev/null +++ b/documentation/text/.gitignore @@ -0,0 +1 @@ +*.h diff --git a/documentation/text/compilation.dox b/documentation/text/compilation.dox new file mode 100644 index 00000000..1222228f --- /dev/null +++ b/documentation/text/compilation.dox @@ -0,0 +1,141 @@ +/** + * @file compilation.dox + * @page compilation Compiling and Running MetalSVM + * + * @section toc Table of Contents + * - @ref checkout + * - @ref compiling + * - @ref runqemu + * - @ref runscc + * - @ref runsccmc + * - @ref msvmuart + * + * @section checkout Checking out MetalSVM online + * + * The MetalSVM project is hosted in a Git repository. To check it out, just type: + * + * \verbatim$ git clone gitosis@git.lfbs.rwth-aachen.de:metalsvm.git \endverbatim + * + * If you are asked for a password you are not authorized to clone the repository. In this case you will need to get your public SSH key authorized. + * + * @section compiling Compiling MetalSVM + * + * To compile MetalSVM, you will need a proper Makefile and configuration. To use the example files, just do the following: + * + * \verbatim +$ cd MetalSVM +$ cp Makefile.example Makefile +$ cp include/metalsvm/config.h.example include/metalsvm/config.h \endverbatim + * + * The standard configuration works on usual PC hardware configurations as well as in emulators. + * + * Compiler settings can be edited in the Makefile, while the kernel configuration can be found in the just copied configuration file. + * + * @section runqemu Running MetalSVM in Qemu + * + * There is a Make-target for running MetalSVM in Qemu: + * \verbatim$ make qemu \endverbatim + * + * The emulator is then started with the following parameters: + * \verbatim$ qemu -monitor stdio -smp 2 -net nic,model=rtl8139 -net user,hostfwd=tcp::12345-:7 -net dump -kernel metalsvm.elf -initrd tools/initrd.img \endverbatim + * + * Please note that qemu versions 0.13 and 0.14 have a bug which keeps MetalSVM from booting properly. Used qemu-0.12.5 instead. + * + * @section runscc Running MetalSVM on the Intel SCC + * + * -# Intel recommends to use their cross-compiler for generating code which is guaranteed to be SCC-compatible. Just set the environment variables with the following command: + * \verbatim$ . /opt/compilerSetupFiles/crosscompile.sh \endverbatim + * -# The Makefile needs to be adapted to actually use the cross compiler: + * \verbatim +CC_FOR_TARGET=i386-unknown-linux-gnu-gcc +CXX_FOR_TARGET=i386-unknown-linux-gnu-g++ +GCC_FOR_TARGET=i386-unknown-linux-gnu-gcc +AR_FOR_TARGET=i386-unknown-linux-gnu-ar +AS_FOR_TARGET=i386-unknown-linux-gnu-as +LD_FOR_TARGET=i386-unknown-linux-gnu-ld +NM_FOR_TARGET=i386-unknown-linux-gnu-nm +OBJDUMP_FOR_TARGET=i386-unknown-linux-gnu-objdump +OBJCOPY_FOR_TARGET=i386-unknown-linux-gnu-objcopy +RANLIB_FOR_TARGET=i386-unknown-linux-gnu-ranlib +STRIP_FOR_TARGET=i386-unknown-linux-gnu-strip +READELF_FOR_TARGET=i386-unknown-linux-gnu-readelf \endverbatim + * -# Another important change in the Makefile is disabling the "-fno-stack-protector" option. It occurs several times. + * -# The SCC requires a special configuration for the MetalSVM kernel: + * \verbatim +//#define CONFIG_PCI +//#define CONFIG_VGA +//#define CONFIG_UART +//#define CONFIG_KEYBOARD +//#define CONFIG_MULTIBOOT +#define CONFIG_ROCKCREEK +// RCCE specific flags +#define SCC +#define COPPERRIDGE +#define MS_BAREMETAL +//#define GORY +#define SHMADD +#define SHMDBG +//#define SHMADD_CACHEABLE \endverbatim + * -# There is only one core per tile, so it is adequate to reduce overhead by disabling SMP in MetalSVM: + * \verbatim#define MAX_CORES 1 \endverbatim + * -# Cache-line size is 32 byte: + * \verbatim#define CACHE_LINE 32 \endverbatim + * -# MetalSVM can now be built using \c make. + * -# Build the SCC tools: + * \verbatim +$ cd tools +$ make SCC \endverbatim + * -# The \c obj directory was just created, containing the MetalSVM kernel image. It can be loaded into the SCC's memory using \verbatim$ sccBoot -g obj \endverbatim + * -# The default configuration lets MetalSVM run only on core 0. Its reset pin needs to be released: + * \verbatim$ sccReset -r 0x00 \endverbatim + * -# Although the display driver was deactivated, MetalSVM's kprintf-output is written into the memory, where you can read it with the following command: + * \verbatim$ sccDump -d 0x00 0x100000 0x10000 | less \endverbatim + * + * + * @section runsccmc Running MetalSVM on multiple SCC cores + * + * -# Build the kernel like described above (items 1-7) and change to the \c tools directory. + * -# The \c scc_bootinfo.asm file contains boot-information relevant to the SCC-cores. + * It is generated automatically by the \c bootinfo.sh script.\n + * \n + * The following example generates the \c scc_bootinfo.asm file needed for use of the cores 0 and 1: + * \verbatim$ ./bootinfo.sh 0x01000000 initrd.img 2 533 0 1 > scc_bootinfo.asm \endverbatim + * Parameters describe the following: + * -# First parameter describes the address at which the initrd shall be located at later + * -# Second is path to the initrd image file + * -# The other parameters are analogous to RCCE-App-parameters. This example starts MetalSVM on cores 0 and 1, clocked with 533MHz. + * -# Now the file \c metalsvm.mt has to be edited. It defines the layout of the memory image (Where the kernels will be located in the memory later). For the example from above it looks like the following: + * \verbatim# pid mch-route mch-dest-id mch-offset-base testcase + 0x00 0x00 6 0x00 metalsvm.obj + 0x01 0x00 6 0x01 metalsvm.obj \endverbatim + * This locates two instances of MetalSVM on core 0 and 1, supplied with memory from memory controller 0. See \c sccMerge \c -h for more information. + * -# The final image must be generated then with \code$ make SCC\endcode + * -# A directory \c obj was created, containing the final MetalSVM Image. This image can now be loaded with the following command: \code$ sccBoot -g obj\endcode + * -# Everything has been placed in the cores' memory. To release the reset pins of the corresponding cores, type \code$ sccReset -r 0x00 0x01\endcode + * + * @section msvmuart Enabling UART support + * + * MetalSVM is able to reroute terminal output to port \c 0x2F8. This way it can be displayed in \c sccGui. Too much output stresses the network load, therefore it should be used for debugging purposes only. + * + * How to enable: + * -# Enable UART-support in the kernel's config file \c include/metalsvm/config.h: + * \code#define CONFIG_UART\endcode + * -# Rebuild the kernel. Do not launch it with \c sccBoot - In the following \c sccGui will be used. + * -# Launch \c sccGui. + * -# Enable UART in the gui by klicking Enable software RAM and UART in the Menu Settings/Debug Settings. + * -# Issue a software interrupt by clicking on the wiper symbol. + * -# Choose the memory image called \c mch_0_0.32.obj from the \c obj folder with Preload object file. + * -# Initialize the LUT with Preload LUT file. It is called \c lut_init.dat and is located in the same directory. + * -# Both L2 cache and MPB can be reset now, if needed. + * -# Activate the corresponding cores with Change selected reset(s). This opens the following window: + * @image html reset.png + * -# A box being checked means that the reset pin is pulled and the core is \e inactive. The example from the picture will boot MetalSVM only on cores 0 and 1. + * + * After following these steps successfully, a similar image to the following should appear on the gui: + * @image html sccGui.png + * + * Another window will be opened automatically as soon as UART output arrives in the gui. This will be similar to the following: + * @image html uart.png + * + * + */ diff --git a/documentation/text/config.dox b/documentation/text/config.dox new file mode 100644 index 00000000..e4e80343 --- /dev/null +++ b/documentation/text/config.dox @@ -0,0 +1,18 @@ +/** + * @file config.dox + * @page config The MetalSVM feature configuration file + * + * @section conf MetalSVM's configuration file + * + * MetalSVM's configuration parameters and some features can be configured/activated in the central configuration file located at \c include/metalsvm/config.h. + * + * The \c config.h is a usual C-header file and the configuration items are usual C preprocessor-definitions like the following: + * \code +#define CONFIGURATION_PARAMETER 123value /* A parameter with a value */ +#define FEATURE_A /* An activated feature */ +//#define FEATURE_B /* A deactivated feature */\endcode + * + * Just like the example suggests, features are deactivated by commenting them out. + * + * + */ diff --git a/documentation/text/documenting.dox b/documentation/text/documenting.dox new file mode 100644 index 00000000..5a77f053 --- /dev/null +++ b/documentation/text/documenting.dox @@ -0,0 +1,112 @@ +/** + * @file documenting.dox + * @page documenting Documenting MetalSVM with Doxygen + * + * The doxygen project has a nice manual at http://www.stack.nl/~dimitri/doxygen/manual.html \n + * All content on this page is extracted from there. + * + * Please check if the \c doxygen command throws errors on your documented code. + * + * @section inline Documenting code inline + * + * To document your code correctly, you will have to follow some (simple) rules: + * + * Place a comment block like this at the beginning of your source code files you intend to document: + * + * @verbatim + /** + * @author John Doe + * @file path/to/your/file.h + * @brief A brief explanation about what this code does or is supposed to do. + */@endverbatim + * + * Functions/procedures are commented in the header file just above the + * function/procedure definition: + * + * @verbatim + /** @brief Blocking wait for semaphore [short explanation] + * + * [space for more detailed explanations] + * + * [describing parameters] + * @param s Address of the according sem_t structure + * @param ms Timeout in milliseconds + * + * [describing possible return values in a list] + * @return + * - 0 on success + * - -EINVAL on invalid argument + * - -ETIME on timer expired + */ + inline static int sem_wait(sem_t* s, uint32_t ms); @endverbatim + * + * Documenting structures and their members looks like the following: + * @verbatim + /** @brief The task_t structure */ + typedef struct task { + /// Task id = position in the task table + tid_t id; + /// Task status (INVALID, READY, RUNNING, ...) + uint32_t status; + ... @endverbatim + * + * @section formatting Formatting text + * + * Although you could use HTML brackets to format your text, + * Doxygen provides special commands. Please use those, since it is possible + * that someone may want to generate CHM, Latex or other formatted output + * from this documentation. + * + * To \e emphasize, \b highlight or \c typewrite text, use the following commands: + * \verbatim To \e emphasize, \b highlight or \c typewrite text... \endverbatim + * + * \verbatim + Preserving the format + of text like + this can be done with \verbatim end \ endverbatim \endverbatim + * + * Code will be color-highlighted with \\code and \\endcode: + * \code + int i; + for (i=0; i < 123; i++) + printf("%d\n", i); + \endcode + * + * It is also easily possible to make listings: + * - item a + * - item b + * - item c + * + * And also enumerated listings: + * -# item a + * -# item b + * -# item c + * + * \verbatim +It is also easily possible to make listings: + - item a + - item b + - item c + +And also enumerated listings: + -# item a + -# item b + -# item c \endverbatim + * + * @section docs Writing documents like this one + * + * To write a stand-alone manual like this one, just create + * a file \c your_manual.dox in \c $MSVM/documentation/text/. + * + * This file's content should look like this: + * + * \verbatim + /** + * @file your_manual.dox + * @page your_manual This is your manual's title. It will be displayed in the "Manuals" section. + * + * @section your_section This starts a section with a title + * + * content, content, content! + */ \endverbatim + */ diff --git a/documentation/text/kernelspace.dox b/documentation/text/kernelspace.dox new file mode 100644 index 00000000..95e014d4 --- /dev/null +++ b/documentation/text/kernelspace.dox @@ -0,0 +1,7 @@ +/** + * @file kernelspace.dox + * @page kernelspace Development in kernel space + * + * @section kernelthreads Starting kernel threads + * + */ diff --git a/documentation/text/mainpage.dox b/documentation/text/mainpage.dox new file mode 100644 index 00000000..03a039da --- /dev/null +++ b/documentation/text/mainpage.dox @@ -0,0 +1,47 @@ +/** + * @file mainpage.dox + * @mainpage + * + * @section Introduction + * + * On a traditional multicore system, a single operating system + * manages all cores and schedules threads and processes among + * them, inherently supported by hardware-implemented cache + * coherence protocols. However, a further growth of the number + * of cores per system implies an increasing chip complexity, + * especially with respect to the cache coherence protocols. + * Therefore, a very attractive alternative for future many-core + * systems is to waive the hardware-based cache coherency and to + * introduce a software-oriented message-passing based architecture + * instead: a so-called Cluster-on-Chip architecture. + * Intel's Single-chip Cloud Computer (SCC), a many-core research + * processor with 48 non-coherent memory-coupled cores, is a very + * recent example for such a Cluster-on-Chip architecture. The SCC + * can be configured to run one operating system per core by + * partitioning the shared main memory in a strict manner. However, + * it is also possible to access the shared main memory in an unsplit + * and concurrent manner, provided that the cache coherency is then + * ensured by software. + * + * @section Research Objective + * + * In this project, we develop a new approach for a SCC-related shared + * virtual memory management system, called MetalSVM, that will be + * implemented in terms of a bare-metal hypervisor, located within a + * virtualization layer between the SCC's hardware and the actual + * operating system. This new hypervisor will undertake the crucial + * task of coherency management by utilizing special SCC-related features + * as, for example, its on-die Message-Passing Buffers (MPB). That way, + * common Linux kernels will be able to run almost transparently across + * the entire SCC system. However, in order to offer a maximum of flexibility + * with respect to resource allocation as well as to an efficiency-adjusted + * degree of parallelism, also a dynamic partitioning of the SCC's computing + * resources into several coherency domains will be made possible. + * + * @image html metalsvm_stack.jpg + * + * @section Acknowledgment + * + * This research project is funded by Intel Corporation. + * + */ diff --git a/documentation/text/userspace.dox b/documentation/text/userspace.dox new file mode 100644 index 00000000..9489f4d2 --- /dev/null +++ b/documentation/text/userspace.dox @@ -0,0 +1,7 @@ +/** + * @file userspace.dox + * @page userspace Development in user space + * + * @section ownapps Installing and launching your own applications + * + */ diff --git a/documentation/tmpl/footer.html b/documentation/tmpl/footer.html index 6725e7cd..3fda0093 100644 --- a/documentation/tmpl/footer.html +++ b/documentation/tmpl/footer.html @@ -1,4 +1,13 @@ + + + + + + + diff --git a/documentation/tmpl/header.html b/documentation/tmpl/header.html index b1a6a471..97a54784 100644 --- a/documentation/tmpl/header.html +++ b/documentation/tmpl/header.html @@ -1,27 +1,50 @@ - - - $title - - - - - - - -
-
- - - - - - -
-
MetalSVM
- - -
A Bare-Metal Hypervisor for Non-Coherent Memory-Coupled Cores
-
-
+ + +$title + + +$treeview +$search +$mathjax + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + +
+
$projectname +  $projectnumber +
+
$projectbrief
+
+
$projectbrief
+
$searchbox
+
+ diff --git a/documentation/tmpl/layout.xml b/documentation/tmpl/layout.xml new file mode 100644 index 00000000..6794c866 --- /dev/null +++ b/documentation/tmpl/layout.xml @@ -0,0 +1,186 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/documentation/tmpl/stylesheet.css b/documentation/tmpl/stylesheet.css index 125800f1..9564fb02 100644 --- a/documentation/tmpl/stylesheet.css +++ b/documentation/tmpl/stylesheet.css @@ -11,6 +11,12 @@ h1 { font-size: 150%; } +.title { + font-size: 150%; + font-weight: bold; + margin: 10px 2px; +} + h2 { font-size: 120%; } @@ -185,7 +191,7 @@ body { div.contents { margin-top: 10px; margin-left: 10px; - margin-right: 10px; + margin-right: 5px; } td.indexkey { @@ -361,6 +367,10 @@ table.memberdecls { white-space: nowrap; } +.memItemRight { + width: 100%; +} + .memTemplParams { color: #4665A2; white-space: nowrap; @@ -388,9 +398,14 @@ table.memberdecls { padding: 2px; } +.mempage { + width: 100%; +} + .memitem { padding: 0; margin-bottom: 10px; + margin-right: 5px; } .memname { @@ -724,7 +739,7 @@ dl.note, dl.warning, dl.attention, dl.pre, dl.post, dl.invariant, dl.deprecated, dl.note { - border-color: #D0D000; + border-color: #D0C000; } dl.warning, dl.attention @@ -768,20 +783,6 @@ dl.bug { border: 0px none; } - -#projectname -{ - font: 300% arial,sans-serif; - margin: 0px; - padding: 0px; -} - -#projectbrief -{ - font: 120% arial,sans-serif; - margin: 0px; - padding: 0px; -} #lfbslogo { @@ -796,10 +797,24 @@ dl.bug top: 5px; right: 5px; } + +#projectname +{ + font: 300% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 2px 0px; +} + +#projectbrief +{ + font: 120% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 0px; +} #projectnumber { - font: 50% arial,sans-serif; + font: 50% Tahoma, Arial,sans-serif; margin: 0px; padding: 0px; } @@ -812,3 +827,28 @@ dl.bug border-bottom: 1px solid #5373B4; } +.image +{ + text-align: center; +} + +.dotgraph +{ + text-align: center; +} + +.mscgraph +{ + text-align: center; +} + +.caption +{ + font-weight: bold; +} + +.textblock +{ + width: 800px; + textalign: justify; +} diff --git a/drivers/char/socket.c b/drivers/char/socket.c index d8af0ba3..8210c249 100755 --- a/drivers/char/socket.c +++ b/drivers/char/socket.c @@ -116,7 +116,7 @@ int socket_init(vfs_node_t* node, const char* name) return -ENOMEM; memset(new_node, 0x00, sizeof(vfs_node_t)); - new_node->type = FS_CHARDEVICE; + new_node->type = FS_SOCKET; new_node->open = &socket_open; new_node->close = &socket_close; new_node->read = &socket_read; diff --git a/drivers/net/mmnif.c b/drivers/net/mmnif.c index 9d81ee77..d63149d0 100644 --- a/drivers/net/mmnif.c +++ b/drivers/net/mmnif.c @@ -18,29 +18,34 @@ * * mmnif.c --- memmory mapped interface * - * Virutal IP Interface for the concept processor SCC + * Virtual IP Interface for the concept processor SCC * */ +/* + * 15th October 2011: + * - Redesign of the interrupt handling (by Stefan Lankes) + * - Add iRCCE support (by Stefan Lankes) + * - Extending the BSD socket interface + */ + #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 #include /* mailbox_ptr_t */ #include #include #include +#include #include #include @@ -51,7 +56,7 @@ #include #include -#include +#include #define TRUE 1 #define FALSE 0 @@ -80,10 +85,8 @@ #define MMNIF_AUTO_SOCKET_TIMEOUT 500 -#define MMNIF_FAST_SOCKET_BLOCK 1 - #ifdef DEBUG_MMNIF -#include "util.h" /* hex dump */ +#include /* hex dump */ #endif /* define constants @@ -120,12 +123,6 @@ 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 @@ -146,14 +143,12 @@ 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; @@ -163,13 +158,13 @@ typedef struct acceptor { typedef struct bypass_rxdesc { /* socket : hashtarget * remote_socket: socket on the remote end - * cnt : atomic counter for the recv function + * counter : packet counter + * last_id : last packet id * 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; @@ -207,6 +202,7 @@ typedef struct rx_desc { * addr : memory address of the packet * fast_sock: (-1) if no socket is associated * else the socket n of the fast socket + * id : packet id */ uint8_t stat; uint16_t len; @@ -223,7 +219,6 @@ typedef struct mm_rx_buffer { */ uint16_t head; uint16_t tail; - spinlock_t rlock; /* descritpor queue * desc_table : descriptor table @@ -254,18 +249,14 @@ typedef struct mmnif { uint32_t ipaddr; // checks the TCPIP thread already the rx buffers? - uint8_t check_in_progress; + volatile uint8_t check_in_progress; /* memory interaction variables: * - pointer to recive buffer */ - mm_rx_buffer_t *rx_buff; + volatile 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; @@ -276,14 +267,6 @@ static void mmnif_irqhandler(struct state* s); inline static void* memcpy_from_nc(void *dest, const void *src, size_t count) { -#if 0 - size_t i; - - for(i=0; istate)->stats; - - return stats; -} - /* mmnif_print_stats(): Print the devices stats of the * current device */ @@ -456,36 +414,15 @@ void mmnif_print_driver_status(void) 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; + ip_addr_p_t ip; /* 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; + ip = iphdr->dest; - /* 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; + return ip4_addr4(&ip); } /* mmnif_rxbuff_alloc(): @@ -495,11 +432,11 @@ static uint8_t mmnif_get_destination(struct netif *netif, struct pbuf *p) */ 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); + uint32_t ret = 0; + volatile 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; + char* memblock = (char*)heap_start_address + (dest-1)/2*16*1024*1024 + (dest-1)%2 * 0x2000; #else char *memblock = (char *)heap_start_address + (dest - 1) * heap_size; #endif @@ -511,7 +448,7 @@ static uint32_t mmnif_rxbuff_alloc(uint8_t dest, uint16_t len) // if ((rb->head - rb->tail < len)&&(rb->tail != rb->head)) // return NULL; - RCCE_acquire_lock(dest-1); + RCCE_acquire_lock(RC_COREID[dest-1]); if (rb->dcount) { if (rb->tail > rb->head) @@ -525,8 +462,6 @@ static uint32_t mmnif_rxbuff_alloc(uint8_t dest, uint16_t len) rb->dcount--; rb->dwrite = (rb->dwrite + 1) % MMNIF_MAX_DESCRIPTORS; rb->tail = (rb->tail + len); - RCCE_release_lock(dest-1); - return ret; } else if (rb->head > len) { rb->desc_table[rb->dwrite].stat = MMNIF_STATUS_PENDING; ret = (uint32_t) memblock; @@ -535,11 +470,6 @@ static uint32_t mmnif_rxbuff_alloc(uint8_t dest, uint16_t len) rb->dcount--; rb->dwrite = (rb->dwrite + 1) % MMNIF_MAX_DESCRIPTORS; rb->tail = len; - RCCE_release_lock(dest-1); - return ret; - } else { - RCCE_release_lock(dest-1); - return 0; } } else { if (rb->head - rb->tail > len) @@ -551,8 +481,6 @@ static uint32_t mmnif_rxbuff_alloc(uint8_t dest, uint16_t len) rb->dcount--; rb->dwrite = (rb->dwrite + 1) % MMNIF_MAX_DESCRIPTORS; rb->tail = (rb->tail + len); - RCCE_release_lock(dest-1); - return ret; } else if (rb->tail == rb->head) { if (MMNIF_RX_BUFFERLEN - rb->tail < len) { @@ -567,17 +495,12 @@ static uint32_t mmnif_rxbuff_alloc(uint8_t dest, uint16_t len) rb->dcount--; rb->dwrite = (rb->dwrite + 1) % MMNIF_MAX_DESCRIPTORS; rb->tail = (rb->tail + len); - RCCE_release_lock(dest-1); - return ret; - } else { - RCCE_release_lock(dest-1); - return 0; } } - } else { - RCCE_release_lock(dest-1); - return 0; } + RCCE_release_lock(RC_COREID[dest-1]); + + return ret; } /* mmnif_commit_packet: this function set the state of the (in advance) @@ -586,7 +509,7 @@ static uint32_t mmnif_rxbuff_alloc(uint8_t dest, uint16_t len) */ 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); + volatile 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++) @@ -596,6 +519,7 @@ static int mmnif_commit_packet(uint8_t dest, uint32_t addr) { rb->desc_table[i].stat = MMNIF_STATUS_RDY; rb->desc_table[i].fast_sock = -1; + return 0; } } @@ -609,7 +533,7 @@ static int mmnif_commit_packet(uint8_t dest, uint32_t addr) */ 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); + volatile 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++) @@ -632,11 +556,11 @@ static int mmnif_commit_packet_bypass(uint8_t dest, uint32_t addr, int dest_sock static void mmnif_rxbuff_free(void) { mmnif_t *mmnif = mmnif_dev->state; - mm_rx_buffer_t *b = mmnif->rx_buff; + volatile mm_rx_buffer_t *b = mmnif->rx_buff; uint32_t i, j; uint32_t rpos; - RCCE_acquire_lock(RCCE_ue()); + RCCE_acquire_lock(RC_MY_COREID); rpos = b->dread; for (i = 0, j = rpos; i < MMNIF_MAX_DESCRIPTORS; i++) @@ -663,7 +587,7 @@ static void mmnif_rxbuff_free(void) break; } - RCCE_release_lock(RCCE_ue()); + RCCE_release_lock(RC_MY_COREID); } /* @@ -676,7 +600,6 @@ static err_t mmnif_tx(struct netif *netif, struct pbuf *p) uint32_t i; struct pbuf *q; /* interator */ uint32_t dest_ip = mmnif_get_destination(netif, p); - //int32_t chances = 4000; /* check for over/underflow */ if (BUILTIN_EXPECT((p->tot_len < 20 /* IP header size */) || (p->tot_len > 1536), 0)) { @@ -684,6 +607,12 @@ static err_t mmnif_tx(struct netif *netif, struct pbuf *p) goto drop_packet; } + /* check destination ip */ + if (BUILTIN_EXPECT((dest_ip < 1) || (dest_ip > MMNIF_CORES), 0)) { + DEBUGPRINTF("mmnif_tx: invalid destination IP %d => drop\n", dest_ip); + goto drop_packet; + } + /* allocate memory for the packet in the remote buffer */ realloc: write_address = mmnif_rxbuff_alloc(dest_ip, p->tot_len); @@ -691,19 +620,10 @@ realloc: { //DEBUGPRINTF("mmnif_tx(): concurrency"); - //if (chances <= 0) - // goto drop_packet; - - //chances--; - //mmnif_trigger_irq(dest_ip); NOP8;NOP8;NOP8;NOP8;NOP8;NOP8;NOP8;NOP8; - //udelay(10); goto realloc; } - if (!write_address) - goto drop_packet; - #if MMNIF_USE_MPB asm volatile (".byte 0x0f; .byte 0x0a;\n"); #endif @@ -711,7 +631,7 @@ realloc: for (q = p, i = 0; q != 0; q = q->next) { #if !MMNIF_USE_MBP - memcpy_to_nc((char*) write_address+ i, q->payload, q->len); + memcpy_to_nc((char*) write_address + i, q->payload, q->len); #else memcpy_put((char*) write_address + i, q->payload, q->len); #endif @@ -737,6 +657,7 @@ realloc: LINK_STATS_INC(link.xmit); mmnif->stats.tx++; mmnif->stats.tx_bytes += p->tot_len; + mmnif_trigger_irq(dest_ip); return ERR_OK; @@ -790,6 +711,7 @@ static int mmnif_hashadd(int sock, int rsock, uint8_t dest_ip) p->socket = sock; p->remote_socket = rsock; p->dest_ip = dest_ip; + return 0; } } @@ -817,6 +739,7 @@ static int mmnif_hashdelete(int sock) p->socket = -1; p->remote_socket = 0; p->dest_ip = 0; + return 0; } } @@ -831,38 +754,16 @@ static err_t mmnif_tx_bypass(struct netif * netif, void *pbuff, uint16_t size, i { mmnif_t *mmnif = netif->state; uint32_t write_address; + //uint32_t id; 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)); + write_address = mmnif_rxbuff_alloc(dest->dest_ip, size); if (!write_address) { - - // DEBUGPRINTF("mmnif_tx_bypass(): concurrency"); - // udelay(exp_delay); - // exp_delay << 1; - // reschedule(); - NOP8; - NOP8; - NOP8; - NOP8; - NOP8; - NOP8; - NOP8; - NOP8; + NOP8;NOP8;NOP8;NOP8;NOP8;NOP8;NOP8;NOP8; goto realloc; } @@ -878,7 +779,7 @@ realloc: #if !MMNIF_USE_MPB memcpy_to_nc((void*) write_address, pbuff, size); #else - memcpy_put(write_address, pbuff, size); + memcpy_put((void*) write_address, pbuff, size); #endif *((int *)RCCE_fool_write_combine_buffer) = 1; @@ -888,7 +789,7 @@ realloc: if (mmnif_commit_packet_bypass(dest->dest_ip, write_address, dest->remote_socket)) { - DEBUGPRINTF("mmnif_tx(): packet somehow lost during commit\n"); + DEBUGPRINTF("mmnif_tx_bypass(): 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); @@ -899,15 +800,10 @@ realloc: 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_trigger_irq(dest->dest_ip); + + return ERR_OK; } /* mmnif_send(): is going to be used as replacement of @@ -916,28 +812,30 @@ drop_packet: 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; + uint32_t i, j, k; + int total_size = 0; 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))); + if (size < ((MMNIF_RX_BUFFERLEN / 2) - CLINE_SIZE)) { + if (mmnif_tx_bypass(mmnif_dev, data, size, s) == ERR_OK) + return size; + } else { + j = size / (((MMNIF_RX_BUFFERLEN / 2) - CLINE_SIZE)); + k = size - (j * (((MMNIF_RX_BUFFERLEN / 2) - CLINE_SIZE))); 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; + if (mmnif_tx_bypass(mmnif_dev, (char*) data + i * ((MMNIF_RX_BUFFERLEN / 2) - CLINE_SIZE), ((MMNIF_RX_BUFFERLEN / 2) - CLINE_SIZE), s) != ERR_OK) + return total_size; + total_size += (MMNIF_RX_BUFFERLEN / 2) - CLINE_SIZE; } - ret = mmnif_tx_bypass(mmnif_dev, data + (j - 1) * ((MMNIF_RX_BUFFERLEN / 2) - 1), k, s); - return ret; + + if (mmnif_tx_bypass(mmnif_dev, data + (j - 1) * ((MMNIF_RX_BUFFERLEN / 2) - CLINE_SIZE), k, s) == ERR_OK) + total_size += k; } + + return total_size; } return lwip_send(s, data, size, flags); @@ -948,8 +846,7 @@ int mmnif_send(int s, void *data, size_t size, int flags) * 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) +static err_t mmnif_link_layer(struct netif *netif, struct pbuf *q, ip_addr_t * ipaddr) { return netif->linkoutput(netif, q); } @@ -968,7 +865,6 @@ err_t mmnif_init(struct netif *netif) DEBUGPRINTF("mmnif init attempt\n"); mmnif_dev = netif; - own_ip_address += RCCE_ue() + 1; /* Alloc and clear memory for the device struct */ @@ -993,7 +889,7 @@ err_t mmnif_init(struct netif *netif) // 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_WT | 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)); + mmnif->rx_buff = (mm_rx_buffer_t *) (header_start_address + header_size * RCCE_IAM); /* Alloc and clear shared memory for rx_buff */ @@ -1007,38 +903,32 @@ err_t mmnif_init(struct netif *netif) if (!RCCE_malloc(RCCE_LINE_SIZE)) { DEBUGPRINTF("mmnif init(): allocating shared memory failed\n"); - //return ERR_MEM; + return ERR_MEM; } } - #else // align size to the granularity of a page size heap_size = (heap_size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); - heap_start_address = (void*) RCCE_shmalloc(heap_size * MMNIF_CORES); - DEBUGPRINTF("RCCE_shmalloc : %p (size %u)\n", header_start_address, MMNIF_CORES * header_size); + DEBUGPRINTF("RCCE_shmalloc : %p (size %u)\n", heap_start_address, MMNIF_CORES * header_size); // 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); uint32_t n = (uint32_t) heap_start_address; heap_start_address = map_region(0, heap_start_address, (MMNIF_CORES * heap_size) >> PAGE_SHIFT, MAP_KERNEL_SPACE | MAP_NO_CACHE | MAP_MPE | MAP_WT); - map_region(heap_start_address + (heap_size) * (own_ip_address - router_ip_address), n + (heap_size) * (own_ip_address - router_ip_address), header_size >> PAGE_SHIFT, MAP_KERNEL_SPACE | MAP_MPE | MAP_WT | MAP_REMAP); + map_region(heap_start_address + (heap_size) * RCCE_IAM, n + (heap_size) * RCCE_IAM, header_size >> PAGE_SHIFT, MAP_KERNEL_SPACE | MAP_MPE | MAP_WT | MAP_REMAP); #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 | MAP_WT); -#endif // USE_CAHCE +#endif // USE_CACHE #endif // MMNIF_USE_MPB - DEBUGPRINTF("map_region : %p\n", header_start_address); + DEBUGPRINTF("map_region : %p\n", heap_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; + heap_start_address = heap_start_address - (RC_MY_COREID/2 * 16*1024*1024 ) - (RC_MY_COREID%2 * 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); + mmnif->rx_heap = heap_start_address + heap_size * RCCE_IAM; #endif if (!(heap_start_address)) @@ -1047,13 +937,9 @@ err_t mmnif_init(struct netif *netif) return ERR_MEM; } -#if !MMNIF_USE_MPB - memset(mmnif->rx_buff, 0x00, header_size); - memset(mmnif->rx_heap, 0x00, heap_size); - - *((int *)RCCE_fool_write_combine_buffer) = 1; -#else +#if MMNIF_USE_MPB asm volatile (".byte 0x0f; .byte 0x0a;\n"); +#endif for(i=0; irx_buff)[i] = 0x00; @@ -1061,6 +947,7 @@ err_t mmnif_init(struct netif *netif) ((uint8_t*)mmnif->rx_heap)[i] = 0x00; *((int *)RCCE_fool_write_combine_buffer) = 1; +#if MMNIF_USE_MPB asm volatile (".byte 0x0f; .byte 0x0a;\n"); #endif @@ -1070,9 +957,7 @@ err_t mmnif_init(struct netif *netif) /* init the lock's for the hdr */ - spinlock_init(&mmnif->rx_buff->rlock); spinlock_init(&pseudolock); - spinlock_init(&mmnif->lock); /* init the sems for communication art */ @@ -1083,10 +968,9 @@ err_t mmnif_init(struct netif *netif) mmnif_hashtable[i].socket = -1; mmnif_hashtable[i].remote_socket = -1; mmnif_hashtable[i].dest_ip = 0; + //mmnif_hashtable[i].counter = 0; -#if MMNIF_FAST_SOCKET_BLOCK sem_init(&mmnif_hashtable[i].sem, 0); -#endif } for (i=0; irx_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 */ @@ -1140,25 +1021,24 @@ err_t mmnif_init(struct netif *netif) static void mmnif_rx(struct netif *netif) { mmnif_t *mmnif = netif->state; - mm_rx_buffer_t *b = mmnif->rx_buff; + volatile 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; + uint32_t i, j, flags; uint8_t rdesc; err_t err = ERR_OK; bypass_rxdesc_t *bp; anotherpacket: + flags = irq_nested_disable(); 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; } @@ -1182,26 +1062,21 @@ anotherpacket: 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(); + goto out; } 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 + irq_nested_enable(flags); + return; } - 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 */ @@ -1216,6 +1091,8 @@ anotherpacket: goto out; } + irq_nested_enable(flags); + /* check for over/underflow */ if (BUILTIN_EXPECT((length < 20 /* IP header size */) || (length > 1536), 0)) { @@ -1235,7 +1112,7 @@ anotherpacket: * and other higher layer can handle it */ p = pbuf_alloc(PBUF_RAW, length, PBUF_POOL); - if (!p) + if (BUILTIN_EXPECT(!p, 0)) { DEBUGPRINTF("mmnif_rx(): low on mem - packet dropped\n"); goto drop_packet; @@ -1248,16 +1125,17 @@ anotherpacket: /* copy packet to pbuf structure going through linked list */ for (q = p, i = 0; q != NULL; q = q->next) { -#if !USE_CACHE || !MMNIF_USE_MBP - memcpy_from_nc((uint8_t *) q->payload, &packet[i], q->len); +#if !USE_CACHE && !MMNIF_USE_MBP + memcpy_from_nc((uint8_t *) q->payload, packet + i, q->len); #elif MMNIF_USE_MPB - memcpy_get((uint8_t *) q->payload, &packet[i], q->len); + memcpy_get((uint8_t *) q->payload, packet + i, q->len); #else - memcpy((uint8_t *) q->payload, &packet[i], q->len); + memcpy((uint8_t *) q->payload, packet + i, q->len); #endif i += q->len; } + *((int *)RCCE_fool_write_combine_buffer) = 1; #if MMNIF_USE_MPB asm volatile (".byte 0x0f; .byte 0x0a;\n"); #endif @@ -1292,9 +1170,12 @@ drop_packet: /* TODO: error handling */ LINK_STATS_INC(link.drop); mmnif->stats.rx_err++; + mmnif->check_in_progress = 0; + return; out: mmnif->check_in_progress = 0; + irq_nested_enable(flags); return; } @@ -1304,20 +1185,15 @@ out: 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; + volatile mm_rx_buffer_t *b = mmnif->rx_buff; + uint16_t length = 0; + char *packet = NULL; 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); + if (b->desc_table[b->dread].stat == MMNIF_STATUS_FREE) { return -1; } @@ -1336,14 +1212,10 @@ static int mmnif_rx_bypass(struct netif *netif, int s, void *data, uint32_t len) } } - // 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 */ @@ -1360,13 +1232,28 @@ static int mmnif_rx_bypass(struct netif *netif, int s, void *data, uint32_t len) #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 + + if (BUILTIN_EXPECT(len < length, 0)) goto drop_packet; +#if USE_CACHE || MMNIF_USE_MPB + asm volatile (".byte 0x0f; .byte 0x0a;\n"); +#endif + +#if !USE_CACHE && !MMNIF_USE_MBP + memcpy_from_nc(data, (void*) mmnif->rx_buff->desc_table[rdesc].addr, mmnif->rx_buff->desc_table[rdesc].len); +#elif MMNIF_USE_MPB + memcpy_get(data, (void*) mmnif->rx_buff->desc_table[rdesc].addr, mmnif->rx_buff->desc_table[rdesc].len); +#else + memcpy(data, (void*) mmnif->rx_buff->desc_table[rdesc].addr, mmnif->rx_buff->desc_table[rdesc].len); +#endif + + *((int *)RCCE_fool_write_combine_buffer) = 1; +#if MMNIF_USE_MPB + asm volatile (".byte 0x0f; .byte 0x0a;\n"); +#endif + /* 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 */ @@ -1385,10 +1272,6 @@ static int mmnif_rx_bypass(struct netif *netif, int s, void *data, uint32_t len) 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++; @@ -1400,28 +1283,47 @@ drop_packet: */ int mmnif_recv(int s, void *data, uint32_t len, int flags) { + mmnif_t* mmnif = (mmnif_t *) mmnif_dev->state; bypass_rxdesc_t *p = mmnif_hashlookup(s); - int ret; if (p == 0) return lwip_recv(s, data, len, flags); -#if MMNIF_FAST_SOCKET_BLOCK + if (sem_trywait(&p->sem) == 0) + return mmnif_rx_bypass(mmnif_dev, s, data, len); + + uint32_t state = irq_nested_disable(); + if (mmnif->check_in_progress) { + uint32_t i,j; + volatile mm_rx_buffer_t *b = mmnif->rx_buff; + bypass_rxdesc_t *bp; + uint8_t rdesc; + + /* 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) { + bp = mmnif_hashlookup(b->desc_table[rdesc].fast_sock); + if (bp) { + b->desc_table[rdesc].stat = MMNIF_STATUS_INPROC; + irq_nested_enable(state); + return mmnif_rx_bypass(mmnif_dev, s, data, len); + } + } + } + } + + mmnif->check_in_progress = 0; + } + irq_nested_enable(state); + 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; + return mmnif_rx_bypass(mmnif_dev, s, data, len); } /* mmnif_socket(): replacement of lwip_socket for @@ -1447,27 +1349,30 @@ int mmnif_socket(int domain, int type, int protocol) */ 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; + struct sockaddr_in *client = (struct sockaddr_in*)addr; + volatile mm_rx_buffer_t *b = ((mmnif_t *) mmnif_dev->state)->rx_buff; bypass_rxdesc_t *p; int tmp1 = get_clock_tick(); - int tmp2 = 0; + int i, tmp2 = 0; + uint16_t port; + + // TODO: Bug, not compatible with BSD sockets + port = client->sin_port; + 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); + RCCE_acquire_lock(RC_MY_COREID); 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); + RCCE_release_lock(RC_MY_COREID); while (b->acceptors[(i + port) % MMNIF_MAX_ACCEPTORS].stat != MMNIF_ACC_STAT_ACCEPT_ME) NOP8; @@ -1475,48 +1380,46 @@ int mmnif_accept(int s, struct sockaddr *addr, socklen_t * addrlen) 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); + RCCE_acquire_lock(RC_MY_COREID); 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); + RCCE_release_lock(RC_MY_COREID); return i; } } - return -1; - } - else - { + 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); + RCCE_acquire_lock(RC_MY_COREID); 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); + RCCE_release_lock(RC_MY_COREID); 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); + RCCE_acquire_lock(RC_MY_COREID); if (b->acceptors[(i + port) % MMNIF_MAX_ACCEPTORS].stat == MMNIF_ACC_STAT_ACCEPT_ME) { - spinlock_unlock(&b->acceptors[(i + port) % MMNIF_MAX_ACCEPTORS].alock); + RCCE_acquire_lock(RC_MY_COREID); break; } DEBUGPRINTF("mmnif_accept(): Timout occoured, switching to normal accept()"); 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); + RCCE_release_lock(RC_MY_COREID); goto normalaccept; } NOP8; @@ -1525,14 +1428,15 @@ int mmnif_accept(int s, struct sockaddr *addr, socklen_t * addrlen) 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); + RCCE_acquire_lock(RC_MY_COREID); 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); + RCCE_release_lock(RC_MY_COREID); return i; } } + return -1; } @@ -1547,48 +1451,29 @@ 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; + volatile 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]; + core = ip4_addr4(&p->sin_addr.s_addr); 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); + b = (volatile 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); + RCCE_acquire_lock(RC_COREID[core-1]); 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); + b->acceptors[(i + port) % MMNIF_MAX_ACCEPTORS].src_ip = ip4_addr4(&mmnif_dev->ip_addr); + mmnif_hashadd(s, b->acceptors[(i + port) % MMNIF_MAX_ACCEPTORS].nsock, core); + RCCE_release_lock(RC_COREID[core-1]); + while (b->acceptors[(i + port) % MMNIF_MAX_ACCEPTORS].stat != MMNIF_ACC_STAT_ACCEPTED) { @@ -1603,9 +1488,11 @@ int mmnif_connect(int s, const struct sockaddr *name, socklen_t namelen) // } NOP8; } - spinlock_lock(&b->acceptors[(i + port) % MMNIF_MAX_ACCEPTORS].alock); + + RCCE_acquire_lock(RC_COREID[core-1]); b->acceptors[(i + port) % MMNIF_MAX_ACCEPTORS].stat = MMNIF_ACC_STAT_CLOSED; - spinlock_unlock(&b->acceptors[(i + port) % MMNIF_MAX_ACCEPTORS].alock); + RCCE_release_lock(RC_COREID[core-1]); + return 0; } } @@ -1629,6 +1516,13 @@ int mmnif_bind(int s, const struct sockaddr *name, socklen_t namelen) return 0; } +int mmnif_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen) +{ + if ((unsigned int)s < MMNIF_PSEUDO_SOCKET_START) + return lwip_setsockopt(s, level, optname, optval, optlen); + return 0; +} + /* mmnif_closesocket(): replacement if lwip_close for * fast_sockets */ @@ -1668,7 +1562,7 @@ static void mmnif_irqhandler(struct state* s) 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; + mmnif->check_in_progress = 1; } else { DEBUGPRINTF("rckemacif_handler: unable to send a poll request to the tcpip thread\n"); } diff --git a/drivers/net/mmnif.h b/drivers/net/mmnif.h index 69046984..67fd46a7 100644 --- a/drivers/net/mmnif.h +++ b/drivers/net/mmnif.h @@ -24,26 +24,50 @@ #ifdef CONFIG_LWIP #include #include /* lwip netif */ +#include -#define AF_MMNIF_NET 0x1337 +#define AF_MMNIF_NET 0x42 -#define MMNIF_AUTOACTIVATE_FAST_SOCKETS 0 +#define MMNIF_AUTOACTIVATE_FAST_SOCKETS 1 #if MMNIF_AUTOACTIVATE_FAST_SOCKETS + +int mmnif_socket(int domain, int type, int protocol); +int mmnif_send(int s, void *data, size_t size, int flags); +int mmnif_recv(int s, void *data, uint32_t len, int flags); +int mmnif_accept(int s, struct sockaddr *addr, socklen_t * addrlen); +int mmnif_connect(int s, const struct sockaddr *name, socklen_t namelen); +int mmnif_listen(int s, int backlog); +int mmnif_bind(int s, const struct sockaddr *name, socklen_t namelen); +int mmnif_closesocket(int s); +int mmnif_getsockopt (int s, int level, int optname, void *optval, socklen_t *optlen); +int mmnif_setsockopt (int s, int level, int optname, const void *optval, socklen_t optlen); + +#undef accept #define accept(a,b,c) mmnif_accept(a,b,c) +#undef closesocket #define closesocket(s) mmnif_closesocket(s) +#undef connect #define connect(a,b,c) mmnif_connect(a,b,c) +#undef recv #define recv(a,b,c,d) mmnif_recv(a,b,c,d) +#undef send #define send(a,b,c,d) mmnif_send(a,b,c,d) +#undef socket #define socket(a,b,c) mmnif_socket(a,b,c) +#undef bind #define bind(a,b,c) mmnif_bind(a,b,c) +#undef listen #define listen(a,b) mmnif_listen(a,b) +#undef setsockopt +#define setsockopt(a,b,c,d,e) mmnif_setsockopt(a,b,c,d,e) +#undef select #endif err_t mmnif_init(struct netif*); err_t mmnif_shutdown(void); int mmnif_worker(void *e); -void mmnif_print_driver_status(); +void mmnif_print_driver_status(void); #endif diff --git a/drivers/net/rckemac.c b/drivers/net/rckemac.c index 0ba62c15..67c25f2f 100644 --- a/drivers/net/rckemac.c +++ b/drivers/net/rckemac.c @@ -132,14 +132,6 @@ static struct netif* mynetif; inline static void* memcpy_from_nc(void *dest, const void *src, size_t count) { -#if 0 - size_t i; - - for(i=0; itot_len < 20 /* IP header size */) || (p->tot_len > 1536), 0)) { @@ -257,6 +240,9 @@ again: if (sum < packets) { LWIP_DEBUGF(NETIF_DEBUG, ("Warning: not enough space available, retrying...\n")); + chance--; + if (chance < 0) + return ERR_MEM; goto again; } #endif @@ -408,7 +394,7 @@ again: length = U16(addr); // Check for over/underflow - if ((length < 20) || (length > 1536)) { + if (BUILTIN_EXPECT((length < 20) || (length > 1536), 0)) { LWIP_DEBUGF(NETIF_DEBUG, ("rckemacif_rx_handler(): illegal packet length %d => drop\n", length)); LWIP_DEBUGF(NETIF_DEBUG, ("start read at %d; write_offset at %d; addr: %p, packet len: %d\n", read_offset, write_offset, addr, length)); @@ -439,7 +425,7 @@ again: //LWIP_DEBUGF(NETIF_DEBUG, ("length %u, read_offset %u, write_offset %u\n", length, read_offset, write_offset)); p = pbuf_alloc(PBUF_RAW, length, PBUF_POOL); - if (p) { + if (BUILTIN_EXPECT(p != NULL, 1)) { #if ETH_PAD_SIZE pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */ #endif diff --git a/fs/fs.c b/fs/fs.c index 2ee3365d..81f74e47 100644 --- a/fs/fs.c +++ b/fs/fs.c @@ -34,11 +34,14 @@ ssize_t read_fs(fildes_t* file, uint8_t* buffer, size_t size) if (BUILTIN_EXPECT(!node || !buffer, 0)) return ret; - spinlock_lock(&node->lock); - // Has the node got a read callback? - if (node->read != 0) + if (node->type != FS_SOCKET) { + spinlock_lock(&node->lock); + // Has the node got a read callback? + if (node->read != 0) + ret = node->read(file, buffer, size); + spinlock_unlock(&node->lock); + } else if (node->read != 0) ret = node->read(file, buffer, size); - spinlock_unlock(&node->lock); return ret; } @@ -51,11 +54,14 @@ ssize_t write_fs(fildes_t* file, uint8_t* buffer, size_t size) if (BUILTIN_EXPECT(!node || !buffer, 0)) return ret; - spinlock_lock(&node->lock); - // Has the node got a write callback? - if (node->write != 0) + if (node->type != FS_SOCKET) { + spinlock_lock(&node->lock); + // Has the node got a write callback? + if (node->write != 0) + ret = node->write(file, buffer, size); + spinlock_unlock(&node->lock); + } else if (node->write != 0) ret = node->write(file, buffer, size); - spinlock_unlock(&node->lock); return ret; } diff --git a/fs/initrd.c b/fs/initrd.c index cc76c994..1034cdee 100644 --- a/fs/initrd.c +++ b/fs/initrd.c @@ -443,7 +443,7 @@ int initrd_init(void) /* create the character device "kmessages" */ tmp = mkdir_fs(fs_root, "var"); - kmsg_init(tmp, "kmessages"); + kmsg_init(tmp, "log"); /* For every module.. */ #ifdef CONFIG_MULTIBOOT diff --git a/include/metalsvm/fs.h b/include/metalsvm/fs.h index 2dd14578..1665b4ad 100644 --- a/include/metalsvm/fs.h +++ b/include/metalsvm/fs.h @@ -29,12 +29,13 @@ #include #include -#define FS_FILE 0x01 -#define FS_DIRECTORY 0x02 -#define FS_CHARDEVICE 0x03 +#define FS_FILE 0x01 +#define FS_DIRECTORY 0x02 +#define FS_CHARDEVICE 0x03 //#define FS_BLOCKDEVICE 0x04 //#define FS_PIPE 0x05 //#define FS_SYMLINK 0x06 +#define FS_SOCKET 0x06 //#define FS_MOUNTPOINT 0x08 // Is the file an active mountpoint? @@ -202,10 +203,9 @@ extern vfs_node_t* fs_root; // The root of the filesystem. */ /** @brief Read from file system into the buffer - * @param node Pointer to the node to read from + * @param file Pointer to the file descriptor to read from * @param buffer Pointer to buffer to write into * @param size Number of bytes to read - * @param offset Offset position of the source range * @return * - number of bytes copied (size) * - 0 on error @@ -213,10 +213,9 @@ extern vfs_node_t* fs_root; // The root of the filesystem. ssize_t read_fs(fildes_t* file, uint8_t* buffer, size_t size); /** @brief Write into the file system from the buffer - * @param node Pointer to the node to write to + * @param file Pointer to the file descriptor to write to * @param buffer Pointer to buffer to read from * @param size Number of bytes to read - * @param offset Offset position of the destination range * @return * - number of bytes copied (size) * - 0 on error diff --git a/include/metalsvm/init.h b/include/metalsvm/init.h index 8ca4a89a..ab77b793 100644 --- a/include/metalsvm/init.h +++ b/include/metalsvm/init.h @@ -36,8 +36,8 @@ extern "C" { * initialize the VGA output. If configured.*/ int lowlevel_init(void); -/** @brief Shutdown the system */ -int shutdown(void); +/** @brief Shutdown the network */ +int network_shutdown(void); /** @brief Entry point of the init task */ int initd(void* arg); diff --git a/include/metalsvm/semaphore.h b/include/metalsvm/semaphore.h index c0dc0f81..1f98471c 100644 --- a/include/metalsvm/semaphore.h +++ b/include/metalsvm/semaphore.h @@ -103,6 +103,7 @@ inline static int sem_trywait(sem_t* s) { /** @brief Blocking wait for semaphore * + * @param s Address of the according sem_t structure * @param ms Timeout in milliseconds * @return * - 0 on success diff --git a/include/metalsvm/tasks.h b/include/metalsvm/tasks.h index 9e6ab05f..63c8b3f4 100644 --- a/include/metalsvm/tasks.h +++ b/include/metalsvm/tasks.h @@ -60,6 +60,7 @@ int multitasking_init(void); * @param id The value behind this pointer will be set to the new task's id * @param ep Pointer to the entry function for the new task * @param arg Arguments the task shall start with + * @param prio Desired priority of the new kernel task * * @return * - 0 on success diff --git a/include/metalsvm/tasks_types.h b/include/metalsvm/tasks_types.h index 857e9d52..759bbeea 100644 --- a/include/metalsvm/tasks_types.h +++ b/include/metalsvm/tasks_types.h @@ -64,7 +64,7 @@ typedef int (*entry_point_t)(void*); typedef int (STDCALL *internal_entry_point_t)(void*); struct page_dir; -/* @brief The task_t structure */ +/** @brief The task_t structure */ typedef struct task { /// Task id = position in the task table tid_t id; diff --git a/include/metalsvm/time.h b/include/metalsvm/time.h index c20d059c..8c4b7258 100644 --- a/include/metalsvm/time.h +++ b/include/metalsvm/time.h @@ -73,7 +73,7 @@ uint64_t get_clock_tick(void); * * This function sleeps some seconds * - * @paran sec Amount of seconds to wait + * @param sec Amount of seconds to wait */ static inline void sleep(unsigned int sec) { timer_wait(sec*TIMER_FREQ); } diff --git a/kernel/init.c b/kernel/init.c index eea20644..294d240f 100644 --- a/kernel/init.c +++ b/kernel/init.c @@ -171,7 +171,7 @@ static void tcpip_init_done(void* arg) } #endif -static int network_shutdown(void) +int network_shutdown(void) { #if defined(CONFIG_LWIP) && defined(CONFIG_ROCKCREEK) mmnif_shutdown(); @@ -183,15 +183,6 @@ static int network_shutdown(void) return 0; } -int shutdown(void) -{ - int ret; - - ret = network_shutdown(); - - return ret; -} - static void list_fs(vfs_node_t* node, uint32_t depth) { int j, i = 0; diff --git a/kernel/tasks.c b/kernel/tasks.c index 39e215e1..206823e7 100644 --- a/kernel/tasks.c +++ b/kernel/tasks.c @@ -244,6 +244,7 @@ void NORETURN abort(void) { * @param id Pointer to a tid_t struct were the id shall be set * @param ep Pointer to the function the task shall start with * @param arg Arguments list + * @param prio Desired priority of the new task * @return * - 0 on success * - -ENOMEM (-12) or -EINVAL (-22) on failure @@ -1107,13 +1108,13 @@ void update_load(void) spinlock_irqsave_lock(&runqueues[core_id].lock); runqueues[core_id].load[0] *= EXP_1; - runqueues[core_id].load[0] += (runqueues[core_id].nr_tasks *FIXED_1) * (FIXED_1 - EXP_1); + runqueues[core_id].load[0] += (runqueues[core_id].nr_tasks * FIXED_1) * (FIXED_1 - EXP_1); runqueues[core_id].load[0] >>= FSHIFT; runqueues[core_id].load[1] *= EXP_5; - runqueues[core_id].load[1] += (runqueues[core_id].nr_tasks *FIXED_1) * (FIXED_1 - EXP_5); + runqueues[core_id].load[1] += (runqueues[core_id].nr_tasks * FIXED_1) * (FIXED_1 - EXP_5); runqueues[core_id].load[1] >>= FSHIFT; runqueues[core_id].load[2] *= EXP_15; - runqueues[core_id].load[2] += (runqueues[core_id].nr_tasks *FIXED_1) * (FIXED_1 - EXP_15); + runqueues[core_id].load[2] += (runqueues[core_id].nr_tasks * FIXED_1) * (FIXED_1 - EXP_15); runqueues[core_id].load[2] >>= FSHIFT; spinlock_irqsave_unlock(&runqueues[core_id].lock); diff --git a/lwip/src/arch/sys_arch.c b/lwip/src/arch/sys_arch.c index 594cf38d..b305ad72 100644 --- a/lwip/src/arch/sys_arch.c +++ b/lwip/src/arch/sys_arch.c @@ -101,8 +101,11 @@ sys_thread_t sys_thread_new(const char *name, lwip_thread_fn thread, void *arg, */ void sys_sem_free(sys_sem_t* sem) { - sem->valid = FALSE; - sem_destroy(&sem->sem); + if (BUILTIN_EXPECT(sem != NULL, 1)) { + sem->valid = FALSE; + SYS_STATS_DEC(sem.used); + sem_destroy(&sem->sem); + } } /* sys_sem_valid(): returns if semaphore is valid @@ -110,16 +113,29 @@ void sys_sem_free(sys_sem_t* sem) */ int sys_sem_valid(sys_sem_t* sem) { + if (BUILTIN_EXPECT(sem == NULL, 0)) + return FALSE; return sem->valid; } /* sys_sem_new(): creates a new semaphre with given count. * This semaphore becomes valid */ -err_t sys_sem_new(sys_sem_t* sem, u8_t count) +err_t sys_sem_new(sys_sem_t* s, u8_t count) { - sem->valid = TRUE; - return sem_init(&sem->sem, count); + int err; + + if (BUILTIN_EXPECT(!s, 0)) + return ERR_VAL; + + err = sem_init(&s->sem, count); + if (err < 0) + return ERR_VAL; + + SYS_STATS_INC_USED(sem); + s->valid = TRUE; + + return ERR_OK; } /* sys_sem_set_invalid(): this semapohore becomes invalid @@ -158,6 +174,8 @@ u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout) */ int sys_mbox_valid(sys_mbox_t * mbox) { + if (BUILTIN_EXPECT(mbox == NULL, 0)) + return FALSE; return mbox->valid; } @@ -182,8 +200,11 @@ u32_t sys_arch_mbox_fetch(sys_mbox_t * mbox, void **msg, u32_t timeout) */ void sys_mbox_free(sys_mbox_t* mbox) { - mbox->valid = FALSE; - mailbox_ptr_destroy(&mbox->mailbox); + if (BUILTIN_EXPECT(mbox != NULL, 1)) { + mbox->valid = FALSE; + SYS_STATS_DEC(mbox.used); + mailbox_ptr_destroy(&mbox->mailbox); + } } /* sys_arch_mbox_tryfetch(): poll for new data in mailbox @@ -192,7 +213,6 @@ void sys_mbox_free(sys_mbox_t* mbox) u32_t sys_arch_mbox_tryfetch(sys_mbox_t* mbox, void** msg) { int ret = mailbox_ptr_tryfetch(&mbox->mailbox, msg); - if (ret) return SYS_MBOX_EMPTY; return 0; @@ -201,12 +221,20 @@ u32_t sys_arch_mbox_tryfetch(sys_mbox_t* mbox, void** msg) /* sys_mbox_new(): create a new mailbox with a minimum size of "size" * */ -err_t sys_mbox_new(sys_mbox_t* mbox, int size) +err_t sys_mbox_new(sys_mbox_t* mb, int size) { - LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_new: create mailbox with the minimum size: %d\n", size)); + int err; + + //LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_new: create mailbox with the minimum size: %d\n", size)); + if (BUILTIN_EXPECT(!mb, 0)) + return ERR_VAL; - mbox->valid = TRUE; - return mailbox_ptr_init(&mbox->mailbox); + mb->valid = TRUE; + SYS_STATS_INC_USED(mbox); + err = mailbox_ptr_init(&mb->mailbox); + if (err) + return ERR_MEM; + return ERR_OK; } /* sys_mbox_set_invalid(): set the given mailbox to invald @@ -261,9 +289,12 @@ void sys_mutex_unlock(sys_mutex_t* mutex) /* sys_mutex_new(): create a new mutex * */ -err_t sys_mutex_new(sys_mutex_t * mutex) +err_t sys_mutex_new(sys_mutex_t * m) { - sem_init(mutex, 1); + if (BUILTIN_EXPECT(!m, 0)) + return ERR_VAL; + SYS_STATS_INC_USED(mutex); + sem_init(m, 1); return ERR_OK; } diff --git a/lwip/src/include/arch/cc.h b/lwip/src/include/arch/cc.h index d4b637cc..b330f204 100644 --- a/lwip/src/include/arch/cc.h +++ b/lwip/src/include/arch/cc.h @@ -74,6 +74,12 @@ typedef size_t mem_ptr_t; #define LWIP_CHKSUM_ALGORITHM 2 +/* define errno to determine error code */ +#ifdef CONFIG_LWIP +#define ERRNO +#define errno per_core(current_task)->lwip_err +#endif + /* prototypes for printf() and abort() */ #include #include diff --git a/lwip/src/include/arch/sys_arch.h b/lwip/src/include/arch/sys_arch.h index e71a6d36..6857d983 100644 --- a/lwip/src/include/arch/sys_arch.h +++ b/lwip/src/include/arch/sys_arch.h @@ -43,10 +43,4 @@ static inline void sys_arch_unprotect(sys_prot_t pval) #endif #endif -/* define errno to determine error code */ -#ifdef CONFIG_LWIP -#define ERRNO -#define errno per_core(current_task)->lwip_err -#endif - #endif /* __ARCH_SYS_ARCH_H__ */ diff --git a/lwip/src/include/lwipopts.h b/lwip/src/include/lwipopts.h index e3de59e0..4bd362be 100644 --- a/lwip/src/include/lwipopts.h +++ b/lwip/src/include/lwipopts.h @@ -235,7 +235,7 @@ #define DHCP_DEBUG LWIP_DBG_OFF #define ETHARP_DEBUG LWIP_DBG_OFF #define TCPIP_DEBUG LWIP_DBG_OFF -#define SYS_DEBUG LWIP_DBG_OFF +#define SYS_DEBUG LWIP_DBG_ON #define RAW_DEBUG LWIP_DBG_OFF #define MEM_DEBUG LWIP_DBG_OFF #define IP_DEBUG LWIP_DBG_OFF diff --git a/newlib/examples/hello.c b/newlib/examples/hello.c index 708bb644..2ea2eeae 100644 --- a/newlib/examples/hello.c +++ b/newlib/examples/hello.c @@ -56,8 +56,10 @@ int main(int argc, char** argv) if (!teststr) return EFAULT; - testfile = open("/bin/test.txt", O_CREAT | O_EXCL, "wr"); - write(testfile, "hello in new file '/bin/test.txt'", 34); + testfile = open("/bin/test/test.txt", O_CREAT | O_EXCL, "wr"); + if (testfile < 1) + printf("error"); + write(testfile, "hello in new file '/bin/test/test.txt'", 34); lseek(testfile, 0, SEEK_SET); read(testfile, teststr, 100); close(testfile);