From d599a063b3b453b705925c58180c93e1f9cb3d79 Mon Sep 17 00:00:00 2001
From: John Hodge <tpg@mutabah.net>
Date: Sun, 23 Jan 2011 10:41:09 +0800
Subject: [PATCH] AcessNative - Reworked protocol to be simpler

- Completed the interface code, not tested yet
- Switched to a single list of parameters, with flags for returned values
---
 AcessNative/acesskernel_src/server.c   | 247 ++++++++++++++++++++++++
 AcessNative/acesskernel_src/syscalls.c |  76 +++++++-
 AcessNative/ld-acess_src/request.c     |  91 +--------
 AcessNative/ld-acess_src/request.h     |  15 +-
 AcessNative/ld-acess_src/syscalls.c    | 255 +++++++++++++------------
 AcessNative/syscalls.h                 |   6 +-
 6 files changed, 470 insertions(+), 220 deletions(-)
 create mode 100644 AcessNative/acesskernel_src/server.c

diff --git a/AcessNative/acesskernel_src/server.c b/AcessNative/acesskernel_src/server.c
new file mode 100644
index 00000000..7491d74a
--- /dev/null
+++ b/AcessNative/acesskernel_src/server.c
@@ -0,0 +1,247 @@
+/*
+ * Acess2 Native Kernel
+ * - Acess kernel emulation on another OS using SDL and UDP
+ *
+ * Syscall Server
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <SDL/SDL.h>
+#ifdef __WIN32__
+# include <windows.h>
+# include <winsock.h>
+#else
+# include <unistd.h>
+# include <sys/socket.h>
+# include <netinet/in.h>
+#endif
+#include "../syscalls.h"
+
+#define	USE_TCP	0
+#define MAX_CLIENTS	16
+
+// === TYPES ===
+typedef struct {
+	 int	ClientID;
+	SDL_Thread	*WorkerThread;
+	#if USE_TCP
+	#else
+	tRequestHeader	*CurrentRequest;
+	struct sockaddr_in	ClientAddr;
+	SDL_cond	*WaitFlag;
+	SDL_mutex	*Mutex;
+	#endif
+}	tClient;
+
+// === IMPORTS ===
+extern tRequestHeader *SyscallRecieve(tRequestHeader *Request, int *ReturnLength);
+
+// === PROTOTYPES ===
+tClient	*Server_GetClient(int ClientID);
+ int	Server_WorkerThread(void *ClientPtr);
+ int	SyscallServer(void);
+
+// === GLOBALS ===
+#ifdef __WIN32__
+WSADATA	gWinsock;
+SOCKET	gSocket = INVALID_SOCKET;
+#else
+# define INVALID_SOCKET -1
+ int	gSocket = INVALID_SOCKET;
+#endif
+ int	giServer_NextClientID = 1;
+tClient	gaServer_Clients[MAX_CLIENTS];
+
+// === CODE ===
+tClient *Server_GetClient(int ClientID)
+{
+	tClient	*ret = NULL;
+	 int	i;
+	
+	for( i = 0; i < MAX_CLIENTS; i ++ )
+	{
+		if( gaServer_Clients[i].ClientID == ClientID ) {
+			ret = &gaServer_Clients[i];
+			break;
+		}
+	}
+	
+	// Uh oh, no free slots
+	// TODO: Dynamic allocation
+	if( !ret )
+		return NULL;
+	
+	if( ClientID == 0 )
+	{
+		ret->ClientID = giServer_NextClientID ++;
+		ret->CurrentRequest = NULL;
+		
+		if( !ret->WorkerThread ) {
+			ret->WorkerThread = SDL_CreateThread( Server_WorkerThread, ret );
+			ret->WaitFlag = SDL_CreateCond();
+			ret->Mutex = SDL_CreateMutex();
+			SDL_mutexP( ret->Mutex );
+		}
+	}
+	
+	return &gaServer_Clients[i];
+}
+
+int Server_WorkerThread(void *ClientPtr)
+{
+	tClient	*Client = ClientPtr;
+	tRequestHeader	*retHeader;
+	 int	retSize = 0;
+	 int	sentSize;
+	
+	#if USE_TCP
+	#else
+	for( ;; )
+	{
+		// Wait for something to do
+		while( !Client->CurrentRequest )	;
+		
+		// Get the response
+		retHeader = SyscallRecieve(Client->CurrentRequest, &retSize);
+		
+		if( !retHeader ) {
+			// Return an error to the client
+			printf("Error returned by SyscallRecieve\n");
+		}
+		
+		// Return the data
+		sentSize = sendto(gSocket, retHeader, retSize, 0,
+			(struct sockaddr*)&Client->ClientAddr, sizeof(Client->ClientAddr)
+			);
+		if( sentSize != retSize ) {
+			perror("Server_WorkerThread - send");
+		}
+		
+		// Free allocated header
+		free( retHeader );
+		
+		Client->CurrentRequest = 0;
+		
+		// Wait for something else
+		SDL_CondWait(Client->WaitFlag, Client->Mutex);
+	}
+	#endif
+}
+
+int SyscallServer(void)
+{
+	struct sockaddr_in	server;
+	
+	#ifdef __WIN32__
+	/* Open windows connection */
+	if (WSAStartup(0x0101, &gWinsock) != 0)
+	{
+		fprintf(stderr, "Could not open Windows connection.\n");
+		exit(0);
+	}
+	#endif
+	
+	#if USE_TCP
+	// Open TCP Connection
+	gSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+	#else
+	// Open UDP Connection
+	gSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+	#endif
+	if (gSocket == INVALID_SOCKET)
+	{
+		fprintf(stderr, "Could not create socket.\n");
+		#if __WIN32__
+		WSACleanup();
+		#endif
+		exit(0);
+	}
+	
+	// Set server address
+	memset(&server, 0, sizeof(struct sockaddr_in));
+	server.sin_family = AF_INET;
+	server.sin_port = htons(SERVER_PORT);
+	server.sin_addr.s_addr = htonl(INADDR_ANY);
+	
+	// Bind
+	if( bind(gSocket, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) == -1 )
+	{
+		fprintf(stderr, "Cannot bind address to socket.\n");
+		perror("SyscallServer - bind");
+		#if __WIN32__
+		closesocket(gSocket);
+		WSACleanup();
+		#else
+		close(gSocket);
+		#endif
+		exit(0);
+	}
+	
+	#if USE_TCP
+	listen(gSocket, 5);
+	#endif
+	
+	Log_Notice("Syscall", "Listening on 0.0.0.0:%i\n", SERVER_PORT);
+	
+	// Wait for something to do :)
+	for( ;; )
+	{
+		#if USE_TCP
+		struct sockaddr_in	client;
+		uint	clientSize = sizeof(client);
+		 int	clientSock = accept(gSocket, (struct sockaddr*)&client, &clientSize);
+		if( clientSock < 0 ) {
+			perror("SyscallServer - accept");
+			break ;
+		}
+		
+		printf("Client connection %x:%i",
+			ntohl(client.sin_addr), ntohs(client.sin_port)
+			);
+		
+		#else
+		char	data[BUFSIZ];
+		tRequestHeader	*req = (void*)data;
+		struct sockaddr_in	addr;
+		uint	clientSize = sizeof(addr);
+		 int	length = recvfrom(gSocket, data, BUFSIZ, 0, (struct sockaddr*)&addr, &clientSize);
+		tClient	*client;
+		
+		if( length == -1 ) {
+			perror("SyscallServer - recv");
+			break;
+		}
+		
+		// Hand off to a worker thread
+		// - TODO: Actually have worker threads
+		printf("%i bytes from %x:%i\n", length,
+			ntohl(addr.sin_addr.s_addr), ntohs(addr.sin_port));
+		
+		client = Server_GetClient(req->ClientID);
+		if( req->ClientID == 0 )
+		{
+			memcpy(&client->ClientAddr, &addr, sizeof(addr));
+		}
+		else if( memcmp(&client->ClientAddr, &addr, sizeof(addr)) != 0 )
+		{
+			printf("ClientID %i used by %x:%i\n",
+				client->ClientID, ntohl(addr.sin_addr.s_addr), ntohs(addr.sin_port));
+			printf(" actually owned by %x:%i\n",
+				ntohl(client->ClientAddr.sin_addr.s_addr), ntohs(client->ClientAddr.sin_port));
+			continue;
+		}
+		
+		if( client->CurrentRequest ) {
+			printf("Worker thread for %x:%i is busy\n",
+				ntohl(client->ClientAddr.sin_addr.s_addr), ntohs(client->ClientAddr.sin_port));
+			continue;
+		}
+		
+		client->CurrentRequest = req;
+		SDL_CondSignal(client->WaitFlag);
+		#endif
+	}
+	
+	return -1;
+}
diff --git a/AcessNative/acesskernel_src/syscalls.c b/AcessNative/acesskernel_src/syscalls.c
index 7e8d1ecd..85a82325 100644
--- a/AcessNative/acesskernel_src/syscalls.c
+++ b/AcessNative/acesskernel_src/syscalls.c
@@ -42,7 +42,7 @@ int Syscall_Null(const char *Format, void *Args)
 	return 0;
 }
 
