diff --git a/AcessNative/acesskernel_src/Makefile b/AcessNative/acesskernel_src/Makefile
index 4ff36c95e0b9bd985c58c6fadeab0306502caa2b..71782a9a444e8bf2c5599471c0c79364d35216ee 100644
--- a/AcessNative/acesskernel_src/Makefile
+++ b/AcessNative/acesskernel_src/Makefile
@@ -7,19 +7,20 @@ endif
 
 KERNEL_SRC = ../../Kernel/
 
-KERNEL_OBJ := logging.o adt.o lib.o
+KERNEL_OBJ := logging.o adt.o lib.o drvutil.o
 KERNEL_OBJ += vfs/main.o vfs/open.o vfs/acls.o vfs/io.o vfs/dir.o vfs/nodecache.o vfs/mount.o vfs/memfile.o
 KERNEL_OBJ += vfs/fs/root.o vfs/fs/devfs.o
 KERNEL_OBJ += drv/vterm.o drv/fifo.o drv/proc.o
 
-OBJ := main.o helpers.o threads.o video.o keyboard.o mouse.o nativefs.o vfs_handle.o
+OBJ := main.o helpers.o threads.o syscalls.o
+OBJ += video.o keyboard.o mouse.o nativefs.o vfs_handle.o ui_sdl.o
 OBJ += $(addprefix $(KERNEL_SRC),$(KERNEL_OBJ))
 
 OBJ := $(addsuffix .$(PLATFORM),$(OBJ))
 
 CPPFLAGS += -I include/ -I $(KERNEL_SRC)include/
-CFLAGS += -Wall
-LDFLAGS += -lSDL -lSDLmain
+CFLAGS += -Wall -g
+LDFLAGS += -lSDL -lSDLmain -g
 
 ifeq ($(PLATFORM),win)
 	BIN := ../AcessKernel.exe
diff --git a/AcessNative/acesskernel_src/helpers.c b/AcessNative/acesskernel_src/helpers.c
index 2209b05f22e518a8e2c52a636430f1185a99f075..ef5f1db13df6290e7608732f1837c2946253085e 100644
--- a/AcessNative/acesskernel_src/helpers.c
+++ b/AcessNative/acesskernel_src/helpers.c
@@ -53,9 +53,9 @@ void Debug_SetKTerminal(const char *Path)
 	// Ignored, kernel debug goes to stdout
 }
 
-void *Heap_Allocate(int Count, const char *File, int Line)
+void *Heap_Allocate(const char *File, int Line, int ByteCount)
 {
-	return malloc(Count);
+	return malloc(ByteCount);
 }
 
 tPAddr MM_GetPhysAddr(tVAddr VAddr)
diff --git a/AcessNative/acesskernel_src/include/arch.h b/AcessNative/acesskernel_src/include/arch.h
index d67b67347058deb0739efe8a6f5baac04a9cd179..8f0eb796eac89abe0a69b8e500a1e9093f746119 100644
--- a/AcessNative/acesskernel_src/include/arch.h
+++ b/AcessNative/acesskernel_src/include/arch.h
@@ -6,7 +6,7 @@
 #include <stdint.h>
 #include <stdlib.h>
 #include <pthread.h>
-
+#undef CLONE_VM
 #define	_MODULE_NAME_	"NativeKernel"
 
 #define BITS	(sizeof(intptr_t)*8)
diff --git a/AcessNative/acesskernel_src/include/heap.h b/AcessNative/acesskernel_src/include/heap.h
index 2052559721256defb62359afbe037ebc5b8afe54..9315142e24ae91183f29484a1eb8b22a4067ebce 100644
--- a/AcessNative/acesskernel_src/include/heap.h
+++ b/AcessNative/acesskernel_src/include/heap.h
@@ -4,5 +4,7 @@
 #define _HEAP_H_
 
 // NOP (stdlib.h defines the heap functions)
+// Heap_Allocate is used in _strdup
+extern void	*Heap_Allocate(const char *File, int Line, int ByteCount);
 
 #endif
diff --git a/AcessNative/acesskernel_src/keyboard.c b/AcessNative/acesskernel_src/keyboard.c
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..768948314e163b4ff683e3f3ba519f19360cc2f8 100644
--- a/AcessNative/acesskernel_src/keyboard.c
+++ b/AcessNative/acesskernel_src/keyboard.c
@@ -0,0 +1,68 @@
+/*
+ * Acess2 Native Kernel
+ * 
+ * Keyboard Driver
+ */
+#include <acess.h>
+#include <modules.h>
+#include <fs_devfs.h>
+#include <tpl_drv_common.h>
+#include <tpl_drv_keyboard.h>
+#include "ui.h"
+
+// === PROTOTYPES ===
+ int	NativeKeyboard_Install(char **Arguments);
+ int	NativeKeyboard_IOCtl(tVFS_Node *Node, int Id, void *Data);
+
+// === GLOBALS ===
+MODULE_DEFINE(0, 0x0100, NativeKeyboard, NativeKeyboard_Install, NULL, NULL);
+tDevFS_Driver	gKB_DevInfo = {
+	NULL, "NativeKeyboard",
+	{
+	.NumACLs = 0,
+	.Size = 0,
+	.IOCtl = NativeKeyboard_IOCtl
+	}
+};
+
+// === CODE ===
+/**
+ * \brief Install the keyboard driver
+ */
+int NativeKeyboard_Install(char **Arguments)
+{
+	DevFS_AddDevice( &gKB_DevInfo );
+	return MODULE_ERR_OK;
+}
+
+static const char * const csaIOCTL_NAMES[] = {
+	DRV_IOCTLNAMES,
+	DRV_KEYBAORD_IOCTLNAMES,
+	NULL
+};
+
+/**
+ * \fn int KB_IOCtl(tVFS_Node *Node, int Id, void *Data)
+ * \brief Calls an IOCtl Command
+ */
+int NativeKeyboard_IOCtl(tVFS_Node *Node, int Id, void *Data)
+{
+	switch(Id)
+	{
+	BASE_IOCTLS(DRV_TYPE_KEYBOARD, "NativeKeyboard", 0x10000, csaIOCTL_NAMES);
+
+	// Sets the Keyboard Callback
+	case KB_IOCTL_SETCALLBACK:
+		// Sanity Check
+		if(Threads_GetUID() != 0)
+			return 0;
+		// Can only be set once
+		if(gUI_KeyboardCallback != NULL)	return 0;
+		// Set Callback
+		gUI_KeyboardCallback = Data;
+		return 1;
+
+	default:
+		return 0;
+	}
+}
diff --git a/AcessNative/acesskernel_src/main.c b/AcessNative/acesskernel_src/main.c
index 09e09dc4b5b21539382073e80b617807f4cc1adf..7de6bf959bf863dbb1e3d2a8cea4eeaebcda0aa0 100644
--- a/AcessNative/acesskernel_src/main.c
+++ b/AcessNative/acesskernel_src/main.c
@@ -6,10 +6,48 @@
  */
 #include <stdio.h>
 #include <stdlib.h>
-#include <SDL/SDL.h>
 
