From 9d3800f60f2212432e550a4e003ae65b498a4d36 Mon Sep 17 00:00:00 2001
From: John Hodge <tpg@portege.thepowersgang.com>
Date: Fri, 2 Oct 2009 21:00:47 +0800
Subject: [PATCH] Cleanup - Unified the build systems for user and kernel space
 code - Fixed bug in VFS when VFS_Open is called by user when the current
 working directory is NULL - Added testing EXT2 and NE2000 drivers - Added
 files forgotten in the FDD commit

---
 Kernel/Makefile                               |   8 +-
 Kernel/Makefile.cfg                           |   6 -
 Kernel/arch/x86/Makefile                      |   8 +-
 Kernel/arch/x86/errors.c                      |  61 ++
 Kernel/arch/x86/mm_virt.c                     |   7 +-
 Kernel/arch/x86/proc.c                        |  37 +-
 Kernel/binary.c                               |   4 +-
 Kernel/debug.c                                |   1 -
 Kernel/drv/ne2000.c                           | 213 +++++++
 Kernel/include/common.h                       |  13 +-
 Kernel/include/dma.h                          |  10 +
 Kernel/include/signal.h                       |  16 +
 Kernel/include/threads.h                      |   6 +-
 Kernel/syscalls.c                             |   5 +
 Kernel/system.c                               |   1 -
 Kernel/threads.c                              |  96 ++-
 Kernel/vfs/fs/ext2.c                          | 584 ++++++++++++++++++
 Kernel/vfs/fs/fs_ext2.h                       | 154 +++++
 Kernel/vfs/open.c                             |  12 +-
 Makefile.cfg                                  |  15 +
 README                                        |  31 +
 Usermode/Applications/CLIShell_src/Makefile   |  33 +-
 Usermode/Applications/Makefile.cfg            |   9 +
 Usermode/Applications/cat_src/Makefile        |  14 +-
 Usermode/Applications/init_src/Makefile       |  21 +-
 Usermode/Applications/login_src/Makefile      |  28 +-
 Usermode/Applications/login_src/header.h      |  25 +
 Usermode/Applications/ls_src/Makefile         |  27 +
 Usermode/Applications/ls_src/main.c           | 165 +++++
 Usermode/Libraries/Makefile.cfg               |   9 +
 Usermode/Libraries/ld-acess.so_src/Makefile   |  26 +-
 .../Libraries/ld-acess.so_src/helpers.asm     |  58 ++
 Usermode/Libraries/ld-acess.so_src/link.ld    |  27 +
 Usermode/Libraries/libacess.so_src/Makefile   |  13 +-
 Usermode/Libraries/libc.so_src/Makefile       |  22 +-
 Usermode/Libraries/libc.so_src/config.h       |  17 +
 Usermode/Libraries/libc.so_src/crt0.asm       |   9 +
 Usermode/Libraries/libc.so_src/lib.h          |  19 +
 Usermode/Libraries/libc.so_src/stdio_int.h    |  31 +
 Usermode/Libraries/libc.so_src/string.c       | 113 ++++
 Usermode/Libraries/libgcc.so_src/Makefile     |  28 +
 Usermode/Libraries/libgcc.so_src/libgcc.c     |  50 ++
 Usermode/include/string.h                     |  21 +
 43 files changed, 1899 insertions(+), 154 deletions(-)
 delete mode 100644 Kernel/Makefile.cfg
 create mode 100644 Kernel/drv/ne2000.c
 create mode 100644 Kernel/include/dma.h
 create mode 100644 Kernel/include/signal.h
 create mode 100644 Kernel/vfs/fs/ext2.c
 create mode 100644 Kernel/vfs/fs/fs_ext2.h
 create mode 100644 Makefile.cfg
 create mode 100644 README
 create mode 100644 Usermode/Applications/Makefile.cfg
 create mode 100644 Usermode/Applications/login_src/header.h
 create mode 100644 Usermode/Applications/ls_src/Makefile
 create mode 100644 Usermode/Applications/ls_src/main.c
 create mode 100644 Usermode/Libraries/Makefile.cfg
 create mode 100644 Usermode/Libraries/ld-acess.so_src/helpers.asm
 create mode 100644 Usermode/Libraries/ld-acess.so_src/link.ld
 create mode 100644 Usermode/Libraries/libc.so_src/config.h
 create mode 100644 Usermode/Libraries/libc.so_src/crt0.asm
 create mode 100644 Usermode/Libraries/libc.so_src/lib.h
 create mode 100644 Usermode/Libraries/libc.so_src/stdio_int.h
 create mode 100644 Usermode/Libraries/libc.so_src/string.c
 create mode 100644 Usermode/Libraries/libgcc.so_src/Makefile
 create mode 100644 Usermode/Libraries/libgcc.so_src/libgcc.c
 create mode 100644 Usermode/include/string.h

diff --git a/Kernel/Makefile b/Kernel/Makefile
index e1534834..ae42dce5 100644
--- a/Kernel/Makefile
+++ b/Kernel/Makefile
@@ -4,12 +4,10 @@
 # - The built objects and dependency files are suffixed with the arch name
 # - The final binary is Acess2.<ARCH>.bin
 
--include Makefile.cfg
+-include ../Makefile.cfg
 
 -include arch/$(ARCHDIR)/Makefile
 
-RM = rm -f
-
 MAKEDEP		= $(CC) -M
 
 CPPFLAGS	+= -I./include -I./arch/$(ARCHDIR)/include -DARCH=$(ARCH)
@@ -43,9 +41,9 @@ $(BIN): $(OBJ) arch/$(ARCHDIR)/link.ld Makefile
 	@echo --- LD -o $(BIN)
 	@$(LD) $(LDFLAGS) -o $(BIN) $(OBJ) -Map ../Map.$(ARCH).txt
 	@objdump $(BIN) -D > $(BIN).dsm
-	@cp $(BIN) /mnt/AcessFDD/
+	cp $(BIN) $(DISTROOT)
 	@wc -l $(SRCFILES) > LineCounts.$(ARCH).txt
-	@git commit -a
+#	@git commit -a
 
 %.ao.$(ARCH): %.asm Makefile
 	@echo --- NASM -o $@
diff --git a/Kernel/Makefile.cfg b/Kernel/Makefile.cfg
deleted file mode 100644
index 8e186b82..00000000
--- a/Kernel/Makefile.cfg
+++ /dev/null
@@ -1,6 +0,0 @@
-# 
-# Acess2 Makefile Config
-# Makefile.cfg
-
-ARCH = i386
-ARCHDIR = x86
diff --git a/Kernel/arch/x86/Makefile b/Kernel/arch/x86/Makefile
index 335d2195..051d126e 100644
--- a/Kernel/arch/x86/Makefile
+++ b/Kernel/arch/x86/Makefile
@@ -4,10 +4,10 @@
 # arch/i386/Makefile
 
 # Assuming build machine is 32-bit ELF
-CC = gcc
-AS = nasm
-LD = ld
-OBJDUMP = objdump
+#CC = gcc
+#AS = nasm
+#LD = ld
+#OBJDUMP = objdump
 
 CPPFLAGS	=
 CFLAGS		=
diff --git a/Kernel/arch/x86/errors.c b/Kernel/arch/x86/errors.c
index 2c3582cd..0c2da16e 100644
--- a/Kernel/arch/x86/errors.c
+++ b/Kernel/arch/x86/errors.c
@@ -5,10 +5,16 @@
  */
 #include <common.h>
 
+// === CONSTANTS ===
+#define	MAX_BACKTRACE	8	//!< Maximum distance to trace the stack backwards
+
 // === IMPORTS ===
 extern void	MM_PageFault(Uint Addr, Uint ErrorCode, tRegs *Regs);
 extern void Threads_Dump();
 
+// === PROTOTYPES ===
+void	Error_Backtrace(Uint eip, Uint ebp);
+
 // === CODE ===
 /**
  * \fn void ErrorHandler(tRegs *Regs)
@@ -45,8 +51,63 @@ void ErrorHandler(tRegs *Regs)
 	__asm__ __volatile__ ("mov %%cr3, %0":"=r"(cr));
 	Warning(" CR3: 0x%08x", cr);
 	
+	// Print Stack Backtrace
+	Error_Backtrace(Regs->eip, Regs->ebp);
+	
 	// Dump running threads
 	Threads_Dump();
 	
 	for(;;)	__asm__ __volatile__ ("hlt");
 }
+/**
+ * \fn void Error_Backtrace(Uint eip, Uint ebp)
+ * \brief Unrolls the stack to trace execution
+ */
+void Error_Backtrace(Uint eip, Uint ebp)
+{
+	 int	i = 0;
+	Uint	delta = 0;
+	char	*str = NULL;
+	
+	//if(eip < 0xC0000000 && eip > 0x1000)
+	//{
+	//	LogF("Backtrace: User - 0x%x\n", eip);
+	//	return;
+	//}
+	
+	if(eip > 0xE0000000)
+	{
+		LogF("Backtrace: Data Area - 0x%x\n", eip);
+		return;
+	}
+	
+	if(eip > 0xC8000000)
+	{
+		LogF("Backtrace: Kernel Module - 0x%x\n", eip);
+		return;
+	}
+	
+	//str = Debug_GetSymbol(eip, &delta);
+	if(str == NULL)
+		LogF("Backtrace: 0x%x", eip);
+	else
+		LogF("Backtrace: %s+0x%x", str, delta);
+	if(!MM_GetPhysAddr(ebp))
+	{
+		LogF("\nBacktrace: Invalid EBP, stopping\n");
+		return;
+	}
+	
+	
+	while( MM_GetPhysAddr(ebp) && i < MAX_BACKTRACE )
+	{
+		//str = Debug_GetSymbol(*(Uint*)(ebp+4), &delta);
+		if(str == NULL)
+			LogF(" >> 0x%x", *(Uint*)(ebp+4));
+		else
+			LogF(" >> %s+0x%x", str, delta);
+		ebp = *(Uint*)ebp;
+		i++;
+	}
+	LogF("\n");
+}
diff --git a/Kernel/arch/x86/mm_virt.c b/Kernel/arch/x86/mm_virt.c
index 2b7d191b..3663d603 100644
--- a/Kernel/arch/x86/mm_virt.c
+++ b/Kernel/arch/x86/mm_virt.c
@@ -41,6 +41,7 @@
 extern Uint32	gaInitPageDir[1024];
 extern Uint32	gaInitPageTable[1024];
 extern void	Threads_SegFault(Uint Addr);
+extern void	Error_Backtrace(Uint eip, Uint ebp);
 
 // === PROTOTYPES ===
 void	MM_PreinitVirtual();
@@ -145,12 +146,14 @@ void MM_PageFault(Uint Addr, Uint ErrorCode, tRegs *Regs)
 			);
 	}
 	
+	Log("Code at %p accessed %p", Regs->eip, Addr);
+	// Print Stack Backtrace
+	Error_Backtrace(Regs->eip, Regs->ebp);
+	
 	Log("gaPageDir[0x%x] = 0x%x", Addr>>22, gaPageDir[Addr>>22]);
 	if( gaPageDir[Addr>>22] & PF_PRESENT )
 		Log("gaPageTable[0x%x] = 0x%x", Addr>>12, gaPageTable[Addr>>12]);
 	
-	Log("Code at %p accessed %p\n", Regs->eip, Addr);
-	
 	MM_DumpTables(0, -1);	
 	
 	Panic("Page Fault at 0x%x\n", Regs->eip);
diff --git a/Kernel/arch/x86/proc.c b/Kernel/arch/x86/proc.c
index 5cfc7a2e..f7bda0fc 100644
--- a/Kernel/arch/x86/proc.c
+++ b/Kernel/arch/x86/proc.c
@@ -33,6 +33,7 @@ extern tThread	*gSleepingThreads;
 extern tThread	*gDeleteThreads;
 extern tThread	*Threads_GetNextToRun(int CPU);
 extern void	Threads_Dump();
+extern tThread	*Threads_CloneTCB(Uint *Err, Uint Flags);
 
 // === PROTOTYPES ===
 void	ArchThreads_Init();
@@ -242,24 +243,19 @@ int Proc_Clone(Uint *Err, Uint Flags)
 	__asm__ __volatile__ ("mov %%esp, %0": "=r"(esp));
 	__asm__ __volatile__ ("mov %%ebp, %0": "=r"(ebp));
 	
-	// Create new thread structure
-	newThread = malloc( sizeof(tThread) );
-	if(!newThread) {
-		Warning("Proc_Clone - Out of memory when creating thread\n");
-		*Err = -ENOMEM;
-		return -1;
-	}
-	
-	// Base new thread on current
-	memcpy(newThread, cur, sizeof(tThread));
+	newThread = Threads_CloneTCB(Err, Flags);
+	if(!newThread)	return -1;
 	
 	// Initialise Memory Space (New Addr space or kernel stack)
 	if(Flags & CLONE_VM) {
-		newThread->TGID = newThread->TID;
 		newThread->MemState.CR3 = MM_Clone();
+		newThread->KernelStack = cur->KernelStack;
 	} else {
 		Uint	tmpEbp, oldEsp = esp;
 
+		// Set CR3
+		newThread->MemState.CR3 = cur->MemState.CR3;
+
 		// Create new KStack
 		newThread->KernelStack = MM_NewKStack();
 		// Check for errors
@@ -285,23 +281,6 @@ int Proc_Clone(Uint *Err, Uint Flags)
 				*(Uint*)tmpEbp += newThread->KernelStack - cur->KernelStack;
 		}
 	}