-SYSCALL2(Syscall_Open, VFS_Open, "di", const char *, int);
+SYSCALL2(Syscall_Open, VFS_Open, "si", const char *, int);
 SYSCALL1V(Syscall_Close, VFS_Close, "i", int);
 SYSCALL3(Syscall_Read, VFS_Read, "iid", int, int, void *);
 SYSCALL3(Syscall_Write, VFS_Write, "iid", int, int, const void *);
@@ -59,13 +59,18 @@ const int	ciNumSyscalls = sizeof(caSyscalls)/sizeof(caSyscalls[0]);
 /**
  * \brief Recieve a syscall structure from the server code
  */
-tRequestHeader *SyscallRecieve(tRequestHeader *Request)
+tRequestHeader *SyscallRecieve(tRequestHeader *Request, int *ReturnLength)
 {
 	char	formatString[Request->NParams+1];
-	char	*inData = (char*)&Request->Params[Request->NParams+Request->NReturn];
+	char	*inData = (char*)&Request->Params[Request->NParams];
 	 int	argListLen = 0;
 	 int	i, retVal;
+	tRequestHeader	*ret;
+	 int	retValueCount = 1;
+	 int	retDataLen = sizeof(Uint64);
+	void	*mallocdData[Request->NParams];
 	
+	// Sanity check
 	if( Request->CallID > ciNumSyscalls ) {
 		return NULL;
 	}
@@ -90,6 +95,10 @@ tRequestHeader *SyscallRecieve(tRequestHeader *Request)
 			formatString[i] = 'd';
 			argListLen += sizeof(void*);
 			break;
+		case ARG_TYPE_STRING:
+			formatString[i] = 's';
+			argListLen += sizeof(char*);
+			break;
 		default:
 			return NULL;	// ERROR!
 		}