+// === IMPORTS ===
+extern int	UI_Initialise(int Width, int Height);
+extern int	VFS_Init(void);
+extern int	Video_Install(char **Arguments);
+extern int	NativeKeyboard_Install(char **Arguments);
+extern int	VT_Install(char **Arguments);
+
+// === CODE ===
 int main(int argc, char *argv[])
 {
+	// Parse command line settings
+	
+	// Start UI subsystem
+	UI_Initialise(640, 480);
+	
+	// Initialise VFS
+	VFS_Init();
+	// - Start IO Drivers
+	Video_Install(NULL);
+	NativeKeyboard_Install(NULL);
+	// - Start VTerm
+	{
+		char	*args[] = {
+			"Video=NativeVideo",
+			"Input=NativeKeyboard",
+			NULL
+			};
+		VT_Install(args);
+	}
+	
+	// Start syscall server
+	for( ;; )
+	{
+		UI_Redraw();
+	}
+	
 	return 0;
 }
 
+void AcessNative_Exit(void)
+{
+	// TODO: Close client applications too
+	exit(0);
+}
diff --git a/AcessNative/acesskernel_src/syscalls.c b/AcessNative/acesskernel_src/syscalls.c
new file mode 100644
index 0000000000000000000000000000000000000000..db7907706033d8be2286f0d563884f1e80ba5b00
--- /dev/null
+++ b/AcessNative/acesskernel_src/syscalls.c
@@ -0,0 +1,131 @@
+/*
+ * Acess2 Native Kernel
+ * - Acess kernel emulation on another OS using SDL and UDP
+ *
+ * Syscall Server
+ */
+#include <acess.h>
+#include "../syscalls.h"
+
+// === TYPES ===
+typedef int	(*tSyscallHandler)(const char *Format, void *Args);
+
+// === MACROS ===
+#define SYSCALL3(_name, _call, _fmtstr, _t1, _t2, _t3) int _name(const char *fmt,void*args){\
+	_t1 a1;_t2 a2;_t3 a3;\
+	if(strcmp(fmt,_fmtstr)!=0)return 0;\
+	a1 = *(_t1*)args;args+=sizeof(_t1);\
+	a2 = *(_t2*)args;args+=sizeof(_t2);\
+	a3 = *(_t3*)args;args+=sizeof(_t3);\
+	return _call(a1,a2,a3);\
+}
+
+#define SYSCALL2(_name, _call, _fmtstr, _t1, _t2) int _name(const char *fmt,void*args){\
+	_t1 a1;_t2 a2;\
+	if(strcmp(fmt,_fmtstr)!=0)return 0;\
+	a1 = *(_t1*)args;args+=sizeof(_t1);\
+	a2 = *(_t2*)args;args+=sizeof(_t2);\
+	return _call(a1,a2);\
+}
+
+#define SYSCALL1V(_name, _call, _fmtstr, _t1) int _name(const char *fmt, void*args){\
+	_t1 a1;\
+	if(strcmp(fmt,_fmtstr)!=0)return 0;\
+	a1 = *(_t1*)args;args+=sizeof(_t1);\
+	_call(a1);\
+	return 0;\
+}
+
+// === CODE ===
+int Syscall_Null(const char *Format, void *Args)
+{
+	return 0;
+}
+
+SYSCALL2(Syscall_Open, VFS_Open, "di", 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 *);
+
+
+const tSyscallHandler	caSyscalls[] = {
+	Syscall_Null,
+	Syscall_Open,
+	Syscall_Close,
+	Syscall_Read,
+	Syscall_Write
+};
+const int	ciNumSyscalls = sizeof(caSyscalls)/sizeof(caSyscalls[0]);
+/**
+ * \brief Recieve a syscall structure from the server code
+ */
+tRequestHeader *SyscallRecieve(tRequestHeader *Request)
+{
+	char	formatString[Request->NParams+1];
+	char	*inData = (char*)&Request->Params[Request->NParams+Request->NReturn];
+	 int	argListLen = 0;
+	 int	i, retVal;
+	
+	if( Request->CallID > ciNumSyscalls ) {
+		return NULL;
+	}
+	
+	// Get size of argument list
+	for( i = 0; i < Request->NParams; i ++ )
+	{
+		switch(Request->Params[i].Type)
+		{
+		case ARG_TYPE_VOID:
+			formatString[i] = '-';
+			break;
+		case ARG_TYPE_INT32:
+			formatString[i] = 'i';
+			argListLen += sizeof(Uint32);
+			break;
+		case ARG_TYPE_INT64:
+			formatString[i] = 'I';
+			argListLen += sizeof(Uint64);
+			break;
+		case ARG_TYPE_DATA:
+			formatString[i] = 'd';
+			argListLen += sizeof(void*);
+			break;
+		default:
+			return NULL;	// ERROR!
+		}
+	}
+	
+	{
+		char	argListData[argListLen];
+		argListLen = 0;
+		// Build argument list
+		for( i = 0; i < Request->NParams; i ++ )
+		{
+			switch(Request->Params[i].Type)
+			{
+			case ARG_TYPE_VOID:
+				break;
+			case ARG_TYPE_INT32:
+				*(Uint32*)&argListData[argListLen] = *(Uint32*)inData;
+				argListLen += sizeof(Uint32);
+				inData += sizeof(Uint32);
+				break;
+			case ARG_TYPE_INT64:
+				*(Uint64*)&argListData[argListLen] = *(Uint64*)inData;
+				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*);
+				break;
+			}
+		}
+		
+		retVal = caSyscalls[Request->CallID](formatString, argListData);
+	}
+	
+	return NULL;
+}
diff --git a/AcessNative/acesskernel_src/threads.c b/AcessNative/acesskernel_src/threads.c
index 5f29f7601346a2fabb3ea2383d97574c32aad339..7b66624f1af4c7559850ae09994ebc01fa03a9e6 100644
--- a/AcessNative/acesskernel_src/threads.c
+++ b/AcessNative/acesskernel_src/threads.c
@@ -44,8 +44,12 @@ typedef struct sThread
 }	tThread;
 
 // === GLOBALS ===
-tThread	*gpThreads;
-__thread tThread	*gpCurrentThread;
+tThread	gThread_Zero = {
+	State: 1,
+	ThreadName: "ThreadZero"
+};
+tThread	*gpThreads = &gThread_Zero;
+__thread tThread	*gpCurrentThread = &gThread_Zero;
 
 // === CODE ===
 tThread	*Threads_GetThread(int TID)
@@ -66,6 +70,10 @@ tPID Threads_GetPID() { return gpCurrentThread->PID; }
 
 Uint *Threads_GetCfgPtr(int Index)
 {
+	if( Index < 0 || Index >= NUM_CFG_ENTRIES )
+		return NULL;
+	if( !gpCurrentThread )
+		return NULL;
 	return &gpCurrentThread->Config[Index];
 }
 