-
-	// Set Pointer, Spinlock and TID
-	newThread->Next = NULL;
-	newThread->IsLocked = 0;
-	newThread->TID = giNextTID++;
-	newThread->PTID = cur->TID;
-	
-	// Create copy of name
-	newThread->ThreadName = malloc(strlen(cur->ThreadName)+1);
-	strcpy(newThread->ThreadName, cur->ThreadName);
-
-	// Clear message list (messages are not inherited)
-	newThread->Messages = NULL;
-	newThread->LastMessage = NULL;
-	
-	// Set remaining (sheduler expects remaining to be correct)
-	newThread->Remaining = newThread->Quantum;
 	
 	// Save core machine state
 	newThread->SavedState.ESP = esp;
@@ -318,8 +297,6 @@ int Proc_Clone(Uint *Err, Uint Flags)
 	// Lock list and add to active
 	Threads_AddActive(newThread);
 	
-	//Threads_Dump();
-	
 	return newThread->TID;
 }
 
diff --git a/Kernel/binary.c b/Kernel/binary.c
index 1884af8a..dae3cfaa 100644
--- a/Kernel/binary.c
+++ b/Kernel/binary.c
@@ -25,8 +25,8 @@ typedef struct sKernelBin {
 extern int	Proc_Clone(Uint *Err, Uint Flags);
 extern void	Threads_SetName(char *Name);
 extern char	*Threads_GetName(int ID);
+extern void	Threads_Exit(int, int);
 extern Uint	MM_ClearUser();
-extern void	Threads_Exit();
 extern void	Proc_StartUser(Uint Entrypoint, Uint *Bases, int ArgC, char **ArgV, char **EnvP, int DataSize);
 extern tKernelSymbol	gKernelSymbols[];
 extern void		gKernelSymbolsEnd;
@@ -147,7 +147,7 @@ int Proc_Execve(char *File, char **ArgV, char **EnvP)
 	if(bases[0] == 0)
 	{
 		Warning("Proc_Execve - Unable to load '%s'", Threads_GetName(-1));
-		Threads_Exit();
+		Threads_Exit(0, 0);
 		for(;;);
 	}
 	
diff --git a/Kernel/debug.c b/Kernel/debug.c
index bd3b4074..bf2282ff 100644
--- a/Kernel/debug.c
+++ b/Kernel/debug.c
@@ -314,7 +314,6 @@ void Debug_HexDump(char *Header, void *Data, Uint Length)
 		cdat --;
 	}
 	E9('\n');
-	
 }
 
 // --- EXPORTS ---
diff --git a/Kernel/drv/ne2000.c b/Kernel/drv/ne2000.c
new file mode 100644
index 00000000..e1f5990b
--- /dev/null
+++ b/Kernel/drv/ne2000.c
@@ -0,0 +1,213 @@
+/* Acess2
+ * NE2000 Driver
+ * 
+ * See: ~/Sources/bochs/bochs.../iodev/ne2k.cc
+ */
+#include <common.h>
+#include <modules.h>
+#include <fs_devfs.h>
+
+// === CONSTANTS ===
+static const struct {
+	Uint16	Vendor;
+	Uint16	Device;
+} csaCOMPAT_DEVICES[] = {
+	{0x10EC, 0x8029},	// Realtek 8029
+	{0x10EC, 0x8129}	// Realtek 8129
+};
+#define NUM_COMPAT_DEVICES	(sizeof(csaCOMPAT_DEVICES)/sizeof(csaCOMPAT_DEVICES[0]))
+
+enum eNe2k_Page0Read {
+	COMMAND = 0,	//!< the master command register
+	CLDA0,		//!< Current Local DMA Address 0
+	CLDA1,		//!< Current Local DMA Address 1
+	BNRY,		//!< Boundary Pointer (for ringbuffer)
+	TSR,		//!< Transmit Status Register
+	NCR,		//!< collisions counter
+	FIFO,		//!< (for what purpose ??)
+	ISR,		//!< Interrupt Status Register
+	CRDA0,		//!< Current Remote DMA Address 0
+	CRDA1,		//!< Current Remote DMA Address 1
+	RSR = 0xC	//!< Receive Status Register
+};
+
+enum eNe2k_Page0Write {
+	PTART = 1,	//!< page start (init only)
+	PSTOP,		//!< page stop  (init only)
+	TPSR = 4,	//!< transmit page start address
+	TBCR0,		//!< transmit byte count (low)
+	TBCR1,		//!< transmit byte count (high)
+	RSAR0 = 8,	//!< remote start address (lo)
+	RSAR1,	//!< remote start address (hi)
+	RBCR0,	//!< remote byte count (lo)
+	RBCR1,	//!< remote byte count (hi)
+	RCR,	//!< receive config register
+	TCR,	//!< transmit config register
+	DCR,	//!< data config register    (init)
+	IMR		//!< interrupt mask register (init)
+};
+
+// === TYPES ===
+typedef struct sNe2k_Card {
+	Uint16	IOBase;	//!< IO Port Address from PCI
+	Uint8	IRQ;	//!< IRQ Assigned from PCI
+	
+	 int	NextMemPage;	//!< Next Card Memory page to use
+	
+	char	Name[2];	// "0"
+	tVFS_Node	*Node;
+	char	MacAddr[6];
+} tCard;
+
+// === PROTOTYPES ===
+ int	Ne2k_Install(char **Arguments);
+Uint64	Ne2k_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+
+// === GLOBALS ===
+MODULE_DEFINE(0, 0x0032, Ne2k, Ne2k_Install, NULL, NULL);
+tDevFS_Driver	gNe2k_DriverInfo = {
+	NULL, "ne2k",
+	{
+	.NumACLs = 1,
+	.ACLs = &gVFS_ACL_EveryoneRW,
+	.Flags = VFS_FFLAG_DIRECTORY
+	}
+};
+Uint16	gNe2k_BaseAddress;
+ int	giNe2k_CardCount = 0;
+
+// === CODE ===
+/**
+ * \fn int Ne2k_Install(char **Options)
+ * \brief Installs the NE2000 Driver
+ */
+int Ne2k_Install(char **Options)
+{
+	 int	i, j, k;
+	
+	// --- Scan PCI Bus ---
+	// Count Cards
+	giNe2k_CardCount = 0;
+	for( i = 0; i < NUM_COMPAT_DEVICES; i ++ )
+	{
+		giNe2k_CardCount += PCI_CountDevices( csaCOMPAT_DEVICES[i].Vendor, csaCOMPAT_DEVICES[i].Device, 0 );
+	}
+	
+	// Enumerate Cards
+	k = 0;
+	gpNe2k_Cards = malloc( giNe2k_CardCount * sizeof(tCard) );
+	memsetd(gpNe2k_Cards, 0, giNe2k_CardCount * sizeof(tCard) / 4);
+	for( i = 0; i < NUM_COMPAT_DEVICES; i ++ )
+	{
+		count = PCI_CountDevices( csaCOMPAT_DEVICES[i].Vendor, csaCOMPAT_DEVICES[i].Device, 0 );
+		for( j = 0; j < count; j ++,k ++ )
+		{
+			id = PCI_GetDevice( csaCOMPAT_DEVICES[i].Vendor, csaCOMPAT_DEVICES[i].Device, 0, j );
+			// Create Structure
+			base = PCI_AssignPort( id, 0, 0x20 );
+			gpNe2k_Cards[ k ].IOBase = base;
+			gpNe2k_Cards[ k ].IRQ = PCI_GetIRQ( id );
+			gpNe2k_Cards[ k ].NextMemPage = 1;
+			
+			//Install IRQ6 Handler
+			IRQ_Set(gpNe2k_Cards[ k ].IRQ, Ne2k_IRQHandler);
+			
+			// Reset Card
+			outb( base + 0x1F, inb(base + 0x1F) );
+			while( (inb( base+ISR ) & 0x80) == 0 );
+			outb( base + ISR, 0x80 );
+			
+			// Initialise Card
+			outb( base + COMMAND, 0x21 );	// No DMA and Stop
+			outb( base + DCR, 0x49 );	// Set WORD mode
+			outb( base + IMR, 0x00 );
+			outb( base + ISR, 0xFF );
+			outb( base + RCR, 0x20 );	// Reciever to Monitor
+			outb( base + TCR, 0x02 );	// Transmitter OFF
+			outb( base + RBCR0, 6*4 );	// Remote Byte Count
+			outb( base + RBCR1, 0 );
+			outb( base + RSAR0, 0 );	// Clear Source Address
+			outb( base + RSAR1, 0 );
+			outb( base + COMMAND, 0x0A );	// Remote Read, Start
+			
+			// Read MAC Address
+			gpNe2k_Cards[ k ].MacAddr[0] = inb(base+0x10);	inb(base+0x10);
+			gpNe2k_Cards[ k ].MacAddr[1] = inb(base+0x10);	inb(base+0x10);
+			gpNe2k_Cards[ k ].MacAddr[2] = inb(base+0x10);	inb(base+0x10);
+			gpNe2k_Cards[ k ].MacAddr[3] = inb(base+0x10);	inb(base+0x10);
+			gpNe2k_Cards[ k ].MacAddr[4] = inb(base+0x10);	inb(base+0x10);
+			gpNe2k_Cards[ k ].MacAddr[5] = inb(base+0x10);	inb(base+0x10);
+			
+			outb( base+PSTART, 0x60);	// Set Receive Start
+			outb( base+BNRY, 0x7F);	// Set Boundary Page
+			outb( base+PSTOP, 0x80);	// Set Stop Page
+			outb( base+ISR, 0xFF );	// Clear all ints
+			outb( base+CMD, 0x22 );	// No DMA, Start
+			outb( base+IMR, 0x3F );	// Set Interupt Mask
+			outb( base+RCR, 0x8F );	// Set WRAP and allow all packet matches
+			outb( base+TCR, 0x00 );	// Set Normal Transmitter mode
+			outb( base+TPSR, 0x40);	// Set Transmit Start
+			
+			// Set MAC Address
+			/*
+			Ne2k_WriteReg(base, MAC0, gpNe2k_Cards[ k ].MacAddr[0]);
+			Ne2k_WriteReg(base, MAC1, gpNe2k_Cards[ k ].MacAddr[1]);
+			Ne2k_WriteReg(base, MAC2, gpNe2k_Cards[ k ].MacAddr[2]);
+			Ne2k_WriteReg(base, MAC3, gpNe2k_Cards[ k ].MacAddr[3]);
+			Ne2k_WriteReg(base, MAC4, gpNe2k_Cards[ k ].MacAddr[4]);
+			Ne2k_WriteReg(base, MAC5, gpNe2k_Cards[ k ].MacAddr[5]);
+			*/
+			
+			Log("[NE2K]: Card #%i: IRQ=%i, Base=0x%x, ",
+				k, gpNe2k_Cards[ k ].IRQ, gpNe2k_Cards[ k ].PortBase,
+				gpNe2k_Cards[ k ].Buffer);
+			Log("MAC Address %x:%x:%x:%x:%x:%x\n",
+				gpNe2k_Cards[ k ].MacAddr[0], gpNe2k_Cards[ k ].MacAddr[1],
+				gpNe2k_Cards[ k ].MacAddr[2], gpNe2k_Cards[ k ].MacAddr[3],
+				gpNe2k_Cards[ k ].MacAddr[4], gpNe2k_Cards[ k ].MacAddr[5]
+				);
+			
+			// Set VFS Node
+			gpNe2k_Cards[ k ].Name[0] = '0'+k;
+			gpNe2k_Cards[ k ].Name[1] = '\0';
+			gpNe2k_Cards[ k ].Node.NumACLs = 1;
+			gpNe2k_Cards[ k ].Node.ACLs = gVFS_ACL_EveryoneRW;
+			gpNe2k_Cards[ k ].Node.CTime = now();
+			gpNe2k_Cards[ k ].Node.Write = Ne2k_Write;
+		}
+	}
+	
+	DevFS_AddDevice( &gNe2k_DriverInfo );
+	return 0;
+}
+
+
+/**
+ * \fn Uint64 Ne2k_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+ */
+Uint64 Ne2k_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+{
+	tCard	*Card = (tCard*)Node->ImplPtr;
+	
+	// Sanity Check Length
+	if(Length > 0xFFFF)	return 0;
+	
+	outb(Card->IOBase + COMMAND, 0|0x22);	// Page 0, Start, NoDMA
+	// Send Size
+	outb(Card->IOBase + RBCR0, Count & 0xFF);
+	outb(Card->IOBase + RBCR1, Count >> 8);
+	// Clear Remote DMA Flag
+	outb(Card->IOBase + ISR, 0x40);	// Bit 6
+	// Set up transfer
+	outb(Card->IOBase + RSAR0, 0x00);	// Page Offset
+	outb(Card->IOBase + RSAR1, Ne2k_int_GetWritePage(Card, Length));	// Page Offset
+	return 0;
+}
+
+/**
+ * \fn Uint8 Ne2k_int_GetWritePage(tCard *Card, Uint16 Length)
+ */
+Uint8 Ne2k_int_GetWritePage(tCard *Card, Uint16 Length)
+{
+	
+}
diff --git a/Kernel/include/common.h b/Kernel/include/common.h
index 7bf59382..590295f5 100644
--- a/Kernel/include/common.h
+++ b/Kernel/include/common.h
@@ -10,13 +10,19 @@
 #include <arch.h>
 #include <stdarg.h>
 