@@ -115,11 +124,36 @@ tRequestHeader *SyscallRecieve(tRequestHeader *Request)
 				argListLen += sizeof(Uint64);
 				inData += sizeof(Uint64);
 				break;
-			case ARG_TYPE_DATA:
 			case ARG_TYPE_STRING:
 				*(void**)&argListData[argListLen] = *(void**)inData;
 				argListLen += sizeof(void*);
-				inData += sizeof(void*);
+				inData += Request->Params[i].Length;
+				break;
+			
+			// Data gets special handling, because only it can be returned to the user
+			// (ARG_TYPE_DATA is a pointer)
+			case ARG_TYPE_DATA:
+				// Prepare the return values
+				if( Request->Params[i].Flags & ARG_FLAG_RETURN )
+				{
+					retDataLen += Request->Params[i].Length;
+					retValueCount ++;
+				}
+				
+				// Check for non-resident data
+				if( Request->Params[i].Flags & ARG_FLAG_ZEROED )
+				{
+					// Allocate and zero the buffer
+					mallocdData[i] = calloc(1, Request->Params[i].Length);
+					*(void**)&argListData[argListLen] = mallocdData[i];
+					argListLen += sizeof(void*);
+				}
+				else
+				{
+					*(void**)&argListData[argListLen] = (void*)inData;
+					argListLen += sizeof(void*);
+					inData += Request->Params[i].Length;
+				}
 				break;
 			}
 		}
@@ -127,5 +161,35 @@ tRequestHeader *SyscallRecieve(tRequestHeader *Request)
 		retVal = caSyscalls[Request->CallID](formatString, argListData);
 	}
 	