diff --git a/AcessNative/acesskernel_src/ui.h b/AcessNative/acesskernel_src/ui.h
new file mode 100644
index 0000000000000000000000000000000000000000..24298b918a9ff183a9f86c56b0994d7e92fcd6da
--- /dev/null
+++ b/AcessNative/acesskernel_src/ui.h
@@ -0,0 +1,24 @@
+/*
+ * Acess2
+ * AcessNative Kernel
+ * 
+ * ui.h - User Interface common header
+ */
+#ifndef _UI_H_
+#define _UI_H_
+
+extern const int	giUI_Width;
+extern const int	giUI_Height;
+extern const int	giUI_Pitch;
+extern const Uint32	* const gUI_Framebuffer;
+
+extern void	UI_SetWindowDims(int Width, int Height);
+extern void	UI_BlitBitmap(int DstX, int DstY, int SrcW, int SrcH, Uint32 *Bitmap);
+extern void	UI_BlitFramebuffer(int DstX, int DstY, int SrcX, int SrcY, int W, int H);
+extern void	UI_FillBitmap(int DstX, int DstY, int SrcW, int SrcH, Uint32 Value);
+extern void	UI_Redraw(void);
+
+typedef void (*tUI_KeybardCallback)(Uint32 Key);
+extern tUI_KeybardCallback	gUI_KeyboardCallback;
+
+#endif
diff --git a/AcessNative/acesskernel_src/ui_sdl.c b/AcessNative/acesskernel_src/ui_sdl.c
new file mode 100644
index 0000000000000000000000000000000000000000..97856f960f4a4c6c8f986c9ca307c8adee236083
--- /dev/null
+++ b/AcessNative/acesskernel_src/ui_sdl.c
@@ -0,0 +1,191 @@
+/*
+ * Acess2 Native Kernel
+ * 
+ * SDL User Interface
+ */
+#include <SDL/SDL.h>
+#define const
+#include "ui.h"
+#undef const
+#include <tpl_drv_keyboard.h>
+
+// === IMPORTS ===
+extern void	AcessNative_Exit(void);
+
+// === PROTOTYPES ===
+ int	UI_Initialise(int MaxWidth, int MaxHeight);
+ int	UI_MainThread(void *Unused);
+void	UI_BlitBitmap(int DstX, int DstY, int SrcW, int SrcH, Uint32 *Bitmap);
+void	UI_BlitFramebuffer(int DstX, int DstY, int SrcX, int SrcY, int W, int H);
+void	UI_FillBitmap(int X, int Y, int W, int H, Uint32 Value);
+void	UI_Redraw(void);
+
+// === GLOBALS ===
+SDL_Surface	*gScreen;
+SDL_Thread	*gInputThread;
+ int	giUI_Width = 0;
+ int	giUI_Height = 0;
+ int	giUI_Pitch = 0;
+tUI_KeybardCallback	gUI_KeyboardCallback;
+Uint32	gUI_Keymap[2][SDLK_LAST];	// Upper/Lower case
+
+// === FUNCTIONS ===
+int UI_Initialise(int MaxWidth, int MaxHeight)
+{	
+	// Changed when the video mode is set
+	giUI_Width = MaxWidth;
+	giUI_Height = MaxHeight;
+	
+	// Start main thread
+	gInputThread = SDL_CreateThread(UI_MainThread, NULL);
+	
+	return 0;
+}
+
+Uint32 UI_GetAcessKeyFromSDL(SDLKey Sym, Uint16 Unicode)
+{
+	Uint8	*keystate = SDL_GetKeyState(NULL);
+	 int	shiftState = 0;
+	Uint32	ret = 0;
+	
+	if( keystate[SDLK_RSHIFT] || keystate[SDLK_LSHIFT] )
+		shiftState = 1;
+	
+	// Fast return
+	if( gUI_Keymap[shiftState][Sym] )
+		return gUI_Keymap[shiftState][Sym];
+	
+	// How nice of you, a unicode value
+	if( Unicode )
+	{
+		ret = Unicode;
+	}
+	// Ok, we need to do work :(
+	else
+	{
+		switch(Sym)
+		{
+		case SDLK_UP:	ret = KEY_UP;	break;
+		case SDLK_DOWN:	ret = KEY_DOWN;	break;
+		case SDLK_LEFT:	ret = KEY_LEFT;	break;
+		case SDLK_RIGHT:ret = KEY_RIGHT;break;
+		case SDLK_CAPSLOCK:	ret = KEY_CAPSLOCK;	break;
+		case SDLK_F1:	ret = KEY_F1;	break;
+		case SDLK_F2:	ret = KEY_F2;	break;
+		case SDLK_F3:	ret = KEY_F3;	break;
+		case SDLK_F4:	ret = KEY_F4;	break;
+		case SDLK_F5:	ret = KEY_F5;	break;
+		case SDLK_F6:	ret = KEY_F6;	break;
+		case SDLK_F7:	ret = KEY_F7;	break;
+		case SDLK_F8:	ret = KEY_F8;	break;
+		case SDLK_F9:	ret = KEY_F9;	break;
+		case SDLK_F10:	ret = KEY_F10;	break;
+		case SDLK_F11:	ret = KEY_F11;	break;
+		case SDLK_F12:	ret = KEY_F12;	break;
+		default:
+			printf("Unhandled key code %i\n", Sym);
+			break;
+		}
+	}
+	
+	gUI_Keymap[shiftState][Sym] = ret;
+	return ret;
+}
+
+int UI_MainThread(void *Unused)
+{
+	SDL_Event	event;
+	Uint32	acess_sym;
+	
+	SDL_Init(SDL_INIT_VIDEO);
+	
+	// Set up video
+	gScreen = SDL_SetVideoMode(giUI_Width, giUI_Height, 32, 0);
+ 	if( !gScreen ) {
+		fprintf(stderr, "Couldn't set %ix%i video mode: %s\n", giUI_Width, giUI_Height, SDL_GetError());
+		SDL_Quit();
+ 	 	exit(2);
+	}
+	SDL_WM_SetCaption("Acess2", "Acess2");
+	
+	giUI_Width = gScreen->w;
+	giUI_Height = gScreen->h;
+	giUI_Pitch = gScreen->pitch;
+	
+	SDL_EnableUNICODE(1);
+	
+	for( ;; )
+	{
+		while(SDL_PollEvent(&event))
+		{
+			switch(event.type)
+			{
+			case SDL_QUIT:
+				AcessNative_Exit();
+				return 0;
+				
+			case SDL_KEYDOWN:
+				acess_sym = UI_GetAcessKeyFromSDL(event.key.keysym.sym,
+					event.key.keysym.unicode);
+				
+				if( gUI_KeyboardCallback )
+					gUI_KeyboardCallback(acess_sym);
+				break;
+			
+			case SDL_KEYUP:
+				acess_sym = UI_GetAcessKeyFromSDL(event.key.keysym.sym,
+					event.key.keysym.unicode);
+				
+				//if( gUI_KeyboardCallback )
+				//	gUI_KeyboardCallback(0x80000000|acess_sym);
+				break;
+			
+			default:
+				break;
+			}
+		}
+	}
+}
+
+void UI_BlitBitmap(int DstX, int DstY, int SrcW, int SrcH, Uint32 *Bitmap)
+{
+	SDL_Surface	*tmp;
+	SDL_Rect	dstRect;
+	
+	tmp = SDL_CreateRGBSurfaceFrom(Bitmap, SrcW, SrcH, 32, SrcW*4,
+		0xFF0000, 0x00FF00, 0x0000FF, 0xFF000000);
+	SDL_SetAlpha(tmp, 0, SDL_ALPHA_OPAQUE);
+	
+	dstRect.x = DstX;	dstRect.y = DstY;
+	
+	SDL_BlitSurface(tmp, NULL, gScreen, &dstRect);
+	
+	SDL_FreeSurface(tmp);
+}
+
+void UI_BlitFramebuffer(int DstX, int DstY, int SrcX, int SrcY, int W, int H)
+{
+	SDL_Rect	srcRect;
+	SDL_Rect	dstRect;
+	
+	srcRect.x = SrcX;	srcRect.y = SrcY;
+	srcRect.w = W;	srcRect.h = H;
+	dstRect.x = DstX;	dstRect.y = DstY;
+	
+	SDL_BlitSurface(gScreen, &srcRect, gScreen, &dstRect); 
+}
+
+void UI_FillBitmap(int X, int Y, int W, int H, Uint32 Value)
+{
+	SDL_Rect	dstRect;
+	
+	dstRect.x = X;	dstRect.y = Y;
+	dstRect.w = W;	dstRect.h = H;
+	
+	SDL_FillRect(gScreen, &dstRect, Value);
+}
+
+void UI_Redraw(void)
+{
+	// No-Op, we're not using double buffering
+}
diff --git a/AcessNative/acesskernel_src/video.c b/AcessNative/acesskernel_src/video.c
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..4645b956974f8365a6efdc18bf515d251d1a51a2 100644
--- a/AcessNative/acesskernel_src/video.c
+++ b/AcessNative/acesskernel_src/video.c
@@ -0,0 +1,298 @@
+/*
+ * Acess2 Native Kernel
+ * 
+ * Video Driver
+ */
+#define VERSION	((0<<8)|10)
+#include <acess.h>
+#include <vfs.h>
+#include <fs_devfs.h>
+#include <modules.h>
+#include <tpl_drv_video.h>
+#include "ui.h"
+
+// === PROTOTYPES ===
+ int	Video_Install(char **Arguments);
+Uint64	Video_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+Uint64	Video_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+ int	Video_IOCtl(tVFS_Node *Node, int ID, void *Data);
+// --- 2D Acceleration Functions --
+void	Video_2D_Fill(void *Ent, Uint16 X, Uint16 Y, Uint16 W, Uint16 H, Uint32 Colour);
+void	Video_2D_Blit(void *Ent, Uint16 DstX, Uint16 DstY, Uint16 SrcX, Uint16 SrcY, Uint16 W, Uint16 H);
+
+// === GLOBALS ===
+//MODULE_DEFINE(0, VERSION, NativeVideo, Video_Install, NULL, NULL);
+tDevFS_Driver	gVideo_DriverStruct = {
+	NULL, "NativeVideo",
+	{
+	.Read = Video_Read,
+	.Write = Video_Write,
+	.IOCtl = Video_IOCtl
+	}
+};
+ int	giVideo_DriverID;
+ int	giVideo_CurrentFormat;
+// --- 2D Video Stream Handlers ---
+tDrvUtil_Video_2DHandlers	gVideo_2DFunctions = {
+	NULL,
+	Video_2D_Fill,
+	Video_2D_Blit
+};
+
+// === CODE ===
+int Video_Install(char **Arguments)
+{
+	// Install Device
+	giVideo_DriverID = DevFS_AddDevice( &gVideo_DriverStruct );
+	if(giVideo_DriverID == -1)
+		return MODULE_ERR_MISC;
+	
+	return MODULE_ERR_OK;
+}
+
+/**
+ * \brief Read from framebuffer (unimplemented)
+ */
+Uint64 Video_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+{
+	return 0;
+}
+
+/**
+ * \brief Write to the framebuffer
+ */
+Uint64 Video_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+{
+	 int	i;
+	ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
+
+	if(Buffer == NULL) {
+		LEAVE('i', 0);
+		return 0;
+	}
+	// Text Mode
+	switch( giVideo_CurrentFormat )
+	{
+	case VIDEO_BUFFMT_TEXT:
+		{
+		tVT_Char	*chars = Buffer;
+		// int	pitch = giUI_Pitch;
+		 int	widthInChars = giUI_Width/giVT_CharWidth;
+		 int	heightInChars = giUI_Height/giVT_CharHeight;
+		 int	x, y;
+		Uint32	tmpBuf[giVT_CharHeight*giVT_CharWidth];
+		
+		Length /= sizeof(tVT_Char);
+		Offset /= sizeof(tVT_Char);
+		
+		x = Offset % widthInChars;
+		y = Offset / widthInChars;
+		
+		// Sanity Check
+		if( Offset > (Uint64)(heightInChars*widthInChars) ) {
+			LEAVE('i', 0);
+			return 0;
+		}
+		if(y >= heightInChars) {
+			LEAVE('i', 0);
+			return 0;
+		}
+		
+		// Clip to screen size
+		if( (int)Offset + (int)Length > heightInChars*widthInChars ) {
+			Log_Debug("Video", "%i + %i > %i*%i (%i)",
+				(int)Offset, (int)Length, heightInChars, widthInChars, heightInChars*widthInChars);
+			Length = heightInChars*widthInChars - Offset;
+			Log_Notice("Video", "Clipping write size to %i characters", (int)Length);
+		}
+		
+		// Print characters
+		for( i = 0; i < (int)Length; i++ )
+		{
+			VT_Font_Render(
+				chars->Ch,
+				//dest + x*giVT_CharWidth, pitch,
+				tmpBuf, giVT_CharWidth,
+				VT_Colour12to24(chars->BGCol),
+				VT_Colour12to24(chars->FGCol)
+				);
+			UI_BlitBitmap(
+				x*giVT_CharWidth, y*giVT_CharHeight,
+				giVT_CharWidth, giVT_CharHeight,
+				tmpBuf
+				);
+			
+			chars ++;
+			x ++;
+			if( x >= widthInChars ) {
+				x = 0;
+				y ++;
+				//dest += pitch*giVT_CharHeight;
+			}
+		}
+		Length *= sizeof(tVT_Char);
+		}
+		break;
+	
+	case VIDEO_BUFFMT_FRAMEBUFFER:
+		{
+		 int	startX, startY;
+		
+		if(giUI_Pitch*giUI_Height < Offset+Length)
+		{
+			Log_Warning("Video", "Video_Write - Framebuffer Overflow");
+			LEAVE('i', 0);
+			return 0;
+		}
+		
+		LOG("buffer = %p", Buffer);
+		LOG("Updating Framebuffer (%p to %p)", destBuf, destBuf + (Uint)Length);
+		
+		startX = Offset % giUI_Width;
+		startY = Offset / giUI_Width;
+		
+		if( Length + startX < giUI_Width )
+		{
+			// Single line
+			UI_BlitBitmap(
+				startX, startY,
+				Length, 1,
+				Buffer);
+		}
+		else
+		{
+			// First scanline (partial or full)
+			UI_BlitBitmap(
+				startX, startY,
+				giUI_Width - startX, 1,
+				Buffer);
+			
+			Length -= giUI_Width - startX;
+			Buffer += giUI_Width - startX;
+			
+			// Middle Scanlines
+			for( i = 0; i < Length / giUI_Height; i ++ )
+			{
+				UI_BlitBitmap(
+					0, startY + i,
+					giUI_Width, 1,
+					Buffer);
+				Buffer += giUI_Width;
+			}
+			
+			// Final scanline (partial)
+			if( Length % giUI_Height )
+			{
+				UI_BlitBitmap(
+					0, startY + i,
+					Length % giUI_Height, 1,
+					Buffer);
+			}
+		}
+		}
+		break;
+	
+	case VIDEO_BUFFMT_2DSTREAM:
+		Length = DrvUtil_Video_2DStream(
+			NULL,	// Single framebuffer, so Ent is unused
+			Buffer, Length, &gVideo_2DFunctions, sizeof(gVideo_2DFunctions)
+			);
+		break;
+	
+	default:
+		LEAVE('i', -1);
+		return -1;
+	}
+	
+	// Tell the UI to blit
+	UI_Redraw();
+	
+	LEAVE('X', Length);
+	return Length;
+}
+
+const char * const csaVIDEO_IOCTLS[] = {DRV_IOCTLNAMES, DRV_VIDEO_IOCTLNAMES, NULL};
+/**
+ * \brief Handle messages to the device
+ */
+int Video_IOCtl(tVFS_Node *Node, int ID, void *Data)
+{
+	 int	ret;
+	tVideo_IOCtl_Mode	*mode = Data;
+	switch(ID)
+	{
+	BASE_IOCTLS(DRV_TYPE_VIDEO, "NativeVideo", VERSION, csaVIDEO_IOCTLS);
+	
+	// Video mode control
+	// - We cheat, and only have one mode
+	case VIDEO_IOCTL_GETSETMODE:
+		return 0;
+	case VIDEO_IOCTL_FINDMODE:
+	case VIDEO_IOCTL_MODEINFO:
+		mode->id = 0;
+		mode->width = giUI_Width;
+		mode->height = giUI_Height;
+		mode->bpp = 32;
+		mode->flags = 0;
+		return 0;
+	
+	// Buffer mode
+	case VIDEO_IOCTL_SETBUFFORMAT:
+		ret = giVideo_CurrentFormat;
+		if(Data) {
+			giVideo_CurrentFormat = *(int*)Data;
+		}
+		return ret;
+	
+	#if 0
+	case VIDEO_IOCTL_SETCURSOR:	// Set cursor position
+		#if !BLINKING_CURSOR
+		if(giVesaCursorX > 0)
+			Vesa_FlipCursor(Node);
+		#endif
+		giVesaCursorX = ((tVideo_IOCtl_Pos*)Data)->x;
+		giVesaCursorY = ((tVideo_IOCtl_Pos*)Data)->y;
+		//Log_Debug("VESA", "Cursor position (%i,%i)", giVesaCursorX, giVesaCursorY);
+		if(
+			giVesaCursorX < 0 || giVesaCursorY < 0
+		||	giVesaCursorX >= gpVesaCurMode->width/giVT_CharWidth
+		||	giVesaCursorY >= gpVesaCurMode->height/giVT_CharHeight)
+		{
+			#if BLINKING_CURSOR
+			if(giVesaCursorTimer != -1) {
+				Time_RemoveTimer(giVesaCursorTimer);
+				giVesaCursorTimer = -1;
+			}
+			#endif
+			giVesaCursorX = -1;
+			giVesaCursorY = -1;
+		}
+		else {
+			#if BLINKING_CURSOR
+		//	Log_Debug("VESA", "Updating timer %i?", giVesaCursorTimer);
+			if(giVesaCursorTimer == -1)
+				giVesaCursorTimer = Time_CreateTimer(VESA_CURSOR_PERIOD, Vesa_FlipCursor, Node);
+			#else
+			Vesa_FlipCursor(Node);
+			#endif
+		}
+		//Log_Debug("VESA", "Cursor position (%i,%i) Timer %i", giVesaCursorX, giVesaCursorY, giVesaCursorTimer);
+		return 0;
+	#endif
+	
+	case VIDEO_IOCTL_REQLFB:	// Request Linear Framebuffer
+		return 0;
+	}
+	return 0;
+}
+
+// --- 2D Acceleration Functions --
+void Video_2D_Fill(void *Ent, Uint16 X, Uint16 Y, Uint16 W, Uint16 H, Uint32 Colour)
+{
+	UI_FillBitmap(X, Y, W, H, Colour);
+}
+
+void Video_2D_Blit(void *Ent, Uint16 DstX, Uint16 DstY, Uint16 SrcX, Uint16 SrcY, Uint16 W, Uint16 H)
+{
+	UI_BlitFramebuffer(DstX, DstY, SrcX, SrcY, W, H);
+}
diff --git a/AcessNative/ld-acess_src/binary.c b/AcessNative/ld-acess_src/binary.c
index b8f6e71bbf8861467e4d814605a07b88ca889cd4..0ce9fac910f91b2c3773839ef353124cf820ca28 100644
--- a/AcessNative/ld-acess_src/binary.c
+++ b/AcessNative/ld-acess_src/binary.c
@@ -147,7 +147,6 @@ void *Binary_Load(const char *Filename, uintptr_t *EntryPoint)
 
 	fread(&dword, 1, 4, fp);
 	fseek(fp, 0, SEEK_SET);