+enum eConfigTypes {
+	CFGT_NULL,
+	CFGT_INT,
+	CFGT_HEAPSTR,
+	CFGT_PTR
+};
 enum eConfigs {
 	CFG_VFS_CWD,
 	CFG_VFS_MAXFILES,
 	NUM_CFG_ENTRIES
 };
-#define CFGINT(_idx)	(*(Uint*)(MM_PPD_CFG+(_idx)*sizeof(void*)))
-#define CFGPTR(_idx)	(*(void**)(MM_PPD_CFG+(_idx)*sizeof(void*)))
+#define CFGINT(id)	(*Threads_GetCfgPtr(id))
+#define CFGPTR(id)	(*(void**)Threads_GetCfgPtr(id))
 
 // === CONSTANTS ===
 // --- Memory Flags --
@@ -43,6 +49,7 @@ extern void	Panic(char *Msg, ...);
 extern void	Warning(char *Msg, ...);
 extern void	Log(char *Fmt, ...);
 extern void	LogV(char *Fmt, va_list Args);
+extern void	LogF(char *Fmt, ...);
 extern void	Debug_Enter(char *FuncName, char *ArgTypes, ...);
 extern void	Debug_Log(char *FuncName, char *Fmt, ...);
 extern void	Debug_Leave(char *FuncName, char RetType, ...);
@@ -114,10 +121,10 @@ extern  int	Proc_Spawn(char *Path);
 extern void	Threads_Exit();
 extern void	Threads_Yield();
 extern void	Threads_Sleep();
-extern int	Threads_GetCfg(int Index);
 extern int	Threads_GetUID();
 extern int	Threads_GetGID();
 extern int	SpawnTask(tThreadFunction Function, void *Arg);
+extern Uint	*Threads_GetCfgPtr(int Id);
 
 #include <binary_ext.h>
 #include <vfs_ext.h>
diff --git a/Kernel/include/dma.h b/Kernel/include/dma.h
new file mode 100644
index 00000000..5b0bbda2
--- /dev/null
+++ b/Kernel/include/dma.h
@@ -0,0 +1,10 @@
+/*
+ * Acess2 DMA Driver
+ */
+#ifndef _DMA_H_
+#define _DMA_H_
+
+extern void	DMA_SetChannel(int channel, int length, int read);
+extern int	DMA_ReadData(int channel, int count, void *buffer);
+
+#endif
diff --git a/Kernel/include/signal.h b/Kernel/include/signal.h
new file mode 100644
index 00000000..d97d6dcb
--- /dev/null
+++ b/Kernel/include/signal.h
@@ -0,0 +1,16 @@
+/*
+ * Acess2 Kernel
+ * Signal List
+ */
+#ifndef _SIGNAL_H_
+#define _SIGNAL_H_
+
+enum eSignals {
+	SIGKILL,
+	SIGSTOP,
+	SIGCONT,
+	SIGCHLD,
+	NSIG
+};
+
+#endif
diff --git a/Kernel/include/threads.h b/Kernel/include/threads.h
index 377b6ac1..1e15547c 100644
--- a/Kernel/include/threads.h
+++ b/Kernel/include/threads.h
@@ -16,6 +16,7 @@ typedef struct sMessage
 
 typedef struct sThread
 {
+	// --- threads.c's
 	struct sThread	*Next;	//!< Next thread in list
 	 int	IsLocked;	//!< Thread's spinlock
 	 int	Status;		//!< Thread Status
@@ -27,7 +28,9 @@ typedef struct sThread
 	Uint	UID, GID;	//!< User and Group
 	char	*ThreadName;	//!< Name of thread
 	
-	tVAddr	KernelStack;	//!< Kernel Stack Base
+	// --- arch/proc.c's responsibility
+	//! Kernel Stack Base
+	tVAddr	KernelStack;
 	
 	//! Memory Manager State
 	tMemoryState	MemState;
@@ -35,6 +38,7 @@ typedef struct sThread
 	//! State on task switch
 	tTaskState	SavedState;
 	
+	// --- threads.c's
 	 int	CurSignal;	//!< Signal currently being handled (0 for none)
 	tVAddr	SignalHandlers[NSIG];	//!< Signal Handler List
 	tTaskState	SignalState;	//!< Saved state for signal handler
diff --git a/Kernel/syscalls.c b/Kernel/syscalls.c
index dd1f4b3a..5774dbe5 100644
--- a/Kernel/syscalls.c
+++ b/Kernel/syscalls.c
@@ -119,6 +119,11 @@ void SyscallHandler(tSyscallRegs *Regs)
 	// Binary Control
 	// ---
 	case SYS_EXECVE:
+		if( !Syscall_ValidString(Regs->Arg1) ) {
+			err = -EINVAL;
+			ret = -1;
+			break;
+		}
 		ret = Proc_Execve((char*)Regs->Arg1, (char**)Regs->Arg2, (char**)Regs->Arg3);
 		break;
 	case SYS_LOADBIN:
diff --git a/Kernel/system.c b/Kernel/system.c
index 26ce100e..9b160d92 100644
--- a/Kernel/system.c
+++ b/Kernel/system.c
@@ -19,7 +19,6 @@ void	System_ExecuteScript();
  int	System_Int_GetString(char *Str, char **Dest);
 
 // === GLOBALS ===
-char	*gsInitPath = "/Acess/Bin/init";
 char	*gsConfigScript = "/Acess/Conf/BootConf.cfg";
 
 // === CODE ===
diff --git a/Kernel/threads.c b/Kernel/threads.c
index 54438c32..5f2e3d7f 100644
--- a/Kernel/threads.c
+++ b/Kernel/threads.c
@@ -5,11 +5,17 @@
  */
 #include <common.h>
 #include <threads.h>
+#include <errno.h>
 
 // === CONSTANTS ===
 #define	DEFAULT_QUANTUM	10
 #define	DEFAULT_TICKETS	5
 #define MAX_TICKETS		10
+const enum eConfigTypes	cCONFIG_TYPES[] = {
+	CFGT_HEAPSTR,	// CFG_VFS_CWD
+	CFGT_INT,	// CFG_VFS_MAXFILES
+	CFGT_NULL
+};
 
 // === IMPORTS ===
 extern void	ArchThreads_Init();
@@ -22,6 +28,7 @@ void	Threads_Init();
 void	Threads_SetName(char *NewName);
 char	*Threads_GetName(int ID);
 void	Threads_SetTickets(int Num);
+tThread	*Threads_CloneTCB(Uint *Err, Uint Flags);
  int	Threads_WaitTID(int TID, int *status);
 tThread	*Threads_GetThread(Uint TID);
 void	Threads_AddToDelete(tThread *Thread);
@@ -148,6 +155,88 @@ void Threads_SetTickets(int Num)
 	RELEASE( &giThreadListLock );
 }
 
+/**
+ * \fn tThread *Threads_CloneTCB(Uint *Err, Uint Flags)
+ */
+tThread *Threads_CloneTCB(Uint *Err, Uint Flags)
+{
+	tThread	*cur, *new;
+	 int	i;
+	cur = Proc_GetCurThread();
+	
+	new = malloc(sizeof(tThread));
+	if(new == NULL) {
+		*Err = -ENOMEM;
+		return NULL;
+	}
+	
+	new->Next = NULL;
+	new->IsLocked = 0;
+	new->Status = THREAD_STAT_ACTIVE;
+	new->RetStatus = 0;
+	
+	// Get Thread ID
+	new->TID = giNextTID++;
+	new->PTID = cur->TID;
+	
+	// Clone Name
+	new->ThreadName = malloc(strlen(cur->ThreadName)+1);
+	strcpy(new->ThreadName, cur->ThreadName);
+	
+	// Set Thread Group ID (PID)
+	if(Flags & CLONE_VM)
+		new->TGID = new->TID;
+	else
+		new->TGID = cur->TGID;
+	
+	// Messages are not inherited
+	new->Messages = NULL;
+	new->LastMessage = NULL;
+	
+	// Set State
+	new->Remaining = new->Quantum = cur->Quantum;
+	new->NumTickets = cur->NumTickets;
+	
+	// Set Signal Handlers
+	new->CurSignal = 0;
+	if(Flags & CLONE_VM)
+		memset(new->SignalHandlers, 0, sizeof(new->SignalHandlers));
+	else
+		memcpy(new->SignalHandlers, cur->SignalHandlers, sizeof(new->SignalHandlers));
+	memset(&new->SignalState, 0, sizeof(tTaskState));
+	
+	for( i = 0; i < NUM_CFG_ENTRIES; i ++ )
+	{
+		switch(cCONFIG_TYPES[i])
+		{
+		default:
+			new->Config[i] = cur->Config[i];
+			break;
+		case CFGT_HEAPSTR:
+			if(cur->Config[i])
+				new->Config[i] = (Uint) strdup( (void*)cur->Config[i] );
+			else
+				new->Config[i] = 0;
+			break;
+		}
+	}
+	
+	return new;
+}
+
+/**
+ * \fn Uint *Threads_GetCfgPtr(int Id)
+ */
+Uint *Threads_GetCfgPtr(int Id)
+{
+	if(Id < 0 || Id >= NUM_CFG_ENTRIES) {
+		Warning("Threads_GetCfgPtr: Index %i is out of bounds", Id);
+		return NULL;
+	}
+	
+	return &Proc_GetCurThread()->Config[Id];
+}
+
 /**
  * \fn void Threads_WaitTID(int TID, int *status)
  * \brief Wait for a task to change state
@@ -408,7 +497,7 @@ void Threads_Sleep()
 }
 
 
-/**
+/**c0108919:
  * \fn void Threads_Wake( tThread *Thread )
  * \brief Wakes a sleeping/waiting thread up
  */
@@ -559,9 +648,10 @@ tThread *Threads_GetNextToRun(int CPU)
 	 int	ticket;
 	 int	number;
 	
+	if(giNumActiveThreads == 0)	return NULL;
+	
 	// Special case: 1 thread