-	return NULL;
+	// Allocate the return
+	ret = malloc(sizeof(tRequestHeader) + retValueCount * sizeof(tRequestValue)
+		+ retDataLen);
+	ret->ClientID = Request->ClientID;
+	ret->CallID = Request->CallID;
+	ret->NParams = retValueCount;
+	inData = &ret->Params[ ret->NParams ];
+	
+	// Static Uint64 return value
+	ret->Params[0].Type = ARG_TYPE_INT64;
+	ret->Params[0].Flags = 0;
+	ret->Params[0].Length = sizeof(Uint64);
+	*(Uint64*)inData = retVal;
+	inData += sizeof(Uint64);
+	
+	for( i = 0; i < Request->NParams; i ++ )
+	{
+		if( Request->Params[i].Type != ARG_TYPE_DATA )	continue;
+		if( !(Request->Params[i].Flags & ARG_FLAG_RETURN) )	continue;
+		
+		ret->Params[1 + i].Type = Request->Params[i].Type;
+		ret->Params[1 + i].Flags = 0;
+		ret->Params[1 + i].Length = Request->Params[i].Length;
+		
+		memcpy(inData, mallocdData[i], Request->Params[i].Length);
+		inData += Request->Params[i].Length;
+		
+		free( mallocdData[i] );	// Free temp buffer from above
+	}
+	
+	return ret;
 }
diff --git a/AcessNative/ld-acess_src/request.c b/AcessNative/ld-acess_src/request.c
index 1fff68e8..3bef3d3e 100644
--- a/AcessNative/ld-acess_src/request.c
+++ b/AcessNative/ld-acess_src/request.c
@@ -114,11 +114,14 @@ int _InitSyscalls()
 		req.ClientID = 0;
 		req.CallID = 0;
 		req.NParams = 0;
-		req.NReturn = 0;
 		
 		SendData(&req, sizeof(req));
 		
 		len = ReadData(&req, sizeof(req), 5);
+		if( len == 0 ) {
+			fprintf(stderr, "Unable to connect to server (localhost:%i)\n", SERVER_PORT);
+			exit(-1);
+		}
 		
 		giSyscall_ClientID = req.ClientID;
 	}
@@ -127,81 +130,21 @@ int _InitSyscalls()
 	return 0;
 }
 
