Merge branch 'master' of git.lfbs.rwth-aachen.de:metalsvm
Conflicts: kernel/netio.c
This commit is contained in:
commit
14785b5e23
23 changed files with 2265 additions and 1364 deletions
|
@ -3,7 +3,7 @@ ARCH = x86
|
|||
NAME = metalsvm
|
||||
LWIPDIRS = lwip/src/arch lwip/src/api lwip/src/core lwip/src/core/ipv4 lwip/src/netif
|
||||
DRIVERDIRS = drivers/net drivers/char
|
||||
KERNDIRS = libkern kernel mm fs arch/$(ARCH)/kernel arch/$(ARCH)/mm arch/$(ARCH)/scc $(LWIPDIRS) $(DRIVERDIRS)
|
||||
KERNDIRS = libkern kernel mm fs apps arch/$(ARCH)/kernel arch/$(ARCH)/mm arch/$(ARCH)/scc $(LWIPDIRS) $(DRIVERDIRS)
|
||||
SUBDIRS = $(KERNDIRS)
|
||||
|
||||
CC_FOR_TARGET=gcc
|
||||
|
|
4
apps/Makefile
Normal file
4
apps/Makefile
Normal file
|
@ -0,0 +1,4 @@
|
|||
C_source := tests.c echo.c netio.c
|
||||
MODULE := apps
|
||||
|
||||
include $(TOPDIR)/Makefile.inc
|
|
@ -24,8 +24,14 @@
|
|||
#include <metalsvm/syscall.h>
|
||||
#include <metalsvm/errno.h>
|
||||
|
||||
#ifdef CONFIG_ROCKCREEK
|
||||
#include <asm/RCCE.h>
|
||||
#include <asm/RCCE_lib.h>
|
||||
#include <asm/SCC_API.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This implements a netio server.
|
||||
* This implements a netio server and client (only TCP version).
|
||||
* The client sends a command word (4 bytes) then a data length word (4 bytes).
|
||||
* If the command is "receive", the server is to consume "data length" bytes into
|
||||
* a circular buffer until the first byte is non-zero, then it is to consume
|
||||
|
@ -40,7 +46,6 @@
|
|||
|
||||
#ifdef CONFIG_LWIP
|
||||
#include <lwip/sockets.h>
|
||||
#include <lwip/stats.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
@ -57,9 +62,12 @@ typedef struct
|
|||
#define DEFAULTPORT 0x494F /* "IO" */
|
||||
#define TMAXSIZE 65536
|
||||
|
||||
static int tSizes[] = {1024, 2048, 4096, 8192, 16384, 32767};
|
||||
static size_t ntSizes = sizeof(tSizes) / sizeof(int);
|
||||
static int nPort = DEFAULTPORT;
|
||||
static const int sobufsize = 131072;
|
||||
static struct in_addr addr_local;
|
||||
static struct in_addr addr_server;
|
||||
|
||||
static int send_data(int socket, void *buffer, size_t size, int flags)
|
||||
{
|
||||
|
@ -132,7 +140,7 @@ static int TCPServer(void* arg)
|
|||
|
||||
if ((cBuffer = InitBuffer(TMAXSIZE)) == NULL) {
|
||||
kprintf("Netio: Not enough memory\n");
|
||||
return -EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((server = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
|
||||
|
@ -271,8 +279,6 @@ static int TCPServer(void* arg)
|
|||
|
||||
closesocket(client);
|
||||
|
||||
stats_display();
|
||||
|
||||
if (rc < 0)
|
||||
break;
|
||||
}
|
||||
|
@ -283,10 +289,170 @@ static int TCPServer(void* arg)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int TCP_Bench(void)
|
||||
{
|
||||
char *cBuffer;
|
||||
CONTROL ctl;
|
||||
uint64_t nData;
|
||||
int i;
|
||||
struct sockaddr_in sa_server;
|
||||
int server;
|
||||
int rc, err;
|
||||
int nByte;
|
||||
uint64_t start, end;
|
||||
uint32_t freq = get_cpu_frequency(); /* in MHz */
|
||||
|
||||
if ((cBuffer = InitBuffer(TMAXSIZE)) == NULL)
|
||||
{
|
||||
kprintf("Netio: Not enough memory\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((server = socket(PF_INET, SOCK_STREAM, 0)) < 0)
|
||||
{
|
||||
kprintf("socket failed: %d\n", server);
|
||||
kfree(cBuffer, TMAXSIZE);
|
||||
return -2;
|
||||
}
|
||||
|
||||
setsockopt(server, SOL_SOCKET, SO_RCVBUF, (char *) &sobufsize, sizeof(sobufsize));
|
||||
setsockopt(server, SOL_SOCKET, SO_SNDBUF, (char *) &sobufsize, sizeof(sobufsize));
|
||||
|
||||
sa_server.sin_family = AF_INET;
|
||||
sa_server.sin_port = htons(nPort);
|
||||
sa_server.sin_addr = addr_server;
|
||||
|
||||
if ((err = connect(server, (struct sockaddr *) &sa_server, sizeof(sa_server))) < 0)
|
||||
{
|
||||
kprintf("connect failed: %d\n", err);
|
||||
closesocket(server);
|
||||
kfree(cBuffer, TMAXSIZE);
|
||||
return -2;
|
||||
}
|
||||
|
||||
kprintf("\nTCP connection established.\n");
|
||||
|
||||
for (i = 0; i < ntSizes; i++)
|
||||
{
|
||||
kprintf("Packet size %s bytes: ", PacketSize(tSizes[i]));
|
||||
|
||||
/* tell the server we will send it data now */
|
||||
|
||||
ctl.cmd = htonl(CMD_C2S);
|
||||
ctl.data = htonl(tSizes[i]);
|
||||
|
||||
if (send_data(server, (void *) &ctl, CTLSIZE, 0))
|
||||
break;
|
||||
|
||||
/* 1 - Tx test */
|
||||
|
||||
start = rdtsc();
|
||||
nData = 0;
|
||||
cBuffer[0] = 0;
|
||||
|
||||
do
|
||||
{
|
||||
//GenerateRandomData(cBuffer, tSizes[i]);
|
||||
|
||||
for (nByte = 0; nByte < tSizes[i]; )
|
||||
{
|
||||
rc = send(server, cBuffer + nByte, tSizes[i] - nByte, 0);
|
||||
|
||||
if (rc < 0)
|
||||
{
|
||||
kprintf("send failed: %d\n", rc);
|
||||
break;
|
||||
}
|
||||
|
||||
if (rc > 0)
|
||||
nByte += rc;
|
||||
}
|
||||
|
||||
nData += tSizes[i];
|
||||
end = rdtsc();
|
||||
} while((end-start)/freq < 6000000ULL /* = 6s */);
|
||||
|
||||
kprintf("%llu KBytes/s\n", (nData/1024ULL)/((end-start)/(1000000ULL*freq)));
|
||||
|
||||
kprintf(" Tx, ");
|
||||
|
||||
cBuffer[0] = 1;
|
||||
|
||||
if (send_data(server, cBuffer, tSizes[i], 0))
|
||||
break;
|
||||
|
||||
/* tell the server we expect him to send us data now */
|
||||
|
||||
ctl.cmd = htonl(CMD_S2C);
|
||||
ctl.data = htonl(tSizes[i]);
|
||||
|
||||
if (send_data(server, (void *) &ctl, CTLSIZE, 0))
|
||||
break;
|
||||
|
||||
/* 2 - Rx test */
|
||||
|
||||
start = rdtsc();
|
||||
nData = 0;
|
||||
cBuffer[0] = 0;
|
||||
rc = 0;
|
||||
|
||||
do
|
||||
{
|
||||
for (nByte = 0; nByte < tSizes[i]; )
|
||||
{
|
||||
rc = recv(server, cBuffer + nByte, tSizes[i] - nByte, 0);
|
||||
|
||||
if (rc < 0)
|
||||
{
|
||||
kprintf("recv failed: %d\n", rc);
|
||||
break;
|
||||
}
|
||||
|
||||
if (rc > 0)
|
||||
nByte += rc;
|
||||
}
|
||||
|
||||
nData += tSizes[i];
|
||||
} while (cBuffer[0] == 0 && rc > 0);
|
||||
|
||||
end = rdtsc();
|
||||
kprintf("%llu KBytes/s\n", (nData/1024ULL)/((end-start)/(1000000ULL*freq)));
|
||||
|
||||
kprintf(" Rx.\n");
|
||||
}
|
||||
|
||||
ctl.cmd = htonl(CMD_QUIT);
|
||||
ctl.data = 0;
|
||||
|
||||
send_data(server, (void *) &ctl, CTLSIZE, 0);
|
||||
|
||||
kprintf("Done.\n");
|
||||
|
||||
closesocket(server);
|
||||
kfree(cBuffer, TMAXSIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int netio_init(void)
|
||||
{
|
||||
addr_local.s_addr = INADDR_ANY;
|
||||
int err = 0;
|
||||
|
||||
return create_kernel_task(NULL, TCPServer, NULL, NORMAL_PRIO);
|
||||
addr_local.s_addr = INADDR_ANY;
|
||||
//addr_server.s_addr = inet_addr("192.168.28.254");
|
||||
addr_server.s_addr = inet_addr("192.168.0.2");
|
||||
|
||||
#ifdef CONFIG_ROCKCREEK
|
||||
if (RCCE_ue() == 1) {
|
||||
err = create_kernel_task(NULL, TCPServer, NULL, NORMAL_PRIO);
|
||||
} else if (RCCE_ue() == 0) {
|
||||
sleep(3);
|
||||
err = TCP_Bench();
|
||||
}
|
||||
#else
|
||||
err = create_kernel_task(NULL, TCPServer, NULL, NORMAL_PRIO);
|
||||
#endif
|
||||
|
||||
return err;
|
||||
}
|
||||
#endif
|
|
@ -279,7 +279,7 @@ int test_init(void)
|
|||
// char* argv[] = {"/bin/mshell", NULL};
|
||||
char* argv[] = {"/bin/tests", NULL};
|
||||
char* server_argv[] = {"/bin/server", "6789", NULL};
|
||||
// char* client_argv[] = {"/bin/client", "127.0.0.1", "6789", NULL};
|
||||
char* client_argv[] = {"/bin/client", "192.168.0.1", "6789", NULL};
|
||||
|
||||
sem_init(&producing, 1);
|
||||
sem_init(&consuming, 0);
|
||||
|
@ -297,9 +297,11 @@ int test_init(void)
|
|||
//create_user_task(NULL, "/bin/jacobi", argv);
|
||||
//create_user_task(NULL, "/bin/mshell", argv);
|
||||
//create_user_task(NULL, "/bin/jacobi", argv);
|
||||
//create_user_task(NULL, "/bin/server", server_argv);
|
||||
//sleep(5);
|
||||
//create_user_task(NULL, "/bin/client", client_argv);
|
||||
/*create_user_task(NULL, "/bin/server", server_argv);
|
||||
if (RCCE_ue() != 0) {
|
||||
sleep(5);
|
||||
create_user_task(NULL, "/bin/client", client_argv);
|
||||
}*/
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -53,7 +53,9 @@ typedef struct
|
|||
|
||||
extern kb_buffer_t kb_buffer;
|
||||
|
||||
void kb_flush();
|
||||
void kb_init(size_t size, tid_t tid);
|
||||
|
||||
void kb_finish(void);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ void kb_init(size_t size, tid_t tid) {
|
|||
return;
|
||||
}
|
||||
|
||||
void kb_finish() {
|
||||
void kb_finish(void) {
|
||||
kfree(kb_buffer.buffer, (kb_buffer.maxsize * sizeof(char)));
|
||||
kb_buffer.buffer = NULL;
|
||||
kb_buffer.size = 0;
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
#ifdef CONFIG_ROCKCREEK
|
||||
|
||||
#include "scc_memcpy.h"
|
||||
#include <asm/scc_memcpy.h>
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
// FUNCTION: RCCE_get
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
#ifdef CONFIG_ROCKCREEK
|
||||
|
||||
#include "scc_memcpy.h"
|
||||
#include <asm/scc_memcpy.h>
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
// FUNCTION: RCCE_put
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
#ifdef CONFIG_ROCKCREEK
|
||||
|
||||
#include <asm/RCCE_lib.h>
|
||||
#include "scc_memcpy.h"
|
||||
#include <asm/scc_memcpy.h>
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
// FUNCTION: RCCE_recv_general
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
#ifdef CONFIG_ROCKCREEK
|
||||
|
||||
#include <asm/RCCE_lib.h>
|
||||
#include "scc_memcpy.h"
|
||||
#include <asm/scc_memcpy.h>
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
// FUNCTION: RCCE_send_general
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
#include <asm/iRCCE_lib.h>
|
||||
|
||||
#if defined(COPPERRIDGE) || defined(SCC)
|
||||
#include "scc_memcpy.h"
|
||||
#include <asm/scc_memcpy.h>
|
||||
#endif
|
||||
|
||||
void* iRCCE_memcpy_get(void *dest, const void *src, size_t count)
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
#include <asm/iRCCE_lib.h>
|
||||
|
||||
#if defined(COPPERRIDGE) || defined(SCC)
|
||||
#include "scc_memcpy.h"
|
||||
#include <asm/scc_memcpy.h>
|
||||
#endif
|
||||
|
||||
void* iRCCE_memcpy_put(void *dest, const void *src, size_t count)
|
||||
|
|
|
@ -90,7 +90,7 @@ static void intr_handler(struct state *s)
|
|||
int tmp, z;
|
||||
|
||||
#ifdef CONFIG_LWIP
|
||||
//mmnif_irqhandler();
|
||||
mmnif_irqhandler();
|
||||
#endif
|
||||
|
||||
z = Z_PID(RC_COREID[my_ue]);
|
||||
|
|
2853
drivers/net/mmnif.c
2853
drivers/net/mmnif.c
File diff suppressed because it is too large
Load diff
|
@ -1,51 +1,51 @@
|
|||
/*
|
||||
* Copyright 2011 Carl-Benedikt Krueger, Chair for Operating Systems,
|
||||
* RWTH Aachen University
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* This file is part of MetalSVM.
|
||||
*/
|
||||
|
||||
#ifndef __MMNIF_H__
|
||||
#define __MMNIF_H__
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
|
||||
typedef char int8_t;
|
||||
typedef short int16_t;
|
||||
typedef int int32_t;
|
||||
|
||||
#else
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Initialize the network driver for mmn
|
||||
*/
|
||||
int mmnif_open(void);
|
||||
int mmnif_close(void);
|
||||
|
||||
int mmnif_poll(void* e);
|
||||
int mmnif_worker(void* e);
|
||||
|
||||
void mmnif_irqhandler(void);
|
||||
|
||||
#endif
|
||||
/*
|
||||
* Copyright 2011 Carl-Benedikt Krueger, Chair for Operating Systems,
|
||||
* RWTH Aachen University
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* This file is part of MetalSVM.
|
||||
*/
|
||||
|
||||
#ifndef __MMNIF_H__
|
||||
#define __MMNIF_H__
|
||||
|
||||
#include <metalsvm/stddef.h>
|
||||
#ifdef CONFIG_LWIP
|
||||
#include <lwip/err.h>
|
||||
#include <lwip/netif.h> /* lwip netif */
|
||||
|
||||
#define AF_MMNIF_NET 0x1337
|
||||
|
||||
#define MMNIF_AUTOACTIVATE_FAST_SOCKETS 0
|
||||
|
||||
#if MMNIF_AUTOACTIVATE_FAST_SOCKETS
|
||||
#define accept(a,b,c) mmnif_accept(a,b,c)
|
||||
#define closesocket(s) mmnif_closesocket(s)
|
||||
#define connect(a,b,c) mmnif_connect(a,b,c)
|
||||
#define recv(a,b,c,d) mmnif_recv(a,b,c,d)
|
||||
#define send(a,b,c,d) mmnif_send(a,b,c,d)
|
||||
#define socket(a,b,c) mmnif_socket(a,b,c)
|
||||
#define bind(a,b,c) mmnif_bind(a,b,c)
|
||||
#define listen(a,b) mmnif_listen(a,b)
|
||||
#endif
|
||||
|
||||
err_t mmnif_init(struct netif*);
|
||||
err_t mmnif_shutdown(void);
|
||||
int mmnif_worker(void *e);
|
||||
void mmnif_irqhandler(void);
|
||||
void mmnif_print_driver_status();
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,55 +1,52 @@
|
|||
/*
|
||||
* Copyright 2011 Carl-Benedikt Krueger, Chair for Operating Systems,
|
||||
* RWTH Aachen University
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* This file is part of MetalSVM.
|
||||
*/
|
||||
|
||||
#include <metalsvm/stdio.h>
|
||||
#include "util.h"
|
||||
|
||||
inline int isprint(unsigned char e)
|
||||
{
|
||||
if ((e < 0x30) || (e > 0x80))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// hex_dumb display network packets in a good way
|
||||
void hex_dump(unsigned n, const unsigned char* buf)
|
||||
{
|
||||
int on_this_line = 0;
|
||||
|
||||
while (n-- > 0)
|
||||
{
|
||||
kprintf("%02X ", *buf++);
|
||||
on_this_line += 1;
|
||||
if (on_this_line == 16 || n == 0)
|
||||
{
|
||||
int i;
|
||||
|
||||
kputs(" ");
|
||||
|
||||
for (i = on_this_line; i < 16; i++)
|
||||
kputs(" ");
|
||||
|
||||
for (i = on_this_line; i > 0; i--)
|
||||
kputchar(isprint(buf[-i]) ? buf[-i] : '.');
|
||||
|
||||
kputs("\n");
|
||||
on_this_line = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright 2011 Carl-Benedikt Krueger, Chair for Operating Systems,
|
||||
* RWTH Aachen University
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* This file is part of MetalSVM.
|
||||
*/
|
||||
|
||||
#include <metalsvm/stdio.h>
|
||||
#include "util.h"
|
||||
inline int isprint(unsigned char e)
|
||||
{
|
||||
if ((e < 0x30) || (e > 0x80))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// hex_dumb display network packets in a good way
|
||||
void hex_dump(unsigned n, const unsigned char *buf)
|
||||
{
|
||||
int on_this_line = 0;
|
||||
|
||||
while (n-- > 0)
|
||||
{
|
||||
kprintf("%02X ", *buf++);
|
||||
on_this_line += 1;
|
||||
|
||||
if (on_this_line == 16 || n == 0)
|
||||
{
|
||||
int i;
|
||||
|
||||
kputs(" ");
|
||||
for (i = on_this_line; i < 16; i++)
|
||||
kputs(" ");
|
||||
for (i = on_this_line; i > 0; i--)
|
||||
kputchar(isprint(buf[-i]) ? buf[-i] : '.');
|
||||
kputs("\n");
|
||||
on_this_line = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,26 +1,26 @@
|
|||
/*
|
||||
* Copyright 2011 Carl-Benedikt Krueger, Chair for Operating Systems,
|
||||
* RWTH Aachen University
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* This file is part of MetalSVM.
|
||||
*/
|
||||
|
||||
#ifndef __UTIL__
|
||||
#define __UTIL__
|
||||
|
||||
// hex_dumb display network packets in a good way
|
||||
void hex_dump(unsigned n, const unsigned char* buf);
|
||||
|
||||
#endif
|
||||
/*
|
||||
* Copyright 2011 Carl-Benedikt Krueger, Chair for Operating Systems,
|
||||
* RWTH Aachen University
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* This file is part of MetalSVM.
|
||||
*/
|
||||
|
||||
#ifndef __UTIL__
|
||||
#define __UTIL__
|
||||
|
||||
// hex_dumb display network packets in a good way
|
||||
void hex_dump(unsigned n, const unsigned char *buf);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
C_source := main.c tasks.c syscall.c tests.c echo.c netio.c init.c
|
||||
C_source := main.c tasks.c syscall.c init.c
|
||||
MODULE := kernel
|
||||
|
||||
include $(TOPDIR)/Makefile.inc
|
||||
|
|
|
@ -71,6 +71,9 @@ int lowlevel_init(void)
|
|||
|
||||
#if defined(CONFIG_LWIP) && (defined(CONFIG_PCI) || defined(CONFIG_ROCKCREEK))
|
||||
static struct netif default_netif;
|
||||
#ifdef CONFIG_ROCKCREEK
|
||||
static struct netif mmnif_netif;
|
||||
#endif
|
||||
|
||||
static int init_netifs(void)
|
||||
{
|
||||
|
@ -83,8 +86,9 @@ static int init_netifs(void)
|
|||
|
||||
// Set up the lwIP network interface
|
||||
memset(&default_netif, 0x00, sizeof(struct netif));
|
||||
|
||||
#ifdef CONFIG_ROCKCREEK
|
||||
memset(&mmnif_netif, 0x00, sizeof(struct netif));
|
||||
|
||||
/* Set network address variables */
|
||||
IP4_ADDR(&gw, 192,168,28,254);
|
||||
IP4_ADDR(&ipaddr, 192,168,28,RCCE_ue()+1);
|
||||
|
@ -92,12 +96,38 @@ static int init_netifs(void)
|
|||
|
||||
/* Bring up the network interface */
|
||||
if ((err = netifapi_netif_add(&default_netif, &ipaddr, &netmask, &gw, NULL, rckemacif_init, tcpip_input)) != ERR_OK) {
|
||||
kprintf("Unable to add network interface: err = %d\n", err);
|
||||
kprintf("Unable to add the network interface: err = %d\n", err);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
netifapi_netif_set_default(&default_netif);
|
||||
netifapi_netif_set_up(&default_netif);
|
||||
|
||||
/* Bring up the intra network interface */
|
||||
struct ip_addr intra_ipaddr;
|
||||
struct ip_addr intra_netmask;
|
||||
struct ip_addr intra_gw;
|
||||
|
||||
IP4_ADDR(&intra_gw, 0,0,0,0);
|
||||
IP4_ADDR(&intra_ipaddr, 192,168,0,RCCE_ue()+1);
|
||||
IP4_ADDR(&intra_netmask, 255,255,255,0);
|
||||
|
||||
/* register our Memory Mapped Virtual IP interface in the lwip stack
|
||||
* and tell him how to use the interface:
|
||||
* - mmnif_dev : the device data storage
|
||||
* - ipaddr : the ip address wich should be used
|
||||
* - gw : the gateway wicht should be used
|
||||
* - mmnif_init : the initialization which has to be done in order to use our interface
|
||||
* - ethernet_input : tells him that he should get ethernet input (inclusice ARP)
|
||||
*/
|
||||
if ((err = netifapi_netif_add(&mmnif_netif, &intra_ipaddr, &intra_netmask, &intra_gw, NULL, mmnif_init, tcpip_input)) != ERR_OK)
|
||||
{
|
||||
kprintf("Unable to add the intra network interface: err = %d\n", err);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* tell lwip all initialization is done and we want to set it ab */
|
||||
netifapi_netif_set_up(&mmnif_netif);
|
||||
#else
|
||||
/* Clear network address because we use DHCP to get an ip address */
|
||||
IP4_ADDR(&gw, 0,0,0,0);
|
||||
|
@ -106,7 +136,7 @@ static int init_netifs(void)
|
|||
|
||||
/* Bring up the network interface */
|
||||
if ((err = netifapi_netif_add(&default_netif, &ipaddr, &netmask, &gw, NULL, rtl8139if_init, tcpip_input)) != ERR_OK) {
|
||||
kprintf("Unable to add network interface: err = %d\n", err);
|
||||
kprintf("Unable to add the network interface: err = %d\n", err);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
@ -144,11 +174,10 @@ static void tcpip_init_done(void* arg)
|
|||
static int network_shutdown(void)
|
||||
{
|
||||
#if defined(CONFIG_LWIP) && defined(CONFIG_ROCKCREEK)
|
||||
mmnif_shutdown();
|
||||
netifapi_netif_set_down(&default_netif);
|
||||
memset(&default_netif, 0x00, sizeof(struct netif));
|
||||
#elif defined(CONFIG_LWIP) && defined(CONFIG_PCI)
|
||||
netifapi_dhcp_stop(&default_netif);
|
||||
memset(&default_netif, 0x00, sizeof(struct netif));
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
@ -209,6 +238,7 @@ int initd(void* arg)
|
|||
{
|
||||
#ifdef CONFIG_LWIP
|
||||
sys_sem_t sem;
|
||||
tid_t id;
|
||||
char* argv[] = {"/bin/rlogind ", NULL};
|
||||
|
||||
// Initialize lwIP modules
|
||||
|
@ -230,9 +260,10 @@ int initd(void* arg)
|
|||
#endif
|
||||
|
||||
// start echo, netio and rlogind
|
||||
echo_init();
|
||||
netio_init();
|
||||
create_user_task(NULL, "/bin/rlogind", argv);
|
||||
//echo_init();
|
||||
create_user_task(&id, "/bin/rlogind", argv);
|
||||
kprintf("Create rlogind with id %u\n", id);
|
||||
//netio_init();
|
||||
#endif
|
||||
|
||||
list_root();
|
||||
|
|
|
@ -60,6 +60,8 @@ int smp_main(void)
|
|||
|
||||
int main(void)
|
||||
{
|
||||
tid_t id;
|
||||
|
||||
lowlevel_init();
|
||||
|
||||
pushbg(COL_BLUE);
|
||||
|
@ -91,7 +93,8 @@ int main(void)
|
|||
kprintf("Current available memory: %u MBytes\n", atomic_int32_read(&total_available_pages)/((1024*1024)/PAGE_SIZE));
|
||||
|
||||
sleep(5);
|
||||
create_kernel_task(NULL, initd, NULL, NORMAL_PRIO);
|
||||
create_kernel_task(&id, initd, NULL, NORMAL_PRIO);
|
||||
kprintf("Create initd with id %u\n", id);
|
||||
reschedule();
|
||||
|
||||
while(1) {
|
||||
|
|
245
kernel/syscall.c
245
kernel/syscall.c
|
@ -47,6 +47,11 @@ static int get_fildes(void)
|
|||
task_t* curr_task = per_core(current_task);
|
||||
int fd;
|
||||
|
||||
/*
|
||||
* Seach the process specific file descriptor table for a free
|
||||
* descriptor. The new descriptor returned by the call is the lowest
|
||||
* numbered descriptor currently not in use by the process.
|
||||
*/
|
||||
for (fd = 0; fd < NR_OPEN; fd++) {
|
||||
if (curr_task->fildes_table[fd] == NULL) {
|
||||
/* Init Filedescriptor */
|
||||
|
@ -60,32 +65,55 @@ static int get_fildes(void)
|
|||
return -EMFILE;
|
||||
}
|
||||
|
||||
static int sys_write(int fd, const char* buf, size_t len)
|
||||
{
|
||||
task_t* curr_task = per_core(current_task);
|
||||
|
||||
/* fd is negative or greater than the maximum allowable number */
|
||||
if (BUILTIN_EXPECT((fd >= NR_OPEN) || (fd < 0), 0))
|
||||
return -EBADF;
|
||||
/* fd is not an active, valid file descriptor. */
|
||||
if (curr_task->fildes_table[fd] == NULL)
|
||||
return -EBADF;
|
||||
|
||||
return write_fs(curr_task->fildes_table[fd], (uint8_t*)buf, len);
|
||||
}
|
||||
|
||||
static int sys_open(const char* name, int flags, int mode)
|
||||
{
|
||||
int fd, check;
|
||||
fildes_t* file = NULL;
|
||||
task_t* curr_task = per_core(current_task);
|
||||
|
||||
/* no name is given */
|
||||
if (name == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
/* Get a free file descriptor */
|
||||
fd = get_fildes();
|
||||
/* validate the fd */
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
file = per_core(current_task)->fildes_table[fd];
|
||||
file->mode = mode;
|
||||
file->flags = flags;
|
||||
file->count = 1;
|
||||
check = open_fs(file, (char*) name);
|
||||
/* fd is negative or greater than the maximum allowable number */
|
||||
if (BUILTIN_EXPECT((fd >= NR_OPEN) || (fd < 0), 0))
|
||||
return fd; /* in this case fd = errno */
|
||||
|
||||
/* init the whole file descriptor structure */
|
||||
curr_task->fildes_table[fd]->mode = mode;
|
||||
curr_task->fildes_table[fd]->flags = flags;
|
||||
curr_task->fildes_table[fd]->count = 1;
|
||||
check = open_fs(curr_task->fildes_table[fd], (char*) name);
|
||||
|
||||
/* file doesn't exist! */
|
||||
if (check < 0) {
|
||||
/* file doesn't exist! */
|
||||
kfree(file, sizeof(fildes_t));
|
||||
file = NULL;
|
||||
/* tidy up the fildescriptor */
|
||||
kfree(curr_task->fildes_table[fd], sizeof(fildes_t));
|
||||
curr_task->fildes_table[fd] = NULL;
|
||||
return check;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static int sys_stat(const char* name, struct stat* st) {
|
||||
static int sys_stat(const char* name, struct stat* st)
|
||||
{
|
||||
vfs_node_t* node;
|
||||
|
||||
node = findnode_fs(name);
|
||||
|
@ -112,43 +140,102 @@ static int sys_stat(const char* name, struct stat* st) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int sys_read(int fd, const char* buf, size_t len)
|
||||
{
|
||||
task_t* curr_task = per_core(current_task);
|
||||
|
||||
/* fd is negative or greater than the maximum allowable number */
|
||||
if (BUILTIN_EXPECT((fd >= NR_OPEN) || (fd < 0), 0))
|
||||
return -EBADF;
|
||||
/* fd is not an active, valid file descriptor. */
|
||||
if (curr_task->fildes_table[fd] == NULL)
|
||||
return -EBADF;
|
||||
|
||||
return read_fs(curr_task->fildes_table[fd], (uint8_t*)buf, len);
|
||||
}
|
||||
|
||||
|
||||
#if defined(CONFIG_LWIP) && LWIP_SOCKET
|
||||
static int sys_socket(int domain, int type, int protocol)
|
||||
{
|
||||
int fd;
|
||||
fildes_t* file = NULL;
|
||||
int fd, sock;
|
||||
task_t* curr_task = per_core(current_task);
|
||||
|
||||
/* Get a free file descriptor */
|
||||
fd = get_fildes();
|
||||
/* validate the fd */
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
file = per_core(current_task)->fildes_table[fd];
|
||||
file->offset = lwip_socket(domain, type, protocol);
|
||||
file->node = findnode_fs("/dev/socket");
|
||||
file->count = 1;
|
||||
/* validate the file descriptor */
|
||||
if (BUILTIN_EXPECT((fd >= NR_OPEN) || (fd < 0), 0))
|
||||
return fd; /* in this case fd = errno */
|
||||
|
||||
/* Get a valid lwip descriptor */
|
||||
sock = lwip_socket(domain, type, protocol);
|
||||
|
||||
/* validate the file descriptor */
|
||||
if (BUILTIN_EXPECT(sock < 0, 0))
|
||||
return sock; /* in this case sock = errno */
|
||||
|
||||
/*
|
||||
* init the whole file descriptor structure.
|
||||
* We use the offset to save the lwip descriptor
|
||||
* TODO: find another solution or change the name 'offset'
|
||||
*/
|
||||
curr_task->fildes_table[fd]->offset = sock;
|
||||
curr_task->fildes_table[fd]->count = 1;
|
||||
curr_task->fildes_table[fd]->node = findnode_fs("/dev/socket");
|
||||
|
||||
/* file doesn't exist! */
|
||||
if (curr_task->fildes_table[fd]->node == NULL) {
|
||||
/* tidy up the fildescriptor */
|
||||
kfree(curr_task->fildes_table[fd], sizeof(fildes_t));
|
||||
curr_task->fildes_table[fd] = NULL;
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static int sys_accept(int s, struct sockaddr* addr, socklen_t* addrlen)
|
||||
{
|
||||
int fd;
|
||||
fildes_t* file = NULL;
|
||||
int fd, sock2;
|
||||
task_t* curr_task = per_core(current_task);
|
||||
|
||||
if (BUILTIN_EXPECT(s >= NR_OPEN, 0))
|
||||
return -EINVAL;
|
||||
/* validate the 'socket'-filedescriptor */
|
||||
if (BUILTIN_EXPECT((s >= NR_OPEN) || (s < 0), 0))
|
||||
return -EBADF;
|
||||
/* validate the 'socket'-file descriptor object */
|
||||
if (curr_task->fildes_table[s] == NULL)
|
||||
return -EBADF;
|
||||
|
||||
/* Get a free file descriptor */
|
||||
fd = get_fildes();
|
||||
/* validate the fd */
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
file = per_core(current_task)->fildes_table[fd];
|
||||
file->offset = lwip_accept(s, addr, addrlen);
|
||||
file->node = findnode_fs("/dev/socket");
|
||||
file->count = 1;
|
||||
/* validate the file descriptor */
|
||||
if (BUILTIN_EXPECT((fd >= NR_OPEN) || (fd < 0), 0))
|
||||
return fd; /* in this case fd = errno */
|
||||
/* Get a valid lwip descriptor */
|
||||
sock2 = lwip_accept(s, addr, addrlen);
|
||||
/* validate the file descriptor */
|
||||
if (BUILTIN_EXPECT(sock2 < 0, 0))
|
||||
return sock2; /* in this case sock = errno */
|
||||
|
||||
/*
|
||||
* init the whole file descriptor structure.
|
||||
* We use the offset to save the lwip descriptor
|
||||
* TODO: find another solution or change the name 'offset'
|
||||
*/
|
||||
curr_task->fildes_table[fd]->offset = sock2;
|
||||
curr_task->fildes_table[fd]->count = 1;
|
||||
curr_task->fildes_table[fd]->node = findnode_fs("/dev/socket");
|
||||
|
||||
/* file doesn't exist! */
|
||||
if (curr_task->fildes_table[fd]->node == NULL) {
|
||||
/* tidy up the fildescriptor */
|
||||
kfree(curr_task->fildes_table[fd], sizeof(fildes_t));
|
||||
curr_task->fildes_table[fd] = NULL;
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
@ -157,13 +244,26 @@ static int sys_accept(int s, struct sockaddr* addr, socklen_t* addrlen)
|
|||
|
||||
static int sys_close(int fd)
|
||||
{
|
||||
int check;
|
||||
task_t* curr_task = per_core(current_task);
|
||||
|
||||
if (BUILTIN_EXPECT(fd >= NR_OPEN, 0))
|
||||
return -EINVAL;
|
||||
|
||||
/* fd is negative or greater than the maximum allowable number */
|
||||
if (BUILTIN_EXPECT((fd >= NR_OPEN) || (fd < 0), 0))
|
||||
return -EBADF;
|
||||
/* fd is not an active, valid file descriptor. */
|
||||
if (curr_task->fildes_table[fd] == NULL)
|
||||
return -EBADF;
|
||||
|
||||
/*
|
||||
* The close() call deletes a descriptor from the per-process object
|
||||
* reference table. If this is the last reference to the underlying
|
||||
* object, the object will be deactivated.
|
||||
*/
|
||||
if (curr_task->fildes_table[fd]->count == 1) {
|
||||
close_fs(curr_task->fildes_table[fd]);
|
||||
check = close_fs(curr_task->fildes_table[fd]);
|
||||
/* close command failed -> return check = errno */
|
||||
if (BUILTIN_EXPECT(check < 0, 0))
|
||||
return check;
|
||||
kfree(curr_task->fildes_table[fd], sizeof(fildes_t));
|
||||
curr_task->fildes_table[fd] = NULL;
|
||||
} else {
|
||||
|
@ -178,30 +278,42 @@ static int sys_close(int fd)
|
|||
static int sys_lseek(int fd, off_t pos, int origin)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
fildes_t* file;
|
||||
task_t* curr_task = per_core(current_task);
|
||||
|
||||
if (BUILTIN_EXPECT(fd >= NR_OPEN, 0))
|
||||
return -EINVAL;
|
||||
/* fd is negative or greater than the maximum allowable number */
|
||||
if (BUILTIN_EXPECT((fd >= NR_OPEN) || (fd < 0), 0))
|
||||
return -EBADF;
|
||||
/* fd is not an active, valid file descriptor. */
|
||||
if (curr_task->fildes_table[fd] == NULL)
|
||||
return -EBADF;
|
||||
|
||||
file = per_core(current_task)->fildes_table[fd];
|
||||
|
||||
if (BUILTIN_EXPECT(!((file->node->type == FS_FILE)
|
||||
|| (file->node->type == FS_CHARDEVICE)), 0))
|
||||
return -EINVAL;
|
||||
/* TODO: in case of Fildes is associated with a pipe, socket, or FIFO. return ESPIPE */
|
||||
/* TODO: The seek location is too large to be stored in an object of type off_t. return EOVERFLOW*/
|
||||
|
||||
switch(origin)
|
||||
{
|
||||
{
|
||||
case SEEK_SET: { /* set file offset to offset */
|
||||
file->offset = pos;
|
||||
ret = pos;
|
||||
/* The seek location is negative. */
|
||||
if (ret < 0)
|
||||
return -EINVAL;
|
||||
curr_task->fildes_table[fd]->offset = ret;
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
case SEEK_CUR: { /* set file offset to current plus offset */
|
||||
ret = pos + file->offset;
|
||||
ret = pos + curr_task->fildes_table[fd]->offset;
|
||||
/* The seek location is negative. */
|
||||
if (ret < 0)
|
||||
return -EINVAL;
|
||||
break;
|
||||
}
|
||||
case SEEK_END: { /* set file offset to EOF plus offset */
|
||||
file->offset = pos + file->node->block_size;
|
||||
ret = pos + curr_task->fildes_table[fd]->node->block_size;
|
||||
/* The seek location is negative. */
|
||||
if (ret < 0)
|
||||
return -EINVAL;
|
||||
curr_task->fildes_table[fd]->offset = ret;
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
@ -209,6 +321,7 @@ static int sys_lseek(int fd, off_t pos, int origin)
|
|||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -217,12 +330,19 @@ static int sys_dup(int fd)
|
|||
task_t* curr_task = per_core(current_task);
|
||||
int new_fd;
|
||||
|
||||
/* fd is negative or greater than the maximum allowable number */
|
||||
if (BUILTIN_EXPECT((fd >= NR_OPEN) || (fd < 0), 0))
|
||||
return -EBADF;
|
||||
/* fd is not an active, valid file descriptor. */
|
||||
if (curr_task->fildes_table[fd] == NULL)
|
||||
return -EBADF;
|
||||
|
||||
/* Get a free file descriptor */
|
||||
new_fd = get_fildes();
|
||||
/* validate the file descriptor */
|
||||
if (BUILTIN_EXPECT((new_fd >= NR_OPEN) || (fd < 0), 0))
|
||||
return new_fd; /* in this case fd = errno */
|
||||
|
||||
curr_task->fildes_table[new_fd] = curr_task->fildes_table[fd];
|
||||
curr_task->fildes_table[fd]->count++;
|
||||
|
||||
|
@ -233,18 +353,26 @@ static int sys_dup2(int fd, int fd2)
|
|||
{
|
||||
task_t* curr_task = per_core(current_task);
|
||||
|
||||
/* fd and fd2 is negative or greater than the maximum allowable number */
|
||||
if (BUILTIN_EXPECT((fd >= NR_OPEN) || (fd < 0), 0))
|
||||
return -EBADF;
|
||||
if (BUILTIN_EXPECT((fd2 >= NR_OPEN) || (fd2 < 0), 0))
|
||||
return -EBADF;
|
||||
/* fd is not an active, valid file descriptor. */
|
||||
if (curr_task->fildes_table[fd] == NULL)
|
||||
return -EBADF;
|
||||
|
||||
if (fd == fd2)
|
||||
/* If fd and fd2 are equal, then dup2() just returns fd2 */
|
||||
if (fd == fd2)
|
||||
return fd2;
|
||||
|
||||
/*
|
||||
* if descriptor fd2 is already in use, it is first deallocated
|
||||
* as if a close(2) call had been done first
|
||||
*/
|
||||
if (curr_task->fildes_table[fd2] != NULL)
|
||||
sys_close(fd2);
|
||||
|
||||
|
||||
curr_task->fildes_table[fd2] = curr_task->fildes_table[fd];
|
||||
curr_task->fildes_table[fd]->count++;
|
||||
|
||||
|
@ -296,9 +424,7 @@ int syscall_handler(uint32_t sys_nr, ...)
|
|||
int fd = va_arg(vl, int);
|
||||
const char* buf = va_arg(vl, const char*);
|
||||
size_t len = va_arg(vl, size_t);
|
||||
if (fd >= 0)
|
||||
ret = write_fs(per_core(current_task)->fildes_table[fd],
|
||||
(uint8_t*)buf, len);
|
||||
ret = sys_write(fd, buf, len);
|
||||
break;
|
||||
}
|
||||
case __NR_open: {
|
||||
|
@ -310,8 +436,7 @@ int syscall_handler(uint32_t sys_nr, ...)
|
|||
}
|
||||
case __NR_close: {
|
||||
int fd = va_arg(vl, int);
|
||||
if (fd >= 0)
|
||||
ret = sys_close(fd);
|
||||
ret = sys_close(fd);
|
||||
break;
|
||||
}
|
||||
case __NR_dup: {
|
||||
|
@ -328,7 +453,6 @@ int syscall_handler(uint32_t sys_nr, ...)
|
|||
case __NR_stat: {
|
||||
const char* name = va_arg(vl, const char*);
|
||||
struct stat* st = va_arg(vl, struct stat*);
|
||||
|
||||
ret = sys_stat(name, st);
|
||||
break;
|
||||
}
|
||||
|
@ -336,17 +460,14 @@ int syscall_handler(uint32_t sys_nr, ...)
|
|||
int fd = va_arg(vl, int);
|
||||
const char* buf = va_arg(vl, const char*);
|
||||
size_t len = va_arg(vl, size_t);
|
||||
if (fd >= 0)
|
||||
ret = read_fs(per_core(current_task)->fildes_table[fd],
|
||||
(uint8_t*)buf, len);
|
||||
ret = sys_read(fd, buf, len);
|
||||
break;
|
||||
}
|
||||
case __NR_lseek: {
|
||||
int fd = va_arg(vl, int);
|
||||
off_t pos = va_arg(vl, off_t);
|
||||
int origin = va_arg(vl, int);
|
||||
if (fd >= 0)
|
||||
ret = sys_lseek(fd, pos, origin);
|
||||
ret = sys_lseek(fd, pos, origin);
|
||||
break;
|
||||
}
|
||||
case __NR_sbrk: {
|
||||
|
|
Loading…
Add table
Reference in a new issue