-	if(giNumActiveThreads == 1)
-	{
+	if(giNumActiveThreads == 1) {
 		return gActiveThreads;
 	}
 	
diff --git a/Kernel/vfs/fs/ext2.c b/Kernel/vfs/fs/ext2.c
new file mode 100644
index 00000000..78c115ed
--- /dev/null
+++ b/Kernel/vfs/fs/ext2.c
@@ -0,0 +1,584 @@
+/*
+ * Acess OS
+ * Ext2 Driver Version 1
+ */
+/**
+ * \file fs/ext2.c
+ * \brief Second Extended Filesystem Driver
+ * \todo Implement file read support
+ */
+#include <common.h>
+#include <vfs.h>
+#include "fs_ext2.h"
+
+// === STRUCTURES ===
+typedef struct {
+	 int	FD;
+	 int	CacheID;
+	vfs_node	RootNode;
+	
+	tExt2_SuperBlock	SuperBlock;
+	 int	BlockSize;
+	 
+	 int	GroupCount;
+	tExt2_Group		Groups[];
+} tExt2_Disk;
+
+// === PROTOTYPES ===
+//Interface Functions
+tVFS_Node	*Ext2_InitDevice(char *Device, char **Options);
+void		Ext2_UnMount(tVFS_Node *Node);
+Uint64		Ext2_Read(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer);
+Uint64		Ext2_Write(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer);
+char		*Ext2_ReadDir(tVFS_Node *Node, int Pos);
+tVFS_Node	*Ext2_FindDir(tVFS_Node *Node, char *FileName);
+tVFS_Node	*Ext2_MkNod(tVFS_Node *Node, char *Name, Uint Flags);
+ int		Ext2_int_GetInode(vfs_node *Node, tExt2_Inode *Inode);
+tVFS_Node	*Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeId, char *Name, Uint64 VfsInode);
+ int		Ext2_int_ReadInode(tExt2_Disk *Disk, Uint InodeId, tExt2_Inode *Inode);
+Uint64		Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum);
+
+// === SEMI-GLOBALS ===
+tExt2_Disk	gExt2_disks[6];
+ int	giExt2_count = 0;
+tVFS_Driver	gExt2_FSInfo = {NULL,
+	"ext2", 0, Ext2_InitDevice, Ext2_UnMount, NULL
+	};
+
+// === CODE ===
+
+/**
+ * \fn void Ext2_Install()
+ * \brief Install the Ext2 Filesystem Driver
+ */
+void Ext2_Install()
+{
+	VFS_AddDriver( &gExt2_FSInfo );
+}
+
+/**
+ \fn tVFS_Node *Ext2_initDevice(char *Device, char **Options)
+ \brief Initializes a device to be read by by the driver
+ \param Device	String - Device to read from
+ \param Options	NULL Terminated array of option strings
+ \return Root Node
+*/
+tVFS_Node *Ext2_InitDevice(char *Device, char **Options)
+{
+	tExt2_Disk	*disk;
+	 int	fd;
+	 int	groupCount;
+	tExt2_SuperBlock	sb;
+	tExt2_Inode	inode;
+	
+	// Open Disk
+	fd = VFS_Open(Device, VFS_OPENFLAG_READ|VFS_OPENFLAG_WRITE);		//Open Device
+	if(fd == -1) {
+		Warning"[EXT2] Unable to open '%s'\n", Device);
+		return NULL;
+	}
+	
+	// Read Superblock at offset 1024
+	VFS_ReadAt(fd, 1024, 1024, &sb);	// Read Superblock
+	
+	// Sanity Check Magic value
+	if(sb.s_magic != 0xEF53) {
+		WarningEx("EXT2", "Volume '%s' is not an EXT2 volume\n", Device);
+		VFS_Close(fd);
+		return NULL;
+	}
+	
+	// Get Group count
+	groupCount = DivUp(sb.s_blocks_count, sb.s_blocks_per_group);
+	//LogF(" Ext2_initDevice: groupCount = %i\n", groupCount);
+	
+	// Allocate Disk Information
+	disk = malloc(sizeof(tExt2_Disk) + sizeof(tExt2_Group)*groupCount);
+	disk->fd = fd;
+	memcpy(&disk->SuperBlock, &sb, 1024);
+	disk->GroupCount = groupCount;
+	
+	// Get an inode cache handle
+	disk->CacheID = Inode_GetHandle();
+	
+	// Get Block Size
+	//LogF(" Ext2_initDevice: s_log_block_size = 0x%x\n", sb.s_log_block_size);
+	disk->BlockSize = 1024 << sb.s_log_block_size;
+	
+	// Read Group Information
+	VFS_ReadAt(disk->fd,
+		sb.s_first_data_block * disk->BlockSize + 1024,
+		sizeof(tExt2_Group)*groupCount,
+		disk->Groups);
+	
+	#if 0
+	Log(" Ext2_initDevice: Block Group 0\n");
+	Log(" Ext2_initDevice: .bg_block_bitmap = 0x%x\n", disk->Groups[0].bg_block_bitmap);
+	Log(" Ext2_initDevice: .bg_inode_bitmap = 0x%x\n", disk->Groups[0].bg_inode_bitmap);
+	Log(" Ext2_initDevice: .bg_inode_table = 0x%x\n", disk->Groups[0].bg_inode_table);
+	Log(" Ext2_initDevice: Block Group 1\n");
+	Log(" Ext2_initDevice: .bg_block_bitmap = 0x%x\n", disk->Groups[1].bg_block_bitmap);
+	Log(" Ext2_initDevice: .bg_inode_bitmap = 0x%x\n", disk->Groups[1].bg_inode_bitmap);
+	Log(" Ext2_initDevice: .bg_inode_table = 0x%x\n", disk->Groups[1].bg_inode_table);
+	#endif
+	
+	// Get root Inode
+	Ext2_int_ReadInode(disk, 2, &inode);
+	
+	// Create Root Node
+	memset(&disk->RootNode, 0, sizeof(vfs_node));
+	disk->RootNode.Inode = 2;	// Root inode ID
+	disk->RootNode.ImplPtr = disk;	// Save disk pointer
+	disk->RootNode.Size = -1;	// Fill in later (on readdir)
+	disk->RootNode.Flags = VFS_FFLAG_DIRECTORY;
+	
+	disk->RootNode.ReadDir = Ext2_ReadDir;
+	disk->RootNode.FindDir = Ext2_FindDir;
+	//disk->RootNode.Relink = Ext2_Relink;
+	
+	// Complete root node
+	disk->RootNode.UID = inode.i_uid;
+	disk->RootNode.GID = inode.i_gid;
+	disk->RootNode.NumACLs = 1;
+	disk->RootNode.ACLs = &gVFS_ACL_EveryoneRW;
+	
+	#if 0
+	Log(" Ext2_InitDevice: inode.i_size = 0x%x\n", inode.i_size);
+	Log(" Ext2_InitDevice: inode.i_block[0] = 0x%x\n", inode.i_block[0]);
+	#endif
+	
+	return &disk->RootNode;
+}
+
+/**
+ * \fn void Ext2_Unmount(tVFS_Node *Node)
+ * \brief Close a mounted device
+ */
+void Ext2_Unmount(tVFS_Node *Node)
+{
+	tExt2_Disk	*disk = Node->ImplPtr;
+	
+	VFS_Close( disk->fd );
+	Inode_ClearCache( disk->CacheID );
+	memset(disk, 0, sizeof(tExt2_Disk)+disk->GroupCount*sizeof(tExt2_Group));
+	free(disk);
+}
+
+/**
+ * \fn Uint64 Ext2_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+ * \brief Read from a file
+ */
+Uint64 Ext2_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+{
+	tExt2_Disk	*disk = Node->ImplPtr;
+	tExt2_Inode	inode;
+	Uint64	base;
+	Uint	block;
+	Uint64	remLen;
+	
+	// Get Inode
+	Ext2_int_GetInode(Node, &inode);
+	
+	block = Offset / disk->BlockSize;
+	Offset = Offset / disk->BlockSize;
+	base = Ext2_int_GetBlockAddr(disk, inode.i_block, block);
+	
+	// Read only block
+	if(Length <= disk->BlockSize - Offset)
+	{
+		VFS_ReadAt( disk->fd, base+Offset, Length, Buffer);
+		return Length;
+	}
+	
+	// Read first block
+	remLen = Length;
+	VFS_ReadAt( disk->fd, base + Offset, disk->BlockSize - Offset, Buffer);
+	remLen -= disk->BlockSize - Offset;
+	Buffer += disk->BlockSize - Offset;
+	block ++;
+	
+	// Read middle blocks
+	while(remLen > disk->BlockSize)
+	{
+		base = Ext2_int_GetBlockAddr(disk, inode.i_block, block);
+		VFS_ReadAt( disk->fd, base, disk->BlockSize, Buffer);
+		Buffer += disk->BlockSize;
+		remLen -= disk->BlockSize;
+		block ++;
+	}
+	
+	// Read last block
+	base = Ext2_int_GetBlockAddr(disk, inode.i_block, block);
+	VFS_ReadAt( disk->fd, base, remLen, Buffer);
+	
+	return Length;
+}
+
+/**
+ * \fn Uint64 Ext2_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+ * \brief Write to a file
+ */
+Uint64 Ext2_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+{
+	tExt2_Disk	*disk = Node->ImplPtr;
+	tExt2_Inode	inode;
+	Uint64	base;
+	Uint64	retLen;
+	Uint	block;
+	Uint64	allocSize;
+	 int	bNewBlocks = 0;
+	
+	Ext2_int_GetInode(Node, &inode);
+	
+	// Round size up to block size
+	// block size is a power of two, so this will work
+	allocSize = (inode.i_size + disk->BlockSize) & ~(disk->BlockSize-1);
+	if( Offset < allocSize )
+	{
+		if(Offset + Length > allocSize) {
+			bNewBlocks = 1;
+			retLen = allocSize - Offset;
+		} else
+			retLen = Length;
+		// Within the allocated space
+		block = Offset / disk->BlockSize;
+		Offset %= disk->BlockSize;
+		base = Ext2_int_GetBlockAddr(disk, inode.i_block, block);
+		
+		// Write only block (if only one)
+		if(Offset + retLen <= disk->BlockSize) {
+			VFS_WriteAt(disk->fd, base+Offset, retLen, Buffer);
+			if(bNewBlocks)	return Length;
+			goto addBlocks;	// Ugh! A goto, but it seems unavoidable
+		}
+		
+		// Write First Block
+		VFS_WriteAt(disk->fd, base+Offset, disk->BlockSize-Offset, Buffer);
+		Buffer += disk->BlockSize-Offset;
+		retLen -= disk->BlockSize-Offset;
+		block ++;
+		
+		// Write middle blocks
+		while(retLen > disk->BlockSize)
+		{
+			base = Ext2_int_GetBlockAddr(disk, inode.i_block, block);
+			VFS_WriteAt(disk->fd, base, disk->BlockSize, Buffer);
+			Buffer += disk->BlockSize;
+			retLen -= disk->BlockSize;
+			block ++;
+		}
+		
+		// Write last block
+		base = Ext2_int_GetBlockAddr(disk, inode.i_block, block);
+		VFS_WriteAt(disk->fd, base, retLen, Buffer);
+		if(bNewBlocks)	return Length;	// Writing in only allocated space
+	}
+	
+addBlocks:
+	///\todo Implement block allocation
+	WarningEx("EXT2", "File extending is not yet supported");
+	
+	return 0;
+}
+
+/**
+ * \fn int Ext2_CloseFile(vfs_node *Node)
+ * \brief Close a file (Remove it from the cache)
+ */
+int Ext2_CloseFile(tVFS_Node *Node)
+{
+	tExt2_Disk	*disk = Node->ImplPtr;
+	inode_uncacheNode(disk->CacheID, Node->impl);
+	return 1;
+}
+
+/**
+ \fn char *Ext2_ReadDir(tVFS_Node *Node, int Pos)
+ \brief Reads a directory entry
+*/
+char *Ext2_ReadDir(tVFS_Node *Node, int Pos)
+{
+	tExt2_Inode	inode;
+	char	namebuf[EXT2_NAME_LEN+1];
+	tExt2_DirEnt	dirent;
+	Uint64	Base;	// Block's Base Address
+	 int	block = 0, ofs = 0;
+	 int	entNum = 0;
+	tExt2_Disk	*disk = Node->ImplPtr;
+	Uint64	vfsInode = 0;
+	tVFS_Node	*retNode;
+	Uint	size;
+	
+	ENTER("pNode iPos", Node, Pos);
+	
+	// Read directory's inode
+	Ext2_int_GetInode(Node, &inode);
+	size = inode.i_size;
+	
+	LOG("inode.i_block[0] = 0x%x\n", inode.i_block[0]);
+	
+	// Find Entry
+	// Get First Block
+	// - Do this ourselves as it is a simple operation
+	Base = inode.i_block[0] * disk->BlockSize;
+	while(Pos -- && size > 0)
+	{
+		VFS_ReadAt( disk->fd, Base+ofs, sizeof(tExt2_DirEnt), &dirent);
+		ofs += dirent.rec_len;
+		size -= dirent.rec_len;
+		entNum ++;
+		
+		if(ofs >= disk->BlockSize) {
+			block ++;
+			if( ofs > disk->BlockSize ) {
+				Warning("[EXT2] Directory Entry %i of inode %i ('%s') extends over a block boundary, ignoring\n",
+					entNum-1, Node->impl, Node->name);
+			}
+			ofs = 0;
+			Base = Ext2_int_GetBlockAddr( disk, inode.i_block, block );
+		}
+	}
+	
+	if(size <= 0)	return NULL;
+	
+	// Read Entry
+	VFS_ReadAt( disk->fd, Base+ofs, sizeof(tExt2_DirEnt), &dirent );
+	//LOG(" Ext2_ReadDir: dirent.inode = %i\n", dirent.inode);
+	//LOG(" Ext2_ReadDir: dirent.rec_len = %i\n", dirent.rec_len);
+	//LOG(" Ext2_ReadDir: dirent.name_len = %i\n", dirent.name_len);
+	VFS_ReadAt( disk->fd, Base+ofs+sizeof(tExt2_DirEnt), dirent.name_len, namebuf );
+	namebuf[ dirent.name_len ] = '\0';	// Cap off string
+	
+	
+	// Ignore . and .. (these are done in the VFS)
+	if( (namebuf[0] == '.' && namebuf[1] == '\0')
+	||  (namebuf[0] == '.' && namebuf[1] == '.' && namebuf[2]=='\0'))
+		LEAVE('p', VFS_SKIP);
+		return VFS_SKIP;	// Skip
+	}
+	
+	LEAVE('s', namebuf);
+	// Create new node
+	return strdup(namebuf);
+}
+
+/**
+ \fn tVFS_Node *Ext2_FindDir(tVFS_Node *node, char *filename)
+ \brief Gets information about a file
+ \param node	vfs node - Parent Node
+ \param filename	String - Name of file
+ \return VFS Node of file
+*/
+tVFS_Node *Ext2_FindDir(tVFS_Node *Node, char *Filename)
+{
+	tExt2_Disk	*disk = Node->ImplPtr;
+	tExt2_Inode	inode;
+	char	namebuf[EXT2_NAME_LEN+1];
+	tExt2_DirEnt	dirent;
+	Uint64	Base;	// Block's Base Address
+	 int	block = 0, ofs = 0;
+	 int	entNum = 0;
+	Uint	size;
+	
+	// Read directory's inode
+	Ext2_int_GetInode(Node, &inode);
+	size = inode.i_size;
+	
+	// Get First Block
+	// - Do this ourselves as it is a simple operation
+	Base = inode.i_block[0] * disk->BlockSize;
+	// Find File
+	while(size > 0)
+	{
+		VFS_ReadAt( disk->fd, Base+ofs, sizeof(tExt2_DirEnt), &dirent);
+		VFS_ReadAt( disk->fd, Base+ofs+sizeof(tExt2_DirEnt), dirent.name_len, namebuf );
+		namebuf[ dirent.name_len ] = '\0';	// Cap off string
+		// If it matches, create a node and return it
+		if(strcmp(namebuf, Filename) == 0)
+			return Ext2_int_CreateNode( disk, dirent.inode, namebuf );
+		// Increment pointers
+		ofs += dirent.rec_len;
+		size -= dirent.rec_len;
+		entNum ++;
+		
+		// Check for end of block
+		if(ofs >= disk->BlockSize) {
+			block ++;
+			if( ofs > disk->BlockSize ) {
+				Warnin("[EXT2 ] Directory Entry %i of inode %i ('%s') extends over a block boundary, ignoring\n",
+					entNum-1, Node->impl, Node->name);
+			}
+			ofs = 0;
+			Base = Ext2_int_GetBlockAddr( disk, inode.i_block, block );
+		}
+	}
+	
+	return NULL;
+}
+
+/**
+ * \fn tVFS_Node *Ext2_MkNod(tVFS_Node *Parent, char *Name, int Flags)
+ * \brief Create a new node
+ */
+tVFS_Node *Ext2_MkNod(tVFS_Node *Parent, char *Name, int Flags)
+{
+	return 0;
+}
+
+//==================================
+//=       INTERNAL FUNCTIONS       =
+//==================================
+
+
+/**
+ \internal
+ \fn int Ext2_int_GetInode(vfs_node *Node, tExt2_Inode *Inode)
+ \brief Gets the inode descriptor for a node
+ \param node	node to get the Inode of
+ \param inode	Destination
+*/
+int Ext2_int_GetInode(tVFS_Node *Node, tExt2_Inode *Inode)
+{
+	return Ext2_int_ReadInode(Node->ImplPtr, Node->Inode, Inode);
+}
+
+/**
+ * \fn vfs_node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeID, char *Name)
+ * \brief Create a new VFS Node
+ */
+tVFS_Node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeID, char *Name)
+{
+	tExt2_Inode	inode;
+	tVFS_Node	retNode;
+	tVFS_Node	*tmpNode;
+	
+	if( !Ext2_int_ReadInode(Disk, InodeID, &inode) )
+		return NULL;
+	
+	if( (tmpNode = inode_getCache(Disk->CacheID, InodeID)) )
+		return tmpNode;
+	
+	
+	// Set identifiers
+	retNode.Inode = InodeID;
+	retNode.ImplPtr = Disk;
+	
+	// Set file length
+	retNode.Size = inode.i_size;
+	
+	// Set Access Permissions
+	retNode.UID = inode.i_uid;
+	retNode.GID = inode.i_gid;
+	retNode.NumACLs = 3;
+	retNode.ACLs = VFS_UnixToAcessACL(inode.i_mode & 0777, inode.i_uid, inode.i_gid);
+	
+	//  Set Function Pointers
+	retNode.Read = Ext2_Read;
+	retNode.Write = Ext2_Write;
+	retNode.Close = Ext2_CloseFile;
+	
+	switch(inode.i_mode & EXT2_S_IFMT)
+	{
+	// Symbolic Link
+	case EXT2_S_IFLNK:
+		retNode.Flags = VFS_FFLAG_SYMLINK;
+		break;
+	// Regular File
+	case EXT2_S_IFREG:
+		retNode.flags = 0;
+		break;
+	// Directory
+	case EXT2_S_IFDIR:
+		retNode.ReadRir = Ext2_ReadDir;
+		retNode.FindDir = Ext2_FindDir;
+		retNode.MkNod = Ext2_MkNod;
+		//retNode.Relink = Ext2_Relink;
+		retNode.Flags = VFS_FFLAG_DIRECTORY;
+		break;
+	// Unknown, Write protect and hide it to be safe 
+	default:
+		retNode.flags = VFS_FFLAG_READONLY|VFS_FFLAG_HIDDEN;
+		break;
+	}
+	
+	// Check if the file should be hidden
+	if(Name[0] == '.')	retNode.Flags |= VFS_FFLAG_HIDDEN;
+	
+	// Set Timestamps
+	retNode.ATime = now();
+	retNode.MTime = inode.i_mtime * 1000;
+	retNode.CTime = inode.i_ctime * 1000;
+	
+	// Save in node cache and return saved node
+	return Inode_CacheNode(Disk->CacheID, &retNode);
+}
+
+/**
+ * \fn int Ext2_int_ReadInode(tExt2_Disk *Disk, Uint InodeId, tExt2_Inode *Inode)
+ * \brief Read an inode into memory
+ */
+int Ext2_int_ReadInode(tExt2_Disk *Disk, Uint InodeId, tExt2_Inode *Inode)
+{
+	 int	group, subId;
+	
+	//LogF("Ext2_int_ReadInode: (Disk=%p, InodeId=%i, Inode=%p)\n", Disk, InodeId, Inode);
+	
+	if(InodeId == 0)	return 0;
+	
+	InodeId --;	// Inodes are numbered starting at 1
+	
+	group = InodeId / Disk->SuperBlock.s_inodes_per_group;
+	subId = InodeId % Disk->SuperBlock.s_inodes_per_group;
+	
+	//LogF(" Ext2_int_ReadInode: group=%i, subId = %i\n", group, subId);
+	
+	//Seek to Block - Absolute
+	vfs_seek(Disk->fd, Disk->Groups[group].bg_inode_table * Disk->BlockSize, SEEK_SET);
+	//Seeek to inode - Relative
+	vfs_seek(Disk->fd, sizeof(tExt2_Inode)*subId, SEEK_CUR);
+	vfs_read(Disk->fd, sizeof(tExt2_Inode), Inode);
+	return 1;
+}
+
+/**
+ * \fn Uint64 Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum)
+ * \brief Get the address of a block from an inode's list
+ * \param Disk	Disk information structure
+ * \param Blocks	Pointer to an inode's block list
+ * \param BlockNum	Block index in list
+ */
+Uint64 Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum)
+{
+	Uint32	*iBlocks;
+	// Direct Blocks
+	if(BlockNum < 12)
+		return (Uint64)Blocks[BlockNum] * Disk->BlockSize;
+	
+	// Single Indirect Blocks
+	iBlocks = malloc( Disk->BlockSize );
+	VFS_ReadAt(Disk->fd, (Uint64)Blocks[12]*Disk->BlockSize, Disk->BlockSize, iBlocks);
+	
+	BlockNum -= 12;
+	if(BlockNum < 256) {
+		BlockNum = iBlocks[BlockNum];
+		free(iBlocks);
+		return (Uint64)BlockNum * Disk->BlockSize;
+	}
+	
+	// Double Indirect Blocks
+	if(BlockNum < 256*256)
+	{
+		VFS_ReadAt(Disk->fd, (Uint64)Blocks[13]*Disk->BlockSize, Disk->BlockSize, iBlocks);
+		VFS_ReadAt(Disk->fd, (Uint64)iBlocks[BlockNum/256]*Disk->BlockSize, Disk->BlockSize, iBlocks);
+		BlockNum = iBlocks[BlockNum%256];
+		free(iBlocks);
+		return (Uint64)BlockNum * Disk->BlockSize;
+	}
+	// Triple Indirect Blocks
+	VFS_ReadAt(Disk->fd, (Uint64)Blocks[14]*Disk->BlockSize, Disk->BlockSize, iBlocks);
+	VFS_ReadAt(Disk->fd, (Uint64)iBlocks[BlockNum/(256*256)]*Disk->BlockSize, Disk->BlockSize, iBlocks);
+	VFS_ReadAt(Disk->fd, (Uint64)iBlocks[(BlockNum/256)%256]*Disk->BlockSize, Disk->BlockSize, iBlocks);
+	BlockNum = iBlocks[BlockNum%256];
+	free(iBlocks);
+	return (Uint64)BlockNum * Disk->BlockSize;
+}
diff --git a/Kernel/vfs/fs/fs_ext2.h b/Kernel/vfs/fs/fs_ext2.h
new file mode 100644
index 00000000..9f84673b
--- /dev/null
+++ b/Kernel/vfs/fs/fs_ext2.h
@@ -0,0 +1,154 @@
+/**
+ Acess Version 1
+ \file fs_ext2_int.h
+ \brief EXT2 Filesystem Driver
+*/
+
+/**
+ \name Inode Flag Values
+ \{
+*/
+#define EXT2_S_IFMT		0xF000	//!< Format Mask
+#define EXT2_S_IFSOCK	0xC000	//!< Socket
+#define EXT2_S_IFLNK	0xA000	//!< Symbolic Link
+#define EXT2_S_IFREG	0x8000	//!< Regular File
+#define EXT2_S_IFBLK	0x6000	//!< Block Device
+#define EXT2_S_IFDIR	0x4000	//!< Directory
+#define EXT2_S_IFCHR	0x2000	//!< Character Device
+#define EXT2_S_IFIFO	0x1000	//!< FIFO
+#define EXT2_S_ISUID	0x0800	//!< SUID
+#define EXT2_S_ISGID	0x0400	//!< SGID
+#define EXT2_S_ISVTX	0x0200	//!< sticky bit
+#define EXT2_S_IRWXU	0700	//!< user access rights mask
+#define EXT2_S_IRUSR	0400	//!< Owner Read
+#define EXT2_S_IWUSR	0200	//!< Owner Write
+#define EXT2_S_IXUSR	0100	//!< Owner Execute
+#define EXT2_S_IRWXG	0070	//!< Group Access rights mask
+#define EXT2_S_IRGRP	0040	//!< Group Read
+#define EXT2_S_IWGRP	0020	//!< Group Write
+#define EXT2_S_IXGRP	0010	//!< Group Execute
+#define EXT2_S_IRWXO	0007	//!< Global Access rights mask
+#define EXT2_S_IROTH	0004	//!< Global Read
+#define EXT2_S_IWOTH	0002	//!< Global Write
+#define EXT2_S_IXOTH	0001	//!< Global Execute
+//! \}
+
+#define EXT2_NAME_LEN 255	//!< Maximum Name Length
+
+//STRUCTURES
+/**
+ \struct ext2_super_block_s
+ \brief EXT2 Superblock Structure
+*/
+struct ext2_super_block_s {
+	Uint32	s_inodes_count;		//!< Inodes count
+	Uint32	s_blocks_count;		//!< Blocks count
+	Uint32	s_r_blocks_count;	//!< Reserved blocks count
+	Uint32	s_free_blocks_count;	//!< Free blocks count
+	Uint32	s_free_inodes_count;	//!< Free inodes count
+	Uint32	s_first_data_block;	//!< First Data Block
+	Uint32	s_log_block_size;	//!< Block size
+	Sint32	s_log_frag_size;	//!< Fragment size
+	Uint32	s_blocks_per_group;	//!< Number Blocks per group
+	Uint32	s_frags_per_group;	//!< Number Fragments per group
+	Uint32	s_inodes_per_group;	//!< Number Inodes per group
+	Uint32	s_mtime;			//!< Mount time
+	Uint32	s_wtime;			//!< Write time
+	Uint16	s_mnt_count;		//!< Mount count
+	Sint16	s_max_mnt_count;	//!< Maximal mount count
+	Uint16	s_magic;			//!< Magic signature
+	Uint16	s_state;			//!< File system state
+	Uint16	s_errors;			//!< Behaviour when detecting errors
+	Uint16	s_pad;				//!< Padding
+	Uint32	s_lastcheck;		//!< time of last check
+	Uint32	s_checkinterval;	//!< max. time between checks
+	Uint32	s_creator_os;		//!< Formatting OS
+	Uint32	s_rev_level;		//!< Revision level
+	Uint16	s_def_resuid;		//!< Default uid for reserved blocks
+	Uint16	s_def_resgid;		//!< Default gid for reserved blocks
+	Uint32	s_reserved[235];	//!< Padding to the end of the block
+};
+
+/**
+ \struct ext2_inode_s
+ \brief EXT2 Inode Definition
+*/
+struct ext2_inode_s {
+	Uint16 i_mode;	//!< File mode
+	Uint16 i_uid;	//!< Owner Uid
+	Uint32 i_size;	//!< Size in bytes
+	Uint32 i_atime;	//!< Access time
+	Uint32 i_ctime; //!< Creation time
+	Uint32 i_mtime; //!< Modification time
+	Uint32 i_dtime; //!< Deletion Time
+	Uint16 i_gid;	//!< Group Id
+	Uint16 i_links_count;	//!< Links count
+	Uint32 i_blocks;	//!< Blocks count
+	Uint32 i_flags;	//!< File flags
+	union {
+		Uint32 linux_reserved1;	//!< Linux: Reserved
+		Uint32 hurd_translator;	//!< HURD: Translator
+		Uint32 masix_reserved1;	//!< Masix: Reserved
+	} osd1;	//!< OS dependent 1
+	Uint32 i_block[15];	//!< Pointers to blocks
+	Uint32 i_version; 	//!< File version (for NFS)
+	Uint32 i_file_acl;	//!< File ACL
+	Uint32 i_dir_acl;	//!< Directory ACL
+	Uint32 i_faddr; 	//!< Fragment address
+	union {
+		struct {
+			Uint8 l_i_frag;	//!< Fragment number
+			Uint8 l_i_fsize;	//!< Fragment size
+			Uint16 i_pad1;	//!< Padding
+			Uint32 l_i_reserved2[2];	//!< Reserved
+		} linux2;
+		struct {
+			Uint8 h_i_frag; //!< Fragment number
+			Uint8 h_i_fsize; //!< Fragment size
+			Uint16 h_i_mode_high;	//!< Mode High Bits
+			Uint16 h_i_uid_high;	//!< UID High Bits
+			Uint16 h_i_gid_high;	//!< GID High Bits
+			Uint32 h_i_author;	//!< Creator ID
+		} hurd2;
+		struct {
+			Uint8 m_i_frag;	//!< Fragment number
+			Uint8 m_i_fsize;	//!< Fragment size
+			Uint16 m_pad1;	//!< Padding
+			Uint32 m_i_reserved2[2];	//!< reserved
+		} masix2;
+	} osd2; //!< OS dependent 2
+};
+
+/**
+ \struct ext2_group_desc_s
+ \brief EXT2 Group Descriptor
+*/
+struct ext2_group_desc_s {
+	Uint32	bg_block_bitmap;	//!< Blocks bitmap block
+	Uint32	bg_inode_bitmap;	//!< Inodes bitmap block
+	Uint32	bg_inode_table;	//!< Inodes table block
+	Uint16	bg_free_blocks_count;	//!< Free blocks count
+	Uint16	bg_free_inodes_count;	//!< Free inodes count
+	Uint16	bg_used_dirs_count;	//!< Directories count
+	Uint16	bg_pad;	//!< Padding
+	Uint32	bg_reserved[3];	//!< Reserved
+};
+
+/**
+ \struct ext2_dir_entry
+ \brief EXT2 Directory Entry
+ \note The name may take up less than 255 characters
+*/
+struct ext2_dir_entry_s {
+	Uint32	inode;		//!< Inode number
+	Uint16	rec_len; 	//!< Directory entry length
+	Uint8	name_len;	//!< Short Name Length
+	Uint8	type;		//!< File Type
+	char	name[];		//!< File name
+};
+
+//TYPEDEFS
+typedef struct ext2_inode_s			tExt2_Inode;	//!< Inode Type
+typedef struct ext2_super_block_s	tExt2_SuperBlock;	//!< Superblock Type
+typedef struct ext2_group_desc_s	tExt2_Group;	//!< Group Descriptor Type
+typedef struct ext2_dir_entry_s		tExt2_DirEnt;	//!< Directory Entry Type
diff --git a/Kernel/vfs/open.c b/Kernel/vfs/open.c
index 0494294d..6f034170 100644
--- a/Kernel/vfs/open.c
+++ b/Kernel/vfs/open.c
@@ -61,7 +61,13 @@ char *VFS_GetAbsPath(char *Path)
 		}
 		strcpy(ret, Path);
 	} else {
-		cwdLen = strlen(cwd);
+		if(cwd == NULL) {
+			cwd = "/";
+			cwdLen = 1;
+		}
+		else {
+			cwdLen = strlen(cwd);
+		}
 		endLen = cwdLen + pathLen + 2;
 		// Prepend the current directory
 		ret = malloc(endLen);
@@ -119,6 +125,7 @@ char *VFS_GetAbsPath(char *Path)
 		write += (pos-read)+1;
 	}
 	