-int SendRequest(int RequestID, int NumOutput, tOutValue **Output, int NumInput, tInValue **Input)
+int SendRequest(tRequestHeader *Request, int RequestSize)
 {
-	tRequestHeader	*request;
-	tRequestValue	*value;
-	char	*data;
-	 int	requestLen;
-	 int	i;
-	
 	if( gSocket == INVALID_SOCKET )
 	{
 		_InitSyscalls();		
 	}
 	
-	// See ../syscalls.h for details of request format
-	requestLen = sizeof(tRequestHeader) + (NumOutput + NumInput) * sizeof(tRequestValue);
-	
-	// Get total param length
-	for( i = 0; i < NumOutput; i ++ )
-		requestLen += Output[i]->Length;
-	
-	// Allocate request
-	request = malloc( requestLen );
-	value = request->Params;
-	data = (char*)&request->Params[ NumOutput + NumInput ];
-	
 	// Set header
-	request->ClientID = giSyscall_ClientID;
-	request->CallID = RequestID;	// Syscall
-	request->NParams = NumOutput;
-	request->NReturn = NumInput;
+	Request->ClientID = giSyscall_ClientID;
 	
-	// Set parameters
-	for( i = 0; i < NumOutput; i ++ )
-	{
-		switch(Output[i]->Type)
-		{
-		case 'i':	value->Type = ARG_TYPE_INT32;	break;
-		case 'I':	value->Type = ARG_TYPE_INT64;	break;
-		case 'd':	value->Type = ARG_TYPE_DATA;	break;
-		case 's':	value->Type = ARG_TYPE_DATA;	break;
-		default:
-			fprintf(stderr, __FILE__" SendRequest: Unknown output type '%c'\n",
-				Output[i]->Type);
-			return -1;
-		}
-		value->Length = Output[i]->Length;
-		
-		memcpy(data, Output[i]->Data, Output[i]->Length);
-		
-		value ++;
-		data += Output[i]->Length;
-	}
-	
-	// Set return values
-	for( i = 0; i < NumInput; i ++ )
-	{
-		switch(Input[i]->Type)
-		{
-		case 'i':	value->Type = ARG_TYPE_INT32;	break;
-		case 'I':	value->Type = ARG_TYPE_INT64;	break;
-		case 'd':	value->Type = ARG_TYPE_DATA;	break;
-		default:
-			fprintf(stderr, " SendRequest: Unknown input type '%c'\n",
-				Input[i]->Type);
-			return -1;
-		}
-		value->Length = Input[i]->Length;
-		value ++;
-	}
 	#if 0
-	printf("value = %p\n", value);
 	{
-		for(i=0;i<requestLen;i++)
+		for(i=0;i<RequestSize;i++)
 		{
-			printf("%02x ", ((uint8_t*)request)[i]);
+			printf("%02x ", ((uint8_t*)Request)[i]);
 			if( i % 16 == 15 )	printf("\n");
 		}
 		printf("\n");
@@ -209,24 +152,10 @@ int SendRequest(int RequestID, int NumOutput, tOutValue **Output, int NumInput,
 	#endif
 	
 	// Send it off
-	SendData(request, requestLen);
+	SendData(Request, RequestSize);
 	
 	// Wait for a response (no timeout)
-	requestLen = ReadData(request, requestLen, -1);
-	
-	// Parse response out
-	if( request->NParams != NumInput ) {
-		fprintf(stderr, "SendRequest: Unexpected number of values retured (%i, exp %i)\n",
-			request->NParams, NumInput
-			);
-		free( request );
-		return -1;
-	}
-	
-	// Free memory
-	free( request );
-	
-	return 0;
+	return ReadData(Request, RequestSize, -1);
 }
 
 void SendData(void *Data, int Length)
diff --git a/AcessNative/ld-acess_src/request.h b/AcessNative/ld-acess_src/request.h
index 8c89e6f6..b33a80f9 100644
--- a/AcessNative/ld-acess_src/request.h
+++ b/AcessNative/ld-acess_src/request.h
@@ -8,19 +8,8 @@
 #ifndef _REQUEST_H_
 #define _REQUEST_H_
 
-typedef struct {
-	char	Type;
-	 int	Length;
-	char	Data[];
-}	tOutValue;
+#include "../syscalls.h"
 
-typedef struct {
-	char	Type;
-	 int	Length;
-	void	*Data;
-}	tInValue;
-
-extern int SendRequest(int RequestID, int NumOutput, tOutValue **Output,
-	int NumInput, tInValue **Input);
+extern int	SendRequest(tRequestHeader *Request, int RequestSize);
 
 #endif
diff --git a/AcessNative/ld-acess_src/syscalls.c b/AcessNative/ld-acess_src/syscalls.c
index 9bdde9b2..50352f87 100644
--- a/AcessNative/ld-acess_src/syscalls.c
+++ b/AcessNative/ld-acess_src/syscalls.c
@@ -15,11 +15,10 @@
 // === IMPORTS ===
 
 // === CODE ===
-const char *ReadEntry(tOutValue **OutDest, tInValue **InDest,
-	int *Direction, const char *ArgTypes, va_list Args)
+const char *ReadEntry(tRequestValue *Dest, void *DataDest, void **PtrDest, const char *ArgTypes, va_list Args)
 {
-	uint64_t	val64, *ptr64;
-	uint32_t	val32, *ptr32;
+	uint64_t	val64;
+	uint32_t	val32;
 	 int	direction = 0;	// 0: Invalid, 1: Out, 2: In, 3: Out
 	char	*str;
 	 int	len;
@@ -31,11 +30,10 @@ const char *ReadEntry(tOutValue **OutDest, tInValue **InDest,
 	// Get direction
 	switch(*ArgTypes)
 	{
+	default:	// Defaults to output
 	case '>':	direction = 1;	break;
 	case '<':	direction = 2;	break;
 	case '?':	direction = 3;	break;
-	default:
-		return NULL;
 	}
 	ArgTypes ++;
 	
@@ -43,99 +41,90 @@ const char *ReadEntry(tOutValue **OutDest, tInValue **InDest,
 	while(*ArgTypes && *ArgTypes == ' ')	ArgTypes ++;
 	if( *ArgTypes == '\0' )	return ArgTypes;
 	
-	// Internal helper macro
-	#define MAKE_OUT(_dest,_typeChar,_typeName,_value) do{if((_dest)){\
-		*(_dest) = (tOutValue*)malloc(sizeof(tOutValue)+sizeof(_typeName));\
-		(*(_dest))->Type=(_typeChar);(*(_dest))->Length=sizeof(_typeName);\
-		*(_typeName*)((*(_dest))->Data) = (_value);\
-		}}while(0)
-	#define MAKE_IN(_dest,_typeChar,_typeName,_value) do{if((_dest)){\
-		*(_dest) = (tInValue*)malloc(sizeof(tInValue));\
-		(*(_dest))->Type=(_typeChar);(*(_dest))->Length=sizeof(_typeName);\
-		(*(_dest))->Data = (_value);\
-		}}while(0)
-	
 	// Get type
 	switch(*ArgTypes)
 	{
-	case 'i':	// 32-bit integer
-		// Input?
-		if( direction & 2 )
-		{
-			ptr32 = va_arg(Args, uint32_t*);
-			MAKE_IN(InDest, 'i', uint32_t*, ptr32);
-			if( direction & 1 )
-				MAKE_OUT(OutDest, 'i', uint32_t, *ptr32);
-		}
-		else
-		{
-			val32 = va_arg(Args, uint32_t);
-			MAKE_OUT(OutDest, 'i', uint32_t, val32);
+	// 32-bit integer
+	case 'i':
+		
+		if( direction != 1 ) {
+			fprintf(stderr, "ReadEntry: Recieving an integer is not defined\n");
+			return NULL;
 		}
+		
+		val32 = va_arg(Args, uint32_t);
+		
+		Dest->Type = ARG_TYPE_INT32;
+		Dest->Length = sizeof(uint32_t);
+		Dest->Flags = 0;
+		
+		if( DataDest )
+			*(uint32_t*)DataDest = val32;
 		break;
-	case 'I':	// 64-bit integer
-		// Input?
-		if( direction & 2 )
-		{
-			ptr64 = va_arg(Args, uint64_t*);
-			MAKE_IN(InDest, 'I', uint64_t*, ptr64);
-			if( direction & 1 )
-				MAKE_OUT(OutDest, 'I', uint64_t, *ptr64);
-		}
-		else
-		{
-			val64 = va_arg(Args, uint64_t);
-			MAKE_OUT(OutDest, 'I', uint64_t, val64);
+	// 64-bit integer
+	case 'I':
+		
+		if( direction != 1 ) {
+			fprintf(stderr, "ReadEntry: Recieving an integer is not defined\n");
+			return NULL;
 		}
+		
+		val64 = va_arg(Args, uint64_t);
+		
+		Dest->Type = ARG_TYPE_INT64;
+		Dest->Length = sizeof(uint64_t);
+		Dest->Flags = 0;
+		if( DataDest )
+			*(uint64_t*)DataDest = val64;
 		break;
+	// String
 	case 's':
 		// Input string makes no sense!
-		if( direction & 2 ) {
-			fprintf(stderr, "ReadEntry: Incoming string is not defined\n");
+		if( direction != 1 ) {
+			fprintf(stderr, "ReadEntry: Recieving a string is not defined\n");
 			return NULL;
 		}
 		
 		str = va_arg(Args, char*);
-		if( OutDest )
+		
+		Dest->Type = ARG_TYPE_STRING;
+		Dest->Length = strlen(str) + 1;
+		Dest->Flags = 0;
+		
+		if( DataDest )
 		{
-			 int	len = strlen(str) + 1;
-			*OutDest = malloc( sizeof(tOutValue) + len );
-			(*OutDest)->Type = 's';
-			(*OutDest)->Length = len;
-			memcpy((*OutDest)->Data, str, len);
+			memcpy(DataDest, str, Dest->Length);
 		}
 		break;
-	
+	// Data (special handling)
 	case 'd':
 		len = va_arg(Args, int);
 		str = va_arg(Args, char*);
 		
-		// Input ?
-		if( (direction & 2) && InDest )
-		{
-			*InDest = (tInValue*)malloc( sizeof(tInValue) );
-			(*InDest)->Type = 'd';
-			(*InDest)->Length = len;
-			(*InDest)->Data = str;
-		}
+		// Save the pointer for later
+		if( PtrDest )	*PtrDest = str;
+		
+		// Create parameter block
+		Dest->Type = ARG_TYPE_INT64;
+		Dest->Length = sizeof(uint64_t);
+		Dest->Flags = 0;
+		if( direction & 2 )
+			Dest->Flags |= ARG_FLAG_RETURN;
 		
-		// Output ?
-		if( (direction & 1) && InDest )
+		// Has data?
+		if( direction & 1 )
 		{
-			*OutDest = (tOutValue*)malloc( sizeof(tOutValue) + len );
-			(*OutDest)->Type = 'd';
-			(*OutDest)->Length = len;
-			memcpy((*OutDest)->Data, str, len);
+			if( DataDest )
+				memcpy(DataDest, str, len);
 		}
+		else
+			Dest->Flags |= ARG_FLAG_ZEROED;
 		break;
 	
 	default:
 		return NULL;
 	}
 	ArgTypes ++;
-	#undef MAKE_ASSIGN
-	
-	*Direction = direction;
 	
 	return ArgTypes;
 }
@@ -153,82 +142,118 @@ const char *ReadEntry(tOutValue **OutDest, tInValue **InDest,
  * ?d:  Bi-directional buffer (Preceded by valid size), buffer contents
  *      are returned
  */
-void _Syscall(int SyscallID, const char *ArgTypes, ...)
+uint64_t _Syscall(int SyscallID, const char *ArgTypes, ...)
 {
 	va_list	args;
-	 int	outCount;
-	 int	inCount;
+	 int	paramCount, dataLength;
+	 int	retCount = 1, retLength = sizeof(uint64_t);
+	void	**retPtrs;	// Pointers to return buffers
 	const char	*str;
-	tOutValue	**output;
-	tInValue	**input;
+	tRequestHeader	*req;
+	void	*dataPtr;
+	uint64_t	retValue;
+	 int	i;
 	
 	// Get data size
 	va_start(args, ArgTypes);
 	str = ArgTypes;
-	outCount = 0;
-	inCount = 0;
+	paramCount = 0;
+	dataLength = 0;
 	while(*str)
 	{
-		 int	dir;
+		tRequestValue	tmpVal;
 		
-		str = ReadEntry(NULL, NULL, &dir, str, args);
+		str = ReadEntry(&tmpVal, NULL, NULL, str, args);
 		if( !str ) {
 			fprintf(stderr, "syscalls.c: ReadEntry failed (SyscallID = %i)\n", SyscallID);
 			exit(127);
 		}
+		paramCount ++;
+		if( !(tmpVal.Flags & ARG_FLAG_ZEROED) )
+			dataLength += tmpVal.Length;
 		
-		// Out!
-		if( dir & 1 )	outCount ++;
-		
-		// and.. In!
-		if( dir & 2 )	inCount ++;
+		if( tmpVal.Flags & ARG_FLAG_RETURN ) {
+			retLength += tmpVal.Length;
+			retCount ++;
+		}
 	}
 	va_end(args);
 	
+	dataLength += sizeof(tRequestHeader) + paramCount*sizeof(tRequestValue);
+	retLength += sizeof(tRequestHeader) + retCount*sizeof(tRequestValue);
+	
 	// Allocate buffers
-	output = malloc( outCount*sizeof(tOutValue*) );
-	input = malloc( inCount*sizeof(tInValue*) );
+	retPtrs = malloc( sizeof(void*) * (retCount+1) );
+	if( dataLength > retLength)
+		req = malloc( dataLength );
+	else
+		req = malloc( retLength );
+	req->ClientID = 0;	//< Filled later
+	req->CallID = SyscallID;
+	req->NParams = paramCount;
+	dataPtr = &req->Params[paramCount];
 	
 	// Fill `output` and `input`
 	va_start(args, ArgTypes);
 	str = ArgTypes;
 	// - re-zero so they can be used as indicies
-	outCount = 0;
-	inCount = 0;
+	paramCount = 0;
+	retCount = 0;
 	while(*str)
-	{
-		tOutValue	*outParam;
-		tInValue	*inParam;
-		 int	dir;
-		
-		str = ReadEntry(&outParam, &inParam, &dir, str, args);
+	{		
+		str = ReadEntry(&req->Params[paramCount], dataPtr, &retPtrs[retCount], str, args);
 		if( !str )	break;
 		
-		if( dir & 1 )
-			output[outCount++] = outParam;
-		if( dir & 2 )
-			input[inCount++] = inParam;
+		if( !(req->Params[paramCount].Flags & ARG_FLAG_ZEROED) )
+			dataPtr += req->Params[paramCount].Length;
+		if( req->Params[paramCount].Flags & ARG_FLAG_RETURN )
+			retCount ++;
+		
+		paramCount ++;
 	}
 	va_end(args);
 	
 	// Send syscall request
-	if( SendRequest(SyscallID, outCount, output, inCount, input) ) {
+	if( SendRequest(req, dataLength) ) {
 		fprintf(stderr, "syscalls.c: SendRequest failed (SyscallID = %i)\n", SyscallID);
 		exit(127);
 	}
 	
-	// Clean up
-	while(outCount--)	free(output[outCount]);
-	free(output);
-	while(inCount--)	free(input[inCount]);
-	free(input);
+	// Parse return value
+	dataPtr = &req->Params[req->NParams];
+	retValue = 0;
+	if( req->NParams > 1 )
+	{
+		switch(req->Params[0].Type)
+		{
+		case ARG_TYPE_INT64:
+			retValue = *(uint64_t*)dataPtr;
+			dataPtr += req->Params[0].Length;
+			break;
+		case ARG_TYPE_INT32:
+			retValue = *(uint32_t*)dataPtr;
+			dataPtr += req->Params[0].Length;
+			break;
+		}	
+	}
+	
+	// Write changes to buffers
+	va_start(args, ArgTypes);
+	for( i = 1; i < req->NParams; i ++ )
+	{
+		memcpy( retPtrs[i-1], dataPtr, req->Params[i].Length );
+		dataPtr += req->Params[i].Length;
+	}
+	va_end(args);
+	
+	free( req );
+	
+	return 0;
 }
 
 // --- VFS Calls
 int open(const char *Path, int Flags) {
-	 int	ret = 0;
-	_Syscall(SYS_OPEN, "<i >s >i", &ret, Path, Flags);
-	return ret;
+	return _Syscall(SYS_OPEN, ">s >i", Path, Flags);
 }
 
 void close(int FD) {
@@ -236,27 +261,19 @@ void close(int FD) {
 }
 
 size_t read(int FD, size_t Bytes, void *Dest) {
-	 int	ret = 0;
-	_Syscall(SYS_READ, "<i >i >i <d", &ret, FD, Bytes, Bytes, Dest);
-	return ret;
+	return _Syscall(SYS_READ, "<i >i >i <d", FD, Bytes, Bytes, Dest);
 }
 
 size_t write(int FD, size_t Bytes, void *Src) {
-	 int	ret = 0;
-	_Syscall(SYS_WRITE, "<i >i >i >d", &ret, FD, Bytes, Bytes, Src);
-	return ret;
+	return _Syscall(SYS_WRITE, ">i >i >d", FD, Bytes, Bytes, Src);
 }
 
 int seek(int FD, int64_t Ofs, int Dir) {
-	 int	ret = 0;
-	_Syscall(SYS_SEEK, "<i >i >I >i", &ret, FD, Ofs, Dir);
-	return ret;
+	return _Syscall(SYS_SEEK, ">i >I >i", FD, Ofs, Dir);
 }
 
 uint64_t tell(int FD) {
-	uint64_t	ret;
-	_Syscall(SYS_TELL, "<I >i", &ret, FD);
-	return ret;
+	return _Syscall(SYS_TELL, ">i", FD);
 }
 
 int ioctl(int fd, int id, void *data) {
diff --git a/AcessNative/syscalls.h b/AcessNative/syscalls.h
index 903cbfae..4a64474b 100644
--- a/AcessNative/syscalls.h
+++ b/AcessNative/syscalls.h
@@ -17,6 +17,7 @@
 typedef struct sRequestValue {
 	/// \see eArgumentTypes
 	uint16_t	Type;
+	 uint8_t	Flags;
 	uint16_t	Length;
 }	tRequestValue;
 
@@ -24,7 +25,6 @@ typedef struct sRequestHeader {
 	uint16_t	ClientID;
 	uint16_t	CallID;	//!< \see eSyscalls
 	uint16_t	NParams;
-	uint16_t	NReturn;
 	
 	tRequestValue	Params[];
 }	tRequestHeader;
@@ -53,5 +53,9 @@ enum eArgumentTypes {
 	ARG_TYPE_STRING,
 	ARG_TYPE_DATA
 };
+enum eArgumentFlags {
+	ARG_FLAG_RETURN = 0x40,	// Pass back in the return message
+	ARG_FLAG_ZEROED = 0x80	// Not present in the message, just fill with zero
+};
 
 #endif
-- 
GitLab