-	printf("dword = %08x\n", dword);
 	
 	if( memcmp(&dword, "\x7F""ELF", 4) == 0 ) {
 		fmt = &gElf_FormatDef;
@@ -211,8 +210,8 @@ int Binary_GetSymbol(const char *SymbolName, uintptr_t *Value)
 	 int	i;
 	tBinary	*bin;
 	
-	printf("Binary_GetSymbol: (SymbolName='%s', Value=%p)\n",
-		SymbolName, Value);
+	//printf("Binary_GetSymbol: (SymbolName='%s', Value=%p)\n",
+	//	SymbolName, Value);
 
 	// Search builtins
 	// - Placed first to override smartarses that define their own versions
@@ -229,12 +228,12 @@ int Binary_GetSymbol(const char *SymbolName, uintptr_t *Value)
 	for(bin = gLoadedBinaries; bin; bin = bin->Next)
 	{
 		if( !bin->Ready )	continue;
-		printf(" Binary_GetSymbol: bin = %p{%p, %s}\n", bin, bin->Base, bin->Path);
+		//printf(" Binary_GetSymbol: bin = %p{%p, %s}\n", bin, bin->Base, bin->Path);
 		if( bin->Format->GetSymbol(bin->Base, (char*)SymbolName, Value) )
 			return 1;
 	}
 
-	printf("Binary_GetSymbol: RETURN 0, not found\n");
+	//printf("Binary_GetSymbol: RETURN 0, not found\n");
 	
 	return 0;
 }