+	ret[write] = '\0';	// Cap string (to deal with . or .. being the last terms)
 	// `ret` should now be the absolute path
 	LEAVE('s', ret);
 	//Log("VFS_GetAbsPath: RETURN '%s'", ret);
@@ -534,7 +541,8 @@ int VFS_ChDir(char *New)
 	VFS_Close(fd);
 	
 	// Free old working directory
-	if( CFGPTR(CFG_VFS_CWD) )	free( CFGPTR(CFG_VFS_CWD) );
+	if( CFGPTR(CFG_VFS_CWD) )
+		free( CFGPTR(CFG_VFS_CWD) );
 	// Set new
 	CFGPTR(CFG_VFS_CWD) = buf;
 	
diff --git a/Makefile.cfg b/Makefile.cfg
new file mode 100644
index 00000000..65d3fa04
--- /dev/null
+++ b/Makefile.cfg
@@ -0,0 +1,15 @@
+#
+# Acess2 Build Configuration
+#
+
+CC = gcc
+LD = ld
+AS = nasm
+OBJDUMP = objdump
+RM = @rm -f
+STRIP = strip
+
+ARCH = i386
+ARCHDIR = x86
+
+DISTROOT = /mnt/AcessHDD/Acess2
diff --git a/README b/README
new file mode 100644
index 00000000..66d70f1b
--- /dev/null
+++ b/README
@@ -0,0 +1,31 @@
+========
+ Acess2
+========
+
+Acess2 is [TPG]'s hobby operating system.
+
+The Acess kernel is SEMI-posix compilant, but will be a comatability
+library that emulates the different functions.
+
+=== Source Tree ===
+--- /Kernel ---
+The /Kernel tree contains the kernel sources.
+ Within the root of the tree is the miscelanious architecture agnostic
+   code for managing threads, loading modules and other things.
+ /Kernel/arch/<archname> - Architecture dependent code
+ /Kernel/bin - Binary file format parsers. Takes a binary file and
+   convertes it into a binary object that the loader can then load into memory.
+ /Kernel/vfs - The Virtual Filesystem
+ /Kernel/vfs/fs - The various filesystem drivers for the VFS.
+ /Kernel/drv - Drivers
+
+--- Usermode ---
+/Usermode contains the base acess system
+ /Usermode/Applications - Usermode applications such as the default
+   command shell and the login shell.
+ /Usermode/Libraries - Usermode shared libraries and crt0.o, currently
+   implemented are libacess (kernel interface), a basic libc and ld-acess
+   (dynamic linker).
+ /Usermode/include - Required include files for the shared libraries.
+
+=== Building ===
diff --git a/Usermode/Applications/CLIShell_src/Makefile b/Usermode/Applications/CLIShell_src/Makefile
index a79952e7..a87f3298 100644
--- a/Usermode/Applications/CLIShell_src/Makefile
+++ b/Usermode/Applications/CLIShell_src/Makefile
@@ -1,36 +1,27 @@
 # Project: Acess Shell
 