diff --git a/AcessNative/ld-acess_src/elf.c b/AcessNative/ld-acess_src/elf.c
index 3ab5a504db8a209a5bd324dbc9812e121c20b775..a79b591fd1af5f9e4957d5feaf4e4252be3525dc 100644
--- a/AcessNative/ld-acess_src/elf.c
+++ b/AcessNative/ld-acess_src/elf.c
@@ -42,7 +42,7 @@ void *Elf_Load(FILE *FP)
 	Elf32_Phdr	*phtab;
 	 int	i, j;
 	 int	iPageCount;
-	uint32_t	max, base = -1;
+	uint32_t	max, base;
 	uint32_t	addr;
 	uint32_t	baseDiff = 0;
 	
@@ -100,6 +100,8 @@ void *Elf_Load(FILE *FP)
 	//ret->Interpreter = NULL;
 
 	// Prescan for base and size
+	max = 0;
+	base = 0xFFFFFFFF;
 	for( i = 0; i < hdr.phentcount; i ++)
 	{
 		if( phtab[i].Type != PT_LOAD )
@@ -157,6 +159,9 @@ void *Elf_Load(FILE *FP)
 		addr = phtab[i].VAddr + baseDiff;
 
 		if( AllocateMemory( addr, phtab[i].MemSize ) ) {
+			fprintf(stderr, "Elf_Load: Unable to map memory at %x (0x%x bytes)\n",
+				addr, phtab[i].MemSize);
+			free( phtab );
 			return NULL;
 		}
 		
diff --git a/AcessNative/ld-acess_src/main.c b/AcessNative/ld-acess_src/main.c
index e310a84a598dfa55818e13f69cf2d311316fffdf..b2a8660e909a0a13175f6248d68e035d5d9f26b3 100644
--- a/AcessNative/ld-acess_src/main.c
+++ b/AcessNative/ld-acess_src/main.c
@@ -37,6 +37,10 @@ int main(int argc, char *argv[], char **envp)
 	printf("base = %p\n", base);
 	if( !base )	return 127;
 	
+	printf("==============================\n");
+	for(i = 0; i < appArgc; i ++)
+		printf("\"%s\" ", appArgv[i]);
+	printf("\n");
 	__asm__ __volatile__ (
 		"push %0;\n\t"
 		"push %1;\n\t"
diff --git a/AcessNative/ld-acess_src/memory.c b/AcessNative/ld-acess_src/memory.c
index 627f90245c2f0934951d448477df4d50b0480d78..072d32660ce88e8e05b1b2eb76a0a79c77694d9b 100644
--- a/AcessNative/ld-acess_src/memory.c
+++ b/AcessNative/ld-acess_src/memory.c
@@ -42,7 +42,7 @@ uintptr_t FindFreeRange(size_t ByteCount, int MaxBits)
 	#else
 	uintptr_t	base, ofs, size;
 	uintptr_t	end = -1;
-	const int	PAGE_SIZE = 0x1000;
+	static const int	PAGE_SIZE = 0x1000;
 	
 	size = (ByteCount + PAGE_SIZE - 1) / PAGE_SIZE;
 	size *= PAGE_SIZE;
diff --git a/AcessNative/ld-acess_src/request.c b/AcessNative/ld-acess_src/request.c
index f9526b3a18e126c139a62370993f70b67ffb97a4..df6e5c5596c1a0d1d99ca3d0533676cc686e36fa 100644
--- a/AcessNative/ld-acess_src/request.c
+++ b/AcessNative/ld-acess_src/request.c
@@ -43,8 +43,10 @@ int _InitSyscalls()
 	}
 	#endif
 	
+	// Open TCP Connection
+	gSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
 	// Open UDP Connection
-	gSocket = socket(AF_INET, SOCK_DGRAM, 0);
+	//gSocket = socket(AF_INET, SOCK_DGRAM, 0);
 	if (gSocket == INVALID_SOCKET)
 	{
 		fprintf(stderr, "Could not create socket.\n");
@@ -66,6 +68,20 @@ int _InitSyscalls()
 	client.sin_port = htons(0);
 	client.sin_addr.s_addr = htonl(0x7F00001);
 	
+	if( connect(gSocket, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) < 0 )
+	{
+		fprintf(stderr, "Cannot connect to server (localhost:%i)\n", SERVER_PORT);
+		perror("_InitSyscalls");
+		#if __WIN32__
+		closesocket(gSocket);
+		WSACleanup();
+		#else
+		close(gSocket);
+		#endif
+		exit(0);
+	}
+	
+	#if 0
 	// Bind
 	if( bind(gSocket, (struct sockaddr *)&client, sizeof(struct sockaddr_in)) == -1 )
 	{
@@ -78,6 +94,8 @@ int _InitSyscalls()
 		#endif
 		exit(0);
 	}
+	#endif
+	
 	return 0;
 }
 
@@ -89,6 +107,11 @@ int SendRequest(int RequestID, int NumOutput, tOutValue **Output, int NumInput,
 	 int	requestLen;
 	 int	i;
 	
+	if( gSocket == INVALID_SOCKET )
+	{
+		_InitSyscalls();		
+	}
+	
 	// See ../syscalls.h for details of request format
 	requestLen = sizeof(tRequestHeader) + (NumOutput + NumInput) * sizeof(tRequestValue);
 	
@@ -115,13 +138,17 @@ int SendRequest(int RequestID, int NumOutput, tOutValue **Output, int NumInput,
 		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;
 	}
 	
@@ -134,18 +161,53 @@ int SendRequest(int RequestID, int NumOutput, tOutValue **Output, int NumInput,
 		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++)
+		{
+			printf("%02x ", ((uint8_t*)request)[i]);
+			if( i % 16 == 15 )	printf("\n");
+		}
+		printf("\n");
 	}
+	#endif
 	
 	// Send it off
-	send(gSocket, request, requestLen, 0);
+	if( send(gSocket, request, requestLen, 0) != requestLen ) {
+		fprintf(stderr, "SendRequest: send() failed\n");
+		perror("SendRequest - send");
+		free( request );
+		return -1;
+	}
 	
 	// Wait for a response
-	recv(gSocket, request, requestLen, 0);
+	requestLen = recv(gSocket, request, requestLen, 0);
+	if( requestLen < 0 ) {
+		fprintf(stderr, "SendRequest: revc() failed\n");
+		perror("SendRequest - recv");
+		free( request );
+		return -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;
 }
diff --git a/AcessNative/ld-acess_src/syscalls.c b/AcessNative/ld-acess_src/syscalls.c
index ec4af017570fa1636deca8c2ee4b3a793de1d3f8..9bdde9b27e7dfade28832df5ced2e5841652975e 100644
--- a/AcessNative/ld-acess_src/syscalls.c
+++ b/AcessNative/ld-acess_src/syscalls.c
@@ -8,6 +8,7 @@
 #include <stdarg.h>
 #include <string.h>
 #include "request.h"
+#include "../syscalls.h"
 
 // === Types ===
 
@@ -152,25 +153,29 @@ const char *ReadEntry(tOutValue **OutDest, tInValue **InDest,
  * ?d:  Bi-directional buffer (Preceded by valid size), buffer contents
  *      are returned
  */
-int _Syscall(const char *ArgTypes, ...)
+void _Syscall(int SyscallID, const char *ArgTypes, ...)
 {
 	va_list	args;
-	 int	outCount = 0;
-	 int	inCount = 0;
+	 int	outCount;
+	 int	inCount;
 	const char	*str;
-	
 	tOutValue	**output;
 	tInValue	**input;
 	
 	// Get data size
 	va_start(args, ArgTypes);
 	str = ArgTypes;
+	outCount = 0;
+	inCount = 0;
 	while(*str)
 	{
 		 int	dir;
 		
 		str = ReadEntry(NULL, NULL, &dir, str, args);
-		if( !str )	break;
+		if( !str ) {
+			fprintf(stderr, "syscalls.c: ReadEntry failed (SyscallID = %i)\n", SyscallID);
+			exit(127);
+		}
 		
 		// Out!
 		if( dir & 1 )	outCount ++;
@@ -184,13 +189,12 @@ int _Syscall(const char *ArgTypes, ...)
 	output = malloc( outCount*sizeof(tOutValue*) );
 	input = malloc( inCount*sizeof(tInValue*) );
 	
-	// - re-zero so they can be used as indicies
-	outCount = 0;
-	inCount = 0;
-	
 	// Fill `output` and `input`
 	va_start(args, ArgTypes);
 	str = ArgTypes;
+	// - re-zero so they can be used as indicies
+	outCount = 0;
+	inCount = 0;
 	while(*str)
 	{
 		tOutValue	*outParam;
@@ -208,66 +212,90 @@ int _Syscall(const char *ArgTypes, ...)
 	va_end(args);
 	
 	// Send syscall request
-	
+	if( SendRequest(SyscallID, outCount, output, inCount, input) ) {
+		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);
-	
-	return 0;
 }
 
 // --- VFS Calls
 int open(const char *Path, int Flags) {
-	return _Syscall(">s >i", Path, Flags);
+	 int	ret = 0;
+	_Syscall(SYS_OPEN, "<i >s >i", &ret, Path, Flags);
+	return ret;
 }
 
 void close(int FD) {
-	_Syscall(">i", FD);
+	_Syscall(SYS_CLOSE, ">i", FD);
 }
 
 size_t read(int FD, size_t Bytes, void *Dest) {
-	return _Syscall(">i >i <d", FD, Bytes, Bytes, Dest);
+	 int	ret = 0;
+	_Syscall(SYS_READ, "<i >i >i <d", &ret, FD, Bytes, Bytes, Dest);
+	return ret;
 }
 
 size_t write(int FD, size_t Bytes, void *Src) {
-	return _Syscall(">i >i >d", FD, Bytes, Bytes, Src);
+	 int	ret = 0;
+	_Syscall(SYS_WRITE, "<i >i >i >d", &ret, FD, Bytes, Bytes, Src);
+	return ret;
 }
 
 int seek(int FD, int64_t Ofs, int Dir) {
-	return _Syscall(">i >I >i", FD, Ofs, Dir);
+	 int	ret = 0;
+	_Syscall(SYS_SEEK, "<i >i >I >i", &ret, FD, Ofs, Dir);
+	return ret;
 }
 
 uint64_t tell(int FD) {
 	uint64_t	ret;
-	_Syscall("<I >i", &ret, FD);
+	_Syscall(SYS_TELL, "<I >i", &ret, FD);
 	return ret;
 }
 
 int ioctl(int fd, int id, void *data) {
+	 int	ret = 0;
 	// NOTE: 1024 byte size is a hack
-	return _Syscall(">i >i ?d", fd, id, 1024, data);
+	_Syscall(SYS_IOCTL, "<i >i >i ?d", &ret, fd, id, 1024, data);
+	return ret;
 }
 int finfo(int fd, t_sysFInfo *info, int maxacls) {
-	return _Syscall(">i <d >i", fd, maxacls*sizeof(t_sysFInfo), info, maxacls);
+	 int	ret = 0;
+	_Syscall(SYS_FINFO, "<i >i <d >i",
+		&ret, fd,
+		sizeof(t_sysFInfo)+maxacls*sizeof(t_sysACL), info,
+		maxacls);
+	return ret;
 }
 
 int readdir(int fd, char *dest) {
-	return _Syscall(">i <s", fd, dest);
+	 int	ret = 0;
+	_Syscall(SYS_READDIR, "<i >i <d", &ret, fd, 256, dest);
+	return ret;
 }
 
 int _SysOpenChild(int fd, char *name, int flags) {
-	return _Syscall(">i >s >i", fd, name, flags);
+	 int	ret = 0;
+	_Syscall(SYS_OPENCHILD, "<i >i >s >i", &ret, fd, name, flags);
+	return ret;
 }
 
 int _SysGetACL(int fd, t_sysACL *dest) {
-	return _Syscall(">i <d", fd, sizeof(t_sysACL), dest);
+	 int	ret = 0;
+	_Syscall(SYS_GETACL, "<i >i <d", &ret, fd, sizeof(t_sysACL), dest);
+	return ret;
 }
 
 int _SysMount(const char *Device, const char *Directory, const char *Type, const char *Options) {
-	return _Syscall(">s >s >s >s", Device, Directory, Type, Options);
+	 int	ret = 0;
+	_Syscall(SYS_MOUNT, "<i >s >s >s >s", &ret, Device, Directory, Type, Options);
+	return ret;
 }
 
 
diff --git a/AcessNative/syscalls.h b/AcessNative/syscalls.h
index e298c94da4faadf7186fc6ab9d17710a4792a0a9..5081a53d2430551ea80cfd7075601ee50ea69ebf 100644
--- a/AcessNative/syscalls.h
+++ b/AcessNative/syscalls.h
@@ -29,13 +29,26 @@ typedef struct sRequestHeader {
 
 enum eSyscalls {
 	SYS_NULL,
-	SYS_OPEN
+	SYS_OPEN,
+	SYS_CLOSE,
+	SYS_READ,
+	SYS_WRITE,
+	SYS_SEEK,
+	SYS_TELL,
+	SYS_IOCTL,
+	SYS_FINFO,
+	SYS_READDIR,
+	SYS_OPENCHILD,
+	SYS_GETACL,
+	SYS_MOUNT,
+	N_SYSCALLS
 };
 
 enum eArgumentTypes {
 	ARG_TYPE_VOID,
 	ARG_TYPE_INT32,
 	ARG_TYPE_INT64,
+	ARG_TYPE_STRING,
 	ARG_TYPE_DATA
 };
 
diff --git a/Kernel/arch/x86/lib.c b/Kernel/arch/x86/lib.c
index 86117ccb6b8f4ff395f22d81c35d60004dbd71bf..2160805c4e81ee298712a01b7a699ecb2bbbbdfb 100644
--- a/Kernel/arch/x86/lib.c
+++ b/Kernel/arch/x86/lib.c
@@ -5,6 +5,8 @@
 #include <acess.h>
 #include <threads.h>
 
+#define TRACE_LOCKS	1
+
 extern int	GetCPUNum(void);
 
 // === CODE ===
@@ -103,6 +105,10 @@ void SHORTLOCK(struct sShortSpinlock *Lock)
 	__ASM__("cli");
 	Lock->IF = IF;
 	#endif
+	
+	#if TRACE_LOCKS
+	Log_Log("LOCK", "%p locked by %p\n", Lock, __builtin_return_address(0));
+	#endif
 }
 /**
  * \brief Release a short lock
@@ -110,6 +116,10 @@ void SHORTLOCK(struct sShortSpinlock *Lock)
  */
 void SHORTREL(struct sShortSpinlock *Lock)
 {
+	#if TRACE_LOCKS
+	Log_Log("LOCK", "%p released by %p\n", Lock, __builtin_return_address(0));
+	#endif
+	
 	#if STACKED_LOCKS
 	if( Lock->Depth ) {
 		Lock->Depth --;
diff --git a/Kernel/drv/vterm.c b/Kernel/drv/vterm.c
index 252f2924574ee4b93bf98fd0b2b888046c215a41..52c3a944b31e584bfe79319477df0f191fbb7733 100644
--- a/Kernel/drv/vterm.c
+++ b/Kernel/drv/vterm.c
@@ -140,13 +140,21 @@ int VT_Install(char **Arguments)
 	// Scan Arguments
 	if(Arguments)
 	{
-		char	**args = Arguments;
-		char	*arg, *opt, *val;
-		for( ; (arg = *args); args++ )
+		char	**args;
+		const char	*arg;
+		for(args = Arguments; (arg = *args); args++ )
 		{
+			char	data[strlen(arg)+1];
+			char	*opt = data;
+			char	*val;
+			
+			val = strchr(arg, '=');
+			strcpy(data, arg);
+			if( val ) {
+				data[ val - arg ] = '\0';
+				val ++;
+			}
 			Log_Debug("VTerm", "Argument '%s'", arg);
-			opt = arg;
-			val = arg + strpos(arg, '=');	*val++ = '\0';
 			
 			if( strcmp(opt, "Video") == 0 ) {
 				gsVT_OutputDevice = val;
@@ -197,6 +205,7 @@ int VT_Install(char **Arguments)
 		gVT_Terminals[i].CurColour = DEFAULT_COLOUR;
 		gVT_Terminals[i].WritePos = 0;
 		gVT_Terminals[i].ViewPos = 0;
+		gVT_Terminals[i].ReadingThread = -1;
 		
 		// Initialise
 		VT_int_ChangeMode( &gVT_Terminals[i],
@@ -233,7 +242,7 @@ int VT_Install(char **Arguments)
 void VT_InitOutput()
 {
 	giVT_OutputDevHandle = VFS_Open(gsVT_OutputDevice, VFS_OPENFLAG_WRITE);
-	if(giVT_InputDevHandle == -1) {
+	if(giVT_OutputDevHandle == -1) {
 		Log_Warning("VTerm", "Oh F**k, I can't open the video device '%s'", gsVT_OutputDevice);
 		return ;
 	}
@@ -249,7 +258,10 @@ void VT_InitOutput()
 void VT_InitInput()
 {
 	giVT_InputDevHandle = VFS_Open(gsVT_InputDevice, VFS_OPENFLAG_READ);
-	if(giVT_InputDevHandle == -1)	return ;
+	if(giVT_InputDevHandle == -1) {
+		Log_Warning("VTerm", "Can't open the input device '%s'", gsVT_InputDevice);
+		return ;
+	}
 	VFS_IOCtl(giVT_InputDevHandle, KB_IOCTL_SETCALLBACK, VT_KBCallBack);
 }
 
diff --git a/Kernel/include/tpl_drv_keyboard.h b/Kernel/include/tpl_drv_keyboard.h
index 8f4c1585598418e1b60c82f255b31ee48d254e30..c93c147e7604ba21ce2d4c6a17d2af187bb86fdb 100644
--- a/Kernel/include/tpl_drv_keyboard.h
+++ b/Kernel/include/tpl_drv_keyboard.h
@@ -57,6 +57,8 @@ enum eTplKeyboard_IOCtl {
 	KB_IOCTL_SETCALLBACK
 };
 
+#define DRV_KEYBAORD_IOCTLNAMES	"getset_repeat_rate", "getset_repeat_delay", "set_callback"
+
 /**
  * \brief Callback type for KB_IOCTL_SETCALLBACK
  * \param Key Unicode character code for the pressed key (with bit 31
diff --git a/Kernel/include/tpl_drv_video.h b/Kernel/include/tpl_drv_video.h
index 1c00c5ed50fa772f7a413bd06535c52f6ada2308..bf67e59865f6df4fc5ec7e96ab1502795d05dfb6 100644
--- a/Kernel/include/tpl_drv_video.h
+++ b/Kernel/include/tpl_drv_video.h
@@ -102,6 +102,7 @@ enum eTplVideo_IOCtl {
 	 */
 	VIDEO_IOCTL_REQLFB
 };
+#define DRV_VIDEO_IOCTLNAMES	"getset_mode", "find+mode", "mode_info", "set_buf_format", "set_cursor", "request_framebuffer"
 
 /**
  * \brief Mode Structure used in IOCtl Calls
diff --git a/Modules/IPStack/tcp.c b/Modules/IPStack/tcp.c
index 374150368dc58de4c316532993cd80caff9abb95..e42e940cd6ebc1608db1e2a7531c1a0166c90cf5 100644
--- a/Modules/IPStack/tcp.c
+++ b/Modules/IPStack/tcp.c
@@ -231,7 +231,7 @@ void TCP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffe
 			srv->ConnectionsTail = conn;
 			if(!srv->NewConnections)
 				srv->NewConnections = conn;
-			SHORTLOCK(&srv->lConnections);
+			SHORTREL(&srv->lConnections);
 
 			// Send the SYN ACK
 			hdr->Flags |= TCP_FLAG_ACK;
diff --git a/Usermode/Libraries/crt0.o_src/crt0.asm b/Usermode/Libraries/crt0.o_src/crt0.asm
index 07db9de2fe662938caf49e5d61d229f01ebc6f7c..b923d1844496974e618d35ee4ca12699b4cfc6d5 100644
--- a/Usermode/Libraries/crt0.o_src/crt0.asm
+++ b/Usermode/Libraries/crt0.o_src/crt0.asm
@@ -10,10 +10,10 @@
 [global _start]
 [global start]
 [extern main]
+[extern _exit]
 _start:
 start:
 	call main
-	mov eax, ebx	; Set Argument 1 to Return Value
-	xor eax, eax	; Set EAX to SYS_EXIT (0)
-	int	0xAC
+	push eax
+	call _exit	
 	jmp $	; This should never be reached