-CC = gcc
-AS = nasm
-LD = ld
-RM = @rm -f
+-include ../Makefile.cfg
 
-COBJ = main.o lib.o
-BIN = ../CLIShell
-ACESSDIR = /home/hodgeja/Projects/Acess2/Usermode
+CPPFLAGS += -I./include
+CFLAGS   += -Wall -fno-builtin -fno-stack-protector
+LDFLAGS  += 
 
-INCS = -I$(ACESSDIR)/include -I./include
-CFLAGS = -Wall -fno-builtin -fno-stack-protector $(INCS)
-ASFLAGS = -felf
-LDFLAGS = -T $(ACESSDIR)/Libraries/acess.ld -I /Acess/Libs/ld-acess.so -lc
+BIN = ../CLIShell
+COBJ = main.o lib.o
 
 .PHONY : all clean
 
 all: $(BIN)
 
-$(BIN): $(AOBJ) $(COBJ)
+clean:
+	$(RM) $(COBJ) $(BIN)
+
+$(BIN): $(COBJ)
 	@echo --- $(LD) -o $@
-	@$(LD) $(LDFLAGS) -o $@ $(AOBJ) $(COBJ) -Map Map.txt
+	@$(LD) $(LDFLAGS) -o $@ $(COBJ) -Map Map.txt
 	objdump -d $(BIN) > $(BIN).dsm
-	cp $(BIN) /mnt/AcessHDD/Acess2/Bin/
-
-clean:
-	$(RM) $(AOBJ) $(COBJ) $(BIN)
+	cp $(BIN) $(DISTROOT)/Bin/
 
 $(COBJ): %.o: %.c
 	@echo --- GCC -o $@
 	@$(CC) $(CFLAGS) -c $? -o $@
-
-$(AOBJ): %.ao: %.asm
-	@echo --- $(AS) -o $@
-	@$(AS) $(ASFLAGS) -o $@ $<
diff --git a/Usermode/Applications/Makefile.cfg b/Usermode/Applications/Makefile.cfg
new file mode 100644
index 00000000..f8cd1515
--- /dev/null
+++ b/Usermode/Applications/Makefile.cfg
@@ -0,0 +1,9 @@
+# Acess 2 Applications
+# General Makefile
+
+-include ../../../Makefile.cfg
+
+ASFLAGS = -felf
+CPPFLAGS = -I../../include/
+CFLAGS   = -fno-stack-protector $(CPPFLAGS)
+LDFLAGS  = -T ../../Libraries/acess.ld -I /Acess/Libs/ld-acess.so -lc
diff --git a/Usermode/Applications/cat_src/Makefile b/Usermode/Applications/cat_src/Makefile
index 5774e570..53b8edfe 100644
--- a/Usermode/Applications/cat_src/Makefile
+++ b/Usermode/Applications/cat_src/Makefile
@@ -1,18 +1,12 @@
 # Project: cat
 
-CC = gcc
-AS = nasm
-LD = ld
-RM = @rm -f
+-include ../Makefile.cfg
 
 COBJ = main.o
 BIN = ../cat
-ACESSDIR = /home/hodgeja/Projects/Acess2/Usermode
 
-INCS = -I$(ACESSDIR)/include -I./include
-CFLAGS = -Wall -fno-builtin -fno-stack-protector $(INCS)
-ASFLAGS = -felf
-LDFLAGS = -T $(ACESSDIR)/Libraries/acess.ld -I /Acess/Libs/ld-acess.so -lc
+CFLAGS  += -Wall -fno-builtin -fno-stack-protector
+LDFLAGS += 
 
 .PHONY : all clean
 
@@ -22,7 +16,7 @@ $(BIN): $(COBJ)
 	@echo --- $(LD) -o $@
 	@$(LD) $(LDFLAGS) -o $@ $(COBJ) -Map Map.txt
 	objdump -d $(BIN) > $(BIN).dsm
-	cp $(BIN) /mnt/AcessHDD/Acess2/Bin/
+	cp $(BIN) $(DISTROOT)/Bin/
 
 clean:
 	$(RM) $(COBJ) $(BIN)
diff --git a/Usermode/Applications/init_src/Makefile b/Usermode/Applications/init_src/Makefile
index a51f61ba..0ec77391 100644
--- a/Usermode/Applications/init_src/Makefile
+++ b/Usermode/Applications/init_src/Makefile
@@ -1,27 +1,24 @@
 #
-#
-#
 
-CC = gcc
-AS = nasm
-LD = ld
-RM = rm -f
+-include ../Makefile.cfg
 
-ASFLAGS = -felf
-CPPFLAGS = -nostdinc -I../../include
-CFLAGS = -Wall -Werror -O3 $(CPPFLAGS)
-LDFLAGS = -I/Acess/Libs/ld-acess.so -L../../Libraries ../../Libraries/crt0.o -lacess
+CPPFLAGS += 
+CFLAGS	 += -Wall -Werror -O3
+LDFLAGS  += 
 
-OBJ = main.o
 BIN = ../init
+OBJ = main.o
 
 .PHONY: all clean
 
 all: $(BIN)
 
+clean:
+	$(RM) $(BIN) $(OBJ)
+
 $(BIN): $(OBJ) Makefile
 	$(LD) $(LDFLAGS) $(OBJ) -o $(BIN)
-	cp $(BIN) /mnt/AcessHDD/Acess2/
+	cp $(BIN) $(DISTROOT)/SBin/
 
 %.o: %.c
 	$(CC) $(CFLAGS) -c $< -o $@
diff --git a/Usermode/Applications/login_src/Makefile b/Usermode/Applications/login_src/Makefile
index 83d9d7a1..c09a174a 100644
--- a/Usermode/Applications/login_src/Makefile
+++ b/Usermode/Applications/login_src/Makefile
@@ -1,18 +1,12 @@
-#
-#
-#
+# Acess 2 Login Shell
 
-DBTYPE = tpl
+-include ../Makefile.cfg
 
-CC = gcc
-AS = nasm
-LD = ld
-RM = rm -f
+DBTYPE = tpl
 
-ASFLAGS = -felf
-CPPFLAGS = -I../../include
-CFLAGS = -fno-stack-protector -Wall -Werror -O3 $(CPPFLAGS)
-LDFLAGS = -I/Acess/Libs/ld-acess.so -L../../Libraries ../../Libraries/crt0.o -lacess -lgcc -lc
+CPPFLAGS += 
+CFLAGS   += -fno-stack-protector -Wall -Werror -O3 $(CPPFLAGS)
+LDFLAGS  += -lgcc -lc
 
 OBJ = main.o database_$(DBTYPE).o
 BIN = ../login
@@ -25,9 +19,11 @@ clean:
 	$(RM) $(BIN) $(OBJ)
 
 $(BIN): $(OBJ)
-	$(LD) $(LDFLAGS) $(OBJ) -o $(BIN)
-	cp $(BIN) /mnt/AcessHDD/Acess2/SBin/
-	objdump -d ../login > login.dsm
+	@echo --- $(LD) -o $@
+	@$(LD) $(LDFLAGS) $(OBJ) -o $@
+	cp $(BIN) $(DISTROOT)/SBin/
+	objdump -d $(BIN) > login.dsm
 
 %.o: %.c Makefile
-	$(CC) $(CFLAGS) -c $< -o $@
+	@echo --- $(CC) -o $@
+	@$(CC) $(CFLAGS) -c $< -o $@
diff --git a/Usermode/Applications/login_src/header.h b/Usermode/Applications/login_src/header.h
new file mode 100644
index 00000000..695e1a9d
--- /dev/null
+++ b/Usermode/Applications/login_src/header.h
@@ -0,0 +1,25 @@
+/*
+ * Acess2 Login Shell
+ */
+#ifndef _HEADER_H_
+#define _HEADER_H_
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <acess/sys.h>
+
+// === TYPES ===
+typedef struct {
+	 int	UID;
+	 int	GID;
+	char	*Home;
+	char	*Shell;
+} tUserInfo;
+
+// === PROTOTYPES ===
+// --- User Database ---
+extern int	ValidateUser(char *Username, char *Password);
+extern tUserInfo	*GetUserInfo(int UID);
+
+#endif
diff --git a/Usermode/Applications/ls_src/Makefile b/Usermode/Applications/ls_src/Makefile
new file mode 100644
index 00000000..893dc556
--- /dev/null
+++ b/Usermode/Applications/ls_src/Makefile
@@ -0,0 +1,27 @@
+# Project: cat
+
+-include ../Makefile.cfg
+
+COBJ = main.o
+BIN = ../ls
+
+CFLAGS  += -Wall -fno-builtin
+LDFLAGS +=
+
+.PHONY : all clean
+
+all: $(BIN)
+
+$(BIN): $(COBJ)
+	@echo --- $(LD) -o $@
+	@$(LD) $(LDFLAGS) -o $@ $(COBJ) -Map Map.txt
+	objdump -d $(BIN) > $(BIN).dsm
+	cp $(BIN) $(DISTROOT)/Bin/
+
+clean:
+	$(RM) $(COBJ) $(BIN)
+
+$(COBJ): %.o: %.c
+	@echo --- GCC -o $@
+	@$(CC) $(CFLAGS) -c $? -o $@
+
diff --git a/Usermode/Applications/ls_src/main.c b/Usermode/Applications/ls_src/main.c
new file mode 100644
index 00000000..82f9c2a6
--- /dev/null
+++ b/Usermode/Applications/ls_src/main.c
@@ -0,0 +1,165 @@
+/*
+ * Acess2 LS command
+ */
+#include <acess/sys.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#define	BUF_SIZE	1024
+
+// === PROTOTYPES ===
+ int	main(int argc, char *argv[]);
+void	ShowUsage(char *ProgName);
+void	ParseArguments(int argc, char *argv[]);
+void	SortFileList();
+
+// === GLOBALS ===
+// --- Flags ---
+ int	gbShowAll = 0;
+ int	gbShowImplicit = 0;
+ int	gbViewExtended = 0;
+ int	gbViewHumanReadable = 0;
+// --- Parameters ---
+char	*gsDirectory = NULL;
+// --- Working Set ---
+char	**gFileList;
+ int	giNumFiles = 0;
+
+/**
+ * \fn int main(int argc, char *argv[])
+ * \brief Entrypoint
+ */
+int main(int argc, char *argv[])
+{
+	 int	fd, tmp;
+	char	buf[BUF_SIZE+1];
+	t_sysFInfo	info;
+	 int	space = 0;
+
+	// Arguments Check
+	ParseArguments(argc, argv);
+
+	// Open Directory
+	fd = open(gsDirectory, OPENFLAG_READ|OPENFLAG_EXEC);
+	if(fd == -1) {
+		printf("Unable to open '%s' for reading\n", gsDirectory);
+		return EXIT_FAILURE;
+	}
+
+	// Check that it is a directory
+	finfo(fd, &info, 0);
+	if( !(info.flags & FILEFLAG_DIRECTORY) ) {
+		fprintf(stderr, "'%s' is a directory\n", gsDirectory);
+		close(fd);
+		return EXIT_FAILURE;
+	}
+
+	// Traverse Directory
+	while( (tmp = readdir(fd, buf)) )
+	{
+		// Error check
+		if(tmp < 0) {
+			close(fd);
+			return EXIT_FAILURE;
+		}
+		
+		// Allocate Space
+		if(space == giNumFiles)
+		{
+			space += 16;
+			gFileList = realloc(gFileList, space*sizeof(char*));
+			if(gFileList == NULL) {
+				close(fd);
+				return EXIT_FAILURE;
+			}
+		}
+		gFileList[giNumFiles++] = strdup(buf);
+	}
+
+	// Sort File List according to rules passed
+	SortFileList();
+
+	close(fd);
+	printf("\n");
+
+	return EXIT_SUCCESS;
+}
+
+/**
+ * \fn void ShowUsage(char *ProgName)
+ */
+void ShowUsage(char *ProgName)
+{
+	fprintf(stderr, "Usage: %s [options] [<directory>]\n", ProgName);
+	fprintf(stderr, "\n");
+}
+
+/**
+ * \fn void ParseArguments(int argc, char *argv[])
+ * \brief Parse the command line arguments
+ */
+void ParseArguments(int argc, char *argv[])
+{
+	 int	i;
+	char	*str;
+	for( i = 1; i < argc; i ++ )
+	{
+		str = argv[i];
+		// Flags
+		if(str[0] == '-')
+		{
+			if(str[1] == '-')
+			{
+				continue;
+			}
+			str = &str[1];
+			for( ; *str; str++ )
+			{
+				switch(*str)
+				{
+				// Show All
+				case 'a':	gbShowAll = 1;	gbShowImplicit = 1;	continue;
+				// Almost All
+				case 'A':	gbShowAll = 1;	gbShowImplicit = 0;	continue;
+				// Extended List
+				case 'l':	gbViewExtended = 1;	continue;
+				// Human readable sizes
+				case 'h':	gbViewHumanReadable = 1;	continue;
+				default:
+					fprintf(stderr, "%s: Unknown option '%c'\n", *str);
+					ShowUsage(argv[0]);
+					exit(EXIT_FAILURE);
+				}
+			}
+			continue;
+		}
+		
+		if(gsDirectory == NULL) {
+			gsDirectory = argv[i];
+		}
+	}
+	
+	// Apply Defaults
+	if(!gsDirectory)	gsDirectory = ".";
+	
+	printf("gsDirectory = '%s'\n", gsDirectory);
+}
+
+/**
+ * \fn int strcmpp(void *p1, void *p2)
+ * \brief Compares two strings given pointers to their pointers
+ */
+int strcmpp(const void *p1, const void *p2)
+{
+	return strcmp( *(char **)p1, *(char **)p2 );
+}
+
+/**
+ * \fn void SortFileList()
+ * \brief Sorts the filled file list
+ */
+void SortFileList()
+{
+	qsort(gFileList, giNumFiles, sizeof(char*), strcmpp);
+}
diff --git a/Usermode/Libraries/Makefile.cfg b/Usermode/Libraries/Makefile.cfg
new file mode 100644
index 00000000..2e09392f
--- /dev/null
+++ b/Usermode/Libraries/Makefile.cfg
@@ -0,0 +1,9 @@
+# Acess 2 Libraries
+# General Makefile
+
+-include ../../../Makefile.cfg
+
+ASFLAGS  = -felf
+CPPFLAGS = -I../../include/
+CFLAGS   = -Wall -fPIC -fno-builtin -fno-stack-protector $(CPPFLAGS)
+LDFLAGS  = -nostdlib -shared -I/Acess/Libs/ld-acess.so -e SoMain -x -L.. -lacess
diff --git a/Usermode/Libraries/ld-acess.so_src/Makefile b/Usermode/Libraries/ld-acess.so_src/Makefile
index 2d005160..63490916 100644
--- a/Usermode/Libraries/ld-acess.so_src/Makefile
+++ b/Usermode/Libraries/ld-acess.so_src/Makefile
@@ -2,22 +2,15 @@
 #  LD-ACESS.SO
 #  Makefile
 
-CC = gcc
-AS = nasm
-RM = @rm -f
-LD = ld
-OBJDUMP = objdump
+-include ../Makefile.cfg
 
 COBJ = main.o lib.o loadlib.o elf.o pe.o
 AOBJ = helpers.ao
 BIN = ../ld-acess.so
 
-CPPFLAGS = -I../../include
-CFLAGS = -Wall -fno-builtin -fleading-underscore -fno-stack-protector
-ASFLAGS = -felf
-#LDFLAGS = --oformat elf32-i386 -Map map.txt -Bstatic -e _SoMain -shared
-#LDFLAGS = --oformat elf32-i386 -Map map.txt -Bstatic -e _SoMain -Ttext 0xBFFFE000
-LDFLAGS = -T link.ld -Map map.txt -Bstatic
+CFLAGS   = -Wall -fno-builtin -fleading-underscore -fno-stack-protector
+ASFLAGS  = -felf
+LDFLAGS  = -T link.ld -Map map.txt -Bstatic
 
 
 .PHONY: all clean
@@ -28,14 +21,17 @@ clean:
 	$(RM) $(BIN) $(AOBJ) $(COBJ)
 
 $(BIN): $(AOBJ) $(COBJ)
-	$(LD) $(LDFLAGS) -o $(BIN) $(AOBJ) $(COBJ) > link.txt
+	@echo --- $(LD) -shared -o $@
+	@$(LD) $(LDFLAGS) -o $(BIN) $(AOBJ) $(COBJ) > link.txt
 	$(OBJDUMP) -x $(BIN) > ld-acess.dmp
 	$(OBJDUMP) -d $(BIN) > ld-acess.dsm
-	cp $(BIN) /mnt/AcessHDD/Acess2/Libs
+	cp $(BIN) $(DISTROOT)/Libs
 
 $(COBJ): %.o: %.c
-	$(CC) $(CFLAGS) -o $@ -c $<
+	@echo $(CC) -o $@
+	@$(CC) $(CFLAGS) -o $@ -c $<
 
 $(AOBJ): %.ao: %.asm
-	$(AS) $(ASFLAGS) -o $@ $<
+	@echo $(AS) -o $@
+	@$(AS) $(ASFLAGS) -o $@ $<
 	
diff --git a/Usermode/Libraries/ld-acess.so_src/helpers.asm b/Usermode/Libraries/ld-acess.so_src/helpers.asm
new file mode 100644
index 00000000..eb275ee2
--- /dev/null
+++ b/Usermode/Libraries/ld-acess.so_src/helpers.asm
@@ -0,0 +1,58 @@
+; AcessOS 1
+; By thePowersGang
+; LD-ACESS.SO
+; - helpers.asm
+
+%include "../libacess.so_src/syscalls.inc.asm"
+
+[global _SysDebug]
+[global _SysExit]
+[global _SysLoadBin]
+[global _SysUnloadBin]
+
+; void SysDebugV(char *fmt, va_list Args)
+_SysDebug:
+	;xchg bx, bx
+	push ebp
+	mov ebp, esp
+	pusha
+	
+	mov eax, 0x100	; User Debug
+	mov ebx, [ebp+8]	; Format
+	mov ecx, [ebp+12]	; Arguments
+	mov edx, [ebp+16]	; Arguments
+	mov edi, [ebp+20]	; Arguments
+	mov esi, [ebp+24]	; Arguments
+	int	0xAC
+	
+	popa
+	pop ebp
+	ret
+
+; void SysExit()
+_SysExit:
+	push ebx
+	mov eax, SYS_EXIT	; Exit
+	mov ebx, [esp+0x8]	; Exit Code
+	int	0xAC
+	pop ebx
+	ret
+
+; Uint SysLoadBin(char *path, Uint *entry)
+_SysLoadBin:
+	push ebx
+	mov eax, SYS_LOADBIN	; SYS_LDBIN
+	mov ebx, [esp+0x8]	; Path
+	mov ecx, [esp+0xC]	; Entry
+	int	0xAC
+	pop ebx
+	ret
+
+; Uint SysUnloadBin(Uint Base)
+_SysUnloadBin:
+	push ebx
+	mov eax, SYS_UNLOADBIN	; SYS_ULDBIN
+	mov ebx, [esp+0x8]	; Base
+	int	0xAC
+	pop ebx
+	ret
diff --git a/Usermode/Libraries/ld-acess.so_src/link.ld b/Usermode/Libraries/ld-acess.so_src/link.ld
new file mode 100644
index 00000000..8ddc2346
--- /dev/null
+++ b/Usermode/Libraries/ld-acess.so_src/link.ld
@@ -0,0 +1,27 @@
+ENTRY(_SoMain)
+OUTPUT_FORMAT(elf32-i386)
+
+SECTIONS {
+    . = 0xBBFF0000;
+	_gLinkedBase = .;
+
+   .text : AT(ADDR(.text)) {
+        code = .;
+        *(.text)
+        *(.rodata*)
+   }
+
+   .data ALIGN (0x1000) : AT(ADDR(.data)) {
+        data = .;
+        *(.data)
+   }
+
+   .bss ALIGN (0x1000) : AT(ADDR(.bss)) {
+        _sbss = .;
+        *(COMMON)
+        *(.bss)
+        _ebss = .;
+        bss = .;
+   }
+   _end = .;
+}
diff --git a/Usermode/Libraries/libacess.so_src/Makefile b/Usermode/Libraries/libacess.so_src/Makefile
index 7b320b93..3118cb67 100644
--- a/Usermode/Libraries/libacess.so_src/Makefile
+++ b/Usermode/Libraries/libacess.so_src/Makefile
@@ -2,10 +2,7 @@
 #
 #
 
-AS = nasm
-LD = ld
-STRIP = strip
-RM = rm -f
+-include ../../../Makefile.cfg
 
 ASFLAGS = -felf
 LDFLAGS = -nostdlib -shared -I/Acess/Libs/ld-acess.so -e SoMain
@@ -21,9 +18,11 @@ clean:
 	$(RM) $(BIN) $(OBJ)
 
 $(BIN): $(OBJ)
-	$(LD) $(LDFLAGS) -o $(BIN) $(OBJ)
+	@echo --- $(LD) -shared -o $@
+	@$(LD) $(LDFLAGS) -o $(BIN) $(OBJ)
 	$(STRIP) $(BIN)
-	cp $(BIN) /mnt/AcessHDD/Acess2/Libs
+	cp $(BIN) $(DISTROOT)/Libs
 	
 %.ao: %.asm syscalls.inc.asm
-	$(AS) $(ASFLAGS) -o $@ $<
+	@echo $(AS) -o $@
+	@$(AS) $(ASFLAGS) -o $@ $<
diff --git a/Usermode/Libraries/libc.so_src/Makefile b/Usermode/Libraries/libc.so_src/Makefile
index fd186a9d..c2979a07 100644
--- a/Usermode/Libraries/libc.so_src/Makefile
+++ b/Usermode/Libraries/libc.so_src/Makefile
@@ -1,19 +1,15 @@
-# AcessOS Basic C Library
+# Acess2 Basic C Library
 # Makefile
 
-CC = gcc
-AS = nasm
-RM = @rm -f
-LD = ld
-OBJDUMP = objdump
-ACESSDIR = /home/hodgeja/Projects/Acess2
+-include ../Makefile.cfg
 
-CPPFLAGS = -I$(ACESSDIR)/Usermode/include
-CFLAGS = -Wall -fPIC -fno-builtin -fno-stack-protector $(CPPFLAGS)
-ASFLAGS = -felf
-LDFLAGS = -x -shared -soname libc.so.1 -Map map.txt -e SoMain -L$(ACESSDIR)/Usermode/Libraries -lacess
+CPPFLAGS += 
+CFLAGS   += 
+ASFLAGS  +=
+LDFLAGS  += -soname libc.so.1 -Map map.txt
 
-OBJ_LIBC = heap.o stdlib.o stub.o env.o fileIO.o signals.o string.o
+OBJ_LIBC = heap.o stdlib.o stub.o env.o fileIO.o string.o
+# signals.o
 BIN = ../libc.so.1
 
 .PHONY:	all clean
@@ -30,7 +26,7 @@ $(BIN): $(OBJ_LIBC)
 	$(OBJDUMP) -d $@ > libc.so.1.dsm
 	$(OBJDUMP) -x -r -R $@ > libc.so.1.dmp
 	cp ../libc.so.1 ../libc.so
-	cp ../libc.so.1 /mnt/AcessHDD/Acess2/Libs/
+	cp ../libc.so.1 $(DISTROOT)/Libs/
 
 # C Runtime 0
 ../crt0.o: crt0.asm
diff --git a/Usermode/Libraries/libc.so_src/config.h b/Usermode/Libraries/libc.so_src/config.h
new file mode 100644
index 00000000..fe3343ee
--- /dev/null
+++ b/Usermode/Libraries/libc.so_src/config.h
@@ -0,0 +1,17 @@
+/*
+ * AcessOS Standard C Library
+ * CONFIG.H
+ * Configuration Options
+ */
+#ifndef _CONFIG_H
+# define _CONFIG_H
+
+// -- COMMON --
+#define	_LIBC_BUILD	1
+#define DEBUG_BUILD	0
+
+// -- STDIO --
+#define STDIO_MAX_STREAMS	64
+#define STDIO_LOCAL_BUFFER	0
+
+#endif
diff --git a/Usermode/Libraries/libc.so_src/crt0.asm b/Usermode/Libraries/libc.so_src/crt0.asm
new file mode 100644
index 00000000..e61a44c9
--- /dev/null
+++ b/Usermode/Libraries/libc.so_src/crt0.asm
@@ -0,0 +1,9 @@
+; AcessOS LibC
+; crt0.asm
+;
+
+[extern _heap_start]
+
+start:
+	
+	
diff --git a/Usermode/Libraries/libc.so_src/lib.h b/Usermode/Libraries/libc.so_src/lib.h
new file mode 100644
index 00000000..9d5194b1
--- /dev/null
+++ b/Usermode/Libraries/libc.so_src/lib.h
@@ -0,0 +1,19 @@
+/*
+AcessOS Basic Lib C
+
+lib.h
+*/
+#ifndef _LIB_H
+#define _LIB_H
+
+#define BUILD_SO	1
+
+#if defined(BUILD_DLL)
+#define	EXPORT	__declspec(dllexport)
+#define	LOCAL
+#elif defined(BUILD_SO)
+#define	EXPORT
+#define	LOCAL
+#endif
+
+#endif
diff --git a/Usermode/Libraries/libc.so_src/stdio_int.h b/Usermode/Libraries/libc.so_src/stdio_int.h
new file mode 100644
index 00000000..5bfbf986
--- /dev/null
+++ b/Usermode/Libraries/libc.so_src/stdio_int.h
@@ -0,0 +1,31 @@
+/*
+ * AcessOS Standard C Library
+ * SDTIO_INT.H
+ * Configuration Options
+ */
+#ifndef _STDIO_INT_H
+# define _STDIO_INT_H
+
+// === CONSTANTS ===
+#define FILE_FLAG_MODE_MASK	0x07
+#define FILE_FLAG_MODE_READ		0x01
+#define FILE_FLAG_MODE_WRITE	0x02
+#define FILE_FLAG_MODE_EXEC		0x03
+#define FILE_FLAG_MODE_APPEND	0x04
+#define FILE_FLAG_M_EXT		0x10
+
+// === TYPES ===
+struct sFILE {
+  	 int	FD;
+  	 int	Flags;
+	#if DEBUG_BUILD
+	char	*FileName;
+	#endif
+	#if STDIO_LOCAL_BUFFER
+	char	*Buffer;
+	Uint64	BufferStart;
+	 int	BufferSize;
+	#endif
+};
+
+#endif
diff --git a/Usermode/Libraries/libc.so_src/string.c b/Usermode/Libraries/libc.so_src/string.c
new file mode 100644
index 00000000..07c20179
--- /dev/null
+++ b/Usermode/Libraries/libc.so_src/string.c
@@ -0,0 +1,113 @@
+/*
+ * AcessOS Basic C Library
+ * string.c
+ */
+#include <acess/sys.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "lib.h"
+
+/**
+ * \fn EXPORT int strcmp(const char *s1, const char *s2)
+ * \brief Compare two strings
+ */
+EXPORT int strcmp(const char *s1, const char *s2)
+{
+	while(*s1 == *s2 && *s1 != '\0' && *s2 != '\0') {
+		s1++; s2++;
+	}
+	return (int)*s1 - (int)*s2;
+}
+
+/**
+ * \fn EXPORT char *strcpy(char *dst, const char *src)
+ * \brief Copy a string to another
+ */
+EXPORT char *strcpy(char *dst, const char *src)
+{
+	char *_dst = dst;
+	while(*src) {
+		*dst = *src;
+		src++; dst++;
+	}
+	*dst = '\0';
+	return _dst;
+}
+
+/**
+ * \fn EXPORT int strlen(const char *str)
+ * \brief Get the length of a string
+ */
+EXPORT int strlen(const char *str)
+{
+	int retval;
+	for(retval = 0; *str != '\0'; str++)
+		retval++;
+	return retval;
+}
+
+/**
+ * \fn EXPORT int strncmp(const char *s1, const char *s2, size_t len)
+ * \brief Compare two strings with a limit
+ */
+EXPORT int strncmp(const char *s1, const char *s2, size_t len)
+{
+	while(--len && *s1 == *s2 && *s1 != '\0' && *s2 != '\0') {
+		s1++; s2++;
+	}
+	return (int)*s1 - (int)*s2;
+}
+
+/**
+ * \fn EXPORT char *strdup(const char *str)
+ * \brief Duplicate a string using heap memory
+ * \note Defined in POSIX Spec, not C spec
+ */
+EXPORT char *strdup(const char *str)
+{
+	size_t	len = strlen(str);
+	char	*ret = malloc(len+1);
+	if(ret == NULL)	return NULL;
+	strcpy(ret, str);
+	return ret;
+}
+
+// --- Memory ---
+/**
+ * \fn EXPORT void *memset(void *dest, int val, size_t num)
+ * \brief Clear memory with the specified value
+ */
+EXPORT void *memset(void *dest, int val, size_t num)
+{
+	unsigned char *p = dest;
+	while(num--)	*p++ = val;
+	return dest;
+}
+
+/**
+ * \fn EXPORT void *memcpy(void *dest, const void *src, size_t count)
+ * \brief Copy one memory area to another
+ */
+EXPORT void *memcpy(void *dest, const void *src, size_t count)
+{
+    char *sp = (char *)src;
+    char *dp = (char *)dest;
+    for(;count--;) *dp++ = *sp++;
+    return dest;
+}
+
+/**
+ * \fn EXPORT void *memmove(void *dest, const void *src, size_t count)
+ * \brief Copy data in memory, avoiding overlap problems
+ */
+EXPORT void *memmove(void *dest, const void *src, size_t count)
+{
+    char *sp = (char *)src;
+    char *dp = (char *)dest;
+	// Check if corruption will happen
+	if( (unsigned int)dest > (unsigned int)src && (unsigned int)dest < (unsigned int)src+count )
+		for(;count--;) dp[count] = sp[count];
+	else
+    	for(;count--;) *dp++ = *sp++;
+    return dest;
+}
diff --git a/Usermode/Libraries/libgcc.so_src/Makefile b/Usermode/Libraries/libgcc.so_src/Makefile
new file mode 100644
index 00000000..ada47db9
--- /dev/null
+++ b/Usermode/Libraries/libgcc.so_src/Makefile
@@ -0,0 +1,28 @@
+#
+# libgcc
+#
+
+-include ../Makefile.cfg
+
+OBJS = libgcc.o
+BIN = ../libgcc.so
+
+CFLAGS  += -Wall -Werror
+LDFLAGS += -soname libgcc.acess.so
+
+.PHONY: all clean
+
+all: $(BIN)
+
+clean:
+	$(RM) $(BIN) $(OBJS)
+
+$(BIN): $(OBJS)
+	@echo -- ld -o $@
+	@$(LD) $(LDFLAGS) -o $(BIN) $(OBJS)
+	@$(OBJDUMP) -d $(BIN) > libgcc.so.dsm
+	cp $(BIN) $(DISTROOT)/Libs
+
+$(OBJS): %.o: %.c
+	@echo -- gcc -o $@
+	@$(CC) $(CFLAGS) -o $@ -c $<
diff --git a/Usermode/Libraries/libgcc.so_src/libgcc.c b/Usermode/Libraries/libgcc.so_src/libgcc.c
new file mode 100644
index 00000000..2127b551
--- /dev/null
+++ b/Usermode/Libraries/libgcc.so_src/libgcc.c
@@ -0,0 +1,50 @@
+/* Acess GCC Helper Library
+ *
+ */
+#include <sys/sys.h>
+
+typedef unsigned long long int uint64_t;
+
+// === CODE ===
+int SoMain()
+{
+	return 0;
+}
+
+// --- Errors ---
+void __stack_chk_fail()
+{
+	write(1, 32, "FATAL ERROR: Stack Check Failed\n");
+	_exit(-1);
+	for(;;);
+}
+
+// --- 64-Bit Math ---
+/**
+ * \fn uint64_t __udivdi3(uint64_t Num, uint64_t Den)
+ * \brief Divide two 64-bit integers
+ */
+uint64_t __udivdi3(uint64_t Num, uint64_t Den)
+{
+	uint64_t	ret = 0;
+	if(Den == 0)	// Call Div by Zero Error
+		__asm__ __volatile__ ("int $0");
+	while(Num > Den) {
+		ret ++;
+		Num -= Den;
+	}
+	return ret;
+}
+
+/**
+ * \fn uint64_t __umoddi3(uint64_t Num, uint64_t Den)
+ * \brief Get the modulus of two 64-bit integers
+ */
+uint64_t __umoddi3(uint64_t Num, uint64_t Den)
+{
+	if(Den == 0)	// Call Div by Zero Error
+		__asm__ __volatile__ ("int $0");
+	while(Num > Den)
+		Num -= Den;
+	return Num;
+}
diff --git a/Usermode/include/string.h b/Usermode/include/string.h
new file mode 100644
index 00000000..158aeeb7
--- /dev/null
+++ b/Usermode/include/string.h
@@ -0,0 +1,21 @@
+/*
+ * AcessOS LibC
+ * string.h
+ */
+#ifndef __STRING_H
+#define __STRING_H
+
+// Memory
+extern void *memset(void *dest, int val, size_t count);
+extern void *memcpy(void *dest, const void *src, size_t count);
+extern void *memmove(void *dest, const void *src, size_t count);
+extern int	memcmp(const void *mem1, const void *mem2, size_t count);
+
+// Strings
+extern int	strlen(const char *string);
+extern int	strcmp(const char *str1, const char *str2);
+extern int	strncmp(const char *str1, const char *str2, size_t len);
+extern char	*strcpy(char *dst, const char *src);
+extern char	*strdup(const char *src);
+
+#endif
-- 
GitLab