Merge branch 'master' of git://git.ucc.asn.au/tpg/acess2
authorJohn Hodge <[email protected]>
Mon, 6 Feb 2012 06:20:20 +0000 (14:20 +0800)
committerJohn Hodge <[email protected]>
Mon, 6 Feb 2012 06:20:20 +0000 (14:20 +0800)
Conflicts:
Kernel/drv/vterm.c

138 files changed:
BuildConf/host/Makefile.cfg
BuildConf/x86/default.mk
DoRelease [new file with mode: 0755]
Kernel/Makefile
Kernel/arch/armv7/mm_virt.c
Kernel/arch/armv7/proc.c
Kernel/arch/x86/desctab.asm
Kernel/arch/x86/errors.c
Kernel/arch/x86/include/arch.h
Kernel/arch/x86/include/arch_int.h [new file with mode: 0644]
Kernel/arch/x86/include/mm_virt.h
Kernel/arch/x86/lib.c
Kernel/arch/x86/mm_phys.c
Kernel/arch/x86/mm_virt.c
Kernel/arch/x86/proc.asm
Kernel/arch/x86/proc.c
Kernel/arch/x86/vm8086.c
Kernel/arch/x86_64/mm_virt.c
Kernel/arch/x86_64/proc.asm
Kernel/arch/x86_64/proc.c
Kernel/arch/x86_64/start64.asm
Kernel/binary.c
Kernel/drv/fifo.c
Kernel/drv/pci.c
Kernel/drv/proc.c
Kernel/drv/vterm.c
Kernel/drv/vterm.h [new file with mode: 0644]
Kernel/drv/vterm_font.c [new file with mode: 0644]
Kernel/drv/vterm_input.c [new file with mode: 0644]
Kernel/drv/vterm_output.c [new file with mode: 0644]
Kernel/drv/vterm_termbuf.c [new file with mode: 0644]
Kernel/drv/vterm_vt100.c [new file with mode: 0644]
Kernel/drvutil.c
Kernel/events.c [new file with mode: 0644]
Kernel/heap.c
Kernel/include/acess.h
Kernel/include/api_drv_disk.h
Kernel/include/api_drv_video.h
Kernel/include/errno.h
Kernel/include/events.h [new file with mode: 0644]
Kernel/include/hal_proc.h
Kernel/include/syscalls.h
Kernel/include/syscalls.inc.asm
Kernel/include/threads.h
Kernel/include/threads_int.h
Kernel/include/vfs.h
Kernel/include/vfs_ext.h
Kernel/include/vfs_int.h
Kernel/include/vfs_threads.h [new file with mode: 0644]
Kernel/lib.c
Kernel/messages.c
Kernel/modules.c
Kernel/mutex.c
Kernel/syscalls.c
Kernel/syscalls.lst
Kernel/threads.c
Kernel/vfs/dir.c
Kernel/vfs/fs/devfs.c
Kernel/vfs/fs/root.c
Kernel/vfs/handle.c
Kernel/vfs/io.c
Kernel/vfs/main.c
Kernel/vfs/memfile.c
Kernel/vfs/mmap.c
Kernel/vfs/nodecache.c
Kernel/vfs/open.c
Kernel/vfs/select.c
MakeReleaseSet
Makefile
Makefile.Version.cfg
Modules/Display/BochsGA/bochsvbe.c
Modules/Display/PL110/main.c
Modules/Display/VESA/main.c
Modules/Filesystems/Ext2/dir.c
Modules/Filesystems/Ext2/ext2.c
Modules/Filesystems/Ext2/ext2_common.h
Modules/Filesystems/Ext2/write.c
Modules/Filesystems/FAT/fat.c
Modules/Filesystems/InitRD/GenerateInitRD.php
Modules/Filesystems/InitRD/initrd.h
Modules/Filesystems/InitRD/main.c
Modules/Filesystems/NTFS/main.c
Modules/IPStack/arp.c
Modules/IPStack/interface.c
Modules/IPStack/ipv4.c
Modules/IPStack/main.c
Modules/IPStack/routing.c
Modules/IPStack/tcp.c
Modules/IPStack/udp.c
Modules/Input/PS2KbMouse/kb.c
Modules/Input/PS2KbMouse/ps2mouse.c
Modules/Network/NE2000/ne2000.c
Modules/Network/RTL8139/rtl8139.c
Modules/Storage/ATA/main.c
Modules/Storage/FDDv2/main.c
Modules/USB/UHCI/uhci.c
Modules/x86/VGAText/vga.c
Notes/20120122-Events.txt [new file with mode: 0644]
Notes/20120204-RoutingNames.txt [new file with mode: 0644]
RunQemu
Usermode/Applications/axwin3_src/Makefile
Usermode/Applications/axwin3_src/WM/decorator.c
Usermode/Applications/axwin3_src/WM/main.c
Usermode/Applications/axwin3_src/WM/renderers/widget.c
Usermode/Applications/axwin3_src/WM/wm_input.c
Usermode/Applications/axwin3_src/WM/wm_render_text.c
Usermode/Applications/axwin3_src/libaxwin3.so_src/msg.c
Usermode/Applications/dhcpclient_src/Makefile [new file with mode: 0644]
Usermode/Applications/dhcpclient_src/main.c [new file with mode: 0644]
Usermode/Applications/ifconfig_src/main.c
Usermode/Applications/irc_src/main.c
Usermode/Applications/ping_src/main.c
Usermode/Applications/telnet_src/main.c
Usermode/Applications/telnetd_src/Makefile [new file with mode: 0644]
Usermode/Applications/telnetd_src/main.c [new file with mode: 0644]
Usermode/Libraries/Makefile.tpl
Usermode/Libraries/acess.ld_src/acess_armv7.ld.h
Usermode/Libraries/ld-acess.so_src/Makefile
Usermode/Libraries/ld-acess.so_src/arch/.gitignore [new file with mode: 0644]
Usermode/Libraries/ld-acess.so_src/arch/syscalls.s.h
Usermode/Libraries/ld-acess.so_src/common.h
Usermode/Libraries/ld-acess.so_src/export.c
Usermode/Libraries/libc.so_src/Makefile
Usermode/Libraries/libc.so_src/rand.c [new file with mode: 0644]
Usermode/Libraries/libnet.so_src/address.c
Usermode/Libraries/libnet.so_src/main.c
Usermode/include/acess/intdefs.h [new file with mode: 0644]
Usermode/include/acess/sys.h
Usermode/include/errno.h
Usermode/include/signal.h
Usermode/include/stddef.h [new file with mode: 0644]
Usermode/include/stdint.h
Usermode/include/stdio.h
Usermode/include/stdlib.h
Usermode/include/sys/stat.h
Usermode/include/sys/types.h
Usermode/include/time.h
Usermode/include/unistd.h [new file with mode: 0644]

index 1a28638..057e96e 100644 (file)
@@ -6,10 +6,17 @@
 SAVED_CC_ := $(CC)
 SAVED_LD_ := $(LD)
 
-include $(ACESSDIR)/BuildConf/x86_64/Makefile.cfg
+include $(ACESSDIR)/BuildConf/$(HOST_ARCH)/Makefile.cfg
 
 OBJDUMP := objdump -S
 
-CC := $(SAVED_CC_)
-LD := $(SAVED_LD_)
+CC_SUFFIX = 
+
+ifeq ($(HOST_ARCH),x86)
+CC_SUFFIX := -m32
+LD_SUFFIX := -melf_i386
+endif
+
+CC := $(SAVED_CC_) $(CC_SUFFIX)
+LD := $(SAVED_LD_) $(LD_SUFFIX)
 
index ec21227..a1911cd 100644 (file)
@@ -6,5 +6,5 @@ MODULES += Display/VESA
 MODULES += Display/BochsGA
 MODULES += Input/PS2KbMouse
 MODULES += x86/ISADMA x86/VGAText
-MODULES += USB/Core USB/UHCI
+#MODULES += USB/Core USB/UHCI
 #MODULES += Interfaces/UDI
diff --git a/DoRelease b/DoRelease
new file mode 100755 (executable)
index 0000000..d26daad
--- /dev/null
+++ b/DoRelease
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+# NOTE: This is rather specific to my setup :)
+
+REL_DOT=`grep 'ACESS_VERSION =' Makefile.Version.cfg | sed -r 's/.*([0-9]+\.[0-9]+).*/\1/'`
+REL=`echo $REL_DOT | sed -r 's/\.//g'`
+
+_RELDIR=/serenade/http/www/Downloads/Acess2/
+
+./MakeReleaseSet x86 smp
+./MakeReleaseSet x86_64
+./MakeReleaseSet armv7 tegra2
+
+for arch in x86 x86_64 armv7; do
+       cp Releases/Acess2_latest_${arch}-bin.tar.gz ${_RELDIR}Acess2_${REL}_${arch}-bin.tar.gz
+       cp Releases/Acess2_latest_${arch}.img.gz ${_RELDIR}Acess2_${REL}_${arch}.img.gz
+done
+
+git archive --format=tar --prefix=Acess2/ HEAD | gzip > ${_RELDIR}Acess2_git.tar.gz
+git tag rel${REL_DOT}
+
+cd ${_RELDIR}
+cp Acess2_git.tar.gz Acess2_${REL}.tar.gz
+rm Acess2.img.gz; ln -s Acess2_${REL}_x86.img.gz Acess2.img.gz
+rm Acess2.tar.gz; ln -s Acess2_${REL}.tar.gz Acess2.tar.gz
index 48a2c9f..d0c8dbf 100644 (file)
@@ -53,8 +53,9 @@ BUILDINFO_SRC := $(OBJDIR)buildinfo.c$(OBJSUFFIX)
 OBJ := $(addprefix arch/$(ARCHDIR)/,$(A_OBJ))
 OBJ += heap.o drvutil.o logging.o debug.o lib.o adt.o time.o
 OBJ += messages.o modules.o syscalls.o system.o
-OBJ += threads.o mutex.o semaphore.o workqueue.o
-OBJ += drv/vterm.o drv/proc.o drv/fifo.o drv/iocache.o drv/pci.o
+OBJ += threads.o mutex.o semaphore.o workqueue.o events.o
+OBJ += drv/proc.o drv/fifo.o drv/iocache.o drv/pci.o
+OBJ += drv/vterm.o drv/vterm_font.o drv/vterm_vt100.o drv/vterm_output.o drv/vterm_input.o drv/vterm_termbuf.o
 OBJ += binary.o bin/elf.o bin/pe.o
 OBJ += vfs/main.o vfs/open.o vfs/acls.o vfs/dir.o vfs/io.o vfs/mount.o
 OBJ += vfs/memfile.o vfs/nodecache.o vfs/handle.o vfs/select.o vfs/mmap.o
@@ -78,20 +79,20 @@ OBJ += $(BUILDINFO_OBJ)
 all: $(BIN)
 
 clean:
-#      $(RM) $(BIN) ../Acess2.$(ARCH).gz $(BIN).dsm ../Map.$(ARCH).txt LineCounts.$(ARCH).txt $(OBJ) $(DEPFILES)
-       @$(RM) $(BIN) ../Acess2.$(ARCH).gz $(BIN).dsm ../Map.$(ARCH).txt LineCounts.$(ARCH).txt -r $(OBJDIR) $(OBJ) $(DEPFILES) $(BUILDINFO_SRC)
+       @$(RM) $(BIN) ../Acess2.$(ARCH).gz $(BIN).dsm ../Map.$(ARCH).txt LineCounts.$(ARCH).txt
+       @$(RM) -r $(OBJDIR) $(OBJ) $(DEPFILES) $(BUILDINFO_SRC)
 
 install: $(BIN) 
-       cp $(BIN) $(BIN)_
-       $(STRIP) $(BIN)_
-       gzip -c $(BIN)_ > $(GZBIN)
-       $(RM) $(BIN)_
+       @cp $(BIN) $(BIN)_
+       @$(STRIP) $(BIN)_
+       @gzip -c $(BIN)_ > $(GZBIN)
+       @$(RM) $(BIN)_
        $(xCP) $(GZBIN) $(DISTROOT)
 
 apidoc:
        doxygen Doxyfile.api
 
-$(BIN): $(OBJ) $(MODS) arch/$(ARCHDIR)/link.ld Makefile
+$(BIN): $(OBJ) $(MODS) arch/$(ARCHDIR)/link.ld Makefile ../BuildConf/$(ARCH)/Makefile.cfg ../BuildConf/$(ARCH)/$(PLATFORM).mk
        @echo --- LD -o $(BIN)
        @$(LD) $(LDFLAGS) -o $(BIN) $(OBJ) $(MODS) --defsym __buildnum=$$(( $(BUILD_NUM) + 1 )) -Map ../Map.$(ARCH).txt
        @$(DISASM) -S $(BIN) > $(BIN).dsm
index 830878e..90655b6 100644 (file)
@@ -937,16 +937,18 @@ void MM_int_DumpTableEnt(tVAddr Start, size_t Len, tMM_PageInfo *Info)
 {
        if( giMM_ZeroPage && Info->PhysAddr == giMM_ZeroPage )
        {
-               Debug("%p => %8s - 0x%7x %i %x",
+               Debug("%p => %8s - 0x%7x %i %x %s",
                        Start, "ZERO", Len,
-                       Info->Domain, Info->AP
+                       Info->Domain, Info->AP,
+                       Info->bGlobal ? "G" : "nG"
                        );
        }
        else
        {
-               Debug("%p => %8x - 0x%7x %i %x",
+               Debug("%p => %8x - 0x%7x %i %x %s",
                        Start, Info->PhysAddr-Len, Len,
-                       Info->Domain, Info->AP
+                       Info->Domain, Info->AP,
+                       Info->bGlobal ? "G" : "nG"
                        );
        }
 }
@@ -957,9 +959,7 @@ void MM_DumpTables(tVAddr Start, tVAddr End)
        tMM_PageInfo    pi, pi_old;
         int    i = 0, inRange=0;
        
-       pi_old.Size = 0;
-       pi_old.AP = 0;
-       pi_old.PhysAddr = 0;
+       memset(&pi_old, 0, sizeof(pi_old));
 
        Debug("Page Table Dump (%p to %p):", Start, End);
        range_start = Start;
@@ -972,6 +972,7 @@ void MM_DumpTables(tVAddr Start, tVAddr End)
                 || pi.Size != pi_old.Size
                 || pi.Domain != pi_old.Domain
                 || pi.AP != pi_old.AP
+                || pi.bGlobal != pi_old.bGlobal
                 || pi_old.PhysAddr != pi.PhysAddr )
                {
                        if(inRange) {
index c3cb226..cd998f2 100644 (file)
@@ -11,6 +11,7 @@
 
 // === IMPORTS ===
 extern tThread gThreadZero;
+extern tProcess        gProcessZero;
 extern void    SwitchTask(Uint32 NewSP, Uint32 *OldSP, Uint32 NewIP, Uint32 *OldIP, Uint32 MemPtr);
 extern void    KernelThreadHeader(void);       // Actually takes args on stack
 extern void    Proc_int_DropToUser(Uint32 IP, Uint32 SP) NORETURN __attribute__((long_call));
@@ -30,7 +31,7 @@ tThread *gpIdleThread = NULL;
 // === CODE ===
 void ArchThreads_Init(void)
 {
-       gThreadZero.MemState.Base = (tPAddr)&kernel_table0 - KERNEL_BASE;
+       gProcessZero.MemState.Base = (tPAddr)&kernel_table0 - KERNEL_BASE;
 }
 
 void Proc_IdleThread(void *unused)
@@ -61,11 +62,11 @@ tThread *Proc_GetCurThread(void)
        return gpCurrentThread;
 }
 
-void Proc_StartUser(Uint Entrypoint, Uint Base, int ArgC, char **ArgV, int DataSize)
+void Proc_StartUser(Uint Entrypoint, Uint Base, int ArgC, const char **ArgV, int DataSize)
 {
        Uint32  *usr_sp;
         int    i;
-       char    **envp;
+       const char      **envp;
        tVAddr  delta;
 
 //     Log_Debug("Proc", "Proc_StartUser: (Entrypoint=%p, Base=%p, ArgC=%i, ArgV=%p, DataSize=0x%x)",
@@ -94,11 +95,15 @@ void Proc_StartUser(Uint Entrypoint, Uint Base, int ArgC, char **ArgV, int DataS
        Proc_int_DropToUser(Entrypoint, (Uint32)usr_sp);
 }
 
-void Proc_ClearThread(tThread *Thread)
+void Proc_ClearProcess(tProcess *Process)
 {
        Log_Warning("Proc", "TODO: Nuke address space etc");
 }
 
+void Proc_ClearThread(tThread *Thread)
+{
+}
+
 tTID Proc_Clone(Uint Flags)
 {
        tThread *new;
@@ -118,14 +123,14 @@ tTID Proc_Clone(Uint Flags)
        new->SavedState.SP = sp;
        new->SavedState.UserSP = Proc_int_SwapUserSP(0);
        new->SavedState.UserIP = Proc_GetCurThread()->SavedState.UserIP;
-       new->MemState.Base = mem;
+       new->Process->MemState.Base = mem;
 
        Threads_AddActive(new);
 
        return new->TID;
 }
 
-tTID Proc_SpawnWorker( void (*Fnc)(void*), void *Ptr )
+int Proc_SpawnWorker( void (*Fnc)(void*), void *Ptr )
 {
        tThread *new;
        Uint32  sp;
@@ -205,7 +210,7 @@ void Proc_Reschedule(void)
 
        Log("Switching to %p (%i %s) IP=%p SP=%p TTBR0=%p UsrSP=%p",
                next, next->TID, next->ThreadName,
-               next->SavedState.IP, next->SavedState.SP, next->MemState.Base,
+               next->SavedState.IP, next->SavedState.SP, next->Process->MemState.Base,
                next->SavedState.UserSP
                );
 
@@ -218,7 +223,7 @@ void Proc_Reschedule(void)
        SwitchTask(
                next->SavedState.SP, &cur->SavedState.SP,
                next->SavedState.IP, &cur->SavedState.IP,
-               next->MemState.Base
+               next->Process->MemState.Base
                );
        
 }
index 8c7d320..6eaa651 100644 (file)
@@ -188,7 +188,7 @@ Isr0xEE:
        push eax        ; Line up with interrupt number
        mov eax, dr1    ; CPU Number
        push eax
-       mov eax, [esp-4]        ; Load EAX back
+       mov eax, [esp+4]        ; Load EAX back
        jmp SchedulerBase
 ; Spurious Interrupt
 [global Isr0xEF]
@@ -323,3 +323,5 @@ IRQCommon:
        popa
        add esp, 8      ; Error Code and ID
        iret
+
+; vim: ft=nasm ts=8
index d73fcea..d2d2cef 100644 (file)
@@ -112,7 +112,7 @@ void ErrorHandler(tRegs *Regs)
        }
        
        // Check if it's a user mode fault
-       if( Regs->eip < KERNEL_BASE || (Regs->cs & 3) == 3 ) {
+       if( (Regs->cs & 3) == 3 ) {
                Log_Warning("Arch", "User Fault -  %s, Code: 0x%x",
                        csaERROR_NAMES[Regs->int_num], Regs->err_code);
                Log_Warning("Arch", "at CS:EIP %04x:%08x",
@@ -136,7 +136,7 @@ void ErrorHandler(tRegs *Regs)
        
        Debug_KernelPanic();
        
-       LogF("CPU %i Error %i - %s, Code: 0x%x - At %08x",
+       LogF("CPU %i Error %i - %s, Code: 0x%x - At %08x\n",
                GetCPUNum(),
                Regs->int_num, csaERROR_NAMES[Regs->int_num], Regs->err_code,
                Regs->eip);
@@ -169,8 +169,8 @@ void ErrorHandler(tRegs *Regs)
        {
        case 6: // #UD
                Warning(" Offending bytes: %02x %02x %02x %02x",
-                       *(Uint8*)Regs->eip+0, *(Uint8*)Regs->eip+1,
-                       *(Uint8*)Regs->eip+2, *(Uint8*)Regs->eip+3);
+                       *(Uint8*)(Regs->eip+0), *(Uint8*)(Regs->eip+1),
+                       *(Uint8*)(Regs->eip+2), *(Uint8*)(Regs->eip+3));
                break;
        }
        
@@ -199,15 +199,16 @@ void Proc_PrintBacktrace(void)
 void Error_Backtrace(Uint eip, Uint ebp)
 {
         int    i = 0;
-       Uint    delta = 0;
-       char    *str = NULL;
+//     Uint    delta = 0;
+//     char    *str = NULL;
        
        //if(eip < 0xC0000000 && eip > 0x1000)
        //{
        //      LogF("Backtrace: User - 0x%x\n", eip);
        //      return;
        //}
-       
+
+       #if 0   
        if(eip > 0xE0000000)
        {
                LogF("Backtrace: Data Area - 0x%x\n", eip);
@@ -219,12 +220,13 @@ void Error_Backtrace(Uint eip, Uint ebp)
                LogF("Backtrace: Kernel Module - 0x%x\n", eip);
                return;
        }
-       
+       #endif  
+
        //str = Debug_GetSymbol(eip, &delta);
-       if(str == NULL)
+//     if(str == NULL)
                LogF("Backtrace: 0x%x", eip);
-       else
-               LogF("Backtrace: %s+0x%x", str, delta);
+//     else
+//             LogF("Backtrace: %s+0x%x", str, delta);
        if(!MM_GetPhysAddr(ebp))
        {
                LogF("\nBacktrace: Invalid EBP, stopping\n");
@@ -236,10 +238,10 @@ void Error_Backtrace(Uint eip, Uint ebp)
        {
                if( ebp >= MM_KERNEL_STACKS_END )       break;
                //str = Debug_GetSymbol(*(Uint*)(ebp+4), &delta);
-               if(str == NULL)
+//             if(str == NULL)
                        LogF(" >> 0x%x", *(Uint*)(ebp+4));
-               else
-                       LogF(" >> %s+0x%x", str, delta);
+//             else
+//                     LogF(" >> %s+0x%x", str, delta);
                ebp = *(Uint*)ebp;
                i++;
        }
index 9307ada..8a98705 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Acess2
  * - x86 Architecture
- * arch/i386/include/arch.h
+ * arch/x86/include/arch.h
  */
 #ifndef _ARCH_H_
 #define _ARCH_H_
diff --git a/Kernel/arch/x86/include/arch_int.h b/Kernel/arch/x86/include/arch_int.h
new file mode 100644 (file)
index 0000000..81ea2d7
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * x86 Arch - Internal Definitions
+ * - arch/x86/include/arch_int.h
+ */
+#ifndef _ARCH_INT_H_
+#define _ARCH_INT_H_
+
+/**
+ * \brief Spinlock primative atomic set-if-zero loop
+ */
+extern void    __AtomicTestSetLoop(Uint *Ptr, Uint Value);
+
+/**
+ * \brief Clear and free an address space
+ */
+extern void    MM_ClearSpace(Uint32 CR3);
+
+#endif
+
index 31642c6..d84c965 100644 (file)
@@ -46,7 +46,7 @@
 // === FUNCTIONS ===
 extern void    MM_FinishVirtualInit(void);
 extern void    MM_SetCR3(Uint CR3);
-extern tPAddr  MM_Clone(void);
+extern tPAddr  MM_Clone(int bCloneUser);
 extern tVAddr  MM_NewKStack(void);
 extern tVAddr  MM_NewWorkerStack(Uint *InitialStack, size_t StackSize);
 
index ecc575c..175f9a5 100644 (file)
@@ -6,6 +6,8 @@
  */
 #include <acess.h>
 #include <threads_int.h>
+#include <arch_int.h>
+#include <hal_proc.h>  // GetCPUNum
 
 #define TRACE_LOCKS    0
 
 // === IMPRORTS ===
 #if TRACE_LOCKS
 extern struct sShortSpinlock   glDebug_Lock;
-extern struct sShortSpinlock   glThreadListLock;
+extern tMutex  glPhysAlloc;
+#define TRACE_LOCK_COND        (Lock != &glDebug_Lock && Lock != &glThreadListLock && Lock != &glPhysAlloc.Protector)
+//#define TRACE_LOCK_COND      (Lock != &glDebug_Lock && Lock != &glPhysAlloc.Protector)
 #endif
-extern int     GetCPUNum(void);
 
 // === PROTOTYPES ==
 Uint64 __divmod64(Uint64 Num, Uint64 Den, Uint64 *Rem);
@@ -49,6 +52,17 @@ int CPU_HAS_LOCK(struct sShortSpinlock *Lock)
        return Lock->Lock == GetCPUNum() + 1;
 }
 
+void __AtomicTestSetLoop(Uint *Ptr, Uint Value)
+{
+       __ASM__(
+               "1:\n\t"
+               "xor %%eax, %%eax;\n\t"
+               "lock cmpxchgl %0, (%1);\n\t"
+               "jnz 1b;\n\t"
+               :: "r"(Value), "r"(Ptr)
+               : "eax" // EAX clobbered
+               );
+}
 /**
  * \brief Acquire a Short Spinlock
  * \param Lock Lock pointer
@@ -64,7 +78,6 @@ int CPU_HAS_LOCK(struct sShortSpinlock *Lock)
  */
 void SHORTLOCK(struct sShortSpinlock *Lock)
 {
-        int    v = 1;
         int    IF;
         int    cpu = GetCPUNum() + 1;
        
@@ -73,31 +86,25 @@ void SHORTLOCK(struct sShortSpinlock *Lock)
        IF &= 0x200;    // AND out all but the interrupt flag
        
        #if TRACE_LOCKS
-       if( Lock != &glDebug_Lock && Lock != &glThreadListLock )
+       if( TRACE_LOCK_COND )
        {
                //Log_Log("LOCK", "%p locked by %p", Lock, __builtin_return_address(0));
-               Debug("%p obtaining %p (Called by %p)", __builtin_return_address(0), Lock, __builtin_return_address(1));
+               Debug("%i %p obtaining %p (Called by %p)", cpu-1,  __builtin_return_address(0), Lock, __builtin_return_address(1));
        }
        #endif
        
        __ASM__("cli");
        
        // Wait for another CPU to release
-       __ASM__(
-               "1: lock cmpxchgl %2, (%3)\n\t"
-               "jnz 1b"
-               : "=a"(v)
-               : "a"(0), "r"(cpu), "r"(&Lock->Lock)
-               );
-       
+       __AtomicTestSetLoop( (Uint*)&Lock->Lock, cpu );
        Lock->IF = IF;
        
        #if TRACE_LOCKS
-       if( Lock != &glDebug_Lock && Lock != &glThreadListLock )
+       if( TRACE_LOCK_COND )
        {
                //Log_Log("LOCK", "%p locked by %p", Lock, __builtin_return_address(0));
-               //Debug("Lock %p locked by %p\t%p", Lock, __builtin_return_address(0), __builtin_return_address(1));
-               Debug("got it");
+               Debug("%i %p locked by %p\t%p", cpu-1, Lock, __builtin_return_address(0), __builtin_return_address(1));
+//             Debug("got it");
        }
        #endif
 }
@@ -108,7 +115,7 @@ void SHORTLOCK(struct sShortSpinlock *Lock)
 void SHORTREL(struct sShortSpinlock *Lock)
 {      
        #if TRACE_LOCKS
-       if( Lock != &glDebug_Lock && Lock != &glThreadListLock )
+       if( TRACE_LOCK_COND )
        {
                //Log_Log("LOCK", "%p released by %p", Lock, __builtin_return_address(0));
                Debug("Lock %p released by %p\t%p", Lock, __builtin_return_address(0), __builtin_return_address(1));
index 81edcf2..aa1b260 100644 (file)
@@ -135,8 +135,8 @@ tPAddr MM_AllocPhys(void)
         int    first, last;
        for( i = numAddrClasses; i -- > 1; )
        {
-               first = 1 << (addrClasses[i-1] - 12);
-               last = (1 << (addrClasses[i] - 12)) - 1;
+               first = 1UL << (addrClasses[i-1] - 12);
+               last = (1UL << (addrClasses[i] - 12)) - 1;
                // Range is above the last free page
                if( first > giLastPossibleFree )
                        continue;
index 137240c..bd7b1df 100644 (file)
@@ -16,6 +16,7 @@
 #include <mm_phys.h>
 #include <proc.h>
 #include <hal_proc.h>
+#include <arch_int.h>
 
 #define TAB    22
 
 
 #define INVLPG(addr)   __asm__ __volatile__ ("invlpg (%0)"::"r"(addr))
 
+#define GET_TEMP_MAPPING(cr3) do { \
+       __ASM__("cli"); \
+       __AtomicTestSetLoop( (Uint *)gpTmpCR3, cr3 | 3 ); \
+} while(0)
+#define REL_TEMP_MAPPING() do { \
+       *gpTmpCR3 = 0; \
+       __ASM__("sti"); \
+} while(0)
+
 typedef Uint32 tTabEnt;
 
 // === IMPORTS ===
@@ -136,6 +146,8 @@ void MM_InstallVirtual(void)
        for( i = ((tVAddr)&_UsertextEnd-(tVAddr)&_UsertextBase+0xFFF)/4096; i--; ) {
                MM_SetFlags( (tVAddr)&_UsertextBase + i*4096, 0, MM_PFLAG_KERNEL );
        }
+       
+       *gpTmpCR3 = 0;
 }
 
 /**
@@ -178,8 +190,9 @@ void MM_PageFault(tVAddr Addr, Uint ErrorCode, tRegs *Regs)
                INVLPG( Addr & ~0xFFF );
                return;
        }
-       
-       __asm__ __volatile__ ("pushf; andw $0xFEFF, 0(%esp); popf");
+
+       // Disable instruction tracing  
+       __ASM__("pushf; andw $0xFEFF, 0(%esp); popf");
        Proc_GetCurThread()->bInstrTrace = 0;
 
        // If it was a user, tell the thread handler
@@ -190,7 +203,7 @@ void MM_PageFault(tVAddr Addr, Uint ErrorCode, tRegs *Regs)
                        (ErrorCode&16?" (Instruction Fetch)":"")
                        );
                Log_Warning("MMVirt", "Instruction %04x:%08x accessed %p", Regs->cs, Regs->eip, Addr);
-               __asm__ __volatile__ ("sti");   // Restart IRQs
+               __ASM__("sti"); // Restart IRQs
                #if 1
                Error_Backtrace(Regs->eip, Regs->ebp);
                #endif
@@ -329,7 +342,7 @@ tPAddr MM_Allocate(tVAddr VAddr)
 {
        tPAddr  paddr;
        //ENTER("xVAddr", VAddr);
-       //__asm__ __volatile__ ("xchg %bx,%bx");
+       //__ASM__("xchg %bx,%bx");
        // Check if the directory is mapped
        if( gaPageDir[ VAddr >> 22 ] == 0 )
        {
@@ -414,7 +427,7 @@ tPAddr MM_GetPhysAddr(tVAddr Addr)
  */
 void MM_SetCR3(Uint CR3)
 {
-       __asm__ __volatile__ ("mov %0, %%cr3"::"r"(CR3));
+       __ASM__("mov %0, %%cr3"::"r"(CR3));
 }
 
 /**
@@ -426,7 +439,7 @@ int MM_Map(tVAddr VAddr, tPAddr PAddr)
        //ENTER("xVAddr xPAddr", VAddr, PAddr);
        // Sanity check
        if( PAddr & 0xFFF || VAddr & 0xFFF ) {
-               Warning("MM_Map - Physical or Virtual Addresses are not aligned");
+               Log_Warning("MM_Virt", "MM_Map - Physical or Virtual Addresses are not aligned");
                //LEAVE('i', 0);
                return 0;
        }
@@ -504,31 +517,83 @@ void MM_ClearUser(void)
        INVLPG( gaPageDir );
 }
 
+/**
+ * \brief Deallocate an address space
+ */
+void MM_ClearSpace(Uint32 CR3)
+{
+        int    i, j;
+       
+       if(CR3 == (*gpPageCR3 & ~0xFFF)) {
+               Log_Error("MMVirt", "Can't clear current address space");
+               return ;
+       }
+
+       if( MM_GetRefCount(CR3) > 1 ) {
+               MM_DerefPhys(CR3);
+               Log_Log("MMVirt", "CR3 %P is still referenced, not cleaning (but dereferenced)", CR3);
+               return ;
+       }
+
+       Log_Debug("MMVirt", "Clearing out address space 0x%x from 0x%x", CR3, *gpPageCR3);
+       
+       GET_TEMP_MAPPING(CR3);
+       INVLPG( gaTmpDir );
+
+       for( i = 0; i < 1024; i ++ )
+       {
+               Uint32  *table = &gaTmpTable[i*1024];
+               if( !(gaTmpDir[i] & PF_PRESENT) )
+                       continue ;
+
+               INVLPG( table );        
+
+               if( i < 768 || (i > MM_KERNEL_STACKS >> 22 && i < MM_KERNEL_STACKS_END >> 22) )
+               {
+                       for( j = 0; j < 1024; j ++ )
+                       {
+                               if( !(table[j] & 1) )
+                                       continue;
+                               MM_DerefPhys( table[j] & ~0xFFF );
+                       }
+               }
+
+               if( i != (PAGE_TABLE_ADDR >> 22) )
+               {               
+                       MM_DerefPhys( gaTmpDir[i] & ~0xFFF );
+               }
+       }
+
+
+       MM_DerefPhys( CR3 );
+
+       REL_TEMP_MAPPING();
+}
+
 /**
  * \fn tPAddr MM_Clone(void)
  * \brief Clone the current address space
  */
-tPAddr MM_Clone(void)
+tPAddr MM_Clone(int bNoUserCopy)
 {
        Uint    i, j;
-       tVAddr  ret;
+       tPAddr  ret;
        Uint    page = 0;
        tVAddr  kStackBase = Proc_GetCurThread()->KernelStack - MM_KERNEL_STACK_SIZE;
        void    *tmp;
        
-       Mutex_Acquire( &glTempFractal );
-       
        // Create Directory Table
-       *gpTmpCR3 = MM_AllocPhys() | 3;
-       if( *gpTmpCR3 == 3 ) {
-               *gpTmpCR3 = 0;
+       ret = MM_AllocPhys();
+       if( ret == 0 ) {
                return 0;
        }
+       
+       // Map
+       GET_TEMP_MAPPING( ret );
        INVLPG( gaTmpDir );
-       //LOG("Allocated Directory (%x)", *gpTmpCR3);
        memsetd( gaTmpDir, 0, 1024 );
        
-       if( Threads_GetPID() != 0 )
+       if( Threads_GetPID() != 0 && !bNoUserCopy )
        {       
                // Copy Tables
                for( i = 0; i < 768; i ++)
@@ -573,6 +638,10 @@ tPAddr MM_Clone(void)
                        gaTmpDir[ PAGE_TABLE_ADDR >> 22 ] = *gpTmpCR3;
                        continue;
                }
+               if( i == (TMP_TABLE_ADDR >> 22) ) {
+                       gaTmpDir[ TMP_TABLE_ADDR >> 22 ] = 0;
+                       continue ;
+               }
                
                if( gaPageDir[i] == 0 ) {
                        gaTmpDir[i] = 0;
@@ -628,8 +697,7 @@ tPAddr MM_Clone(void)
                }
        }
        
-       ret = *gpTmpCR3 & ~0xFFF;
-       Mutex_Release( &glTempFractal );
+       REL_TEMP_MAPPING();
        
        //LEAVE('x', ret);
        return ret;
@@ -709,15 +777,10 @@ tVAddr MM_NewWorkerStack(Uint *StackContents, size_t ContentsSize)
        base = WORKER_STACKS + base * WORKER_STACK_SIZE;
        //Log(" MM_NewWorkerStack: base = 0x%x", base);
        
-       // Acquire the lock for the temp fractal mappings
-       Mutex_Acquire(&glTempFractal);
-       
        // Set the temp fractals to TID0's address space
-       *gpTmpCR3 = ((Uint)gaInitPageDir - KERNEL_BASE) | 3;
-       //Log(" MM_NewWorkerStack: *gpTmpCR3 = 0x%x", *gpTmpCR3);
+       GET_TEMP_MAPPING( ((Uint)gaInitPageDir - KERNEL_BASE) );
        INVLPG( gaTmpDir );
        
-       
        // Check if the directory is mapped (we are assuming that the stacks
        // will fit neatly in a directory)
        //Log(" MM_NewWorkerStack: gaTmpDir[ 0x%x ] = 0x%x", base>>22, gaTmpDir[ base >> 22 ]);
@@ -732,9 +795,9 @@ tVAddr MM_NewWorkerStack(Uint *StackContents, size_t ContentsSize)
                page = MM_AllocPhys();
                gaTmpTable[ (base + addr) >> 12 ] = page | 3;
        }
-       *gpTmpCR3 = 0;
-       // Release the temp mapping lock
-       Mutex_Release(&glTempFractal);
+
+       // Release temporary fractal
+       REL_TEMP_MAPPING();
 
        // NOTE: Max of 1 page
        // `page` is the last allocated page from the previious for loop
index 014cfed..8da7971 100644 (file)
@@ -31,7 +31,9 @@ Proc_CloneInt:
        ; Save RSP
        mov eax, [esp+0x20+4]
        mov [eax], esp
+       push DWORD [esp+0x20+12]
        call MM_Clone
+       add esp, 4
        ; Save CR3
        mov esi, [esp+0x20+8]
        mov [esi], eax
@@ -76,7 +78,6 @@ SwitchTasks:
        jmp ecx
 
 .restore:
-
        popa
        xor eax, eax
        ret
@@ -263,7 +264,7 @@ SpawnTask:
 .parent:
        ret
 
-; void Proc_ReturnToUser(void *Method, Uint Parameter)
+; void Proc_ReturnToUser(void *Method, Uint Parameter, tVAddr KernelStack)
 ; Calls a user fault handler
 ;
 [global Proc_ReturnToUser]
@@ -275,12 +276,8 @@ Proc_ReturnToUser:
        ; [EBP+12]: parameter
        ; [EBP+16]: kernel stack top
        
-       ;call Proc_GetCurThread
-       
-       ; EAX is the current thread
-       ;mov ebx, eax
-       ;mov eax, [ebx+12*4]    ; Get Kernel Stack
-       mov eax, [ebp+16]       ; Get Kernel Stack
+       ; Get kernel stack      
+       mov eax, [ebp+16]
        sub eax, KSTACK_USERSTATE_SIZE
        
        ;
@@ -346,10 +343,6 @@ Proc_ReturnToUser:
 
 [global GetCPUNum]
 GetCPUNum:     ; TODO: Store in debug registers
-;      xor eax, eax
-;      str ax
-;      sub ax, 0x30
-;      shr ax, 3       ; ax /= 8
        mov eax, dr1
        ret
 
index 7d54d0c..82a3f40 100644 (file)
@@ -12,6 +12,7 @@
 # include <mp.h>
 #endif
 #include <hal_proc.h>
+#include <arch_int.h>
 
 // === FLAGS ===
 #define DEBUG_TRACE_SWITCH     0
@@ -44,12 +45,13 @@ extern void APStartup(void);        // 16-bit AP startup code
 extern Uint    GetEIP(void);   // start.asm
 extern Uint    GetEIP_Sched(void);     // proc.asm
 extern void    NewTaskHeader(tThread *Thread, void *Fcn, int nArgs, ...);      // Actually takes cdecl args
-extern Uint    Proc_CloneInt(Uint *ESP, Uint32 *CR3);
+extern Uint    Proc_CloneInt(Uint *ESP, Uint32 *CR3, int bNoUserClone);
 extern Uint32  gaInitPageDir[1024];    // start.asm
 extern char    Kernel_Stack_Top[];
 extern int     giNumCPUs;
 extern int     giNextTID;
 extern tThread gThreadZero;
+extern tProcess        gProcessZero;
 extern void    Isr8(void);     // Double Fault
 extern void    Proc_ReturnToUser(tVAddr Handler, Uint Argument, tVAddr KernelStack);
 extern char    scheduler_return[];     // Return address in SchedulerBase
@@ -372,7 +374,7 @@ void ArchThreads_Init(void)
        gaCPUs[0].Current = &gThreadZero;
        gThreadZero.CurCPU = 0;
        
-       gThreadZero.MemState.CR3 = (Uint)gaInitPageDir - KERNEL_BASE;
+       gProcessZero.MemState.CR3 = (Uint)gaInitPageDir - KERNEL_BASE;
        
        // Create Per-Process Data Block
        if( !MM_Allocate(MM_PPD_CFG) )
@@ -568,16 +570,20 @@ void Proc_ChangeStack(void)
        __asm__ __volatile__ ("mov %0, %%ebp"::"r"(ebp));
 }
 
+void Proc_ClearProcess(tProcess *Process)
+{
+       MM_ClearSpace(Process->MemState.CR3);
+}
+
 void Proc_ClearThread(tThread *Thread)
 {
-       Log_Warning("Proc", "TODO: Nuke address space etc");
        if(Thread->SavedState.SSE) {
                free(Thread->SavedState.SSE);
                Thread->SavedState.SSE = NULL;
        }
 }
 
-int Proc_NewKThread(void (*Fcn)(void*), void *Data)
+tTID Proc_NewKThread(void (*Fcn)(void*), void *Data)
 {
        Uint    esp;
        tThread *newThread, *cur;
@@ -586,9 +592,6 @@ int Proc_NewKThread(void (*Fcn)(void*), void *Data)
        newThread = Threads_CloneTCB(0);
        if(!newThread)  return -1;
        
-       // Set CR3
-       newThread->MemState.CR3 = cur->MemState.CR3;
-
        // Create new KStack
        newThread->KernelStack = MM_NewKStack();
        // Check for errors
@@ -618,7 +621,7 @@ int Proc_NewKThread(void (*Fcn)(void*), void *Data)
  * \fn int Proc_Clone(Uint *Err, Uint Flags)
  * \brief Clone the current process
  */
-int Proc_Clone(Uint Flags)
+tPID Proc_Clone(Uint Flags)
 {
        tThread *newThread;
        tThread *cur = Proc_GetCurThread();
@@ -637,9 +640,8 @@ int Proc_Clone(Uint Flags)
        newThread->KernelStack = cur->KernelStack;
 
        // Clone state
-       eip = Proc_CloneInt(&newThread->SavedState.ESP, &newThread->MemState.CR3);
+       eip = Proc_CloneInt(&newThread->SavedState.ESP, &newThread->Process->MemState.CR3, Flags & CLONE_NOUSER);
        if( eip == 0 ) {
-               // ACK the interrupt
                return 0;
        }
        newThread->SavedState.EIP = eip;
@@ -647,7 +649,7 @@ int Proc_Clone(Uint Flags)
        newThread->SavedState.bSSEModified = 0;
        
        // Check for errors
-       if( newThread->MemState.CR3 == 0 ) {
+       if( newThread->Process->MemState.CR3 == 0 ) {
                Log_Error("Proc", "Proc_Clone: MM_Clone failed");
                Threads_Delete(newThread);
                return -1;
@@ -725,16 +727,16 @@ Uint Proc_MakeUserStack(void)
        return base + USER_STACK_SZ;
 }
 
-void Proc_StartUser(Uint Entrypoint, Uint Base, int ArgC, char **ArgV, int DataSize)
+void Proc_StartUser(Uint Entrypoint, Uint Base, int ArgC, const char **ArgV, int DataSize)
 {
        Uint    *stack;
         int    i;
-       char    **envp = NULL;
+       const char      **envp = NULL;
        Uint16  ss, cs;
        
        // Copy data to the user stack and free original buffer
        stack = (void*)Proc_MakeUserStack();
-       stack -= DataSize/sizeof(*stack);
+       stack -= (DataSize+sizeof(*stack)-1)/sizeof(*stack);
        memcpy( stack, ArgV, DataSize );
        free(ArgV);
        
@@ -742,7 +744,7 @@ void Proc_StartUser(Uint Entrypoint, Uint Base, int ArgC, char **ArgV, int DataS
        if( DataSize )
        {
                Uint delta = (Uint)stack - (Uint)ArgV;
-               ArgV = (char**)stack;
+               ArgV = (const char**)stack;
                for( i = 0; ArgV[i]; i++ )      ArgV[i] += delta;
                envp = &ArgV[i+1];
                for( i = 0; envp[i]; i++ )      envp[i] += delta;
@@ -927,10 +929,11 @@ void Proc_Reschedule(void)
                LogF("\nSwitching CPU %i to %p (%i %s) - CR3 = 0x%x, EIP = %p, ESP = %p\n",
                        GetCPUNum(),
                        nextthread, nextthread->TID, nextthread->ThreadName,
-                       nextthread->MemState.CR3,
+                       nextthread->Process->MemState.CR3,
                        nextthread->SavedState.EIP,
                        nextthread->SavedState.ESP
                        );
+               LogF("OldCR3 = %P\n", curthread->Process->MemState.CR3);
        }
        #endif
 
@@ -952,7 +955,7 @@ void Proc_Reschedule(void)
                SwitchTasks(
                        nextthread->SavedState.ESP, &curthread->SavedState.ESP,
                        nextthread->SavedState.EIP, &curthread->SavedState.EIP,
-                       nextthread->MemState.CR3
+                       nextthread->Process->MemState.CR3
                        );
        }
        else
@@ -960,7 +963,7 @@ void Proc_Reschedule(void)
                SwitchTasks(
                        nextthread->SavedState.ESP, 0,
                        nextthread->SavedState.EIP, 0,
-                       nextthread->MemState.CR3
+                       nextthread->Process->MemState.CR3
                        );
        }
 
@@ -973,6 +976,7 @@ void Proc_Reschedule(void)
  */
 void Proc_Scheduler(int CPU)
 {
+#if 0
        tThread *thread;
        
        // If the spinlock is set, let it complete
@@ -1005,7 +1009,6 @@ void Proc_Scheduler(int CPU)
                        regs->eflags &= ~0x100; // Clear TF
        }
 
-#if 0
        // TODO: Ack timer?
        #if USE_MP
        if( GetCPUNum() )
index 839a640..6134862 100644 (file)
@@ -172,7 +172,7 @@ void VM8086_GPF(tRegs *Regs)
        && Threads_GetPID() == gVM8086_WorkerPID)
        {
                if( gpVM8086_State == (void*)-1 ) {
-//                     Log_Log("VM8086", "Worker thread ready and waiting");
+                       Log_Log("VM8086", "Worker thread ready and waiting");
                        gpVM8086_State = NULL;
                        Mutex_Release( &glVM8086_Process );     // Release lock obtained in VM8086_Install
                }
index 511803c..89aeaa1 100644 (file)
@@ -10,6 +10,9 @@
 #include <proc.h>
 #include <hal_proc.h>
 
+// === DEBUG OPTIONS ===
+#define TRACE_COW      0
+
 // === CONSTANTS ===
 #define PHYS_BITS      52      // TODO: Move out
 #define VIRT_BITS      48
@@ -109,7 +112,9 @@ void MM_int_ClonePageEnt( Uint64 *Ent, void *NextLevel, tVAddr Addr, int bTable
        {
                *Ent &= ~PF_COW;
                *Ent |= PF_PRESENT|PF_WRITE;
+               #if TRACE_COW
                Log_Debug("MMVirt", "COW ent at %p (%p) only %P", Ent, NextLevel, curpage);
+               #endif
        }
        else
        {
@@ -127,7 +132,9 @@ void MM_int_ClonePageEnt( Uint64 *Ent, void *NextLevel, tVAddr Addr, int bTable
                memcpy( tmp, NextLevel, 0x1000 );
                MM_FreeTemp( (tVAddr)tmp );
                
+               #if TRACE_COW
                Log_Debug("MMVirt", "COW ent at %p (%p) from %P to %P", Ent, NextLevel, curpage, paddr);
+               #endif
 
                MM_DerefPhys( curpage );
                *Ent &= PF_USER;
@@ -271,8 +278,10 @@ void MM_int_DumpTablesEnt(tVAddr RangeStart, size_t Length, tPAddr Expected)
                LogF("%13s", "zero" );
        else
                LogF("%13llx", PAGETABLE(RangeStart>>12) & PADDR_MASK );
-       LogF(" : 0x%6llx (%c%c%c%c)\r\n",
+       LogF(" : 0x%6llx (%c%c%c%c%c%c)\r\n",
                Length,
+               (Expected & PF_GLOBAL ? 'G' : '-'),
+               (Expected & PF_NX ? '-' : 'x'),
                (Expected & PF_PAGED ? 'p' : '-'),
                (Expected & PF_COW ? 'C' : '-'),
                (Expected & PF_USER ? 'U' : '-'),
@@ -286,13 +295,17 @@ void MM_int_DumpTablesEnt(tVAddr RangeStart, size_t Length, tPAddr Expected)
  */
 void MM_DumpTables(tVAddr Start, tVAddr End)
 {
-       const tPAddr    CHANGEABLE_BITS = ~(PF_PRESENT|PF_WRITE|PF_USER|PF_COW|PF_PAGED) & 0xFFF;
+       const tPAddr    FIXED_BITS = PF_PRESENT|PF_WRITE|PF_USER|PF_COW|PF_PAGED|PF_NX|PF_GLOBAL;
+       const tPAddr    CHANGEABLE_BITS = ~FIXED_BITS & 0xFFF;
        const tPAddr    MASK = ~CHANGEABLE_BITS;        // Physical address and access bits
        tVAddr  rangeStart = 0;
        tPAddr  expected = CHANGEABLE_BITS;     // CHANGEABLE_BITS is used because it's not a vaild value
        tVAddr  curPos;
        Uint    page;
-       
+       tPAddr  expected_pml4 = PF_WRITE|PF_USER;       
+       tPAddr  expected_pdp = PF_WRITE|PF_USER;        
+       tPAddr  expected_pd = PF_WRITE|PF_USER; 
+
        Log("Table Entries: (%p to %p)", Start, End);
        
        End &= (1L << 48) - 1;
@@ -310,13 +323,26 @@ void MM_DumpTables(tVAddr Start, tVAddr End)
                
                // End of a range
                if(!(PAGEMAPLVL4(page>>27) & PF_PRESENT)
+               ||  (PAGEMAPLVL4(page>>27) & FIXED_BITS) != expected_pml4
                || !(PAGEDIRPTR(page>>18) & PF_PRESENT)
+               ||  (PAGEDIRPTR(page>>18) & FIXED_BITS) != expected_pdp
                || !(PAGEDIR(page>>9) & PF_PRESENT)
+               ||  (PAGEDIR(page>>9) & FIXED_BITS) != expected_pd
                || !(PAGETABLE(page) & PF_PRESENT)
-               || (PAGETABLE(page) & MASK) != expected)
+               ||  (PAGETABLE(page) & MASK) != expected)
                {                       
                        if(expected != CHANGEABLE_BITS)
                        {
+                               // Merge
+                               expected &= expected_pml4 | ~(PF_WRITE|PF_USER);
+                               expected &= expected_pdp  | ~(PF_WRITE|PF_USER);
+                               expected &= expected_pd   | ~(PF_WRITE|PF_USER);
+                               expected |= expected_pml4 & PF_NX;
+                               expected |= expected_pdp  & PF_NX;
+                               expected |= expected_pd   & PF_NX;
+                               Log("expected (pml4 = %x, pdp = %x, pd = %x)",
+                                       expected_pml4, expected_pdp, expected_pd);
+                               // Dump
                                MM_int_DumpTablesEnt( rangeStart, curPos - rangeStart, expected );
                                expected = CHANGEABLE_BITS;
                        }
@@ -342,6 +368,9 @@ void MM_DumpTables(tVAddr Start, tVAddr End)
                        if( !(PAGETABLE(page) & PF_PRESENT) )   continue;
                        
                        expected = (PAGETABLE(page) & MASK);
+                       expected_pml4 = (PAGEMAPLVL4(page>>27) & FIXED_BITS);
+                       expected_pdp  = (PAGEDIRPTR (page>>18) & FIXED_BITS);
+                       expected_pd   = (PAGEDIR    (page>> 9) & FIXED_BITS);
                        rangeStart = curPos;
                }
                if(gMM_ZeroPage && (expected & PADDR_MASK) == gMM_ZeroPage )
@@ -351,6 +380,9 @@ void MM_DumpTables(tVAddr Start, tVAddr End)
        }
        
        if(expected != CHANGEABLE_BITS) {
+               // Merge
+               
+               // Dump
                MM_int_DumpTablesEnt( rangeStart, curPos - rangeStart, expected );
                expected = 0;
        }
@@ -413,8 +445,8 @@ int MM_GetPageEntryPtr(tVAddr Addr, BOOL bTemp, BOOL bAllocate, BOOL bLargePage,
                                *ent |= PF_USER;
                        INVLPG( &pmlevels[i+1][ (Addr>>size)*512 ] );
                        memset( &pmlevels[i+1][ (Addr>>size)*512 ], 0, 0x1000 );
-                       LOG("Init PML%i ent 0x%x %p with %P", 4 - i,
-                               Addr>>size, (Addr>>size) << size, tmp);
+                       LOG("Init PML%i ent 0x%x %p with %P (*ent = %P)", 4 - i,
+                               Addr>>size, (Addr>>size) << size, tmp, *ent);
                }
                // Catch large pages
                else if( *ent & PF_LARGE )
@@ -633,6 +665,7 @@ void MM_SetFlags(tVAddr VAddr, Uint Flags, Uint Mask)
                if( Flags & MM_PFLAG_COW ) {
                        *ent &= ~PF_WRITE;
                        *ent |= PF_COW;
+       INVLPG_ALL();
                }
                else {
                        *ent &= ~PF_COW;
@@ -875,18 +908,28 @@ tPAddr MM_Clone(void)
        INVLPG_ALL();
        
        // #3 Set Copy-On-Write to all user pages
-       for( i = 0; i < 256; i ++)
+       if( Threads_GetPID() != 0 )
        {
-               if( PAGEMAPLVL4(i) & PF_WRITE ) {
-                       PAGEMAPLVL4(i) |= PF_COW;
-                       PAGEMAPLVL4(i) &= ~PF_WRITE;
+               for( i = 0; i < 256; i ++)
+               {
+                       if( PAGEMAPLVL4(i) & PF_WRITE ) {
+                               PAGEMAPLVL4(i) |= PF_COW;
+                               PAGEMAPLVL4(i) &= ~PF_WRITE;
+                       }
+       
+                       TMPMAPLVL4(i) = PAGEMAPLVL4(i);
+//                     Log_Debug("MM", "TMPMAPLVL4(%i) = 0x%016llx", i, TMPMAPLVL4(i));
+                       if( !(TMPMAPLVL4(i) & PF_PRESENT) )     continue ;
+                       
+                       MM_RefPhys( TMPMAPLVL4(i) & PADDR_MASK );
+               }
+       }
+       else
+       {
+               for( i = 0; i < 256; i ++ )
+               {
+                       TMPMAPLVL4(i) = 0;
                }
-
-               TMPMAPLVL4(i) = PAGEMAPLVL4(i);
-//             Log_Debug("MM", "TMPMAPLVL4(%i) = 0x%016llx", i, TMPMAPLVL4(i));
-               if( !(TMPMAPLVL4(i) & PF_PRESENT) )     continue ;
-               
-               MM_RefPhys( TMPMAPLVL4(i) & PADDR_MASK );
        }
        
        // #4 Map in kernel pages
@@ -981,11 +1024,13 @@ void MM_ClearUser(void)
 tVAddr MM_NewWorkerStack(void *StackData, size_t StackSize)
 {
        tVAddr  ret;
+       tPAddr  phys;
         int    i;
        
        // #1 Set temp fractal to PID0
        Mutex_Acquire(&glMM_TempFractalLock);
        TMPCR3() = ((tPAddr)gInitialPML4 - KERNEL_BASE) | 3;
+       INVLPG_ALL();
        
        // #2 Scan for a free stack addresss < 2^47
        for(ret = 0x100000; ret < (1ULL << 47); ret += KERNEL_STACK_SIZE)
@@ -1000,31 +1045,35 @@ tVAddr MM_NewWorkerStack(void *StackData, size_t StackSize)
        }
        
        // #3 Map all save the last page in the range
-       //    - This acts as as guard page, and doesn't cost us anything.
+       //  - This acts as as guard page
+       MM_GetPageEntryPtr(ret, 1, 1, 0, NULL); // Make sure tree is allocated
        for( i = 0; i < KERNEL_STACK_SIZE/0x1000 - 1; i ++ )
        {
-               tPAddr  phys = MM_AllocPhys();
+               phys = MM_AllocPhys();
                if(!phys) {
                        // TODO: Clean up
                        Log_Error("MM", "MM_NewWorkerStack - Unable to allocate page");
                        return 0;
                }
                MM_MapEx(ret + i*0x1000, phys, 1, 0);
+               MM_SetFlags(ret + i*0x1000, MM_PFLAG_KERNEL|MM_PFLAG_RO, MM_PFLAG_KERNEL);
        }
 
+       // Copy data
        if( StackSize > 0x1000 ) {
                Log_Error("MM", "MM_NewWorkerStack: StackSize(0x%x) > 0x1000, cbf handling", StackSize);
        }
        else {
-               tPAddr  *ptr, paddr;
-               tVAddr  tmp_addr;
-               MM_GetPageEntryPtr(ret + i*0x1000, 1, 0, 0, &ptr);
-               paddr = *ptr & ~0xFFF;
-               tmp_addr = MM_MapTemp(paddr);
-               memcpy( (void*)(tmp_addr + (0x1000 - StackSize)), StackData, StackSize );
+               tVAddr  tmp_addr, dest;
+               tmp_addr = MM_MapTemp(phys);
+               dest = tmp_addr + (0x1000 - StackSize);
+               memcpy( (void*)dest, StackData, StackSize );
+               Log_Debug("MM", "MM_NewWorkerStack: %p->%p %i bytes (i=%i)", StackData, dest, StackSize, i);
+               Log_Debug("MM", "MM_NewWorkerStack: ret = %p", ret);
                MM_FreeTemp(tmp_addr);
        }
-       
+
+       TMPCR3() = 0;
        Mutex_Release(&glMM_TempFractalLock);
        
        return ret + i*0x1000;
index db22a16..f540b3b 100644 (file)
@@ -14,29 +14,14 @@ GetRIP:
 
 [global NewTaskHeader]
 NewTaskHeader:
-       mov rax, [rsp]
-       mov dr0, rax
-       
-       sti
-       mov al, 0x20
-       mov dx, 0x20
-       out dx, al
+       ; [rsp+0x00]: Thread
+       ; [rsp+0x08]: Function
+       ; [rsp+0x10]: Argument
 
-       mov rdi, [rsp+0x18]
-       dec QWORD [rsp+0x10]
-       jz .call
-       mov rsi, [rsp+0x20]
-       dec QWORD [rsp+0x10]
-       jz .call
-       mov rdx, [rsp+0x28]
-       dec QWORD [rsp+0x10]
-       jz .call
-       mov rcx, [rsp+0x30]
-       dec QWORD [rsp+0x10]
-       jz .call
-.call:
+       mov rdi, [rsp+0x10]
        mov rax, [rsp+0x8]
-;      xchg bx, bx
+       add rsp, 0x10   ; Reclaim stack space (thread/fcn)
+       xchg bx, bx
        call rax
        
        ; Quit thread with RAX as the return code
@@ -113,6 +98,7 @@ SwitchTasks:
        mov cr3, r8
        
        ; Make sure the stack is valid before jumping
+       invlpg [rdi-0x1000]
        invlpg [rdi]
        invlpg [rdi+0x1000]
        
index 3594552..5f71a45 100644 (file)
@@ -49,6 +49,7 @@ extern int    giNextTID;
 extern int     giTotalTickets;
 extern int     giNumActiveThreads;
 extern tThread gThreadZero;
+extern tProcess        gProcessZero;
 extern void    Threads_Dump(void);
 extern void    Proc_ReturnToUser(tVAddr Handler, tVAddr KStackTop, int Argument);
 extern void    Time_UpdateTimestamp(void);
@@ -310,7 +311,7 @@ void ArchThreads_Init(void)
        
        gaCPUs[0].Current = &gThreadZero;
        
-       gThreadZero.MemState.CR3 = (Uint)gInitialPML4 - KERNEL_BASE;
+       gProcessZero.MemState.CR3 = (Uint)gInitialPML4 - KERNEL_BASE;
        gThreadZero.CurCPU = 0;
        gThreadZero.KernelStack = 0xFFFFA00000000000 + KERNEL_STACK_SIZE;
        
@@ -405,6 +406,7 @@ void Proc_Start(void)
        
        // BSP still should run the current task
        gaCPUs[0].Current = &gThreadZero;
+       __asm__ __volatile__ ("mov %0, %%db0" : : "r"(&gThreadZero));
        
        // Start interrupts and wait for APs to come up
        Log("Waiting for APs to come up\n");
@@ -427,24 +429,30 @@ void Proc_Start(void)
 tThread *Proc_GetCurThread(void)
 {
        #if USE_MP
-       return gaCPUs[ GetCPUNum() ].Current;
+       tThread *ret;
+       __asm__ __volatile__ ("mov %%db0, %0" : "=r"(thread));
+       return ret;     // gaCPUs[ GetCPUNum() ].Current;
        #else
        return gaCPUs[ 0 ].Current;
        #endif
 }
 
+void Proc_ClearProcess(tProcess *Process)
+{
+       Log_Warning("Proc", "TODO: Nuke address space etc");
+}
+
 /*
  * 
  */
 void Proc_ClearThread(tThread *Thread)
 {
-       Log_Warning("Proc", "TODO: Nuke address space etc");
 }
 
 /**
  * \brief Create a new kernel thread
  */
-int Proc_NewKThread(void (*Fcn)(void*), void *Data)
+tTID Proc_NewKThread(void (*Fcn)(void*), void *Data)
 {
        Uint    rsp;
        tThread *newThread, *cur;
@@ -453,9 +461,6 @@ int Proc_NewKThread(void (*Fcn)(void*), void *Data)
        newThread = Threads_CloneTCB(0);
        if(!newThread)  return -1;
        
-       // Set CR3
-       newThread->MemState.CR3 = cur->MemState.CR3;
-
        // Create new KStack
        newThread->KernelStack = MM_NewKStack();
        // Check for errors
@@ -466,7 +471,6 @@ int Proc_NewKThread(void (*Fcn)(void*), void *Data)
 
        rsp = newThread->KernelStack;
        *(Uint*)(rsp-=8) = (Uint)Data;  // Data (shadowed)
-       *(Uint*)(rsp-=8) = 1;   // Number of params
        *(Uint*)(rsp-=8) = (Uint)Fcn;   // Function to call
        *(Uint*)(rsp-=8) = (Uint)newThread;     // Thread ID
        
@@ -485,7 +489,7 @@ int Proc_NewKThread(void (*Fcn)(void*), void *Data)
  * \fn int Proc_Clone(Uint Flags)
  * \brief Clone the current process
  */
-int Proc_Clone(Uint Flags)
+tTID Proc_Clone(Uint Flags)
 {
        tThread *newThread, *cur = Proc_GetCurThread();
        Uint    rip;
@@ -501,7 +505,7 @@ int Proc_Clone(Uint Flags)
        if(!newThread)  return -1;
        
        // Save core machine state
-       rip = Proc_CloneInt(&newThread->SavedState.RSP, &newThread->MemState.CR3);
+       rip = Proc_CloneInt(&newThread->SavedState.RSP, &newThread->Process->MemState.CR3);
        if(rip == 0)    return 0;       // Child
        newThread->KernelStack = cur->KernelStack;
        newThread->SavedState.RIP = rip;
@@ -531,28 +535,24 @@ int Proc_Clone(Uint Flags)
 int Proc_SpawnWorker(void (*Fcn)(void*), void *Data)
 {
        tThread *new, *cur;
-       Uint    stack_contents[4];
+       Uint    stack_contents[3];
 
        cur = Proc_GetCurThread();
        
        // Create new thread
-       new = malloc( sizeof(tThread) );
+       new = Threads_CloneThreadZero();
        if(!new) {
                Warning("Proc_SpawnWorker - Out of heap space!\n");
                return -1;
        }
-       memcpy(new, &gThreadZero, sizeof(tThread));
-       // Set Thread ID
-       new->TID = giNextTID++;
 
        // Create the stack contents
-       stack_contents[3] = (Uint)Data;
-       stack_contents[2] = 1;
+       stack_contents[2] = (Uint)Data;
        stack_contents[1] = (Uint)Fcn;
        stack_contents[0] = (Uint)new;
        
        // Create a new worker stack (in PID0's address space)
-       // The stack is relocated by this code
+       // - The stack is built by this code using stack_contents
        new->KernelStack = MM_NewWorkerStack(stack_contents, sizeof(stack_contents));
 
        new->SavedState.RSP = new->KernelStack - sizeof(stack_contents);
@@ -586,10 +586,12 @@ Uint Proc_MakeUserStack(void)
        if(i != -1)     return 0;
        
        // Allocate Stack - Allocate incrementally to clean up MM_Dump output
+       // - Most of the user stack is the zero page
        for( i = 0; i < (USER_STACK_SZ-USER_STACK_PREALLOC)/0x1000; i++ )
        {
                MM_AllocateZero( base + (i<<12) );
        }
+       // - but the top USER_STACK_PREALLOC pages are actually allocated
        for( ; i < USER_STACK_SZ/0x1000; i++ )
        {
                tPAddr  alloc = MM_Allocate( base + (i<<12) );
@@ -606,11 +608,11 @@ Uint Proc_MakeUserStack(void)
        return base + USER_STACK_SZ;
 }
 
-void Proc_StartUser(Uint Entrypoint, Uint Base, int ArgC, char **ArgV, int DataSize)
+void Proc_StartUser(Uint Entrypoint, Uint Base, int ArgC, const char **ArgV, int DataSize)
 {
        Uint    *stack;
         int    i;
-       char    **envp = NULL;
+       const char      **envp = NULL;
        Uint16  ss, cs;
        
        
@@ -628,7 +630,7 @@ void Proc_StartUser(Uint Entrypoint, Uint Base, int ArgC, char **ArgV, int DataS
        if(DataSize)
        {
                Uint    delta = (Uint)stack - (Uint)ArgV;
-               ArgV = (char**)stack;
+               ArgV = (const char**)stack;
                for( i = 0; ArgV[i]; i++ )      ArgV[i] += delta;
                envp = &ArgV[i+1];
                for( i = 0; envp[i]; i++ )      envp[i] += delta;
@@ -744,7 +746,7 @@ void Proc_Reschedule(void)
 
        #if DEBUG_TRACE_SWITCH
        LogF("\nSwitching to task CR3 = 0x%x, RIP = %p, RSP = %p - %i (%s)\n",
-               nextthread->MemState.CR3,
+               nextthread->Process->MemState.CR3,
                nextthread->SavedState.RIP,
                nextthread->SavedState.RSP,
                nextthread->TID,
@@ -757,19 +759,30 @@ void Proc_Reschedule(void)
        gTSSs[cpu].RSP0 = nextthread->KernelStack-4;
        __asm__ __volatile__ ("mov %0, %%db0" : : "r" (nextthread));
 
-       // Save FPU/MMX/XMM/SSE state
-       if( curthread->SavedState.SSE )
+       if( curthread )
+       {
+               // Save FPU/MMX/XMM/SSE state
+               if( curthread->SavedState.SSE )
+               {
+                       Proc_SaveSSE( ((Uint)curthread->SavedState.SSE + 0xF) & ~0xF );
+                       curthread->SavedState.bSSEModified = 0;
+                       Proc_DisableSSE();
+               }
+               SwitchTasks(
+                       nextthread->SavedState.RSP, &curthread->SavedState.RSP,
+                       nextthread->SavedState.RIP, &curthread->SavedState.RIP,
+                       nextthread->Process->MemState.CR3
+                       );
+       }
+       else
        {
-               Proc_SaveSSE( ((Uint)curthread->SavedState.SSE + 0xF) & ~0xF );
-               curthread->SavedState.bSSEModified = 0;
-               Proc_DisableSSE();
+               Uint    tmp;
+               SwitchTasks(
+                       nextthread->SavedState.RSP, &tmp,
+                       nextthread->SavedState.RIP, &tmp,
+                       nextthread->Process->MemState.CR3
+                       );
        }
-
-       SwitchTasks(
-               nextthread->SavedState.RSP, &curthread->SavedState.RSP,
-               nextthread->SavedState.RIP, &curthread->SavedState.RIP,
-               nextthread->MemState.CR3
-               );
        return ;
 }
 
@@ -780,7 +793,6 @@ void Proc_Reschedule(void)
 void Proc_Scheduler(int CPU, Uint RSP, Uint RIP)
 {
 #if 0
-       {
        tThread *thread;
 
        // If the spinlock is set, let it complete
@@ -808,7 +820,6 @@ void Proc_Scheduler(int CPU, Uint RSP, Uint RIP)
        // ACK Timer here?
 
        Proc_Reschedule();
-       }
 #endif
 }
 
index b63b63a..c8e7f9a 100644 (file)
@@ -50,10 +50,7 @@ start64:
 
 [global GetCPUNum]
 GetCPUNum:
-       xor rax, rax
-       str ax
-       sub ax, 0x38    ; TSS Base
-       shr ax, 4       ; One 16-byte TSS per CPU
+       mov rax, dr1
        ret
 
 KSTACK_USERSTATE_SIZE  equ     (5+2+16+2)*8    ; IRET, ErrorNum, ErrorCode, GPRs, FS&GS
index 20da5c4..5213bf2 100644 (file)
@@ -7,6 +7,7 @@
 #include <binary.h>
 #include <mm_virt.h>
 #include <hal_proc.h>
+#include <vfs_threads.h>
 
 // === CONSTANTS ===
 #define BIN_LOWEST     MM_USER_MIN             // 1MiB
@@ -30,7 +31,7 @@ extern tKernelSymbol  gKernelSymbolsEnd[];
 extern tBinaryType     gELF_Info;
 
 // === PROTOTYPES ===
- int   Proc_Execve(const char *File, const char **ArgV, const char **EnvP);
+ int   Binary_int_CacheArgs(const char **Path, const char ***ArgV, const char ***EnvP, void *DestBuffer);
 tVAddr Binary_Load(const char *Path, tVAddr *EntryPoint);
 tBinary        *Binary_GetInfo(tMount MountID, tInode InodeID);
 tVAddr Binary_MapIn(tBinary *Binary, const char *Path, tVAddr LoadMin, tVAddr LoadMax);
@@ -78,18 +79,129 @@ int Proc_Spawn(const char *Path)
        
        LOG("stackPath = '%s'", stackPath);
        
-       if(Proc_Clone(CLONE_VM) == 0)
+       if(Proc_Clone(CLONE_VM|CLONE_NOUSER) == 0)
        {
                // CHILD
                const char      *args[2] = {stackPath, NULL};
                LOG("stackPath = '%s'", stackPath);
-               Proc_Execve(stackPath, args, &args[1]);
+               Proc_Execve(stackPath, args, &args[1], 0);
                for(;;);
        }
        LEAVE('i', 0);
        return 0;
 }
 
+/**
+ * \todo Document
+ */
+int Binary_int_CacheArgs(const char **Path, const char ***ArgV, const char ***EnvP, void *DestBuffer)
+{
+        int    size, argc=0, envc=0;
+        int    i;
+       char    *strbuf;
+       const char      **arrays;
+       
+       // Calculate size
+       size = 0;
+       if( ArgV && *ArgV )
+       {
+               const char      **argv = *ArgV;
+               for( argc = 0; argv[argc]; argc ++ )
+                       size += strlen( argv[argc] ) + 1;
+       }
+       if( EnvP && *EnvP )
+       {
+               const char      **envp = *EnvP;
+               for( envc = 0; envp[envc]; envc ++ )
+                       size += strlen( envp[envc] ) + 1;
+       }
+       size = (size + sizeof(void*)-1) & ~(sizeof(void*)-1);   // Word align
+       size += (argc+1+envc+1)*sizeof(void*);  // Arrays
+       if( Path )
+       {
+               size += strlen( *Path ) + 1;
+       }
+
+       if( DestBuffer )        
+       {
+               arrays = DestBuffer;
+               strbuf = (void*)&arrays[argc+1+envc+1];
+       
+               // Fill ArgV
+               if( ArgV && *ArgV )
+               {
+                       const char      **argv = *ArgV;
+                       for( i = 0; argv[i]; i ++ )
+                       {
+                               arrays[i] = strbuf;
+                               strcpy(strbuf, argv[i]);
+                               strbuf += strlen( argv[i] ) + 1;
+                       }
+                       *ArgV = arrays;
+                       arrays += i;
+               }
+               *arrays++ = NULL;
+               // Fill EnvP
+               if( EnvP && *EnvP )
+               {
+                       const char      **envp = *EnvP;
+                       for( i = 0; envp[i]; i ++ )
+                       {
+                               arrays[i] = strbuf;
+                               strcpy(strbuf, envp[i]);
+                               strbuf += strlen( envp[i] ) + 1;
+                       }
+                       *EnvP = arrays;
+                       arrays += i;
+               }
+               *arrays++ = NULL;
+               // Fill path
+               if( Path )
+               {
+                       strcpy(strbuf, *Path);
+                       *Path = strbuf;
+               }
+       }
+       
+       return size;
+}
+
+/**
+ * \brief Create a new process with the specified set of file descriptors
+ */
+int Proc_SysSpawn(const char *Binary, const char **ArgV, const char **EnvP, int nFD, int *FDs)
+{
+       void    *handles;
+       void    *cachebuf;
+        int    size;
+       tPID    ret;
+       
+       // --- Save File, ArgV and EnvP
+       size = Binary_int_CacheArgs( &Binary, &ArgV, &EnvP, NULL );
+       cachebuf = malloc( size );
+       Binary_int_CacheArgs( &Binary, &ArgV, &EnvP, cachebuf );
+
+       // Cache the VFS handles        
+       handles = VFS_SaveHandles(nFD, FDs);
+
+       // Create new process   
+       ret = Proc_Clone(CLONE_VM|CLONE_NOUSER);
+       if( ret == 0 )
+       {
+               VFS_RestoreHandles(nFD, handles);
+               VFS_FreeSavedHandles(nFD, handles);
+               // Frees cachebuf
+               Proc_Execve(Binary, ArgV, EnvP, size);
+               for(;;);
+       }
+       if( ret < 0 )
+       {
+               VFS_FreeSavedHandles(nFD, handles);
+       }
+       
+       return ret;
+}
+
 /**
  * \brief Replace the current user image with another
  * \param File File to load as the next image
@@ -97,87 +209,56 @@ int Proc_Spawn(const char *Path)
  * \param EnvP User's environment
  * \note Called Proc_ for historical reasons
  */
-int Proc_Execve(const char *File, const char **ArgV, const char **EnvP)
+int Proc_Execve(const char *File, const char **ArgV, const char **EnvP, int DataSize)
 {
-        int    argc, envc, i;
-        int    argenvBytes;
-       char    **argenvBuf, *strBuf;
-       char    **argvSaved, **envpSaved;
-       char    *savedFile;
+       void    *cachebuf;
        tVAddr  entry;
        Uint    base;   // Uint because Proc_StartUser wants it
+        int    argc;
        
        ENTER("sFile pArgV pEnvP", File, ArgV, EnvP);
        
-       // --- Save File, ArgV and EnvP (also get argc)
-       
-       // Count Arguments, Environment Variables and total string sizes
-       argenvBytes = 0;
-       for( argc = 0; ArgV && ArgV[argc]; argc++ )
-               argenvBytes += strlen(ArgV[argc])+1;
-       for( envc = 0; EnvP && EnvP[envc]; envc++ )
-               argenvBytes += strlen(EnvP[envc])+1;
-       LOG("argc = %i, envc = %i", envc);
-       argenvBytes = (argenvBytes + sizeof(void*)-1) & ~(sizeof(void*)-1);
-       argenvBytes += (argc+1)*sizeof(void*) + (envc+1)*sizeof(void*);
-       
-       // Allocate
-       argenvBuf = malloc(argenvBytes);
-       if(argenvBuf == NULL) {
-               Log_Error("Binary", "Proc_Execve - What the hell? The kernel is out of heap space");
-               LEAVE('i', 0);
-               return 0;
-       }
-       strBuf = (char*)argenvBuf + (argc+1)*sizeof(void*) + (envc+1)*sizeof(void*);
-       
-       // Populate
-       argvSaved = argenvBuf;
-       for( i = 0; i < argc; i++ )
-       {
-               argvSaved[i] = strBuf;
-               strcpy(argvSaved[i], ArgV[i]);
-               LOG("argv[%i] = '%s'", i, strBuf);
-               strBuf += strlen(ArgV[i])+1;
-       }
-       argvSaved[i] = NULL;
-       envpSaved = &argvSaved[i+1];
-       for( i = 0; i < envc; i++ )
+       // --- Save File, ArgV and EnvP
+       if( DataSize == 0 )
        {
-               envpSaved[i] = strBuf;
-               LOG("envp[%i] = '%s'", i, strBuf);
-               strcpy(envpSaved[i], EnvP[i]);
-               strBuf += strlen(EnvP[i])+1;
+               DataSize = Binary_int_CacheArgs( &File, &ArgV, &EnvP, NULL );
+               cachebuf = malloc( DataSize );
+               Binary_int_CacheArgs( &File, &ArgV, &EnvP, cachebuf );
        }
-       envpSaved[i] = NULL;
-       
-       savedFile = malloc(strlen(File)+1);
-       strcpy(savedFile, File);
+
+       // --- Get argc 
+       for( argc = 0; ArgV && ArgV[argc]; argc ++ );
        
        // --- Set Process Name
        Threads_SetName(File);
        
        // --- Clear User Address space
-       MM_ClearUser();
+       // NOTE: This is a little roundabout, maybe telling ClearUser to not touch the
+       //       PPD area would be a better idea.
+       {
+                int    nfd = *Threads_GetMaxFD();
+               void    *handles;
+               handles = VFS_SaveHandles(nfd, NULL);
+               VFS_CloseAllUserHandles();
+               MM_ClearUser();
+               VFS_RestoreHandles(nfd, handles);
+               VFS_FreeSavedHandles(nfd, handles);
+       }
        
        // --- Load new binary
-       base = Binary_Load(savedFile, &entry);
-       free(savedFile);
+       base = Binary_Load(File, &entry);
        if(base == 0)
        {
-               free(argvSaved);
-               Log_Warning("Binary", "Proc_Execve - Unable to load '%s'", Threads_GetName(-1));
+               Log_Warning("Binary", "Proc_Execve - Unable to load '%s'", File);
                LEAVE('-');
                Threads_Exit(0, -10);
                for(;;);
        }
        
        LOG("entry = 0x%x, base = 0x%x", entry, base);
-
-//     MM_DumpTables(0, KERNEL_BASE);
-
        LEAVE('-');
        // --- And... Jump to it
-       Proc_StartUser(entry, base, argc, argvSaved, argenvBytes);
+       Proc_StartUser(entry, base, argc, ArgV, DataSize);
        for(;;);        // Tell GCC that we never return
 }
 
index b27c678..0779a60 100644 (file)
@@ -1,6 +1,7 @@
 /* AcessOS
  * FIFO Pipe Driver
  */
+#define DEBUG  0
 #include <acess.h>
 #include <modules.h>
 #include <fs_devfs.h>
@@ -28,14 +29,30 @@ typedef struct sPipe {
 char   *FIFO_ReadDir(tVFS_Node *Node, int Id);
 tVFS_Node      *FIFO_FindDir(tVFS_Node *Node, const char *Filename);
  int   FIFO_MkNod(tVFS_Node *Node, const char *Name, Uint Flags);
+void   FIFO_Reference(tVFS_Node *Node);
 void   FIFO_Close(tVFS_Node *Node);
  int   FIFO_Relink(tVFS_Node *Node, const char *OldName, const char *NewName);
 Uint64 FIFO_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
-Uint64 FIFO_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+Uint64 FIFO_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer);
 tPipe  *FIFO_Int_NewPipe(int Size, const char *Name);
 
 // === GLOBALS ===
 MODULE_DEFINE(0, 0x0032, FIFO, FIFO_Install, NULL, NULL);
+tVFS_NodeType  gFIFO_DirNodeType = {
+       .TypeName = "FIFO Dir Node",
+       .ReadDir = FIFO_ReadDir,
+       .FindDir = FIFO_FindDir,
+       .MkNod = FIFO_MkNod,
+       .Relink = FIFO_Relink,
+       .IOCtl = FIFO_IOCtl
+};
+tVFS_NodeType  gFIFO_PipeNodeType = {
+       .TypeName = "FIFO Pipe Node",
+       .Read = FIFO_Read,
+       .Write = FIFO_Write,
+       .Close = FIFO_Close,
+       .Reference = FIFO_Reference
+};
 tDevFS_Driver  gFIFO_DriverInfo = {
        NULL, "fifo",
        {
@@ -43,11 +60,7 @@ tDevFS_Driver        gFIFO_DriverInfo = {
        .NumACLs = 1,
        .ACLs = &gVFS_ACL_EveryoneRW,
        .Flags = VFS_FFLAG_DIRECTORY,
-       .ReadDir = FIFO_ReadDir,
-       .FindDir = FIFO_FindDir,
-       .MkNod = FIFO_MkNod,
-       .Relink = FIFO_Relink,
-       .IOCtl = FIFO_IOCtl
+       .Type = &gFIFO_DirNodeType
        }
 };
 tVFS_Node      gFIFO_AnonNode = {
@@ -134,6 +147,13 @@ int FIFO_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
        return 0;
 }
 
+void FIFO_Reference(tVFS_Node *Node)
+{
+       if(!Node->ImplPtr)      return ;
+       
+       Node->ReferenceCount ++;
+}
+
 /**
  * \fn void FIFO_Close(tVFS_Node *Node)
  * \brief Close a FIFO end
@@ -149,6 +169,7 @@ void FIFO_Close(tVFS_Node *Node)
        pipe = Node->ImplPtr;
        
        if(strcmp(pipe->Name, "anon") == 0) {
+               Log_Debug("FIFO", "Pipe %p closed", Node->ImplPtr);
                free(Node->ImplPtr);
                return ;
        }
@@ -213,37 +234,44 @@ Uint64 FIFO_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
        tPipe   *pipe = Node->ImplPtr;
        Uint    len;
        Uint    remaining = Length;
-       
+
        if(!pipe)       return 0;
        
+       ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
+       
        while(remaining)
        {
                // Wait for buffer to fill
                if(pipe->Flags & PF_BLOCKING)
                {
-                       #if 0
-                       len = Semaphore_Wait( &pipe->Semaphore, remaining );
-                       #else
-                       VFS_SelectNode(Node, VFS_SELECT_READ, NULL, "FIFO_Read");
-                       // Read buffer
-                       // TODO: Rethink this, it might not work on buffer overflow
-                       if(pipe->WritePos - pipe->ReadPos < remaining)
-                               len = pipe->WritePos - pipe->ReadPos;
-                       else
-                               len = remaining;
-                       #endif
+                       if( pipe->ReadPos == pipe->WritePos )
+                               VFS_SelectNode(Node, VFS_SELECT_READ, NULL, "FIFO_Read");
+                       
                }
                else
                {
                        if(pipe->ReadPos == pipe->WritePos)
+                       {
+                               VFS_MarkAvaliable(Node, 0);
+                               LEAVE('i', 0);
                                return 0;
-                       // Read buffer
-                       if(pipe->WritePos - pipe->ReadPos < remaining)
-                               len = pipe->WritePos - pipe->ReadPos;
-                       else
-                               len = remaining;
+                       }
                }
-               
+       
+               len = remaining;
+               if( pipe->ReadPos < pipe->WritePos )
+               {
+                        int    avail_bytes = pipe->WritePos - pipe->ReadPos;
+                       if( avail_bytes < remaining )   len = avail_bytes;
+               }
+               else
+               {
+                        int    avail_bytes = pipe->WritePos + pipe->BufSize - pipe->ReadPos;
+                       if( avail_bytes < remaining )   len = avail_bytes;
+               }
+
+               LOG("len = %i, remaining = %i", len, remaining);                
+
                // Check if read overflows buffer
                if(len > pipe->BufSize - pipe->ReadPos)
                {
@@ -270,8 +298,13 @@ Uint64 FIFO_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
                remaining -= len;
                // Increment Buffer address
                Buffer = (Uint8*)Buffer + len;
+               
+               // TODO: Option to read differently
+               LEAVE('i', len);
+               return len;
        }
 
+       LEAVE('i', Length);
        return Length;
 
 }
@@ -280,32 +313,42 @@ Uint64 FIFO_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
  * \fn Uint64 FIFO_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
  * \brief Write to a fifo pipe
  */
-Uint64 FIFO_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+Uint64 FIFO_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
 {
        tPipe   *pipe = Node->ImplPtr;
        Uint    len;
        Uint    remaining = Length;
        
        if(!pipe)       return 0;
+
+       ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
        
        while(remaining)
        {
                // Wait for buffer to empty
                if(pipe->Flags & PF_BLOCKING) {
-                       #if 0
-                       len = Semaphore_Signal( &pipe->Semaphore, remaining );
-                       #else
-                       VFS_SelectNode(Node, VFS_SELECT_WRITE, NULL, "FIFO_Write");
-                       if(pipe->ReadPos - pipe->WritePos < remaining)
-                               len = pipe->ReadPos - pipe->WritePos;
+                       if( pipe->ReadPos == (pipe->WritePos+1)%pipe->BufSize )
+                               VFS_SelectNode(Node, VFS_SELECT_WRITE, NULL, "FIFO_Write");
+
+                       len = remaining;
+                       if( pipe->ReadPos > pipe->WritePos )
+                       {
+                                int    rem_space = pipe->ReadPos - pipe->WritePos;
+                               if(rem_space < remaining)       len = rem_space;
+                       }
                        else
-                               len = remaining;
-                       #endif
+                       {
+                                int    rem_space = pipe->ReadPos + pipe->BufSize - pipe->WritePos;
+                               if(rem_space < remaining)       len = rem_space;
+                       }
                }
                else
                {
                        if(pipe->ReadPos == (pipe->WritePos+1)%pipe->BufSize)
+                       {
+                               LEAVE('i', 0);
                                return 0;
+                       }
                        // Write buffer
                        if(pipe->ReadPos - pipe->WritePos < remaining)
                                len = pipe->ReadPos - pipe->WritePos;
@@ -341,6 +384,7 @@ Uint64 FIFO_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
                Buffer = (Uint8*)Buffer + len;
        }
 
+       LEAVE('i', Length);
        return Length;
 }
 
@@ -355,11 +399,10 @@ tPipe *FIFO_Int_NewPipe(int Size, const char *Name)
         int    namelen = strlen(Name) + 1;
         int    allocsize = sizeof(tPipe) + sizeof(tVFS_ACL) + Size + namelen;
        
-       ret = malloc(allocsize);
+       ret = calloc(1, allocsize);
        if(!ret)        return NULL;
        
        // Clear Return
-       memset(ret, 0, allocsize);
        ret->Flags = PF_BLOCKING;
        
        // Allocate Buffer
@@ -373,6 +416,7 @@ tPipe *FIFO_Int_NewPipe(int Size, const char *Name)
        //Semaphore_Init( &ret->Semaphore, 0, Size, "FIFO", ret->Name );
        
        // Set Node
+       ret->Node.ReferenceCount = 1;
        ret->Node.Size = 0;
        ret->Node.ImplPtr = ret;
        ret->Node.UID = Threads_GetUID();
@@ -386,9 +430,7 @@ tPipe *FIFO_Int_NewPipe(int Size, const char *Name)
        ret->Node.CTime
                = ret->Node.MTime
                = ret->Node.ATime = now();
-       ret->Node.Read = FIFO_Read;
-       ret->Node.Write = FIFO_Write;
-       ret->Node.Close = FIFO_Close;
+       ret->Node.Type = &gFIFO_PipeNodeType;
        
        return ret;
 }
index 7234296..8745080 100644 (file)
@@ -44,6 +44,15 @@ MODULE_DEFINE(0, 0x0100, PCI, PCI_Install, NULL, NULL);
  int   giPCI_InodeHandle = -1;\r
  int   giPCI_DeviceCount = 0;\r
 tPCIDevice     *gPCI_Devices = NULL;\r
+tVFS_NodeType  gPCI_RootNodeType = {\r
+       .TypeName = "PCI Root Node",\r
+       .ReadDir = PCI_int_ReadDirRoot,\r
+       .FindDir = PCI_int_FindDirRoot\r
+};\r
+tVFS_NodeType  gPCI_DevNodeType = {\r
+       .TypeName = "PCI Dev Node",\r
+       .Read = PCI_int_ReadDevice\r
+};\r
 tDevFS_Driver  gPCI_DriverStruct = {\r
        NULL, "pci",\r
        {\r
@@ -51,8 +60,7 @@ tDevFS_Driver gPCI_DriverStruct = {
        .Size = -1,\r
        .NumACLs = 1,\r
        .ACLs = &gVFS_ACL_EveryoneRX,\r
-       .ReadDir = PCI_int_ReadDirRoot,\r
-       .FindDir = PCI_int_FindDirRoot\r
+       .Type = &gPCI_RootNodeType\r
        }\r
 };\r
 Uint32 *gaPCI_PortBitmap = NULL;\r
@@ -473,7 +481,7 @@ int PCI_int_EnumDevice(Uint16 bus, Uint16 slot, Uint16 fcn, tPCIDevice *info)
        info->Node.NumACLs = 1;\r
        info->Node.ACLs = &gVFS_ACL_EveryoneRO;\r
        \r
-       info->Node.Read = PCI_int_ReadDevice;\r
+       info->Node.Type = &gPCI_RootNodeType;\r
        \r
        return 1;\r
 }\r
index 3283c86..73f4535 100644 (file)
@@ -40,6 +40,15 @@ void SysFS_Comm_CloseFile(tVFS_Node *Node);
 extern tSysFS_Ent      gSysFS_Version; // Defined Later
 extern tSysFS_Ent      gSysFS_Root;    // Defined Later
 MODULE_DEFINE(0, VERSION, SysFS, SysFS_Install, NULL, NULL);
+tVFS_NodeType  gSysFS_FileNodeType = {
+       .TypeName = "SysFS File",
+       .Read = SysFS_Comm_ReadFile
+       };
+tVFS_NodeType  gSysFS_DirNodeType = {
+       .TypeName = "SysFS Dir",
+       .ReadDir = SysFS_Comm_ReadDir,
+       .FindDir = SysFS_Comm_FindDir
+       };
 tSysFS_Ent     gSysFS_Version_Kernel = {
        NULL, NULL,     // Nexts
        &gSysFS_Version,        // Parent
@@ -50,7 +59,7 @@ tSysFS_Ent    gSysFS_Version_Kernel = {
                .Size = 0,
                .NumACLs = 1,
                .ACLs = &gVFS_ACL_EveryoneRO,
-               .Read = SysFS_Comm_ReadFile
+               .Type = &gSysFS_FileNodeType
        },
        "Kernel"
 };
@@ -64,8 +73,7 @@ tSysFS_Ent    gSysFS_Version = {
                .NumACLs = 1,
                .ACLs = &gVFS_ACL_EveryoneRX,
                .Flags = VFS_FFLAG_DIRECTORY,
-               .ReadDir = SysFS_Comm_ReadDir,
-               .FindDir = SysFS_Comm_FindDir
+               .Type = &gSysFS_DirNodeType
        },
        "Version"
 };
@@ -88,9 +96,7 @@ tDevFS_Driver gSysFS_DriverInfo = {
        .Flags = VFS_FFLAG_DIRECTORY,
        .ImplPtr = &gSysFS_Version,
        .Size = sizeof(gSysFS_Root)/sizeof(tSysFS_Ent),
-       .ReadDir = SysFS_Comm_ReadDir,
-       .FindDir = SysFS_Comm_FindDir,
-       .IOCtl = NULL
+       .Type = &gSysFS_DirNodeType
        }
 };
  int   giSysFS_NextFileID = 2;
@@ -158,8 +164,7 @@ int SysFS_RegisterFile(const char *Path, const char *Data, int Length)
                        child->Node.NumACLs = 1;
                        child->Node.ACLs = &gVFS_ACL_EveryoneRX;
                        child->Node.Flags = VFS_FFLAG_DIRECTORY;
-                       child->Node.ReadDir = SysFS_Comm_ReadDir;
-                       child->Node.FindDir = SysFS_Comm_FindDir;
+                       child->Node.Type = &gSysFS_DirNodeType;
                        if( !prev ) {
                                if(ent)
                                        ent->Node.ImplPtr = child;
@@ -212,8 +217,7 @@ int SysFS_RegisterFile(const char *Path, const char *Data, int Length)
        child->Node.Size = Length;
        child->Node.NumACLs = 1;
        child->Node.ACLs = &gVFS_ACL_EveryoneRO;
-       child->Node.Read = SysFS_Comm_ReadFile;
-       child->Node.Close = SysFS_Comm_CloseFile;
+       child->Node.Type = &gSysFS_FileNodeType;
        
        // Add to parent's child list
        if(ent) {
index e81f5e1..71c4d4a 100644 (file)
@@ -2,12 +2,11 @@
  * Acess2 Virtual Terminal Driver
  */
 #define DEBUG  0
-#include <acess.h>
+#include "vterm.h"
 #include <fs_devfs.h>
 #include <modules.h>
-#include <api_drv_video.h>
 #include <api_drv_keyboard.h>
-#include <api_drv_terminal.h>
+#include <api_drv_video.h>
 #include <errno.h>
 #include <semaphore.h>
 
@@ -15,8 +14,6 @@
 #define VERSION        ((0<<8)|(50))
 
 #define        NUM_VTS 8
-#define MAX_INPUT_CHARS32      64
-#define MAX_INPUT_CHARS8       (MAX_INPUT_CHARS32*4)
 //#define DEFAULT_OUTPUT       "BochsGA"
 #define DEFAULT_OUTPUT "Vesa"
 #define FALLBACK_OUTPUT        "x86_VGAText"
 #define        DEFAULT_HEIGHT  480
 #define DEFAULT_SCROLLBACK     2       // 2 Screens of text + current screen
 //#define DEFAULT_SCROLLBACK   0
-#define        DEFAULT_COLOUR  (VT_COL_BLACK|(0xAAA<<16))
-
-#define        VT_FLAG_HIDECSR 0x01
-#define        VT_FLAG_ALTBUF  0x02    //!< Alternate screen buffer
-#define VT_FLAG_RAWIN  0x04    //!< Don't handle ^Z/^C/^V
-#define        VT_FLAG_HASFB   0x10    //!< Set if the VTerm has requested the Framebuffer
-#define VT_FLAG_SHOWCSR        0x20    //!< Always show the text cursor
-
-enum eVT_InModes {
-       VT_INMODE_TEXT8,        // UTF-8 Text Mode (VT100/xterm Emulation)
-       VT_INMODE_TEXT32,       // UTF-32 Text Mode (Acess Native)
-       NUM_VT_INMODES
-};
 
 // === TYPES ===
-typedef struct {
-        int    Mode;   //!< Current Mode (see ::eTplTerminal_Modes)
-        int    Flags;  //!< Flags (see VT_FLAG_*)
-       
-       short   NewWidth;       //!< Un-applied dimensions (Width)
-       short   NewHeight;      //!< Un-applied dimensions (Height)
-       short   Width;  //!< Virtual Width
-       short   Height; //!< Virtual Height
-       short   TextWidth;      //!< Text Virtual Width
-       short   TextHeight;     //!< Text Virtual Height
-       
-       Uint32  CurColour;      //!< Current Text Colour
-       
-        int    ViewPos;        //!< View Buffer Offset (Text Only)
-        int    WritePos;       //!< Write Buffer Offset (Text Only)
-       tVT_Char        *Text;
-       
-       tVT_Char        *AltBuf;        //!< Alternate Screen Buffer
-        int    AltWritePos;    //!< Alternate write position
-       short   ScrollTop;      //!< Top of scrolling region (smallest)
-       short   ScrollHeight;   //!< Length of scrolling region
-
-        int    VideoCursorX;
-        int    VideoCursorY;
-       
-       tMutex  ReadingLock;    //!< Lock the VTerm when a process is reading from it
-       tTID    ReadingThread;  //!< Owner of the lock
-        int    InputRead;      //!< Input buffer read position
-        int    InputWrite;     //!< Input buffer write position
-       char    InputBuffer[MAX_INPUT_CHARS8];
-//     tSemaphore      InputSemaphore;
-       
-       Uint32          *Buffer;
-
-       // TODO: Do I need to keep this about?
-       // When should it be deallocated? on move to text mode, or some other time
-       // Call set again, it's freed, and if NULL it doesn't get reallocated.
-       tVideo_IOCtl_Bitmap     *VideoCursor;
-       
-       char    Name[2];        //!< Name of the terminal
-       tVFS_Node       Node;
-} tVTerm;
 
 // === IMPORTS ===
 extern void    Debug_SetKTerminal(const char *File);
 
 // === PROTOTYPES ===
  int   VT_Install(char **Arguments);
-void   VT_InitOutput(void);
-void   VT_InitInput(void);
 char   *VT_ReadDir(tVFS_Node *Node, int Pos);
 tVFS_Node      *VT_FindDir(tVFS_Node *Node, const char *Name);
  int   VT_Root_IOCtl(tVFS_Node *Node, int Id, void *Data);
 Uint64 VT_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
-Uint64 VT_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+Uint64 VT_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer);
  int   VT_Terminal_IOCtl(tVFS_Node *Node, int Id, void *Data);
-void   VT_SetResolution(int Width, int Height);
-void   VT_SetMode(int Mode);
-void   VT_SetTerminal(int ID);
-void   VT_KBCallBack(Uint32 Codepoint);
-void   VT_int_PutString(tVTerm *Term, Uint8 *Buffer, Uint Count);
-void   VT_int_ClearLine(tVTerm *Term, int Num);
-void   VT_int_ParseEscape_StandardLarge(tVTerm *Term, char CmdChar, int argc, int *args);
- int   VT_int_ParseEscape(tVTerm *Term, char *Buffer);
-void   VT_int_PutChar(tVTerm *Term, Uint32 Ch);
-void   VT_int_ScrollText(tVTerm *Term, int Count);
-void   VT_int_ScrollFramebuffer( tVTerm *Term, int Count );
-void   VT_int_UpdateCursor( tVTerm *Term, int bShow );
-void   VT_int_UpdateScreen( tVTerm *Term, int UpdateAll );
-void   VT_int_ChangeMode(tVTerm *Term, int NewMode, int NewWidth, int NewHeight);
-void   VT_int_ToggleAltBuffer(tVTerm *Term, int Enabled);
 
 // === CONSTANTS ===
-const Uint16   caVT100Colours[] = {
-               // Black, Red, Green, Yellow, Blue, Purple, Cyan, Gray
-               // Same again, but bright
-               VT_COL_BLACK, 0x700, 0x070, 0x770, 0x007, 0x707, 0x077, 0xAAA,
-               VT_COL_GREY, 0xF00, 0x0F0, 0xFF0, 0x00F, 0xF0F, 0x0FF, VT_COL_WHITE
-       };
 
 // === GLOBALS ===
 MODULE_DEFINE(0, VERSION, VTerm, VT_Install, NULL, NULL);
+tVFS_NodeType  gVT_RootNodeType = {
+       .TypeName = "VTerm Root",
+       .ReadDir = VT_ReadDir,
+       .FindDir = VT_FindDir,
+       .IOCtl = VT_Root_IOCtl
+       };
+tVFS_NodeType  gVT_TermNodeType = {
+       .TypeName = "VTerm",
+       .Read = VT_Read,
+       .Write = VT_Write,
+       .IOCtl = VT_Terminal_IOCtl
+       };
 tDevFS_Driver  gVT_DrvInfo = {
        NULL, "VTerm",
        {
@@ -129,9 +60,7 @@ tDevFS_Driver        gVT_DrvInfo = {
        .Size = NUM_VTS,
        .Inode = -1,
        .NumACLs = 0,
-       .ReadDir = VT_ReadDir,
-       .FindDir = VT_FindDir,
-       .IOCtl = VT_Root_IOCtl
+       .Type = &gVT_RootNodeType
        }
 };
 // --- Terminals ---
@@ -147,10 +76,6 @@ char        *gsVT_OutputDevice = NULL;
 char   *gsVT_InputDevice = NULL;
  int   giVT_OutputDevHandle = -2;
  int   giVT_InputDevHandle = -2;
-// --- Key States --- (Used for VT Switching/Magic Combos)
- int   gbVT_CtrlDown = 0;
- int   gbVT_AltDown = 0;
- int   gbVT_SysrqDown = 0;
 
 // === CODE ===
 /**
@@ -257,10 +182,8 @@ int VT_Install(char **Arguments)
                gVT_Terminals[i].Node.Inode = i;
                gVT_Terminals[i].Node.ImplPtr = &gVT_Terminals[i];
                gVT_Terminals[i].Node.NumACLs = 0;      // Only root can open virtual terminals
-               
-               gVT_Terminals[i].Node.Read = VT_Read;
-               gVT_Terminals[i].Node.Write = VT_Write;
-               gVT_Terminals[i].Node.IOCtl = VT_Terminal_IOCtl;
+       
+               gVT_Terminals[i].Node.Type = &gVT_TermNodeType; 
 //             Semaphore_Init(&gVT_Terminals[i].InputSemaphore, 0, MAX_INPUT_CHARS8, "VTerm", gVT_Terminals[i].Name);
        }
        
@@ -273,36 +196,6 @@ int VT_Install(char **Arguments)
        return MODULE_ERR_OK;
 }
 
-/**
- * \fn void VT_InitOutput()
- * \brief Initialise Video Output
- */
-void VT_InitOutput()
-{
-       giVT_OutputDevHandle = VFS_Open(gsVT_OutputDevice, VFS_OPENFLAG_WRITE);
-       if(giVT_OutputDevHandle == -1) {
-               Log_Warning("VTerm", "Oh F**k, I can't open the video device '%s'", gsVT_OutputDevice);
-               return ;
-       }
-       VT_SetResolution( giVT_RealWidth, giVT_RealHeight );
-       VT_SetTerminal( 0 );
-       VT_SetMode( VIDEO_BUFFMT_TEXT );
-}
-
-/**
- * \fn void VT_InitInput()
- * \brief Initialises the input
- */
-void VT_InitInput()
-{
-       giVT_InputDevHandle = VFS_Open(gsVT_InputDevice, VFS_OPENFLAG_READ);
-       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);
-}
-
 /**
  * \brief Set the video resolution
  * \param Width        New screen width
@@ -361,14 +254,6 @@ void VT_SetResolution(int Width, int Height)
        }
 }
 
-/**
- * \brief Set video output buffer mode
- */
-void VT_SetMode(int Mode)
-{
-       VFS_IOCtl( giVT_OutputDevHandle, VIDEO_IOCTL_SETBUFFORMAT, &Mode );
-}
-
 /**
  * \fn char *VT_ReadDir(tVFS_Node *Node, int Pos)
  * \brief Read from the VTerm Directory
@@ -531,10 +416,10 @@ Uint64 VT_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
 }
 
 /**
- * \fn Uint64 VT_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+ * \fn Uint64 VT_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
  * \brief Write to a virtual terminal
  */
-Uint64 VT_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+Uint64 VT_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
 {
        tVTerm  *term = &gVT_Terminals[ Node->Inode ];
         int    size;
@@ -880,1246 +765,3 @@ void VT_SetTerminal(int ID)
        // Update the screen
        VT_int_UpdateScreen(gpVT_CurTerm, 1);
 }
-
-/**
- * \fn void VT_KBCallBack(Uint32 Codepoint)
- * \brief Called on keyboard interrupt
- * \param Codepoint    Pseudo-UTF32 character
- * 
- * Handles a key press and sends the key code to the user's buffer.
- * If the code creates a kernel-magic sequence, it is not passed to the
- * user and is handled in-kernel.
- */
-void VT_KBCallBack(Uint32 Codepoint)
-{
-       tVTerm  *term = gpVT_CurTerm;
-
-       // Catch VT binds
-       switch( Codepoint & KEY_ACTION_MASK )
-       {
-       case KEY_ACTION_RELEASE:
-               switch(Codepoint & KEY_CODEPOINT_MASK)
-               {
-               case KEY_LALT:  gbVT_AltDown &= ~1;     break;
-               case KEY_RALT:  gbVT_AltDown &= ~2;     break;
-               case KEY_LCTRL: gbVT_CtrlDown &= ~1;    break;
-               case KEY_RCTRL: gbVT_CtrlDown &= ~2;    break;
-               }
-               break;
-       
-       case KEY_ACTION_PRESS:
-               switch(Codepoint & KEY_CODEPOINT_MASK)
-               {
-               case KEY_LALT:  gbVT_AltDown |= 1;      break;
-               case KEY_RALT:  gbVT_AltDown |= 2;      break;
-               case KEY_LCTRL: gbVT_CtrlDown |= 1;     break;
-               case KEY_RCTRL: gbVT_CtrlDown |= 2;     break;
-               }
-               
-               if(!gbVT_AltDown || !gbVT_CtrlDown)
-                       break;
-               switch(Codepoint & KEY_CODEPOINT_MASK)
-               {
-               case KEY_F1:    VT_SetTerminal(0);      return;
-               case KEY_F2:    VT_SetTerminal(1);      return;
-               case KEY_F3:    VT_SetTerminal(2);      return;
-               case KEY_F4:    VT_SetTerminal(3);      return;
-               case KEY_F5:    VT_SetTerminal(4);      return;
-               case KEY_F6:    VT_SetTerminal(5);      return;
-               case KEY_F7:    VT_SetTerminal(6);      return;
-               case KEY_F8:    VT_SetTerminal(7);      return;
-               case KEY_F9:    VT_SetTerminal(8);      return;
-               case KEY_F10:   VT_SetTerminal(9);      return;
-               case KEY_F11:   VT_SetTerminal(10);     return;
-               case KEY_F12:   VT_SetTerminal(11);     return;
-               }
-               
-               // Scrolling is only valid in text mode
-               if(gpVT_CurTerm->Mode != TERM_MODE_TEXT)
-                       break;
-               
-               switch(Codepoint & KEY_CODEPOINT_MASK)
-               {
-               // Scrolling
-               case KEY_PGUP:
-                       if( gpVT_CurTerm->Flags & VT_FLAG_ALTBUF )
-                               return ;
-                       gpVT_CurTerm->ViewPos = MAX(
-                               0,
-                               gpVT_CurTerm->ViewPos - gpVT_CurTerm->Width
-                               );
-                       return;
-               case KEY_PGDOWN:
-                       if( gpVT_CurTerm->Flags & VT_FLAG_ALTBUF )
-                               return ;
-                       gpVT_CurTerm->ViewPos = MIN(
-                               gpVT_CurTerm->ViewPos + gpVT_CurTerm->Width,
-                               gpVT_CurTerm->Width * gpVT_CurTerm->Height*giVT_Scrollback
-                               );
-                       return;
-               }
-               break;
-       }
-       
-       // Encode key
-       if(term->Mode == TERM_MODE_TEXT)
-       {
-               Uint8   buf[6] = {0};
-                int    len = 0;
-       
-               // Ignore anything that isn't a press or refire
-               if( (Codepoint & KEY_ACTION_MASK) != KEY_ACTION_PRESS
-                && (Codepoint & KEY_ACTION_MASK) != KEY_ACTION_REFIRE
-                   )
-               {
-                       return ;
-               }
-       
-               Codepoint &= KEY_CODEPOINT_MASK;
-
-               // Ignore Modifer Keys
-               if(Codepoint > KEY_MODIFIERS)   return;
-               
-               // Get UTF-8/ANSI Encoding
-               switch(Codepoint)
-               {
-               // 0: No translation, don't send to user
-               case 0: break;
-               case KEY_LEFT:
-                       buf[0] = '\x1B'; buf[1] = '['; buf[2] = 'D';
-                       len = 3;
-                       break;
-               case KEY_RIGHT:
-                       buf[0] = '\x1B'; buf[1] = '['; buf[2] = 'C';
-                       len = 3;
-                       break;
-               case KEY_UP:
-                       buf[0] = '\x1B'; buf[1] = '['; buf[2] = 'A';
-                       len = 3;
-                       break;
-               case KEY_DOWN:
-                       buf[0] = '\x1B'; buf[1] = '['; buf[2] = 'B';
-                       len = 3;
-                       break;
-               
-               case KEY_PGUP:
-                       buf[0] = '\x1B'; buf[1] = '['; buf[2] = '5'; buf[3] = '~';
-                       len = 4;
-                       break;
-               case KEY_PGDOWN:
-                       buf[0] = '\x1B'; buf[1] = '['; buf[2] = '6'; buf[3] = '~';
-                       len = 4;
-                       break;
-               
-               // Attempt to encode in UTF-8
-               default:
-                       len = WriteUTF8( buf, Codepoint );
-                       if(len == 0) {
-                               Warning("Codepoint (%x) is unrepresentable in UTF-8", Codepoint);
-                       }
-                       break;
-               }
-               
-               if(len == 0) {
-                       // Unprintable / Don't Pass
-                       return;
-               }
-
-#if 0
-               // Handle meta characters
-               if( !(term->Flags & VT_FLAG_RAWIN) )
-               {
-                       switch(buf[0])
-                       {
-                       case '\3':      // ^C
-                               
-                               break;
-                       }
-               }
-#endif
-               
-               // Write
-               if( MAX_INPUT_CHARS8 - term->InputWrite >= len )
-                       memcpy( &term->InputBuffer[term->InputWrite], buf, len );
-               else {
-                       memcpy( &term->InputBuffer[term->InputWrite], buf, MAX_INPUT_CHARS8 - term->InputWrite );
-                       memcpy( &term->InputBuffer[0], buf, len - (MAX_INPUT_CHARS8 - term->InputWrite) );
-               }
-               // Roll the buffer over
-               term->InputWrite += len;
-               term->InputWrite %= MAX_INPUT_CHARS8;
-               if( (term->InputWrite - term->InputRead + MAX_INPUT_CHARS8)%MAX_INPUT_CHARS8 < len ) {
-                       term->InputRead = term->InputWrite + 1;
-                       term->InputRead %= MAX_INPUT_CHARS8;
-               }
-       }
-       else
-       {
-               // Encode the raw key event
-               Uint32  *raw_in = (void*)term->InputBuffer;
-       
-               #if 0
-               // Drop new keys
-               if( term->InputWrite == term->InputRead )
-                       return ;                
-               #endif
-
-               raw_in[ term->InputWrite ] = Codepoint;
-               term->InputWrite ++;
-               if(term->InputWrite >= MAX_INPUT_CHARS32)
-                       term->InputWrite -= MAX_INPUT_CHARS32;
-               
-               #if 1
-               // TODO: Should old or new be dropped?
-               if(term->InputRead == term->InputWrite) {
-                       term->InputRead ++;
-                       if( term->InputRead >= MAX_INPUT_CHARS32 )
-                               term->InputRead -= MAX_INPUT_CHARS32;
-               }
-               #endif
-       }
-       
-       VFS_MarkAvaliable(&term->Node, 1);
-}
-
-/**
- * \brief Clears a line in a virtual terminal
- * \param Term Terminal to modify
- * \param Num  Line number to clear
- */
-void VT_int_ClearLine(tVTerm *Term, int Num)
-{
-        int    i;
-       tVT_Char        *cell;
-       
-       if( Num < 0 || Num >= Term->TextHeight * (giVT_Scrollback + 1) )        return ;
-       
-       cell = (Term->Flags & VT_FLAG_ALTBUF) ? Term->AltBuf : Term->Text;
-       cell = &cell[ Num*Term->TextWidth ];
-       
-       for( i = Term->TextWidth; i--; )
-       {
-               cell[ i ].Ch = 0;
-               cell[ i ].Colour = Term->CurColour;
-       }
-}
-
-/**
- * \brief Handle a standard large escape code
- * 
- * Handles any escape code of the form \x1B[n,...A where n is an integer
- * and A is any letter.
- */
-void VT_int_ParseEscape_StandardLarge(tVTerm *Term, char CmdChar, int argc, int *args)
-{
-        int    tmp = 1;
-       switch(CmdChar)
-       {
-       // Left
-       case 'D':
-               tmp = -1;
-       // Right
-       case 'C':
-               if(argc == 1)   tmp *= args[0];
-               if( Term->Flags & VT_FLAG_ALTBUF )
-               {
-                       if( (Term->AltWritePos + tmp) % Term->TextWidth == 0 ) {
-                               Term->AltWritePos -= Term->AltWritePos % Term->TextWidth;
-                               Term->AltWritePos += Term->TextWidth - 1;
-                       }
-                       else
-                               Term->AltWritePos += tmp;
-               }
-               else
-               {
-                       if( (Term->WritePos + tmp) % Term->TextWidth == 0 ) {
-                               Term->WritePos -= Term->WritePos % Term->TextWidth;
-                               Term->WritePos += Term->TextWidth - 1;
-                       }
-                       else
-                               Term->WritePos += tmp;
-               }
-               break;
-       
-       // Erase
-       case 'J':
-               switch(args[0])
-               {
-               case 0: // Erase below
-                       break;
-               case 1: // Erase above
-                       break;
-               case 2: // Erase all
-                       if( Term->Flags & VT_FLAG_ALTBUF )
-                       {
-                                int    i = Term->TextHeight;
-                               while( i-- )    VT_int_ClearLine(Term, i);
-                               Term->AltWritePos = 0;
-                               VT_int_UpdateScreen(Term, 1);
-                       }
-                       else
-                       {
-                                int    i = Term->TextHeight * (giVT_Scrollback + 1);
-                               while( i-- )    VT_int_ClearLine(Term, i);
-                               Term->WritePos = 0;
-                               Term->ViewPos = 0;
-                               VT_int_UpdateScreen(Term, 1);
-                       }
-                       break;
-               }
-               break;
-       
-       // Erase in line
-       case 'K':
-               switch(args[0])
-               {
-               case 0: // Erase to right
-                       if( Term->Flags & VT_FLAG_ALTBUF )
-                       {
-                                int    i, max;
-                               max = Term->Width - Term->AltWritePos % Term->Width;
-                               for( i = 0; i < max; i ++ )
-                                       Term->AltBuf[Term->AltWritePos+i].Ch = 0;
-                       }
-                       else
-                       {
-                                int    i, max;
-                               max = Term->Width - Term->WritePos % Term->Width;
-                               for( i = 0; i < max; i ++ )
-                                       Term->Text[Term->WritePos+i].Ch = 0;
-                       }
-                       VT_int_UpdateScreen(Term, 0);
-                       break;
-               case 1: // Erase to left
-                       if( Term->Flags & VT_FLAG_ALTBUF )
-                       {
-                                int    i = Term->AltWritePos % Term->Width;
-                               while( i -- )
-                                       Term->AltBuf[Term->AltWritePos++].Ch = 0;
-                       }
-                       else
-                       {
-                                int    i = Term->WritePos % Term->Width;
-                               while( i -- )
-                                       Term->Text[Term->WritePos++].Ch = 0;
-                       }
-                       VT_int_UpdateScreen(Term, 0);
-                       break;
-               case 2: // Erase all
-                       if( Term->Flags & VT_FLAG_ALTBUF )
-                       {
-                               VT_int_ClearLine(Term, Term->AltWritePos / Term->Width);
-                       }
-                       else
-                       {
-                               VT_int_ClearLine(Term, Term->WritePos / Term->Width);
-                       }
-                       VT_int_UpdateScreen(Term, 0);
-                       break;
-               }
-               break;
-       
-       // Set cursor position
-       case 'H':
-               if( Term->Flags & VT_FLAG_ALTBUF )
-                       Term->AltWritePos = args[0] + args[1]*Term->TextWidth;
-               else
-                       Term->WritePos = args[0] + args[1]*Term->TextWidth;
-               //Log_Debug("VTerm", "args = {%i, %i}", args[0], args[1]);
-               break;
-       
-       // Scroll up `n` lines
-       case 'S':
-               tmp = -1;
-       // Scroll down `n` lines
-       case 'T':
-               if(argc == 1)   tmp *= args[0];
-               if( Term->Flags & VT_FLAG_ALTBUF )
-                       VT_int_ScrollText(Term, tmp);
-               else
-               {
-                       if(Term->ViewPos/Term->TextWidth + tmp < 0)
-                               break;
-                       if(Term->ViewPos/Term->TextWidth + tmp  > Term->TextHeight * (giVT_Scrollback + 1))
-                               break;
-                       
-                       Term->ViewPos += Term->TextWidth*tmp;
-               }
-               break;
-       
-       // Set Font flags
-       case 'm':
-               for( ; argc--; )
-               {
-                        int    colour_idx;
-                       // Flags
-                       if( 0 <= args[argc] && args[argc] <= 8)
-                       {
-                               switch(args[argc])
-                               {
-                               case 0: Term->CurColour = DEFAULT_COLOUR;       break;  // Reset
-                               case 1: Term->CurColour |= 0x80000000;  break;  // Bright
-                               case 2: Term->CurColour &= ~0x80000000; break;  // Dim
-                               }
-                       }
-                       // Foreground Colour
-                       else if(30 <= args[argc] && args[argc] <= 37) {
-                               // Get colour index, accounting for bright bit
-                               colour_idx = args[argc]-30 + ((Term->CurColour>>28) & 8);
-                               Term->CurColour &= 0x8000FFFF;
-                               Term->CurColour |= (Uint32)caVT100Colours[ colour_idx ] << 16;
-                       }
-                       // Background Colour
-                       else if(40 <= args[argc] && args[argc] <= 47) {
-                               // Get colour index, accounting for bright bit
-                               colour_idx = args[argc]-40 + ((Term->CurColour>>12) & 8);
-                               Term->CurColour &= 0xFFFF8000;
-                               Term->CurColour |= caVT100Colours[ colour_idx ];
-                       }
-                       else {
-                               Log_Warning("VTerm", "Unknown font flag %i", args[argc]);
-                       }
-               }
-               break;
-       
-       // Set scrolling region
-       case 'r':
-               if( argc != 2 ) break;
-               Term->ScrollTop = args[0];
-               Term->ScrollHeight = args[1] - args[0];
-               break;
-       
-       default:
-               Log_Warning("VTerm", "Unknown control sequence '\\x1B[%c'", CmdChar);
-               break;
-       }
-}
-
-/**
- * \fn int VT_int_ParseEscape(tVTerm *Term, char *Buffer)
- * \brief Parses a VT100 Escape code
- */
-int VT_int_ParseEscape(tVTerm *Term, char *Buffer)
-{
-       char    c;
-        int    argc = 0, j = 1;
-        int    args[6] = {0,0,0,0};
-        int    bQuestionMark = 0;
-       
-       switch(Buffer[0])
-       {
-       //Large Code
-       case '[':
-               // Get Arguments
-               c = Buffer[j++];
-               if(c == '?') {
-                       bQuestionMark = 1;
-                       c = Buffer[j++];
-               }
-               if( '0' <= c && c <= '9' )
-               {
-                       do {
-                               if(c == ';')    c = Buffer[j++];
-                               while('0' <= c && c <= '9') {
-                                       args[argc] *= 10;
-                                       args[argc] += c-'0';
-                                       c = Buffer[j++];
-                               }
-                               argc ++;
-                       } while(c == ';');
-               }
-               
-               // Get Command
-               if( ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'))
-               {
-                       if( bQuestionMark )
-                       {
-                               switch(c)
-                               {
-                               // DEC Private Mode Set
-                               case 'h':
-                                       if(argc != 1)   break;
-                                       switch(args[0])
-                                       {
-                                       case 25:
-                                               Term->Flags &= ~VT_FLAG_HIDECSR;
-                                               break;
-                                       case 1047:
-                                               VT_int_ToggleAltBuffer(Term, 1);
-                                               break;
-                                       }
-                                       break;
-                               case 'l':
-                                       if(argc != 1)   break;
-                                       switch(args[0])
-                                       {
-                                       case 25:
-                                               Term->Flags |= VT_FLAG_HIDECSR;
-                                               break;
-                                       case 1047:
-                                               VT_int_ToggleAltBuffer(Term, 0);
-                                               break;
-                                       }
-                                       break;
-                               default:
-                                       Log_Warning("VTerm", "Unknown control sequence '\\x1B[?%c'", c);
-                                       break;
-                               }
-                       }
-                       else
-                       {
-                               VT_int_ParseEscape_StandardLarge(Term, c, argc, args);
-                       }
-               }
-               break;
-               
-       default:
-               Log_Notice("VTerm", "TODO: Handle short escape codes");
-               break;
-       }
-       
-       //Log_Debug("VTerm", "j = %i, Buffer = '%s'", j, Buffer);
-       return j;
-}
-
-/**
- * \fn void VT_int_PutString(tVTerm *Term, Uint8 *Buffer, Uint Count)
- * \brief Print a string to the Virtual Terminal
- */
-void VT_int_PutString(tVTerm *Term, Uint8 *Buffer, Uint Count)
-{
-       Uint32  val;
-        int    i;
-       
-       // Iterate
-       for( i = 0; i < Count; i++ )
-       {
-               // Handle escape sequences
-               if( Buffer[i] == 0x1B )
-               {
-                       i ++;
-                       i += VT_int_ParseEscape(Term, (char*)&Buffer[i]) - 1;
-                       continue;
-               }
-               
-               // Fast check for non UTF-8
-               if( Buffer[i] < 128 )   // Plain ASCII
-                       VT_int_PutChar(Term, Buffer[i]);
-               else {  // UTF-8
-                       i += ReadUTF8(&Buffer[i], &val) - 1;
-                       VT_int_PutChar(Term, val);
-               }
-       }
-       // Update Screen
-       VT_int_UpdateScreen( Term, 0 );
-}
-
-/**
- * \fn void VT_int_PutChar(tVTerm *Term, Uint32 Ch)
- * \brief Write a single character to a VTerm
- */
-void VT_int_PutChar(tVTerm *Term, Uint32 Ch)
-{
-        int    i;
-       tVT_Char        *buffer;
-        int    write_pos;
-       
-       if(Term->Flags & VT_FLAG_ALTBUF) {
-               buffer = Term->AltBuf;
-               write_pos = Term->AltWritePos;
-       }
-       else {
-               buffer = Term->Text;
-               write_pos = Term->WritePos;
-       }
-       
-       switch(Ch)
-       {
-       case '\0':      return; // Ignore NULL byte
-       case '\n':
-               VT_int_UpdateScreen( Term, 0 ); // Update the line before newlining
-               write_pos += Term->TextWidth;
-       case '\r':
-               write_pos -= write_pos % Term->TextWidth;
-               break;
-       
-       case '\t': { int tmp = write_pos / Term->TextWidth;
-               write_pos %= Term->TextWidth;
-               do {
-                       buffer[ write_pos ].Ch = '\0';
-                       buffer[ write_pos ].Colour = Term->CurColour;
-                       write_pos ++;
-               } while(write_pos & 7);
-               write_pos += tmp * Term->TextWidth;
-               break; }
-       
-       case '\b':
-               // Backspace is invalid at Offset 0
-               if(write_pos == 0)      break;
-               
-               write_pos --;
-               // Singe Character
-               if(buffer[ write_pos ].Ch != '\0') {
-                       buffer[ write_pos ].Ch = 0;
-                       buffer[ write_pos ].Colour = Term->CurColour;
-                       break;
-               }
-               // Tab
-               i = 7;  // Limit it to 8
-               do {
-                       buffer[ write_pos ].Ch = 0;
-                       buffer[ write_pos ].Colour = Term->CurColour;
-                       write_pos --;
-               } while(write_pos && i-- && buffer[ write_pos ].Ch == '\0');
-               if(buffer[ write_pos ].Ch != '\0')
-                       write_pos ++;
-               break;
-       
-       default:
-               buffer[ write_pos ].Ch = Ch;
-               buffer[ write_pos ].Colour = Term->CurColour;
-               // Update the line before wrapping
-               if( (write_pos + 1) % Term->TextWidth == 0 )
-                       VT_int_UpdateScreen( Term, 0 );
-               write_pos ++;
-               break;
-       }
-       
-       if(Term->Flags & VT_FLAG_ALTBUF)
-       {
-               Term->AltBuf = buffer;
-               Term->AltWritePos = write_pos;
-               
-               if(Term->AltWritePos >= Term->TextWidth*Term->TextHeight)
-               {
-                       Term->AltWritePos -= Term->TextWidth;
-                       VT_int_ScrollText(Term, 1);
-               }
-               
-       }
-       else
-       {
-               Term->Text = buffer;
-               Term->WritePos = write_pos;
-               // Move Screen
-               // - Check if we need to scroll the entire scrollback buffer
-               if(Term->WritePos >= Term->TextWidth*Term->TextHeight*(giVT_Scrollback+1))
-               {
-                        int    base;
-                       
-                       // Update previous line
-                       Term->WritePos -= Term->TextWidth;
-                       VT_int_UpdateScreen( Term, 0 );
-                       
-                       // Update view position
-                       base = Term->TextWidth*Term->TextHeight*(giVT_Scrollback);
-                       if(Term->ViewPos < base)
-                               Term->ViewPos += Term->Width;
-                       if(Term->ViewPos > base)
-                               Term->ViewPos = base;
-                       
-                       VT_int_ScrollText(Term, 1);
-               }
-               // Ok, so we only need to scroll the screen
-               else if(Term->WritePos >= Term->ViewPos + Term->TextWidth*Term->TextHeight)
-               {
-                       // Update the last line
-                       Term->WritePos -= Term->TextWidth;
-                       VT_int_UpdateScreen( Term, 0 );
-                       Term->WritePos += Term->TextWidth;
-                       
-                       VT_int_ScrollText(Term, 1);
-                       
-                       Term->ViewPos += Term->TextWidth;
-               }
-       }
-       
-       //LEAVE('-');
-}
-
-void VT_int_ScrollText(tVTerm *Term, int Count)
-{
-       tVT_Char        *buf;
-        int    height, init_write_pos;
-        int    len, i;
-        int    scroll_top, scroll_height;
-
-       // Get buffer pointer and attributes    
-       if( Term->Flags & VT_FLAG_ALTBUF )
-       {
-               buf = Term->AltBuf;
-               height = Term->TextHeight;
-               init_write_pos = Term->AltWritePos;
-               scroll_top = Term->ScrollTop;
-               scroll_height = Term->ScrollHeight;
-       }
-       else
-       {
-               buf = Term->Text;
-               height = Term->TextHeight*(giVT_Scrollback+1);
-               init_write_pos = Term->WritePos;
-               scroll_top = 0;
-               scroll_height = height;
-       }
-
-       // Scroll text downwards        
-       if( Count > 0 )
-       {
-                int    base;
-       
-               // Set up
-               if(Count > scroll_height)       Count = scroll_height;
-               base = Term->TextWidth*(scroll_top + scroll_height - Count);
-               len = Term->TextWidth*(scroll_height - Count);
-               
-               // Scroll terminal cache
-               memmove(
-                       &buf[Term->TextWidth*scroll_top],
-                       &buf[Term->TextWidth*(scroll_top+Count)],
-                       len*sizeof(tVT_Char)
-                       );
-               // Clear last rows
-               for( i = 0; i < Term->TextWidth*Count; i ++ )
-               {
-                       buf[ base + i ].Ch = 0;
-                       buf[ base + i ].Colour = Term->CurColour;
-               }
-               
-               // Update Screen
-               VT_int_ScrollFramebuffer( Term, Count );
-               if( Term->Flags & VT_FLAG_ALTBUF )
-                       Term->AltWritePos = base;
-               else
-                       Term->WritePos = Term->ViewPos + Term->TextWidth*(Term->TextHeight - Count);
-               for( i = 0; i < Count; i ++ )
-               {
-                       VT_int_UpdateScreen( Term, 0 );
-                       if( Term->Flags & VT_FLAG_ALTBUF )
-                               Term->AltWritePos += Term->TextWidth;
-                       else
-                               Term->WritePos += Term->TextWidth;
-               }
-       }
-       else
-       {
-               Count = -Count;
-               if(Count > scroll_height)       Count = scroll_height;
-               
-               len = Term->TextWidth*(scroll_height - Count);
-               
-               // Scroll terminal cache
-               memmove(
-                       &buf[Term->TextWidth*(scroll_top+Count)],
-                       &buf[Term->TextWidth*scroll_top],
-                       len*sizeof(tVT_Char)
-                       );
-               // Clear preceding rows
-               for( i = 0; i < Term->TextWidth*Count; i ++ )
-               {
-                       buf[ i ].Ch = 0;
-                       buf[ i ].Colour = Term->CurColour;
-               }
-               
-               VT_int_ScrollFramebuffer( Term, -Count );
-               if( Term->Flags & VT_FLAG_ALTBUF )
-                       Term->AltWritePos = Term->TextWidth*scroll_top;
-               else
-                       Term->WritePos = Term->ViewPos;
-               for( i = 0; i < Count; i ++ )
-               {
-                       VT_int_UpdateScreen( Term, 0 );
-                       if( Term->Flags & VT_FLAG_ALTBUF )
-                               Term->AltWritePos += Term->TextWidth;
-                       else
-                               Term->WritePos += Term->TextWidth;
-               }
-       }
-       
-       if( Term->Flags & VT_FLAG_ALTBUF )
-               Term->AltWritePos = init_write_pos;
-       else
-               Term->WritePos = init_write_pos;
-}
-
-/**
- * \fn void VT_int_ScrollFramebuffer( tVTerm *Term, int Count )
- * \note Scrolls the framebuffer down by \a Count text lines
- */
-void VT_int_ScrollFramebuffer( tVTerm *Term, int Count )
-{
-        int    tmp;
-       struct {
-               Uint8   Op;
-               Uint16  DstX, DstY;
-               Uint16  SrcX, SrcY;
-               Uint16  W, H;
-       } PACKED        buf;
-       
-       // Only update if this is the current terminal
-       if( Term != gpVT_CurTerm )      return;
-       
-       if( Count > Term->ScrollHeight )        Count = Term->ScrollHeight;
-       if( Count < -Term->ScrollHeight )       Count = -Term->ScrollHeight;
-       
-       // Switch to 2D Command Stream
-       tmp = VIDEO_BUFFMT_2DSTREAM;
-       VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETBUFFORMAT, &tmp);
-       
-       // BLIT to 0,0 from 0,giVT_CharHeight
-       buf.Op = VIDEO_2DOP_BLIT;
-       buf.SrcX = 0;   buf.DstX = 0;
-       // TODO: Don't assume character dimensions
-       buf.W = Term->TextWidth * giVT_CharWidth;
-       if( Count > 0 )
-       {
-               buf.SrcY = (Term->ScrollTop+Count) * giVT_CharHeight;
-               buf.DstY = Term->ScrollTop * giVT_CharHeight;
-       }
-       else    // Scroll up, move text down
-       {
-               Count = -Count;
-               buf.SrcY = Term->ScrollTop * giVT_CharHeight;
-               buf.DstY = (Term->ScrollTop+Count) * giVT_CharHeight;
-       }
-       buf.H = (Term->ScrollHeight-Count) * giVT_CharHeight;
-       VFS_WriteAt(giVT_OutputDevHandle, 0, sizeof(buf), &buf);
-       
-       // Restore old mode (this function is only called during text mode)
-       tmp = VIDEO_BUFFMT_TEXT;
-       VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETBUFFORMAT, &tmp);
-}
-
-void VT_int_UpdateCursor( tVTerm *Term, int bShow )
-{
-       tVideo_IOCtl_Pos        csr_pos;
-
-       if( Term != gpVT_CurTerm )      return ;
-
-       if( !bShow )
-       {
-               csr_pos.x = -1; 
-               csr_pos.y = -1; 
-       }
-       else if( Term->Mode == TERM_MODE_TEXT )
-       {
-                int    offset;
-               
-//             if( !(Term->Flags & VT_FLAG_SHOWCSR)
-//              && ( (Term->Flags & VT_FLAG_HIDECSR) || !Term->Node.ReadThreads)
-//               )
-               if( !Term->Text || Term->Flags & VT_FLAG_HIDECSR )
-               {
-                       csr_pos.x = -1;
-                       csr_pos.y = -1;
-               }
-               else
-               {
-                       if(Term->Flags & VT_FLAG_ALTBUF)
-                               offset = Term->AltWritePos;
-                       else
-                               offset = Term->WritePos - Term->ViewPos;
-                                       
-                       csr_pos.x = offset % Term->TextWidth;
-                       csr_pos.y = offset / Term->TextWidth;
-                       if( 0 > csr_pos.y || csr_pos.y >= Term->TextHeight )
-                               csr_pos.y = -1, csr_pos.x = -1;
-               }
-       }
-       else
-       {
-               csr_pos.x = Term->VideoCursorX;
-               csr_pos.y = Term->VideoCursorY;
-       }
-       VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETCURSOR, &csr_pos);
-}      
-
-/**
- * \fn void VT_int_UpdateScreen( tVTerm *Term, int UpdateAll )
- * \brief Updates the video framebuffer
- */
-void VT_int_UpdateScreen( tVTerm *Term, int UpdateAll )
-{
-       tVT_Char        *buffer;
-        int    view_pos, write_pos;
-       // Only update if this is the current terminal
-       if( Term != gpVT_CurTerm )      return;
-       
-       switch( Term->Mode )
-       {
-       case TERM_MODE_TEXT:
-               view_pos = (Term->Flags & VT_FLAG_ALTBUF) ? 0 : Term->ViewPos;
-               write_pos = (Term->Flags & VT_FLAG_ALTBUF) ? Term->AltWritePos : Term->WritePos;
-               buffer = (Term->Flags & VT_FLAG_ALTBUF) ? Term->AltBuf : Term->Text;
-               // Re copy the entire screen?
-               if(UpdateAll) {
-                       VFS_WriteAt(
-                               giVT_OutputDevHandle,
-                               0,
-                               Term->TextWidth*Term->TextHeight*sizeof(tVT_Char),
-                               &buffer[view_pos]
-                               );
-               }
-               // Only copy the current line
-               else {
-                        int    ofs = write_pos - write_pos % Term->TextWidth;
-                       VFS_WriteAt(
-                               giVT_OutputDevHandle,
-                               (ofs - view_pos)*sizeof(tVT_Char),
-                               Term->TextWidth*sizeof(tVT_Char),
-                               &buffer[ofs]
-                               );
-               }
-               break;
-       case TERM_MODE_FB:
-               break;
-       }
-       
-       VT_int_UpdateCursor(Term, 1);
-}
-
-/**
- * \brief Update the screen mode
- * \param Term Terminal to update
- * \param NewMode      New mode to set
- * \param NewWidth     New framebuffer width
- * \param NewHeight    New framebuffer height
- */
-void VT_int_ChangeMode(tVTerm *Term, int NewMode, int NewWidth, int NewHeight)
-{
-        int    oldW = Term->Width;
-        int    oldTW = Term->TextWidth;
-        int    oldH = Term->Height;
-        int    oldTH = Term->TextHeight;
-       tVT_Char        *oldTBuf = Term->Text;
-       Uint32  *oldFB = Term->Buffer;
-        int    w, h, i;
-       
-       // TODO: Increase RealWidth/RealHeight when this happens
-       if(NewWidth > giVT_RealWidth)   NewWidth = giVT_RealWidth;
-       if(NewHeight > giVT_RealHeight) NewHeight = giVT_RealHeight;
-       
-       Term->Mode = NewMode;
-
-       // Fast exit if no resolution change
-       if(NewWidth == Term->Width && NewHeight == Term->Height)
-               return ;
-       
-       // Calculate new dimensions
-       Term->Width = NewWidth;
-       Term->Height = NewHeight;
-       Term->TextWidth = NewWidth / giVT_CharWidth;
-       Term->TextHeight = NewHeight / giVT_CharHeight;
-       Term->ScrollHeight = Term->TextHeight - (oldTH - Term->ScrollHeight) - Term->ScrollTop;
-       
-       // Allocate new buffers
-       // - Text
-       Term->Text = calloc(
-               Term->TextWidth * Term->TextHeight * (giVT_Scrollback+1),
-               sizeof(tVT_Char)
-               );
-       if(oldTBuf) {
-               // Copy old buffer
-               w = (oldTW > Term->TextWidth) ? Term->TextWidth : oldTW;
-               h = (oldTH > Term->TextHeight) ? Term->TextHeight : oldTH;
-               h *= giVT_Scrollback + 1;
-               for( i = 0; i < h; i ++ )
-               {
-                       memcpy(
-                               &Term->Text[i*Term->TextWidth],
-                               &oldTBuf[i*oldTW],
-                               w*sizeof(tVT_Char)
-                               );      
-               }
-               free(oldTBuf);
-       }
-       
-       // - Alternate Text
-       Term->AltBuf = realloc(
-               Term->AltBuf,
-               Term->TextWidth * Term->TextHeight * sizeof(tVT_Char)
-               );
-       
-       // - Framebuffer
-       if(oldFB) {
-               Term->Buffer = calloc( Term->Width * Term->Height, sizeof(Uint32) );
-               // Copy old buffer
-               w = (oldW > Term->Width) ? Term->Width : oldW;
-               h = (oldH > Term->Height) ? Term->Height : oldH;
-               for( i = 0; i < h; i ++ )
-               {
-                       memcpy(
-                               &Term->Buffer[i*Term->Width],
-                               &oldFB[i*oldW],
-                               w*sizeof(Uint32)
-                               );
-               }
-               free(oldFB);
-       }
-       
-       // Debug
-       switch(NewMode)
-       {
-       case TERM_MODE_TEXT:
-               Log_Log("VTerm", "Set VT %p to text mode (%ix%i)",
-                       Term, Term->TextWidth, Term->TextHeight);
-               break;
-       case TERM_MODE_FB:
-               Log_Log("VTerm", "Set VT %p to framebuffer mode (%ix%i)",
-                       Term, Term->Width, Term->Height);
-               break;
-       //case TERM_MODE_2DACCEL:
-       //case TERM_MODE_3DACCEL:
-       //      return;
-       }
-}
-
-
-void VT_int_ToggleAltBuffer(tVTerm *Term, int Enabled)
-{      
-       if(Enabled)
-               Term->Flags |= VT_FLAG_ALTBUF;
-       else
-               Term->Flags &= ~VT_FLAG_ALTBUF;
-       VT_int_UpdateScreen(Term, 1);
-}
-
-// ---
-// Font Render
-// ---
-#define MONOSPACE_FONT 10816
-
-#if MONOSPACE_FONT == 10808    // 8x8
-# include "vterm_font_8x8.h"
-#elif MONOSPACE_FONT == 10816  // 8x16
-# include "vterm_font_8x16.h"
-#endif
-
-// === PROTOTYPES ===
-Uint8  *VT_Font_GetChar(Uint32 Codepoint);
-
-// === GLOBALS ===
-int    giVT_CharWidth = FONT_WIDTH;
-int    giVT_CharHeight = FONT_HEIGHT;
-
-// === CODE ===
-/**
- * \brief Render a font character
- */
-void VT_Font_Render(Uint32 Codepoint, void *Buffer, int Depth, int Pitch, Uint32 BGC, Uint32 FGC)
-{
-       Uint8   *font;
-        int    x, y;
-       
-       // 8-bpp and below
-       if( Depth <= 8 )
-       {
-               Uint8   *buf = Buffer;
-               
-               font = VT_Font_GetChar(Codepoint);
-               
-               for(y = 0; y < FONT_HEIGHT; y ++)
-               {
-                       for(x = 0; x < FONT_WIDTH; x ++)
-                       {
-                               if(*font & (1 << (FONT_WIDTH-x-1)))
-                                       buf[x] = FGC;
-                               else
-                                       buf[x] = BGC;
-                       }
-                       buf = (void*)( (tVAddr)buf + Pitch );
-                       font ++;
-               }
-       }
-       // 16-bpp and below
-       else if( Depth <= 16 )
-       {
-               Uint16  *buf = Buffer;
-               
-               font = VT_Font_GetChar(Codepoint);
-               
-               for(y = 0; y < FONT_HEIGHT; y ++)
-               {
-                       for(x = 0; x < FONT_WIDTH; x ++)
-                       {
-                               if(*font & (1 << (FONT_WIDTH-x-1)))
-                                       buf[x] = FGC;
-                               else
-                                       buf[x] = BGC;
-                       }
-                       buf = (void*)( (tVAddr)buf + Pitch );
-                       font ++;
-               }
-       }
-       // 24-bpp colour
-       // - Special handling to not overwrite the next pixel
-       //TODO: Endian issues here
-       else if( Depth == 24 )
-       {
-               Uint8   *buf = Buffer;
-               Uint8   bg_r = (BGC >> 16) & 0xFF;
-               Uint8   bg_g = (BGC >>  8) & 0xFF;
-               Uint8   bg_b = (BGC >>  0) & 0xFF;
-               Uint8   fg_r = (FGC >> 16) & 0xFF;
-               Uint8   fg_g = (FGC >>  8) & 0xFF;
-               Uint8   fg_b = (FGC >>  0) & 0xFF;
-               
-               font = VT_Font_GetChar(Codepoint);
-               
-               for(y = 0; y < FONT_HEIGHT; y ++)
-               {
-                       for(x = 0; x < FONT_WIDTH; x ++)
-                       {
-                               Uint8   r, g, b;
-                               
-                               if(*font & (1 << (FONT_WIDTH-x-1))) {
-                                       r = fg_r;       g = fg_g;       b = fg_b;
-                               }
-                               else {
-                                       r = bg_r;       g = bg_g;       b = bg_b;
-                               }
-                               buf[x*3+0] = b;
-                               buf[x*3+1] = g;
-                               buf[x*3+2] = r;
-                       }
-                       buf = (void*)( (tVAddr)buf + Pitch );
-                       font ++;
-               }
-       }
-       // 32-bpp colour (nice and easy)
-       else if( Depth == 32 )
-       {
-               Uint32  *buf = Buffer;
-               
-               font = VT_Font_GetChar(Codepoint);
-               
-               for(y = 0; y < FONT_HEIGHT; y ++)
-               {
-                       for(x = 0; x < FONT_WIDTH; x ++)
-                       {
-                               if(*font & (1 << (FONT_WIDTH-x-1)))
-                                       buf[x] = FGC;
-                               else
-                                       buf[x] = BGC;
-                       }
-                       buf = (Uint32*)( (tVAddr)buf + Pitch );
-                       font ++;
-               }
-       }
-}
-
-/**
- * \fn Uint32 VT_Colour12to24(Uint16 Col12)
- * \brief Converts a 12-bit colour into 24 bits
- */
-Uint32 VT_Colour12to24(Uint16 Col12)
-{
-       Uint32  ret;
-        int    tmp;
-       tmp = Col12 & 0xF;
-       ret  = (tmp << 0) | (tmp << 4);
-       tmp = (Col12 & 0xF0) >> 4;
-       ret |= (tmp << 8) | (tmp << 12);
-       tmp = (Col12 & 0xF00) >> 8;
-       ret |= (tmp << 16) | (tmp << 20);
-       return ret;
-}
-/**
- * \brief Converts a 12-bit colour into 15 bits
- */
-Uint16 VT_Colour12to15(Uint16 Col12)
-{
-       Uint32  ret;
-        int    tmp;
-       tmp = Col12 & 0xF;
-       ret  = (tmp << 1) | (tmp & 1);
-       tmp = (Col12 & 0xF0) >> 4;
-       ret |= ( (tmp << 1) | (tmp & 1) ) << 5;
-       tmp = (Col12 & 0xF00) >> 8;
-       ret |= ( (tmp << 1) | (tmp & 1) ) << 10;
-       return ret;
-}
-
-/**
- * \brief Converts a 12-bit colour into any other depth
- * \param Col12        12-bit source colour
- * \param Depth        Desired bit deptj
- * \note Green then blue get the extra avaliable bits (16:5-6-5, 14:4-5-5)
- */
-Uint32 VT_Colour12toN(Uint16 Col12, int Depth)
-{
-       Uint32  ret;
-       Uint32  r, g, b;
-        int    rSize, gSize, bSize;
-       
-       // Fast returns
-       if( Depth == 24 )       return VT_Colour12to24(Col12);
-       if( Depth == 15 )       return VT_Colour12to15(Col12);
-       // - 32 is a special case, it's usually 24-bit colour with an unused byte
-       if( Depth == 32 )       return VT_Colour12to24(Col12);
-       
-       // Bounds checks
-       if( Depth < 8 ) return 0;
-       if( Depth > 32 )        return 0;
-       
-       r = Col12 & 0xF;
-       g = (Col12 & 0xF0) >> 4;
-       b = (Col12 & 0xF00) >> 8;
-       
-       rSize = gSize = bSize = Depth / 3;
-       if( rSize + gSize + bSize < Depth )     // Depth % 3 == 1
-               gSize ++;
-       if( rSize + gSize + bSize < Depth )     // Depth % 3 == 2
-               bSize ++;
-       
-       // Expand
-       r <<= rSize - 4;        g <<= gSize - 4;        b <<= bSize - 4;
-       // Fill with the lowest bit
-       if( Col12 & 0x001 )     r |= (1 << (rSize - 4)) - 1;
-       if( Col12 & 0x010 )     r |= (1 << (gSize - 4)) - 1;
-       if( Col12 & 0x100 )     r |= (1 << (bSize - 4)) - 1;
-       
-       // Create output
-       ret  = r;
-       ret |= g << rSize;
-       ret |= b << (rSize + gSize);
-       
-       return ret;
-}
-
-/**
- * \fn Uint8 *VT_Font_GetChar(Uint32 Codepoint)
- * \brief Gets an index into the font array given a Unicode Codepoint
- * \note See http://en.wikipedia.org/wiki/CP437
- */
-Uint8 *VT_Font_GetChar(Uint32 Codepoint)
-{
-        int    index = 0;
-       if(Codepoint < 128)
-               return &VTermFont[Codepoint*FONT_HEIGHT];
-       switch(Codepoint)
-       {
-       case 0xC7:      index = 128;    break;  // Ã‡
-       case 0xFC:      index = 129;    break;  // Ã¼
-       case 0xE9:      index = 130;    break;  // Ã©
-       case 0xE2:      index = 131;    break;  // Ã¢
-       case 0xE4:      index = 132;    break;  // Ã¤
-       case 0xE0:      index = 133;    break;  // Ã 
-       case 0xE5:      index = 134;    break;  // Ã¥
-       case 0xE7:      index = 135;    break;  // Ã§
-       case 0xEA:      index = 136;    break;  // Ãª
-       case 0xEB:      index = 137;    break;  // Ã«
-       case 0xE8:      index = 138;    break;  // Ã¨
-       case 0xEF:      index = 139;    break;  // Ã¯
-       case 0xEE:      index = 140;    break;  // Ã®
-       case 0xEC:      index = 141;    break;  // Ã¬
-       case 0xC4:      index = 142;    break;  // Ã„
-       case 0xC5:      index = 143;    break;  // Ã…
-       }
-       
-       return &VTermFont[index*FONT_HEIGHT];
-}
-
-EXPORTAS(&giVT_CharWidth, giVT_CharWidth);
-EXPORTAS(&giVT_CharHeight, giVT_CharHeight);
-EXPORT(VT_Font_Render);
-EXPORT(VT_Colour12to24);
diff --git a/Kernel/drv/vterm.h b/Kernel/drv/vterm.h
new file mode 100644 (file)
index 0000000..cd37ebd
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * drv/vterm.h
+ * - Virtual Terminal - Common
+ */
+#ifndef _VTERM_H_
+#define _VTERM_H_
+
+#include <acess.h>
+#include <api_drv_video.h>     // tVT_Char
+#include <api_drv_terminal.h>
+#include <vfs.h>
+
+// === CONSTANTS ===
+#define MAX_INPUT_CHARS32      64
+#define MAX_INPUT_CHARS8       (MAX_INPUT_CHARS32*4)
+#define        DEFAULT_COLOUR  (VT_COL_BLACK|(0xAAA<<16))
+
+/**
+ * \{
+ */
+#define        VT_FLAG_HIDECSR 0x01    //!< Hide the cursor
+#define        VT_FLAG_ALTBUF  0x02    //!< Alternate screen buffer
+#define VT_FLAG_RAWIN  0x04    //!< Don't handle ^Z/^C/^V
+#define        VT_FLAG_HASFB   0x10    //!< Set if the VTerm has requested the Framebuffer
+#define VT_FLAG_SHOWCSR        0x20    //!< Always show the text cursor
+/**
+ * \}
+ */
+
+enum eVT_InModes {
+       VT_INMODE_TEXT8,        // UTF-8 Text Mode (VT100/xterm Emulation)
+       VT_INMODE_TEXT32,       // UTF-32 Text Mode (Acess Native)
+       NUM_VT_INMODES
+};
+
+
+// === TYPES ==
+typedef struct sVTerm  tVTerm;
+
+// === STRUCTURES ===
+struct sVTerm
+{
+        int    Mode;   //!< Current Mode (see ::eTplTerminal_Modes)
+        int    Flags;  //!< Flags (see VT_FLAG_*)
+       
+       short   NewWidth;       //!< Un-applied dimensions (Width)
+       short   NewHeight;      //!< Un-applied dimensions (Height)
+       short   Width;  //!< Virtual Width
+       short   Height; //!< Virtual Height
+       short   TextWidth;      //!< Text Virtual Width
+       short   TextHeight;     //!< Text Virtual Height
+       
+       Uint32  CurColour;      //!< Current Text Colour
+       
+        int    ViewPos;        //!< View Buffer Offset (Text Only)
+        int    WritePos;       //!< Write Buffer Offset (Text Only)
+       tVT_Char        *Text;
+       
+       tVT_Char        *AltBuf;        //!< Alternate Screen Buffer
+        int    AltWritePos;    //!< Alternate write position
+       short   ScrollTop;      //!< Top of scrolling region (smallest)
+       short   ScrollHeight;   //!< Length of scrolling region
+
+        int    VideoCursorX;
+        int    VideoCursorY;
+       
+       tMutex  ReadingLock;    //!< Lock the VTerm when a process is reading from it
+       tTID    ReadingThread;  //!< Owner of the lock
+        int    InputRead;      //!< Input buffer read position
+        int    InputWrite;     //!< Input buffer write position
+       char    InputBuffer[MAX_INPUT_CHARS8];
+//     tSemaphore      InputSemaphore;
+       
+       Uint32          *Buffer;
+
+       // TODO: Do I need to keep this about?
+       // When should it be deallocated? on move to text mode, or some other time
+       // Call set again, it's freed, and if NULL it doesn't get reallocated.
+       tVideo_IOCtl_Bitmap     *VideoCursor;
+       
+       char    Name[2];        //!< Name of the terminal
+       tVFS_Node       Node;
+};
+
+// === GOBALS ===
+extern tVTerm  *gpVT_CurTerm;
+extern int     giVT_Scrollback;
+extern short   giVT_RealWidth; //!< Screen Width
+extern short   giVT_RealHeight;        //!< Screen Width
+extern char    *gsVT_OutputDevice;
+extern char    *gsVT_InputDevice;
+extern int     giVT_OutputDevHandle;
+extern int     giVT_InputDevHandle;
+
+// === FUNCTIONS ===
+extern void    VT_SetResolution(int Width, int Height);
+extern void    VT_SetTerminal(int ID);
+// --- Output ---
+extern void    VT_InitOutput(void);
+extern void    VT_SetMode(int Mode);
+extern void    VT_int_ScrollFramebuffer( tVTerm *Term, int Count );
+extern void    VT_int_UpdateCursor( tVTerm *Term, int bShow );
+extern void    VT_int_UpdateScreen( tVTerm *Term, int UpdateAll );
+// --- Input ---
+extern void    VT_InitInput(void);
+extern void    VT_KBCallBack(Uint32 Codepoint);
+// --- VT100 Emulation ---
+extern void    VT_int_ParseEscape_StandardLarge(tVTerm *Term, char CmdChar, int argc, int *args);
+extern int     VT_int_ParseEscape(tVTerm *Term, const char *Buffer);
+// --- Terminal Buffer ---
+extern void    VT_int_PutString(tVTerm *Term, const Uint8 *Buffer, Uint Count);
+extern void    VT_int_PutChar(tVTerm *Term, Uint32 Ch);
+extern void    VT_int_ScrollText(tVTerm *Term, int Count);
+extern void    VT_int_ClearLine(tVTerm *Term, int Num);
+extern void    VT_int_ChangeMode(tVTerm *Term, int NewMode, int NewWidth, int NewHeight);
+extern void    VT_int_ToggleAltBuffer(tVTerm *Term, int Enabled);
+
+#endif
+
diff --git a/Kernel/drv/vterm_font.c b/Kernel/drv/vterm_font.c
new file mode 100644 (file)
index 0000000..841ea50
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * drv/vterm_font.c
+ * - Virtual Terminal - Font rendering code
+ */
+#include "vterm.h"
+#include <api_drv_terminal.h>
+
+// ---
+// Font Render
+// ---
+#define MONOSPACE_FONT 10816
+
+#if MONOSPACE_FONT == 10808    // 8x8
+# include "vterm_font_8x8.h"
+#elif MONOSPACE_FONT == 10816  // 8x16
+# include "vterm_font_8x16.h"
+#endif
+
+// === PROTOTYPES ===
+Uint8  *VT_Font_GetChar(Uint32 Codepoint);
+
+// === GLOBALS ===
+int    giVT_CharWidth = FONT_WIDTH;
+int    giVT_CharHeight = FONT_HEIGHT;
+
+// === CODE ===
+/**
+ * \brief Render a font character
+ */
+void VT_Font_Render(Uint32 Codepoint, void *Buffer, int Depth, int Pitch, Uint32 BGC, Uint32 FGC)
+{
+       Uint8   *font;
+        int    x, y;
+       
+       // 8-bpp and below
+       if( Depth <= 8 )
+       {
+               Uint8   *buf = Buffer;
+               
+               font = VT_Font_GetChar(Codepoint);
+               
+               for(y = 0; y < FONT_HEIGHT; y ++)
+               {
+                       for(x = 0; x < FONT_WIDTH; x ++)
+                       {
+                               if(*font & (1 << (FONT_WIDTH-x-1)))
+                                       buf[x] = FGC;
+                               else
+                                       buf[x] = BGC;
+                       }
+                       buf = (void*)( (tVAddr)buf + Pitch );
+                       font ++;
+               }
+       }
+       // 16-bpp and below
+       else if( Depth <= 16 )
+       {
+               Uint16  *buf = Buffer;
+               
+               font = VT_Font_GetChar(Codepoint);
+               
+               for(y = 0; y < FONT_HEIGHT; y ++)
+               {
+                       for(x = 0; x < FONT_WIDTH; x ++)
+                       {
+                               if(*font & (1 << (FONT_WIDTH-x-1)))
+                                       buf[x] = FGC;
+                               else
+                                       buf[x] = BGC;
+                       }
+                       buf = (void*)( (tVAddr)buf + Pitch );
+                       font ++;
+               }
+       }
+       // 24-bpp colour
+       // - Special handling to not overwrite the next pixel
+       //TODO: Endian issues here
+       else if( Depth == 24 )
+       {
+               Uint8   *buf = Buffer;
+               Uint8   bg_r = (BGC >> 16) & 0xFF;
+               Uint8   bg_g = (BGC >>  8) & 0xFF;
+               Uint8   bg_b = (BGC >>  0) & 0xFF;
+               Uint8   fg_r = (FGC >> 16) & 0xFF;
+               Uint8   fg_g = (FGC >>  8) & 0xFF;
+               Uint8   fg_b = (FGC >>  0) & 0xFF;
+               
+               font = VT_Font_GetChar(Codepoint);
+               
+               for(y = 0; y < FONT_HEIGHT; y ++)
+               {
+                       for(x = 0; x < FONT_WIDTH; x ++)
+                       {
+                               Uint8   r, g, b;
+                               
+                               if(*font & (1 << (FONT_WIDTH-x-1))) {
+                                       r = fg_r;       g = fg_g;       b = fg_b;
+                               }
+                               else {
+                                       r = bg_r;       g = bg_g;       b = bg_b;
+                               }
+                               buf[x*3+0] = b;
+                               buf[x*3+1] = g;
+                               buf[x*3+2] = r;
+                       }
+                       buf = (void*)( (tVAddr)buf + Pitch );
+                       font ++;
+               }
+       }
+       // 32-bpp colour (nice and easy)
+       else if( Depth == 32 )
+       {
+               Uint32  *buf = Buffer;
+               
+               font = VT_Font_GetChar(Codepoint);
+               
+               for(y = 0; y < FONT_HEIGHT; y ++)
+               {
+                       for(x = 0; x < FONT_WIDTH; x ++)
+                       {
+                               if(*font & (1 << (FONT_WIDTH-x-1)))
+                                       buf[x] = FGC;
+                               else
+                                       buf[x] = BGC;
+                       }
+                       buf = (Uint32*)( (tVAddr)buf + Pitch );
+                       font ++;
+               }
+       }
+}
+
+/**
+ * \fn Uint32 VT_Colour12to24(Uint16 Col12)
+ * \brief Converts a 12-bit colour into 24 bits
+ */
+Uint32 VT_Colour12to24(Uint16 Col12)
+{
+       Uint32  ret;
+        int    tmp;
+       tmp = Col12 & 0xF;
+       ret  = (tmp << 0) | (tmp << 4);
+       tmp = (Col12 & 0xF0) >> 4;
+       ret |= (tmp << 8) | (tmp << 12);
+       tmp = (Col12 & 0xF00) >> 8;
+       ret |= (tmp << 16) | (tmp << 20);
+       return ret;
+}
+/**
+ * \brief Converts a 12-bit colour into 15 bits
+ */
+Uint16 VT_Colour12to15(Uint16 Col12)
+{
+       Uint32  ret;
+        int    tmp;
+       tmp = Col12 & 0xF;
+       ret  = (tmp << 1) | (tmp & 1);
+       tmp = (Col12 & 0xF0) >> 4;
+       ret |= ( (tmp << 1) | (tmp & 1) ) << 5;
+       tmp = (Col12 & 0xF00) >> 8;
+       ret |= ( (tmp << 1) | (tmp & 1) ) << 10;
+       return ret;
+}
+
+/**
+ * \brief Converts a 12-bit colour into any other depth
+ * \param Col12        12-bit source colour
+ * \param Depth        Desired bit deptj
+ * \note Green then blue get the extra avaliable bits (16:5-6-5, 14:4-5-5)
+ */
+Uint32 VT_Colour12toN(Uint16 Col12, int Depth)
+{
+       Uint32  ret;
+       Uint32  r, g, b;
+        int    rSize, gSize, bSize;
+       
+       // Fast returns
+       if( Depth == 24 )       return VT_Colour12to24(Col12);
+       if( Depth == 15 )       return VT_Colour12to15(Col12);
+       // - 32 is a special case, it's usually 24-bit colour with an unused byte
+       if( Depth == 32 )       return VT_Colour12to24(Col12);
+       
+       // Bounds checks
+       if( Depth < 8 ) return 0;
+       if( Depth > 32 )        return 0;
+       
+       r = Col12 & 0xF;
+       g = (Col12 & 0xF0) >> 4;
+       b = (Col12 & 0xF00) >> 8;
+       
+       rSize = gSize = bSize = Depth / 3;
+       if( rSize + gSize + bSize < Depth )     // Depth % 3 == 1
+               gSize ++;
+       if( rSize + gSize + bSize < Depth )     // Depth % 3 == 2
+               bSize ++;
+       
+       // Expand
+       r <<= rSize - 4;        g <<= gSize - 4;        b <<= bSize - 4;
+       // Fill with the lowest bit
+       if( Col12 & 0x001 )     r |= (1 << (rSize - 4)) - 1;
+       if( Col12 & 0x010 )     r |= (1 << (gSize - 4)) - 1;
+       if( Col12 & 0x100 )     r |= (1 << (bSize - 4)) - 1;
+       
+       // Create output
+       ret  = r;
+       ret |= g << rSize;
+       ret |= b << (rSize + gSize);
+       
+       return ret;
+}
+
+/**
+ * \fn Uint8 *VT_Font_GetChar(Uint32 Codepoint)
+ * \brief Gets an index into the font array given a Unicode Codepoint
+ * \note See http://en.wikipedia.org/wiki/CP437
+ */
+Uint8 *VT_Font_GetChar(Uint32 Codepoint)
+{
+        int    index = 0;
+       if(Codepoint < 128)
+               return &VTermFont[Codepoint*FONT_HEIGHT];
+       switch(Codepoint)
+       {
+       case 0xC7:      index = 128;    break;  // Ã‡
+       case 0xFC:      index = 129;    break;  // Ã¼
+       case 0xE9:      index = 130;    break;  // Ã©
+       case 0xE2:      index = 131;    break;  // Ã¢
+       case 0xE4:      index = 132;    break;  // Ã¤
+       case 0xE0:      index = 133;    break;  // Ã 
+       case 0xE5:      index = 134;    break;  // Ã¥
+       case 0xE7:      index = 135;    break;  // Ã§
+       case 0xEA:      index = 136;    break;  // Ãª
+       case 0xEB:      index = 137;    break;  // Ã«
+       case 0xE8:      index = 138;    break;  // Ã¨
+       case 0xEF:      index = 139;    break;  // Ã¯
+       case 0xEE:      index = 140;    break;  // Ã®
+       case 0xEC:      index = 141;    break;  // Ã¬
+       case 0xC4:      index = 142;    break;  // Ã„
+       case 0xC5:      index = 143;    break;  // Ã…
+       }
+       
+       return &VTermFont[index*FONT_HEIGHT];
+}
+
+EXPORTAS(&giVT_CharWidth, giVT_CharWidth);
+EXPORTAS(&giVT_CharHeight, giVT_CharHeight);
+EXPORT(VT_Font_Render);
+EXPORT(VT_Colour12to24);
diff --git a/Kernel/drv/vterm_input.c b/Kernel/drv/vterm_input.c
new file mode 100644 (file)
index 0000000..d83cede
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * drv/vterm_input.c
+ * - Virtual Terminal - Input code
+ */
+#include "vterm.h"
+#include <api_drv_keyboard.h>
+
+// === GLOBALS ===
+// --- Key States --- (Used for VT Switching/Magic Combos)
+ int   gbVT_CtrlDown = 0;
+ int   gbVT_AltDown = 0;
+ int   gbVT_SysrqDown = 0;
+
+// === CODE ===
+/**
+ * \fn void VT_InitInput()
+ * \brief Initialises the input
+ */
+void VT_InitInput()
+{
+       giVT_InputDevHandle = VFS_Open(gsVT_InputDevice, VFS_OPENFLAG_READ);
+       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);
+}
+
+/**
+ * \fn void VT_KBCallBack(Uint32 Codepoint)
+ * \brief Called on keyboard interrupt
+ * \param Codepoint    Pseudo-UTF32 character
+ * 
+ * Handles a key press and sends the key code to the user's buffer.
+ * If the code creates a kernel-magic sequence, it is not passed to the
+ * user and is handled in-kernel.
+ */
+void VT_KBCallBack(Uint32 Codepoint)
+{
+       tVTerm  *term = gpVT_CurTerm;
+
+       // Catch VT binds
+       switch( Codepoint & KEY_ACTION_MASK )
+       {
+       case KEY_ACTION_RELEASE:
+               switch(Codepoint & KEY_CODEPOINT_MASK)
+               {
+               case KEY_LALT:  gbVT_AltDown &= ~1;     break;
+               case KEY_RALT:  gbVT_AltDown &= ~2;     break;
+               case KEY_LCTRL: gbVT_CtrlDown &= ~1;    break;
+               case KEY_RCTRL: gbVT_CtrlDown &= ~2;    break;
+               }
+               break;
+       
+       case KEY_ACTION_PRESS:
+               switch(Codepoint & KEY_CODEPOINT_MASK)
+               {
+               case KEY_LALT:  gbVT_AltDown |= 1;      break;
+               case KEY_RALT:  gbVT_AltDown |= 2;      break;
+               case KEY_LCTRL: gbVT_CtrlDown |= 1;     break;
+               case KEY_RCTRL: gbVT_CtrlDown |= 2;     break;
+               }
+               
+               if(!gbVT_AltDown || !gbVT_CtrlDown)
+                       break;
+               switch(Codepoint & KEY_CODEPOINT_MASK)
+               {
+               case KEY_F1:    VT_SetTerminal(0);      return;
+               case KEY_F2:    VT_SetTerminal(1);      return;
+               case KEY_F3:    VT_SetTerminal(2);      return;
+               case KEY_F4:    VT_SetTerminal(3);      return;
+               case KEY_F5:    VT_SetTerminal(4);      return;
+               case KEY_F6:    VT_SetTerminal(5);      return;
+               case KEY_F7:    VT_SetTerminal(6);      return;
+               case KEY_F8:    VT_SetTerminal(7);      return;
+               case KEY_F9:    VT_SetTerminal(8);      return;
+               case KEY_F10:   VT_SetTerminal(9);      return;
+               case KEY_F11:   VT_SetTerminal(10);     return;
+               case KEY_F12:   VT_SetTerminal(11);     return;
+               }
+               
+               // Scrolling is only valid in text mode
+               if(gpVT_CurTerm->Mode != TERM_MODE_TEXT)
+                       break;
+               
+               switch(Codepoint & KEY_CODEPOINT_MASK)
+               {
+               // Scrolling
+               case KEY_PGUP:
+                       if( gpVT_CurTerm->Flags & VT_FLAG_ALTBUF )
+                               return ;
+                       gpVT_CurTerm->ViewPos = MAX(
+                               0,
+                               gpVT_CurTerm->ViewPos - gpVT_CurTerm->Width
+                               );
+                       return;
+               case KEY_PGDOWN:
+                       if( gpVT_CurTerm->Flags & VT_FLAG_ALTBUF )
+                               return ;
+                       gpVT_CurTerm->ViewPos = MIN(
+                               gpVT_CurTerm->ViewPos + gpVT_CurTerm->Width,
+                               gpVT_CurTerm->Width * gpVT_CurTerm->Height*giVT_Scrollback
+                               );
+                       return;
+               }
+               break;
+       }
+       
+       // Encode key
+       if(term->Mode == TERM_MODE_TEXT)
+       {
+               Uint8   buf[6] = {0};
+                int    len = 0;
+       
+               // Ignore anything that isn't a press or refire
+               if( (Codepoint & KEY_ACTION_MASK) != KEY_ACTION_PRESS
+                && (Codepoint & KEY_ACTION_MASK) != KEY_ACTION_REFIRE
+                   )
+               {
+                       return ;
+               }
+       
+               Codepoint &= KEY_CODEPOINT_MASK;
+
+               // Ignore Modifer Keys
+               if(Codepoint > KEY_MODIFIERS)   return;
+               
+               // Get UTF-8/ANSI Encoding
+               switch(Codepoint)
+               {
+               // 0: No translation, don't send to user
+               case 0: break;
+               case KEY_LEFT:
+                       buf[0] = '\x1B'; buf[1] = '['; buf[2] = 'D';
+                       len = 3;
+                       break;
+               case KEY_RIGHT:
+                       buf[0] = '\x1B'; buf[1] = '['; buf[2] = 'C';
+                       len = 3;
+                       break;
+               case KEY_UP:
+                       buf[0] = '\x1B'; buf[1] = '['; buf[2] = 'A';
+                       len = 3;
+                       break;
+               case KEY_DOWN:
+                       buf[0] = '\x1B'; buf[1] = '['; buf[2] = 'B';
+                       len = 3;
+                       break;
+               
+               case KEY_PGUP:
+                       buf[0] = '\x1B'; buf[1] = '['; buf[2] = '5'; buf[3] = '~';
+                       len = 4;
+                       break;
+               case KEY_PGDOWN:
+                       buf[0] = '\x1B'; buf[1] = '['; buf[2] = '6'; buf[3] = '~';
+                       len = 4;
+                       break;
+               
+               // Attempt to encode in UTF-8
+               default:
+                       len = WriteUTF8( buf, Codepoint );
+                       if(len == 0) {
+                               Warning("Codepoint (%x) is unrepresentable in UTF-8", Codepoint);
+                       }
+                       break;
+               }
+               
+               if(len == 0) {
+                       // Unprintable / Don't Pass
+                       return;
+               }
+
+#if 0
+               // Handle meta characters
+               if( !(term->Flags & VT_FLAG_RAWIN) )
+               {
+                       switch(buf[0])
+                       {
+                       case '\3':      // ^C
+                               
+                               break;
+                       }
+               }
+#endif
+               
+               // Write
+               if( MAX_INPUT_CHARS8 - term->InputWrite >= len )
+                       memcpy( &term->InputBuffer[term->InputWrite], buf, len );
+               else {
+                       memcpy( &term->InputBuffer[term->InputWrite], buf, MAX_INPUT_CHARS8 - term->InputWrite );
+                       memcpy( &term->InputBuffer[0], buf, len - (MAX_INPUT_CHARS8 - term->InputWrite) );
+               }
+               // Roll the buffer over
+               term->InputWrite += len;
+               term->InputWrite %= MAX_INPUT_CHARS8;
+               if( (term->InputWrite - term->InputRead + MAX_INPUT_CHARS8)%MAX_INPUT_CHARS8 < len ) {
+                       term->InputRead = term->InputWrite + 1;
+                       term->InputRead %= MAX_INPUT_CHARS8;
+               }
+       }
+       else
+       {
+               // Encode the raw key event
+               Uint32  *raw_in = (void*)term->InputBuffer;
+       
+               #if 0
+               // Drop new keys
+               if( term->InputWrite == term->InputRead )
+                       return ;                
+               #endif
+
+               raw_in[ term->InputWrite ] = Codepoint;
+               term->InputWrite ++;
+               if(term->InputWrite >= MAX_INPUT_CHARS32)
+                       term->InputWrite -= MAX_INPUT_CHARS32;
+               
+               #if 1
+               // TODO: Should old or new be dropped?
+               if(term->InputRead == term->InputWrite) {
+                       term->InputRead ++;
+                       if( term->InputRead >= MAX_INPUT_CHARS32 )
+                               term->InputRead -= MAX_INPUT_CHARS32;
+               }
+               #endif
+       }
+       
+       VFS_MarkAvaliable(&term->Node, 1);
+}
+
diff --git a/Kernel/drv/vterm_output.c b/Kernel/drv/vterm_output.c
new file mode 100644 (file)
index 0000000..95a2bce
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * drv/vterm_input.c
+ * - Virtual Terminal - Input code
+ */
+#include "vterm.h"
+#include <api_drv_video.h>
+
+// === CODE ===
+/**
+ * \fn void VT_InitOutput()
+ * \brief Initialise Video Output
+ */
+void VT_InitOutput()
+{
+       giVT_OutputDevHandle = VFS_Open(gsVT_OutputDevice, VFS_OPENFLAG_WRITE);
+       if(giVT_OutputDevHandle == -1) {
+               Log_Warning("VTerm", "Oh F**k, I can't open the video device '%s'", gsVT_OutputDevice);
+               return ;
+       }
+       VT_SetResolution( giVT_RealWidth, giVT_RealHeight );
+       VT_SetTerminal( 0 );
+       VT_SetMode( VIDEO_BUFFMT_TEXT );
+}
+
+/**
+ * \brief Set video output buffer mode
+ */
+void VT_SetMode(int Mode)
+{
+       VFS_IOCtl( giVT_OutputDevHandle, VIDEO_IOCTL_SETBUFFORMAT, &Mode );
+}
+
+/**
+ * \fn void VT_int_ScrollFramebuffer( tVTerm *Term, int Count )
+ * \note Scrolls the framebuffer down by \a Count text lines
+ */
+void VT_int_ScrollFramebuffer( tVTerm *Term, int Count )
+{
+        int    tmp;
+       struct {
+               Uint8   Op;
+               Uint16  DstX, DstY;
+               Uint16  SrcX, SrcY;
+               Uint16  W, H;
+       } PACKED        buf;
+       
+       // Only update if this is the current terminal
+       if( Term != gpVT_CurTerm )      return;
+       
+       if( Count > Term->ScrollHeight )        Count = Term->ScrollHeight;
+       if( Count < -Term->ScrollHeight )       Count = -Term->ScrollHeight;
+       
+       // Switch to 2D Command Stream
+       tmp = VIDEO_BUFFMT_2DSTREAM;
+       VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETBUFFORMAT, &tmp);
+       
+       // BLIT to 0,0 from 0,giVT_CharHeight
+       buf.Op = VIDEO_2DOP_BLIT;
+       buf.SrcX = 0;   buf.DstX = 0;
+       // TODO: Don't assume character dimensions
+       buf.W = Term->TextWidth * giVT_CharWidth;
+       if( Count > 0 )
+       {
+               buf.SrcY = (Term->ScrollTop+Count) * giVT_CharHeight;
+               buf.DstY = Term->ScrollTop * giVT_CharHeight;
+       }
+       else    // Scroll up, move text down
+       {
+               Count = -Count;
+               buf.SrcY = Term->ScrollTop * giVT_CharHeight;
+               buf.DstY = (Term->ScrollTop+Count) * giVT_CharHeight;
+       }
+       buf.H = (Term->ScrollHeight-Count) * giVT_CharHeight;
+       VFS_WriteAt(giVT_OutputDevHandle, 0, sizeof(buf), &buf);
+       
+       // Restore old mode (this function is only called during text mode)
+       tmp = VIDEO_BUFFMT_TEXT;
+       VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETBUFFORMAT, &tmp);
+}
+
+void VT_int_UpdateCursor( tVTerm *Term, int bShow )
+{
+       tVideo_IOCtl_Pos        csr_pos;
+
+       if( Term != gpVT_CurTerm )      return ;
+
+       if( !bShow )
+       {
+               csr_pos.x = -1; 
+               csr_pos.y = -1; 
+       }
+       else if( Term->Mode == TERM_MODE_TEXT )
+       {
+                int    offset;
+               
+//             if( !(Term->Flags & VT_FLAG_SHOWCSR)
+//              && ( (Term->Flags & VT_FLAG_HIDECSR) || !Term->Node.ReadThreads)
+//               )
+               if( !Term->Text || Term->Flags & VT_FLAG_HIDECSR )
+               {
+                       csr_pos.x = -1;
+                       csr_pos.y = -1;
+               }
+               else
+               {
+                       if(Term->Flags & VT_FLAG_ALTBUF)
+                               offset = Term->AltWritePos;
+                       else
+                               offset = Term->WritePos - Term->ViewPos;
+                                       
+                       csr_pos.x = offset % Term->TextWidth;
+                       csr_pos.y = offset / Term->TextWidth;
+                       if( 0 > csr_pos.y || csr_pos.y >= Term->TextHeight )
+                               csr_pos.y = -1, csr_pos.x = -1;
+               }
+       }
+       else
+       {
+               csr_pos.x = Term->VideoCursorX;
+               csr_pos.y = Term->VideoCursorY;
+       }
+       VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETCURSOR, &csr_pos);
+}      
+
+/**
+ * \fn void VT_int_UpdateScreen( tVTerm *Term, int UpdateAll )
+ * \brief Updates the video framebuffer
+ */
+void VT_int_UpdateScreen( tVTerm *Term, int UpdateAll )
+{
+       tVT_Char        *buffer;
+        int    view_pos, write_pos;
+       // Only update if this is the current terminal
+       if( Term != gpVT_CurTerm )      return;
+       
+       switch( Term->Mode )
+       {
+       case TERM_MODE_TEXT:
+               view_pos = (Term->Flags & VT_FLAG_ALTBUF) ? 0 : Term->ViewPos;
+               write_pos = (Term->Flags & VT_FLAG_ALTBUF) ? Term->AltWritePos : Term->WritePos;
+               buffer = (Term->Flags & VT_FLAG_ALTBUF) ? Term->AltBuf : Term->Text;
+               // Re copy the entire screen?
+               if(UpdateAll) {
+                       VFS_WriteAt(
+                               giVT_OutputDevHandle,
+                               0,
+                               Term->TextWidth*Term->TextHeight*sizeof(tVT_Char),
+                               &buffer[view_pos]
+                               );
+               }
+               // Only copy the current line
+               else {
+                        int    ofs = write_pos - write_pos % Term->TextWidth;
+                       VFS_WriteAt(
+                               giVT_OutputDevHandle,
+                               (ofs - view_pos)*sizeof(tVT_Char),
+                               Term->TextWidth*sizeof(tVT_Char),
+                               &buffer[ofs]
+                               );
+               }
+               break;
+       case TERM_MODE_FB:
+               break;
+       }
+       
+       VT_int_UpdateCursor(Term, 1);
+}
+
diff --git a/Kernel/drv/vterm_termbuf.c b/Kernel/drv/vterm_termbuf.c
new file mode 100644 (file)
index 0000000..2511048
--- /dev/null
@@ -0,0 +1,398 @@
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * drv/vterm_termbuf.c
+ * - Virtual Terminal - Terminal buffer manipulation
+ */
+#include "vterm.h"
+
+// === CODE ===
+
+/**
+ * \fn void VT_int_PutString(tVTerm *Term, const Uint8 *Buffer, Uint Count)
+ * \brief Print a string to the Virtual Terminal
+ */
+void VT_int_PutString(tVTerm *Term, const Uint8 *Buffer, Uint Count)
+{
+       Uint32  val;
+        int    i;
+       
+       // Iterate
+       for( i = 0; i < Count; i++ )
+       {
+               // Handle escape sequences
+               if( Buffer[i] == 0x1B )
+               {
+                       i ++;
+                       i += VT_int_ParseEscape(Term, (const char*)&Buffer[i]) - 1;
+                       continue;
+               }
+               
+               // Fast check for non UTF-8
+               if( Buffer[i] < 128 )   // Plain ASCII
+                       VT_int_PutChar(Term, Buffer[i]);
+               else {  // UTF-8
+                       i += ReadUTF8(&Buffer[i], &val) - 1;
+                       VT_int_PutChar(Term, val);
+               }
+       }
+       // Update Screen
+       VT_int_UpdateScreen( Term, 0 );
+}
+
+/**
+ * \fn void VT_int_PutChar(tVTerm *Term, Uint32 Ch)
+ * \brief Write a single character to a VTerm
+ */
+void VT_int_PutChar(tVTerm *Term, Uint32 Ch)
+{
+        int    i;
+       tVT_Char        *buffer;
+        int    write_pos;
+       
+       if(Term->Flags & VT_FLAG_ALTBUF) {
+               buffer = Term->AltBuf;
+               write_pos = Term->AltWritePos;
+       }
+       else {
+               buffer = Term->Text;
+               write_pos = Term->WritePos;
+       }
+       
+       switch(Ch)
+       {
+       case '\0':      return; // Ignore NULL byte
+       case '\n':
+               VT_int_UpdateScreen( Term, 0 ); // Update the line before newlining
+               write_pos += Term->TextWidth;
+       case '\r':
+               write_pos -= write_pos % Term->TextWidth;
+               break;
+       
+       case '\t': { int tmp = write_pos / Term->TextWidth;
+               write_pos %= Term->TextWidth;
+               do {
+                       buffer[ write_pos ].Ch = '\0';
+                       buffer[ write_pos ].Colour = Term->CurColour;
+                       write_pos ++;
+               } while(write_pos & 7);
+               write_pos += tmp * Term->TextWidth;
+               break; }
+       
+       case '\b':
+               // Backspace is invalid at Offset 0
+               if(write_pos == 0)      break;
+               
+               write_pos --;
+               // Singe Character
+               if(buffer[ write_pos ].Ch != '\0') {
+                       buffer[ write_pos ].Ch = 0;
+                       buffer[ write_pos ].Colour = Term->CurColour;
+                       break;
+               }
+               // Tab
+               i = 7;  // Limit it to 8
+               do {
+                       buffer[ write_pos ].Ch = 0;
+                       buffer[ write_pos ].Colour = Term->CurColour;
+                       write_pos --;
+               } while(write_pos && i-- && buffer[ write_pos ].Ch == '\0');
+               if(buffer[ write_pos ].Ch != '\0')
+                       write_pos ++;
+               break;
+       
+       default:
+               buffer[ write_pos ].Ch = Ch;
+               buffer[ write_pos ].Colour = Term->CurColour;
+               // Update the line before wrapping
+               if( (write_pos + 1) % Term->TextWidth == 0 )
+                       VT_int_UpdateScreen( Term, 0 );
+               write_pos ++;
+               break;
+       }
+       
+       if(Term->Flags & VT_FLAG_ALTBUF)
+       {
+               Term->AltBuf = buffer;
+               Term->AltWritePos = write_pos;
+               
+               if(Term->AltWritePos >= Term->TextWidth*Term->TextHeight)
+               {
+                       Term->AltWritePos -= Term->TextWidth;
+                       VT_int_ScrollText(Term, 1);
+               }
+               
+       }
+       else
+       {
+               Term->Text = buffer;
+               Term->WritePos = write_pos;
+               // Move Screen
+               // - Check if we need to scroll the entire scrollback buffer
+               if(Term->WritePos >= Term->TextWidth*Term->TextHeight*(giVT_Scrollback+1))
+               {
+                        int    base;
+                       
+                       // Update previous line
+                       Term->WritePos -= Term->TextWidth;
+                       VT_int_UpdateScreen( Term, 0 );
+                       
+                       // Update view position
+                       base = Term->TextWidth*Term->TextHeight*(giVT_Scrollback);
+                       if(Term->ViewPos < base)
+                               Term->ViewPos += Term->Width;
+                       if(Term->ViewPos > base)
+                               Term->ViewPos = base;
+                       
+                       VT_int_ScrollText(Term, 1);
+               }
+               // Ok, so we only need to scroll the screen
+               else if(Term->WritePos >= Term->ViewPos + Term->TextWidth*Term->TextHeight)
+               {
+                       // Update the last line
+                       Term->WritePos -= Term->TextWidth;
+                       VT_int_UpdateScreen( Term, 0 );
+                       Term->WritePos += Term->TextWidth;
+                       
+                       VT_int_ScrollText(Term, 1);
+                       
+                       Term->ViewPos += Term->TextWidth;
+               }
+       }
+       
+       //LEAVE('-');
+}
+
+void VT_int_ScrollText(tVTerm *Term, int Count)
+{
+       tVT_Char        *buf;
+        int    height, init_write_pos;
+        int    len, i;
+        int    scroll_top, scroll_height;
+
+       // Get buffer pointer and attributes    
+       if( Term->Flags & VT_FLAG_ALTBUF )
+       {
+               buf = Term->AltBuf;
+               height = Term->TextHeight;
+               init_write_pos = Term->AltWritePos;
+               scroll_top = Term->ScrollTop;
+               scroll_height = Term->ScrollHeight;
+       }
+       else
+       {
+               buf = Term->Text;
+               height = Term->TextHeight*(giVT_Scrollback+1);
+               init_write_pos = Term->WritePos;
+               scroll_top = 0;
+               scroll_height = height;
+       }
+
+       // Scroll text downwards        
+       if( Count > 0 )
+       {
+                int    base;
+       
+               // Set up
+               if(Count > scroll_height)       Count = scroll_height;
+               base = Term->TextWidth*(scroll_top + scroll_height - Count);
+               len = Term->TextWidth*(scroll_height - Count);
+               
+               // Scroll terminal cache
+               memmove(
+                       &buf[Term->TextWidth*scroll_top],
+                       &buf[Term->TextWidth*(scroll_top+Count)],
+                       len*sizeof(tVT_Char)
+                       );
+               // Clear last rows
+               for( i = 0; i < Term->TextWidth*Count; i ++ )
+               {
+                       buf[ base + i ].Ch = 0;
+                       buf[ base + i ].Colour = Term->CurColour;
+               }
+               
+               // Update Screen
+               VT_int_ScrollFramebuffer( Term, Count );
+               if( Term->Flags & VT_FLAG_ALTBUF )
+                       Term->AltWritePos = base;
+               else
+                       Term->WritePos = Term->ViewPos + Term->TextWidth*(Term->TextHeight - Count);
+               for( i = 0; i < Count; i ++ )
+               {
+                       VT_int_UpdateScreen( Term, 0 );
+                       if( Term->Flags & VT_FLAG_ALTBUF )
+                               Term->AltWritePos += Term->TextWidth;
+                       else
+                               Term->WritePos += Term->TextWidth;
+               }
+       }
+       else
+       {
+               Count = -Count;
+               if(Count > scroll_height)       Count = scroll_height;
+               
+               len = Term->TextWidth*(scroll_height - Count);
+               
+               // Scroll terminal cache
+               memmove(
+                       &buf[Term->TextWidth*(scroll_top+Count)],
+                       &buf[Term->TextWidth*scroll_top],
+                       len*sizeof(tVT_Char)
+                       );
+               // Clear preceding rows
+               for( i = 0; i < Term->TextWidth*Count; i ++ )
+               {
+                       buf[ i ].Ch = 0;
+                       buf[ i ].Colour = Term->CurColour;
+               }
+               
+               VT_int_ScrollFramebuffer( Term, -Count );
+               if( Term->Flags & VT_FLAG_ALTBUF )
+                       Term->AltWritePos = Term->TextWidth*scroll_top;
+               else
+                       Term->WritePos = Term->ViewPos;
+               for( i = 0; i < Count; i ++ )
+               {
+                       VT_int_UpdateScreen( Term, 0 );
+                       if( Term->Flags & VT_FLAG_ALTBUF )
+                               Term->AltWritePos += Term->TextWidth;
+                       else
+                               Term->WritePos += Term->TextWidth;
+               }
+       }
+       
+       if( Term->Flags & VT_FLAG_ALTBUF )
+               Term->AltWritePos = init_write_pos;
+       else
+               Term->WritePos = init_write_pos;
+}
+
+/**
+ * \brief Clears a line in a virtual terminal
+ * \param Term Terminal to modify
+ * \param Num  Line number to clear
+ */
+void VT_int_ClearLine(tVTerm *Term, int Num)
+{
+        int    i;
+       tVT_Char        *cell;
+       
+       if( Num < 0 || Num >= Term->TextHeight * (giVT_Scrollback + 1) )        return ;
+       
+       cell = (Term->Flags & VT_FLAG_ALTBUF) ? Term->AltBuf : Term->Text;
+       cell = &cell[ Num*Term->TextWidth ];
+       
+       for( i = Term->TextWidth; i--; )
+       {
+               cell[ i ].Ch = 0;
+               cell[ i ].Colour = Term->CurColour;
+       }
+}
+
+/**
+ * \brief Update the screen mode
+ * \param Term Terminal to update
+ * \param NewMode      New mode to set
+ * \param NewWidth     New framebuffer width
+ * \param NewHeight    New framebuffer height
+ */
+void VT_int_ChangeMode(tVTerm *Term, int NewMode, int NewWidth, int NewHeight)
+{
+        int    oldW = Term->Width;
+        int    oldTW = Term->TextWidth;
+        int    oldH = Term->Height;
+        int    oldTH = Term->TextHeight;
+       tVT_Char        *oldTBuf = Term->Text;
+       Uint32  *oldFB = Term->Buffer;
+        int    w, h, i;
+       
+       // TODO: Increase RealWidth/RealHeight when this happens
+       if(NewWidth > giVT_RealWidth)   NewWidth = giVT_RealWidth;
+       if(NewHeight > giVT_RealHeight) NewHeight = giVT_RealHeight;
+       
+       Term->Mode = NewMode;
+
+       // Fast exit if no resolution change
+       if(NewWidth == Term->Width && NewHeight == Term->Height)
+               return ;
+       
+       // Calculate new dimensions
+       Term->Width = NewWidth;
+       Term->Height = NewHeight;
+       Term->TextWidth = NewWidth / giVT_CharWidth;
+       Term->TextHeight = NewHeight / giVT_CharHeight;
+       Term->ScrollHeight = Term->TextHeight - (oldTH - Term->ScrollHeight) - Term->ScrollTop;
+       
+       // Allocate new buffers
+       // - Text
+       Term->Text = calloc(
+               Term->TextWidth * Term->TextHeight * (giVT_Scrollback+1),
+               sizeof(tVT_Char)
+               );
+       if(oldTBuf) {
+               // Copy old buffer
+               w = (oldTW > Term->TextWidth) ? Term->TextWidth : oldTW;
+               h = (oldTH > Term->TextHeight) ? Term->TextHeight : oldTH;
+               h *= giVT_Scrollback + 1;
+               for( i = 0; i < h; i ++ )
+               {
+                       memcpy(
+                               &Term->Text[i*Term->TextWidth],
+                               &oldTBuf[i*oldTW],
+                               w*sizeof(tVT_Char)
+                               );      
+               }
+               free(oldTBuf);
+       }
+       
+       // - Alternate Text
+       Term->AltBuf = realloc(
+               Term->AltBuf,
+               Term->TextWidth * Term->TextHeight * sizeof(tVT_Char)
+               );
+       
+       // - Framebuffer
+       if(oldFB) {
+               Term->Buffer = calloc( Term->Width * Term->Height, sizeof(Uint32) );
+               // Copy old buffer
+               w = (oldW > Term->Width) ? Term->Width : oldW;
+               h = (oldH > Term->Height) ? Term->Height : oldH;
+               for( i = 0; i < h; i ++ )
+               {
+                       memcpy(
+                               &Term->Buffer[i*Term->Width],
+                               &oldFB[i*oldW],
+                               w*sizeof(Uint32)
+                               );
+               }
+               free(oldFB);
+       }
+       
+       // Debug
+       switch(NewMode)
+       {
+       case TERM_MODE_TEXT:
+               Log_Log("VTerm", "Set VT %p to text mode (%ix%i)",
+                       Term, Term->TextWidth, Term->TextHeight);
+               break;
+       case TERM_MODE_FB:
+               Log_Log("VTerm", "Set VT %p to framebuffer mode (%ix%i)",
+                       Term, Term->Width, Term->Height);
+               break;
+       //case TERM_MODE_2DACCEL:
+       //case TERM_MODE_3DACCEL:
+       //      return;
+       }
+}
+
+
+void VT_int_ToggleAltBuffer(tVTerm *Term, int Enabled)
+{      
+       if(Enabled)
+               Term->Flags |= VT_FLAG_ALTBUF;
+       else
+               Term->Flags &= ~VT_FLAG_ALTBUF;
+       VT_int_UpdateScreen(Term, 1);
+}
+
diff --git a/Kernel/drv/vterm_vt100.c b/Kernel/drv/vterm_vt100.c
new file mode 100644 (file)
index 0000000..fb152a3
--- /dev/null
@@ -0,0 +1,295 @@
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * drv/vterm_vt100.c
+ * - Virtual Terminal - VT100 (Kinda) Emulation
+ */
+#include "vterm.h"
+
+// === CONSTANTS ===
+const Uint16   caVT100Colours[] = {
+               // Black, Red, Green, Yellow, Blue, Purple, Cyan, Gray
+               // Same again, but bright
+               VT_COL_BLACK, 0x700, 0x070, 0x770, 0x007, 0x707, 0x077, 0xAAA,
+               VT_COL_GREY, 0xF00, 0x0F0, 0xFF0, 0x00F, 0xF0F, 0x0FF, VT_COL_WHITE
+       };
+
+// === CODE ===
+/**
+ * \brief Handle a standard large escape code
+ * 
+ * Handles any escape code of the form \x1B[n,...A where n is an integer
+ * and A is any letter.
+ */
+void VT_int_ParseEscape_StandardLarge(tVTerm *Term, char CmdChar, int argc, int *args)
+{
+        int    tmp = 1;
+       switch(CmdChar)
+       {
+       // Left
+       case 'D':
+               tmp = -1;
+       // Right
+       case 'C':
+               if(argc == 1)   tmp *= args[0];
+               if( Term->Flags & VT_FLAG_ALTBUF )
+               {
+                       if( (Term->AltWritePos + tmp) % Term->TextWidth == 0 ) {
+                               Term->AltWritePos -= Term->AltWritePos % Term->TextWidth;
+                               Term->AltWritePos += Term->TextWidth - 1;
+                       }
+                       else
+                               Term->AltWritePos += tmp;
+               }
+               else
+               {
+                       if( (Term->WritePos + tmp) % Term->TextWidth == 0 ) {
+                               Term->WritePos -= Term->WritePos % Term->TextWidth;
+                               Term->WritePos += Term->TextWidth - 1;
+                       }
+                       else
+                               Term->WritePos += tmp;
+               }
+               break;
+       
+       // Erase
+       case 'J':
+               switch(args[0])
+               {
+               case 0: // Erase below
+                       break;
+               case 1: // Erase above
+                       break;
+               case 2: // Erase all
+                       if( Term->Flags & VT_FLAG_ALTBUF )
+                       {
+                                int    i = Term->TextHeight;
+                               while( i-- )    VT_int_ClearLine(Term, i);
+                               Term->AltWritePos = 0;
+                               VT_int_UpdateScreen(Term, 1);
+                       }
+                       else
+                       {
+                                int    i = Term->TextHeight * (giVT_Scrollback + 1);
+                               while( i-- )    VT_int_ClearLine(Term, i);
+                               Term->WritePos = 0;
+                               Term->ViewPos = 0;
+                               VT_int_UpdateScreen(Term, 1);
+                       }
+                       break;
+               }
+               break;
+       
+       // Erase in line
+       case 'K':
+               switch(args[0])
+               {
+               case 0: // Erase to right
+                       if( Term->Flags & VT_FLAG_ALTBUF )
+                       {
+                                int    i, max;
+                               max = Term->Width - Term->AltWritePos % Term->Width;
+                               for( i = 0; i < max; i ++ )
+                                       Term->AltBuf[Term->AltWritePos+i].Ch = 0;
+                       }
+                       else
+                       {
+                                int    i, max;
+                               max = Term->Width - Term->WritePos % Term->Width;
+                               for( i = 0; i < max; i ++ )
+                                       Term->Text[Term->WritePos+i].Ch = 0;
+                       }
+                       VT_int_UpdateScreen(Term, 0);
+                       break;
+               case 1: // Erase to left
+                       if( Term->Flags & VT_FLAG_ALTBUF )
+                       {
+                                int    i = Term->AltWritePos % Term->Width;
+                               while( i -- )
+                                       Term->AltBuf[Term->AltWritePos++].Ch = 0;
+                       }
+                       else
+                       {
+                                int    i = Term->WritePos % Term->Width;
+                               while( i -- )
+                                       Term->Text[Term->WritePos++].Ch = 0;
+                       }
+                       VT_int_UpdateScreen(Term, 0);
+                       break;
+               case 2: // Erase all
+                       if( Term->Flags & VT_FLAG_ALTBUF )
+                       {
+                               VT_int_ClearLine(Term, Term->AltWritePos / Term->Width);
+                       }
+                       else
+                       {
+                               VT_int_ClearLine(Term, Term->WritePos / Term->Width);
+                       }
+                       VT_int_UpdateScreen(Term, 0);
+                       break;
+               }
+               break;
+       
+       // Set cursor position
+       case 'H':
+               if( Term->Flags & VT_FLAG_ALTBUF )
+                       Term->AltWritePos = args[0] + args[1]*Term->TextWidth;
+               else
+                       Term->WritePos = args[0] + args[1]*Term->TextWidth;
+               //Log_Debug("VTerm", "args = {%i, %i}", args[0], args[1]);
+               break;
+       
+       // Scroll up `n` lines
+       case 'S':
+               tmp = -1;
+       // Scroll down `n` lines
+       case 'T':
+               if(argc == 1)   tmp *= args[0];
+               if( Term->Flags & VT_FLAG_ALTBUF )
+                       VT_int_ScrollText(Term, tmp);
+               else
+               {
+                       if(Term->ViewPos/Term->TextWidth + tmp < 0)
+                               break;
+                       if(Term->ViewPos/Term->TextWidth + tmp  > Term->TextHeight * (giVT_Scrollback + 1))
+                               break;
+                       
+                       Term->ViewPos += Term->TextWidth*tmp;
+               }
+               break;
+       
+       // Set Font flags
+       case 'm':
+               for( ; argc--; )
+               {
+                        int    colour_idx;
+                       // Flags
+                       if( 0 <= args[argc] && args[argc] <= 8)
+                       {
+                               switch(args[argc])
+                               {
+                               case 0: Term->CurColour = DEFAULT_COLOUR;       break;  // Reset
+                               case 1: Term->CurColour |= 0x80000000;  break;  // Bright
+                               case 2: Term->CurColour &= ~0x80000000; break;  // Dim
+                               }
+                       }
+                       // Foreground Colour
+                       else if(30 <= args[argc] && args[argc] <= 37) {
+                               // Get colour index, accounting for bright bit
+                               colour_idx = args[argc]-30 + ((Term->CurColour>>28) & 8);
+                               Term->CurColour &= 0x8000FFFF;
+                               Term->CurColour |= (Uint32)caVT100Colours[ colour_idx ] << 16;
+                       }
+                       // Background Colour
+                       else if(40 <= args[argc] && args[argc] <= 47) {
+                               // Get colour index, accounting for bright bit
+                               colour_idx = args[argc]-40 + ((Term->CurColour>>12) & 8);
+                               Term->CurColour &= 0xFFFF8000;
+                               Term->CurColour |= caVT100Colours[ colour_idx ];
+                       }
+                       else {
+                               Log_Warning("VTerm", "Unknown font flag %i", args[argc]);
+                       }
+               }
+               break;
+       
+       // Set scrolling region
+       case 'r':
+               if( argc != 2 ) break;
+               Term->ScrollTop = args[0];
+               Term->ScrollHeight = args[1] - args[0];
+               break;
+       
+       default:
+               Log_Warning("VTerm", "Unknown control sequence '\\x1B[%c'", CmdChar);
+               break;
+       }
+}
+
+/**
+ * \fn int VT_int_ParseEscape(tVTerm *Term, const char *Buffer)
+ * \brief Parses a VT100 Escape code
+ */
+int VT_int_ParseEscape(tVTerm *Term, const char *Buffer)
+{
+       char    c;
+        int    argc = 0, j = 1;
+        int    args[6] = {0,0,0,0};
+        int    bQuestionMark = 0;
+       
+       switch(Buffer[0])
+       {
+       //Large Code
+       case '[':
+               // Get Arguments
+               c = Buffer[j++];
+               if(c == '?') {
+                       bQuestionMark = 1;
+                       c = Buffer[j++];
+               }
+               if( '0' <= c && c <= '9' )
+               {
+                       do {
+                               if(c == ';')    c = Buffer[j++];
+                               while('0' <= c && c <= '9') {
+                                       args[argc] *= 10;
+                                       args[argc] += c-'0';
+                                       c = Buffer[j++];
+                               }
+                               argc ++;
+                       } while(c == ';');
+               }
+               
+               // Get Command
+               if( ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'))
+               {
+                       if( bQuestionMark )
+                       {
+                               switch(c)
+                               {
+                               // DEC Private Mode Set
+                               case 'h':
+                                       if(argc != 1)   break;
+                                       switch(args[0])
+                                       {
+                                       case 25:
+                                               Term->Flags &= ~VT_FLAG_HIDECSR;
+                                               break;
+                                       case 1047:
+                                               VT_int_ToggleAltBuffer(Term, 1);
+                                               break;
+                                       }
+                                       break;
+                               case 'l':
+                                       if(argc != 1)   break;
+                                       switch(args[0])
+                                       {
+                                       case 25:
+                                               Term->Flags |= VT_FLAG_HIDECSR;
+                                               break;
+                                       case 1047:
+                                               VT_int_ToggleAltBuffer(Term, 0);
+                                               break;
+                                       }
+                                       break;
+                               default:
+                                       Log_Warning("VTerm", "Unknown control sequence '\\x1B[?%c'", c);
+                                       break;
+                               }
+                       }
+                       else
+                       {
+                               VT_int_ParseEscape_StandardLarge(Term, c, argc, args);
+                       }
+               }
+               break;
+               
+       default:
+               Log_Notice("VTerm", "TODO: Handle short escape codes");
+               break;
+       }
+       
+       //Log_Debug("VTerm", "j = %i, Buffer = '%s'", j, Buffer);
+       return j;
+}
index 00ab5ce..d19a050 100644 (file)
@@ -53,17 +53,17 @@ tVideo_IOCtl_Bitmap gDrvUtil_TextModeCursor = {
 
 // === CODE ===
 // --- Video Driver Helpers ---
-int DrvUtil_Video_2DStream(void *Ent, void *Buffer, int Length,
+int DrvUtil_Video_2DStream(void *Ent, const void *Buffer, int Length,
        tDrvUtil_Video_2DHandlers *Handlers, int SizeofHandlers)
 {
-       void    *stream = Buffer;
+       const Uint8     *stream = Buffer;
         int    rem = Length;
         int    op;
        while( rem )
        {
                rem --;
-               op = *(Uint8*)stream;
-               stream = (void*)((tVAddr)stream + 1);
+               op = *stream;
+               stream ++;
                
                if(op > NUM_VIDEO_2DOPS) {
                        Log_Warning("DrvUtil",
@@ -84,7 +84,7 @@ int DrvUtil_Video_2DStream(void *Ent, void *Buffer, int Length,
                case VIDEO_2DOP_NOP:    break;
                
                case VIDEO_2DOP_FILL:
-                       if(rem < 12)    return Length-rem;
+                       if(rem < 10)    return Length-rem;
                        
                        if(!Handlers->Fill) {
                                Log_Warning("DrvUtil", "DrvUtil_Video_2DStream: Driver"
@@ -94,13 +94,13 @@ int DrvUtil_Video_2DStream(void *Ent, void *Buffer, int Length,
                        
                        Handlers->Fill(
                                Ent,
-                               ((Uint16*)stream)[0], ((Uint16*)stream)[1],
-                               ((Uint16*)stream)[2], ((Uint16*)stream)[3],
-                               ((Uint32*)stream)[2]
+                               ((const Uint16*)stream)[0], ((const Uint16*)stream)[1],
+                               ((const Uint16*)stream)[2], ((const Uint16*)stream)[3],
+                               ((const Uint32*)stream)[4]
                                );
                        
-                       rem -= 12;
-                       stream = (void*)((tVAddr)stream + 12);
+                       rem -= 10;
+                       stream += 10;
                        break;
                
                case VIDEO_2DOP_BLIT:
@@ -114,13 +114,13 @@ int DrvUtil_Video_2DStream(void *Ent, void *Buffer, int Length,
                        
                        Handlers->Blit(
                                Ent,
-                               ((Uint16*)stream)[0], ((Uint16*)stream)[1],
-                               ((Uint16*)stream)[2], ((Uint16*)stream)[3],
-                               ((Uint16*)stream)[4], ((Uint16*)stream)[5]
+                               ((const Uint16*)stream)[0], ((const Uint16*)stream)[1],
+                               ((const Uint16*)stream)[2], ((const Uint16*)stream)[3],
+                               ((const Uint16*)stream)[4], ((const Uint16*)stream)[5]
                                );
                        
                        rem -= 12;
-                       stream = (void*)((tVAddr)stream + 12);
+                       stream += 12;
                        break;
                
                }
@@ -128,10 +128,10 @@ int DrvUtil_Video_2DStream(void *Ent, void *Buffer, int Length,
        return 0;
 }
 
-int DrvUtil_Video_WriteLFB(tDrvUtil_Video_BufInfo *FBInfo, size_t Offset, size_t Length, void *Buffer)
+int DrvUtil_Video_WriteLFB(tDrvUtil_Video_BufInfo *FBInfo, size_t Offset, size_t Length, const void *Buffer)
 {
        Uint8   *dest;
-       Uint32  *src = Buffer;
+       const Uint32    *src = Buffer;
         int    csr_x, csr_y;
         int    x, y;
         int    bytes_per_px = (FBInfo->Depth + 7) / 8;
@@ -147,7 +147,7 @@ int DrvUtil_Video_WriteLFB(tDrvUtil_Video_BufInfo *FBInfo, size_t Offset, size_t
        {
        case VIDEO_BUFFMT_TEXT:
                {
-               tVT_Char        *chars = Buffer;
+               const tVT_Char  *chars = Buffer;
                 int    widthInChars = FBInfo->Width/giVT_CharWidth;
                 int    heightInChars = FBInfo->Height/giVT_CharHeight;
                 int    i;
@@ -556,7 +556,7 @@ void DrvUtil_Video_2D_Blit(void *Ent, Uint16 DstX, Uint16 DstY, Uint16 SrcX, Uin
 
 // --- Disk Driver Helpers ---
 Uint64 DrvUtil_ReadBlock(Uint64 Start, Uint64 Length, void *Buffer,
-       tDrvUtil_Callback ReadBlocks, Uint64 BlockSize, Uint Argument)
+       tDrvUtil_Read_Callback ReadBlocks, Uint64 BlockSize, Uint Argument)
 {
        Uint8   tmp[BlockSize]; // C99
        Uint64  block = Start / BlockSize;
@@ -625,8 +625,8 @@ Uint64 DrvUtil_ReadBlock(Uint64 Start, Uint64 Length, void *Buffer,
        return Length;
 }
 
-Uint64 DrvUtil_WriteBlock(Uint64 Start, Uint64 Length, void *Buffer,
-       tDrvUtil_Callback ReadBlocks, tDrvUtil_Callback WriteBlocks,
+Uint64 DrvUtil_WriteBlock(Uint64 Start, Uint64 Length, const void *Buffer,
+       tDrvUtil_Read_Callback ReadBlocks, tDrvUtil_Write_Callback WriteBlocks,
        Uint64 BlockSize, Uint Argument)
 {
        Uint8   tmp[BlockSize]; // C99
diff --git a/Kernel/events.c b/Kernel/events.c
new file mode 100644 (file)
index 0000000..a9eab78
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * events.c
+ * - Thread level event handling
+ */
+#define DEBUG  0
+#include <acess.h>
+#include <threads_int.h>
+#include <events.h>
+
+// === CODE ===
+void Threads_PostEvent(tThread *Thread, Uint32 EventMask)
+{
+       // Sanity checking
+       if( !Thread )   return ;
+       if( EventMask == 0 )    return ;
+       // TODO: Check that only one bit is set?
+       
+       ENTER("pThread xEventMask", Thread, EventMask);
+
+       SHORTLOCK( &Thread->IsLocked );
+
+       Thread->EventState |= EventMask;
+       LOG("Thread->EventState = 0x%x", Thread->EventState);
+       
+       // Currently sleeping on an event?
+       if( Thread->Status == THREAD_STAT_EVENTSLEEP )
+       {
+               // Waiting on this event?
+               if( (Uint32)Thread->RetStatus & EventMask )
+               {
+                       // Wake up
+                       LOG("Waking thread %p(%i %s)", Thread, Thread->TID, Thread->ThreadName);
+                       Threads_AddActive(Thread);
+               }
+       }
+       
+       SHORTREL( &Thread->IsLocked );
+       LEAVE('-');
+}
+
+/**
+ * \brief Wait for an event to occur
+ */
+Uint32 Threads_WaitEvents(Uint32 EventMask)
+{
+       Uint32  rv;
+       tThread *us = Proc_GetCurThread();
+
+       ENTER("xEventMask", EventMask);
+
+       // Early return check
+       if( EventMask == 0 )
+       {
+               LEAVE('i', 0);
+               return 0;
+       }
+       
+       LOG("us = %p(%i %s)", us, us->TID, us->ThreadName);
+
+       // Check if a wait is needed
+       SHORTLOCK( &us->IsLocked );
+       while( !(us->EventState & EventMask) )
+       {
+               LOG("Locked and preparing for wait");
+               // Wait
+               us->RetStatus = EventMask;      // HACK: Store EventMask in RetStatus
+               SHORTLOCK( &glThreadListLock );
+               us = Threads_RemActive();
+               us->Status = THREAD_STAT_EVENTSLEEP;
+               // Note stored anywhere because we're woken using other means
+               SHORTREL( &glThreadListLock );
+               SHORTREL( &us->IsLocked );
+               while(us->Status == THREAD_STAT_EVENTSLEEP)     Threads_Yield();
+               // Woken when lock is acquired
+               SHORTLOCK( &us->IsLocked );
+       }
+       
+       // Get return value and clear changed event bits
+       rv = us->EventState & EventMask;
+       us->EventState &= ~EventMask;
+       
+       SHORTREL( &us->IsLocked );
+       
+       LEAVE('x', rv);
+       return rv;
+}
+
index 921cc6b..eefd13c 100644 (file)
@@ -68,7 +68,7 @@ void *Heap_Extend(int Bytes)
        
        // Bounds Check
        if( (tVAddr)gHeapEnd + ((Bytes+0xFFF)&~0xFFF) > MM_KHEAP_MAX ) {
-               Bytes = MM_KHEAP_MAX - (tVAddr)gHeapEnd;
+//             Bytes = MM_KHEAP_MAX - (tVAddr)gHeapEnd;
                return NULL;
        }
        
index 0d0e1bb..1c645c2 100644 (file)
 #include "errno.h"
 
 // --- Types ---
-typedef  int   tPID;   //!< Process ID type
-typedef  int   tTID;   //!< Thread ID Type
-typedef Uint   tUID;   //!< User ID Type
-typedef Uint   tGID;   //!< Group ID Type
+typedef Uint32 tPID;   //!< Process ID type
+typedef Uint32 tTID;   //!< Thread ID Type
+typedef Uint32 tUID;   //!< User ID Type
+typedef Uint32 tGID;   //!< Group ID Type
 typedef Sint64 tTimestamp;     //!< Timestamp (miliseconds since 00:00 1 Jan 1970)
 typedef Sint64 tTime;  //!< Same again
 typedef struct sShortSpinlock  tShortSpinlock; //!< Opaque (kinda) spinlock
@@ -63,30 +63,8 @@ extern const char gsGitHash[];
  * \}
  */
 
-/**
- * \name Per-Thread Configuration Settings
- * \{
- */
-enum eConfigTypes {
-       CFGT_NULL,
-       CFGT_INT,
-       CFGT_HEAPSTR,
-       CFGT_PTR
-};
-enum eConfigs {
-       CFG_VFS_CWD,
-       CFG_VFS_MAXFILES,
-       CFG_VFS_CHROOT,
-       CFG_ERRNO,
-       NUM_CFG_ENTRIES
-};
-#define CFGINT(id)     (*Threads_GetCfgPtr(id))
-#define CFGPTR(id)     (*(void**)Threads_GetCfgPtr(id))
-
-#define errno  (CFGINT(CFG_ERRNO))
-/**
- * \}
- */
+//! \brief Error number
+#define errno  (*Threads_GetErrno())
 
 // === CONSTANTS ===
 // --- Memory Flags --
@@ -110,6 +88,8 @@ enum eConfigs {
  */
 //! Clone the entire process
 #define CLONE_VM       0x10
+//! Don't copy user pages
+#define CLONE_NOUSER   0x20
 /**
  * \}
  */
@@ -212,7 +192,7 @@ extern void Debug_HexDump(const char *Header, const void *Data, Uint Length);
 
 // --- IO ---
 #if NO_IO_BUS
-#define inb(a) (Log_Panic("Arch", "ARMv7 does not support in*/out* (%s:%i)", __FILE__, __LINE__),0)
+#define inb(a) (Log_Panic("Arch", STR(ARCHDIR)" does not support in*/out* (%s:%i)", __FILE__, __LINE__),0)
 #define inw(a) inb(a)
 #define ind(a) inb(a)
 #define inq(a) inb(a)
@@ -437,12 +417,14 @@ extern int        strpos(const char *Str, char Ch);
 extern int     strpos8(const char *str, Uint32 search);
 extern void    itoa(char *buf, Uint64 num, int base, int minLength, char pad);
 extern int     atoi(const char *string);
+extern int     ParseInt(const char *string, int *Val);
 extern int     ReadUTF8(const Uint8 *str, Uint32 *Val);
 extern int     WriteUTF8(Uint8 *str, Uint32 Val);
 extern int     ModUtil_SetIdent(char *Dest, const char *Value);
 extern int     ModUtil_LookupString(const char **Array, const char *Needle);
 
 extern Uint8   ByteSum(const void *Ptr, int Size);
+extern int     Hex(char *Dest, size_t Size, const Uint8 *SourceData);
 extern int     UnHex(Uint8 *Dest, size_t DestSize, const char *SourceString);
 /**
  * \}
@@ -465,6 +447,10 @@ extern int CallWithArgArray(void *Function, int NArgs, Uint *Args);
 
 // --- Heap ---
 #include <heap.h>
+/**
+ * \brief Magic heap allocation function
+ */
+extern void    *alloca(size_t Size);
 
 // --- Modules ---
 /**
@@ -520,6 +506,8 @@ extern void Time_Delay(int Delay);
  */
 extern int     Proc_SpawnWorker(void (*Fcn)(void*), void *Data);
 extern int     Proc_Spawn(const char *Path);
+extern int     Proc_SysSpawn(const char *Binary, const char **ArgV, const char **EnvP, int nFD, int *FDs);
+extern int     Proc_Execve(const char *File, const char **ArgV, const char **EnvP, int DataSize);
 extern void    Threads_Exit(int TID, int Status);
 extern void    Threads_Yield(void);
 extern void    Threads_Sleep(void);
@@ -529,7 +517,7 @@ extern tTID Threads_GetTID(void);
 extern tUID    Threads_GetUID(void);
 extern tGID    Threads_GetGID(void);
 extern int     SpawnTask(tThreadFunction Function, void *Arg);
-extern Uint    *Threads_GetCfgPtr(int Id);
+extern int     *Threads_GetErrno(void);
 extern int     Threads_SetName(const char *NewName);
 /**
  * \}
index 68e5330..94ea2c9 100644 (file)
@@ -148,7 +148,8 @@ enum eTplDisk_CacheFlags
  * \param Buffer       Destination for read blocks\r
  * \param Argument     Argument provided in ::DrvUtil_ReadBlock and ::DrvUtil_WriteBlock\r
  */\r
-typedef Uint   (*tDrvUtil_Callback)(Uint64 Address, Uint Count, void *Buffer, Uint Argument);\r
+typedef Uint   (*tDrvUtil_Read_Callback)(Uint64 Address, Uint Count, void *Buffer, Uint Argument);\r
+typedef Uint   (*tDrvUtil_Write_Callback)(Uint64 Address, Uint Count, const void *Buffer, Uint Argument);\r
 \r
 /**\r
  * \brief Reads a range from a block device using aligned reads\r
@@ -161,7 +162,7 @@ typedef Uint        (*tDrvUtil_Callback)(Uint64 Address, Uint Count, void *Buffer, Uint
  * \return Number of bytes read\r
  */\r
 extern Uint64 DrvUtil_ReadBlock(Uint64 Start, Uint64 Length, void *Buffer,\r
-       tDrvUtil_Callback ReadBlocks, Uint64 BlockSize, Uint Argument);\r
+       tDrvUtil_Read_Callback ReadBlocks, Uint64 BlockSize, Uint Argument);\r
 /**\r
  * \brief Writes a range to a block device using aligned writes\r
  * \param Start        Base byte offset\r
@@ -173,8 +174,8 @@ extern Uint64 DrvUtil_ReadBlock(Uint64 Start, Uint64 Length, void *Buffer,
  * \param Argument     An argument to pass to \a ReadBlocks and \a WriteBlocks\r
  * \return Number of bytes written\r
  */\r
-extern Uint64 DrvUtil_WriteBlock(Uint64 Start, Uint64 Length, void *Buffer,\r
-       tDrvUtil_Callback ReadBlocks, tDrvUtil_Callback WriteBlocks,\r
+extern Uint64 DrvUtil_WriteBlock(Uint64 Start, Uint64 Length, const void *Buffer,\r
+       tDrvUtil_Read_Callback ReadBlocks, tDrvUtil_Write_Callback WriteBlocks,\r
        Uint64 BlockSize, Uint Argument);\r
 \r
 /**\r
index f2d1a2d..ff9c395 100644 (file)
@@ -435,7 +435,7 @@ typedef struct sDrvUtil_Video_2DHandlers
  * \param SizeofHandlers       Size of \a tDrvUtil_Video_2DHandlers according\r
  *        to the driver. Used as version control and error avoidence.\r
  */\r
-extern int     DrvUtil_Video_2DStream(void *Ent, void *Buffer, int Length,\r
+extern int     DrvUtil_Video_2DStream(void *Ent, const void *Buffer, int Length,\r
        tDrvUtil_Video_2DHandlers *Handlers, int SizeofHandlers);\r
 \r
 /**\r
@@ -449,7 +449,7 @@ extern int  DrvUtil_Video_2DStream(void *Ent, void *Buffer, int Length,
  * Handles all write modes in software, using the VT font calls for rendering.\r
  * \note Calls the cursor clear and redraw if the cursor area is touched\r
  */\r
-extern int     DrvUtil_Video_WriteLFB(tDrvUtil_Video_BufInfo *FBInfo, size_t Offset, size_t Length, void *Src);\r
+extern int     DrvUtil_Video_WriteLFB(tDrvUtil_Video_BufInfo *FBInfo, size_t Offset, size_t Length, const void *Src);\r
 \r
 /**\r
  * \name Software cursor rendering\r
index a1a9582..3652f19 100644 (file)
@@ -17,6 +17,7 @@ enum eErrorNums
        EREADONLY,      // Read only
        ENOTIMPL,       // Not implemented
        ENOENT, // No entry?
+       EEXIST, // Already exists
        ENFILE, // Too many open files
        ENOTDIR,        // Not a directory
        
diff --git a/Kernel/include/events.h b/Kernel/include/events.h
new file mode 100644 (file)
index 0000000..9aa941d
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * events.h
+ * - Thread Events
+ */
+#ifndef _EVENTS_H_
+#define _EVENTS_H_
+
+#include <threads.h>
+
+#define THREAD_EVENT_VFS       0x00000001
+#define THREAD_EVENT_IPCMSG    0x00000002
+#define THREAD_EVENT_SIGNAL    0x00000004
+
+// === FUNCTIONS ===
+extern void    Threads_PostEvent(tThread *Thread, Uint32 EventMask);
+extern Uint32  Threads_WaitEvents(Uint32 EventMask);
+
+#endif
+
index a189d56..0f21a1c 100644 (file)
@@ -27,6 +27,10 @@ extern void  Proc_Start(void);
  * \brief Called just before a thread is freed
  */
 extern void    Proc_ClearThread(tThread *Thread);
+/**
+ * \brief Called just before a process is freed
+ */
+extern void    Proc_ClearProcess(tProcess *Process);
 /**
  * \brief Get the ID of this CPU
  * \return Zero based CPU ID
@@ -54,7 +58,7 @@ extern tTID   Proc_NewKThread( void (*Fnc)(void*), void *Ptr );
  * \param DataSize     Size of the \a ArgV buffer in bytes
  * \note This function should free \a ArgV
  */
-extern void    Proc_StartUser(Uint Entrypoint, Uint Base, int ArgC, char **ArgV, int DataSize) NORETURN;
+extern void    Proc_StartUser(Uint Entrypoint, Uint Base, int ArgC, const char **ArgV, int DataSize) NORETURN;
 /**
  * \brief Call the fault handler for a thread
  * \param Thread       Thread that is at fault :)
index 98bb979..5ce2814 100644 (file)
 #define SYS_SETFAULTHANDLER    3       // Set signal Handler
 #define SYS_YIELD      4       // Yield remainder of timestamp
 #define SYS_SLEEP      5       // Sleep until messaged or signaled
-#define SYS_WAIT       6       // Wait for a time or a message
+#define SYS_WAITEVENT  6       // Wait for an event
 #define SYS_WAITTID    7       // Wait for a thread to do something
-#define SYS_SETNAME    8       // Set's the name of the current thread
-#define SYS_GETNAME    9       // Get's the name of a thread
+#define SYS_SETNAME    8       // Sets the name of the current thread
+#define SYS_GETNAME    9       // Gets the name of a thread
 #define SYS_GETTID     10      // Get current thread ID
 #define SYS_GETPID     11      // Get current thread group ID
 #define SYS_SETPRI     12      // Set process priority
@@ -73,7 +73,7 @@ static const char *cSYSCALL_NAMES[] = {
        "SYS_SETFAULTHANDLER",
        "SYS_YIELD",
        "SYS_SLEEP",
-       "SYS_WAIT",
+       "SYS_WAITEVENT",
        "SYS_WAITTID",
        "SYS_SETNAME",
        "SYS_GETNAME",
index 307e582..149fe37 100644 (file)
@@ -8,10 +8,10 @@
 %define SYS_SETFAULTHANDLER    3        ;Set signal Handler
 %define SYS_YIELD      4        ;Yield remainder of timestamp
 %define SYS_SLEEP      5        ;Sleep until messaged or signaled
-%define SYS_WAIT       6        ;Wait for a time or a message
+%define SYS_WAITEVENT  6        ;Wait for an event
 %define SYS_WAITTID    7        ;Wait for a thread to do something
-%define SYS_SETNAME    8        ;Set's the name of the current thread
-%define SYS_GETNAME    9        ;Get's the name of a thread
+%define SYS_SETNAME    8        ;Sets the name of the current thread
+%define SYS_GETNAME    9        ;Gets the name of a thread
 %define SYS_GETTID     10       ;Get current thread ID
 %define SYS_GETPID     11       ;Get current thread group ID
 %define SYS_SETPRI     12       ;Set process priority
index d138cf0..9ff7b62 100644 (file)
@@ -1,11 +1,12 @@
 /*
+ * Acess2 Kernel
  */
 #ifndef _THREADS_H_
 #define _THREADS_H_
 
 #include <arch.h>
 #include <signal.h>
-#include <proc.h>
+//#include <proc.h>
 
 enum eFaultNumbers
 {
@@ -19,14 +20,21 @@ enum eFaultNumbers
 
 #define GETMSG_IGNORE  ((void*)-1)
 
+typedef struct sThread tThread;
+
 // === FUNCTIONS ===
 extern void    Threads_SetFaultHandler(Uint Handler);
 
-extern int     Threads_SetUID(Uint *Errno, tUID ID);
-extern int     Threads_SetGID(Uint *Errno, tUID ID);
-extern int     Threads_WaitTID(int TID, int *Status);
+extern int     Threads_SetUID(tUID ID);
+extern int     Threads_SetGID(tUID ID);
+extern tTID    Threads_WaitTID(int TID, int *Status);
+
+
+extern int     *Threads_GetMaxFD(void);
+extern char    **Threads_GetCWD(void);
+extern char    **Threads_GetChroot(void);
 
-extern int     Proc_SendMessage(Uint *Err, Uint Dest, int Length, void *Data);
-extern int     Proc_GetMessage(Uint *Err, Uint *Source, void *Buffer);
+extern int     Proc_SendMessage(Uint Dest, int Length, void *Data);
+extern int     Proc_GetMessage(Uint *Source, void *Buffer);
 
 #endif
index 6516b35..66bb8c1 100644 (file)
@@ -8,6 +8,9 @@
 #include <threads.h>
 #include <proc.h>
 
+
+typedef struct sProcess        tProcess;
+
 /**
  * \brief IPC Message
  */
@@ -19,11 +22,28 @@ typedef struct sMessage
        Uint8   Data[]; //!< Message data
 } tMsg;
 
+/**
+ * \brief Process state
+ */
+struct sProcess
+{
+       tPID    PID;
+        int    nThreads;
+       
+       tUID    UID;    //!< User ID
+       tGID    GID;    //!< User and Group
+       tMemoryState    MemState;
+
+        int    MaxFD;
+       char    *CurrentWorkingDir;
+       char    *RootDir;
+};
+
 /**
  * \brief Core threading structure
  * 
  */
-typedef struct sThread
+struct sThread
 {
        // --- threads.c's
        /**
@@ -38,19 +58,15 @@ typedef struct sThread
        void    *WaitPointer;   //!< What (Mutex/Thread/other) is the thread waiting on
         int    RetStatus;      //!< Return Status
        
-       Uint    TID;    //!< Thread ID
-       Uint    TGID;   //!< Thread Group (Process)
+       tTID    TID;    //!< Thread ID
+       struct sProcess *Process;       //!< Thread Group / Process
        struct sThread  *Parent;        //!< Parent Thread
-       Uint    UID, GID;       //!< User and Group
        char    *ThreadName;    //!< Name of thread
        
        // --- arch/proc.c's responsibility
        //! Kernel Stack Base
        tVAddr  KernelStack;
        
-       //! Memory Manager State
-       tMemoryState    MemState;
-       
        //! State on task switch
        tTaskState      SavedState;
        
@@ -64,12 +80,15 @@ typedef struct sThread
         int    Quantum, Remaining;     //!< Quantum Size and remaining timesteps
         int    Priority;       //!< Priority - 0: Realtime, higher means less time
        
-       Uint    Config[NUM_CFG_ENTRIES];        //!< Per-process configuration
+        int    _errno;
        
        volatile int    CurCPU;
        
-        int    bInstrTrace;
-} tThread;
+       bool    bInstrTrace;
+       
+       // --- event.c
+       Uint32  EventState;
+};
 
 
 enum {
@@ -79,6 +98,7 @@ enum {
        THREAD_STAT_MUTEXSLEEP, // Mutex Sleep
        THREAD_STAT_SEMAPHORESLEEP,     // Semaphore Sleep
        THREAD_STAT_QUEUESLEEP, // Queue
+       THREAD_STAT_EVENTSLEEP, // Event sleep
        THREAD_STAT_WAITING,    // ??? (Waiting for a thread)
        THREAD_STAT_PREINIT,    // Being created
        THREAD_STAT_ZOMBIE,     // Died/Killed, but parent not informed
@@ -92,6 +112,7 @@ static const char * const casTHREAD_STAT[] = {
        "THREAD_STAT_MUTEXSLEEP",
        "THREAD_STAT_SEMAPHORESLEEP",
        "THREAD_STAT_QUEUESLEEP",
+       "THREAD_STAT_EVENTSLEEP",
        "THREAD_STAT_WAITING",
        "THREAD_STAT_PREINIT",
        "THREAD_STAT_ZOMBIE",
index 91771c8..1aa073b 100644 (file)
@@ -26,6 +26,8 @@
  */
 typedef struct sVFS_SelectList tVFS_SelectList;
 
+typedef struct sVFS_NodeType   tVFS_NodeType;
+
 /**
  * \name tVFS_Node Flags
  * \brief Flag values for tVFS_Node.Flags
@@ -177,6 +179,22 @@ typedef struct sVFS_Node
         * \}
         */
        
+       /**
+        * \brief Functions associated with the node
+        */
+       tVFS_NodeType   *Type;
+} tVFS_Node;
+
+/**
+ * \brief Functions for a specific node type
+ */
+struct sVFS_NodeType
+{
+       /**
+        * \brief Debug name for the type
+        */
+       const char      *TypeName;
+
        /**
         * \name Common Functions
         * \brief Functions that are used no matter the value of .Flags
@@ -233,7 +251,7 @@ typedef struct sVFS_Node
         * \param Buffer        Source of written data
         * \return Number of bytes read
         */
-       Uint64  (*Write)(struct sVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+       Uint64  (*Write)(struct sVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer);
 
        /**
         * \brief Map a region of a file into memory
@@ -299,14 +317,14 @@ typedef struct sVFS_Node
         * \param Node  Pointer to this node (directory)
         * \param Child Node to create a new link to
         * \param NewName       Name for the new link
-        * \return Zeron on success, non-zero on error (see errno.h)
+        * \retur Zeron on success, non-zero on error (see errno.h)
         */
         int    (*Link)(struct sVFS_Node *Node, struct sVFS_Node *Child, const char *NewName);
         
         /**
          * \}
          */
-} tVFS_Node;
+};
 
 /**
  * \brief VFS Driver (Filesystem) Definition
index d7d74c4..b4d5e2a 100644 (file)
@@ -27,8 +27,10 @@ typedef Uint32       tMount;
 #define VFS_OPENFLAG_WRITE     0x04
 //! Do not resolve the final symbolic link
 #define        VFS_OPENFLAG_NOLINK     0x40
+//! Create the file if it doesn't exist
+#define VFS_OPENFLAG_CREATE    0x80
 //! Open as a user
-#define        VFS_OPENFLAG_USER       0x80
+#define        VFS_OPENFLAG_USER       0x8000
 /**
  * \}
  */
@@ -176,10 +178,19 @@ extern int        VFS_Init(void);
 /**
  * \brief Open a file
  * \param Path Absolute or relative path to the file
- * \param Mode Flags defining how to open the file
+ * \param Flags        Flags defining how to open the file
  * \return VFS Handle (an integer) or -1 if an error occured
+ * \note Calls VFS_OpenEx(Path, Flags, 0)
  */
-extern int     VFS_Open(const char *Path, Uint Mode);
+extern int     VFS_Open(const char *Path, Uint Flags);
+/**
+ * \brief Open a file
+ * \param Path Absolute or relative path to the file
+ * \param Flags        Flags defining how to open the file
+ * \param Mode Mode for newly created file (POSIX compatability)
+ * \return VFS Handle (an integer) or -1 if an error occured
+ */
+extern int     VFS_OpenEx(const char *Path, Uint Flags, Uint Mode);
 /**
  * \brief Opens a file via an open directory
  * \note The file to open must be a direct child of the parent
@@ -353,10 +364,11 @@ extern int        VFS_ReadDir(int FD, char *Dest);
  * \param WriteHandles Handles to wait to write to
  * \param ErrHandles   Handle to wait for errors on
  * \param Timeout      Timeout for select() (if null, there is no timeout), if zero select() is non blocking
+ * \param ExtraEvents  Extra event set to wait on
  * \param IsKernel     Use kernel handles as opposed to user handles
  * \return Number of handles that actioned
  */
-extern int VFS_Select(int MaxHandle, fd_set *ReadHandles, fd_set *WriteHandles, fd_set *ErrHandles, tTime *Timeout, BOOL IsKernel);
+extern int VFS_Select(int MaxHandle, fd_set *ReadHandles, fd_set *WriteHandles, fd_set *ErrHandles, tTime *Timeout, Uint32 ExtraEvents, BOOL IsKernel);
 
 /**
  * \brief Map a file into memory
index 4961f08..a8eadb6 100644 (file)
@@ -53,5 +53,16 @@ extern tVFS_Handle   *VFS_GetHandle(int FD);
 extern int     VFS_CheckACL(tVFS_Node *Node, Uint Permissions);
 // --- mount.c ---
 extern tVFS_Mount      *VFS_GetMountByIdent(Uint32 MountID);
+// --- dir.c ---
+extern int     VFS_MkNod(const char *Path, Uint Flags);
+
+
+// --- VFS Helpers ---
+static inline void _CloseNode(tVFS_Node *Node)
+{
+       if(Node && Node->Type && Node->Type->Close)
+               Node->Type->Close( Node );
+}
+
 
 #endif
diff --git a/Kernel/include/vfs_threads.h b/Kernel/include/vfs_threads.h
new file mode 100644 (file)
index 0000000..95ec227
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * include/vfs_threads.h
+ * - Handle maintainance functions for the VFS used by threading code
+ */
+#ifndef _VFS_THREADS_H_
+#define _VFS_THREADS_H_
+
+// === FUNCTIONS ===
+extern void    VFS_ReferenceUserHandles(void);
+extern void    VFS_CloseAllUserHandles(void);
+
+extern void    *VFS_SaveHandles(int NumFDs, int *FDs);
+extern void    VFS_RestoreHandles(int NumFDs, void *Handles);
+extern void    VFS_FreeSavedHandles(int NumFDs, void *Handles);
+
+#endif
index 76cc428..8612638 100644 (file)
@@ -39,6 +39,9 @@ char  **str_split(const char *__str, char __ch);
  int   WriteUTF8(Uint8 *str, Uint32 Val);
  int   DivUp(int num, int dem);
 Sint64 timestamp(int sec, int mins, int hrs, int day, int month, int year);
+#endif
+void   format_date(tTime TS, int *year, int *month, int *day, int *hrs, int *mins, int *sec, int *ms);
+#if 0
  int   rand(void);
  
  int   CheckString(char *String);
@@ -47,6 +50,7 @@ Sint64        timestamp(int sec, int mins, int hrs, int day, int month, int year);
  int   ModUtil_LookupString(char **Array, char *Needle);
  int   ModUtil_SetIdent(char *Dest, char *Value);
  
+ int   Hex(char *Dest, size_t Size, const Uint8 *SourceData);
  int   UnHex(Uint8 *Dest, size_t DestSize, const char *SourceString);
 #endif
 
@@ -89,9 +93,16 @@ EXPORT(memmove);
  * \brief Convert a string into an integer
  */
 int atoi(const char *string)
+{
+       int ret = 0;
+       ParseInt(string, &ret);
+       return ret;
+}
+int ParseInt(const char *string, int *Val)
 {
         int    ret = 0;
         int    bNeg = 0;
+       const char *orig_string = string;
        
        //Log("atoi: (string='%s')", string);
        
@@ -143,13 +154,17 @@ int atoi(const char *string)
                        ret *= 10;
                        ret += *string - '0';
                }
+               // Error check
+               if( ret == 0 )  return 0;
        }
        
        if(bNeg)        ret = -ret;
        
        //Log("atoi: RETURN %i", ret);
        
-       return ret;
+       if(Val) *Val = ret;
+       
+       return string - orig_string;
 }
 
 static const char cUCDIGITS[] = "0123456789ABCDEF";
@@ -769,28 +784,118 @@ int WriteUTF8(Uint8 *str, Uint32 Val)
  * \fn Uint64 timestamp(int sec, int mins, int hrs, int day, int month, int year)
  * \brief Converts a date into an Acess Timestamp
  */
-Sint64 timestamp(int sec, int mins, int hrs, int day, int month, int year)
+Sint64 timestamp(int sec, int min, int hrs, int day, int month, int year)
 {
+        int    is_leap;
        Sint64  stamp;
-       stamp = sec;
-       stamp += mins*60;
-       stamp += hrs*3600;
-       
-       stamp += day*3600*24;
-       stamp += month*DAYS_BEFORE[month]*3600*24;
-       if(     (
-               ((year&3) == 0 || year%100 != 0)
-               || (year%100 == 0 && ((year/100)&3) == 0)
-               ) && month > 1) // Leap year and after feb
-               stamp += 3600*24;
+
+       if( !(0 <= sec && sec < 60) )   return 0;
+       if( !(0 <= min && min < 60) )   return 0;
+       if( !(0 <= hrs && hrs < 24) )   return 0;
+       if( !(0 <= day && day < 31) )   return 0;
+       if( !(0 <= month && month < 12) )       return 0;
+
+       stamp = DAYS_BEFORE[month] + day;
+
+       // Every 4 years
+       // - every 100 years
+       // + every 400 years
+       is_leap = (year % 4 == 0) - (year % 100 == 0) + (year % 400 == 0);
+       ASSERT(is_leap == 0 || is_leap == 1);
+
+       if( is_leap && month > 1 )      // Leap year and after feb
+               stamp += 1;
+
+       // Get seconds before the first of specified year
+       year -= 2000;   // Base off Y2K
+       // base year days + total leap year days
+       stamp += year*365 + (year/400) - (year/100) + (year/4);
        
-       stamp += ((365*4+1) * ((year-2000)&~3)) * 3600*24;      // Four Year Segments
-       stamp += ((year-2000)&3) * 365*3600*24; // Inside four year segment
+       stamp *= 3600*24;
        stamp += UNIX_TO_2K;
+       stamp += sec;
+       stamp += min*60;
+       stamp += hrs*3600;
        
        return stamp * 1000;
 }
 
+void format_date(tTime TS, int *year, int *month, int *day, int *hrs, int *mins, int *sec, int *ms)
+{
+        int    is_leap = 0, i;
+
+       auto Sint64 DivMod64(Sint64 N, Sint64 D, Sint64 *R);
+       
+       Sint64 DivMod64(Sint64 N, Sint64 D, Sint64 *R)
+       {
+               int sign = (N < 0) != (D < 0);
+               if(N < 0)       N = -N;
+               if(D < 0)       D = -D;
+               if(sign)
+                       return -DivMod64U(N, D, (Uint64*)R);
+               else
+                       return DivMod64U(N, D, (Uint64*)R);
+       }
+
+       // Get time
+       // TODO: Leap-seconds?
+       {
+               Sint64  rem;
+               TS = DivMod64( TS, 1000, &rem );
+               *ms = rem;
+               TS = DivMod64( TS, 60, &rem );
+               *sec = rem;
+               TS = DivMod64( TS, 60, &rem );
+               *mins = rem;
+               TS = DivMod64( TS, 24, &rem );
+               *hrs = rem;
+       }
+
+       // Adjust to Y2K
+       TS -= UNIX_TO_2K/(3600*24);
+
+       // Year (400 yr blocks) - (400/4-3) leap years
+       *year = 400 * DivMod64( TS, 365*400 + (400/4-3), &TS );
+       if( TS < 366 )  // First year in 400 is a leap
+               is_leap = 1;
+       else
+       {
+               // 100 yr blocks - 100/4-1 leap years
+               *year += 100 * DivMod64( TS, 365*100 + (100/4-1), &TS );
+               if( TS < 366 )  // First year in 100 isn't a leap
+                       is_leap = 0;
+               else
+               {
+                       *year += 4 * DivMod64( TS, 365*4 + 1, &TS );
+                       if( TS < 366 )  // First year in 4 is a leap
+                               is_leap = 1;
+                       else
+                       {
+                               *year += DivMod64( TS, 356, &TS );
+                       }
+               }
+       }
+       *year += 2000;
+
+       ASSERT(TS >= 0);
+       
+       *day = 0;
+       // Month (if after the first of march, which is 29 Feb in a leap year)
+       if( is_leap && TS > DAYS_BEFORE[2] ) {
+               TS -= 1;        // Shifts 29 Feb to 28 Feb
+               *day = 1;
+       }
+       // Get what month it is
+       for( i = 0; i < 12; i ++ ) {
+               if( TS < DAYS_BEFORE[i] )
+                       break;
+       }
+       *month = i - 1;
+       // Get day
+       TS -= DAYS_BEFORE[i-1];
+       *day += TS;     // Plus offset from leap handling above
+}
+
 /**
  * \fn int rand()
  * \brief Pseudo random number generator
@@ -888,6 +993,16 @@ int ModUtil_SetIdent(char *Dest, const char *Value)
        return 1;
 }
 
+int Hex(char *Dest, size_t Size, const Uint8 *SourceData)
+{
+        int    i;
+       for( i = 0; i < Size; i ++ )
+       {
+               sprintf(Dest + i*2, "%02x", SourceData[i]);
+       }
+       return i*2;
+}
+
 /**
  * \brief Convert a string of hexadecimal digits into a byte stream
  */
index 1391d99..afdcdbd 100644 (file)
 #include <threads.h>
 #include <threads_int.h>
 #include <errno.h>
+#include <events.h>
 
 // === CODE ===
 /**
- * \fn int Proc_SendMessage(Uint *Err, Uint Dest, int Length, void *Data)
+ * \fn int Proc_SendMessage(Uint Dest, int Length, void *Data)
  * \brief Send an IPC message
- * \param Err  Pointer to the errno variable
  * \param Dest Destination Thread
  * \param Length       Length of the message
  * \param Data Message data
  */
-int Proc_SendMessage(Uint *Err, Uint Dest, int Length, void *Data)
+int Proc_SendMessage(Uint Dest, int Length, void *Data)
 {
        tThread *thread;
        tMsg    *msg;
@@ -28,10 +28,13 @@ int Proc_SendMessage(Uint *Err, Uint Dest, int Length, void *Data)
        ENTER("pErr iDest iLength pData", Err, Dest, Length, Data);
        
        if(Length <= 0 || !Data) {
-               *Err = -EINVAL;
+               errno = -EINVAL;
                LEAVE_RET('i', -1);
        }
        
+       // TODO: Check message length against global/per-thread maximums
+       // TODO: Restrict queue length
+
        // Get thread
        thread = Threads_GetThread( Dest );
        
@@ -64,21 +67,22 @@ int Proc_SendMessage(Uint *Err, Uint Dest, int Length, void *Data)
        }
        
        SHORTREL(&thread->IsLocked);
-       
+
+       // Wake the thread      
        LOG("Waking %p (%i %s)", thread, thread->TID, thread->ThreadName);
-       Threads_Wake( thread );
+       Threads_PostEvent( thread, THREAD_EVENT_IPCMSG );
        
        LEAVE_RET('i', 0);
 }
 
 /**
- * \fn int Proc_GetMessage(Uint *Err, Uint *Source, void *Buffer)
+ * \fn int Proc_GetMessage(Uint *Source, void *Buffer)
  * \brief Gets a message
- * \param Err  Pointer to \a errno
  * \param Source       Where to put the source TID
  * \param Buffer       Buffer to place the message data (set to NULL to just get message length)
+ * \return Message length
  */
-int Proc_GetMessage(Uint *Err, Uint *Source, void *Buffer)
+int Proc_GetMessage(Uint *Source, void *Buffer)
 {
         int    ret;
        void    *tmp;
@@ -113,7 +117,7 @@ int Proc_GetMessage(Uint *Err, Uint *Source, void *Buffer)
                if( !CheckMem( Buffer, cur->Messages->Length ) )
                {
                        LOG("Invalid buffer");
-                       *Err = -EINVAL;
+                       errno = -EINVAL;
                        SHORTREL( &cur->IsLocked );
                        LEAVE('i', -1);
                        return -1;
index c0c0216..98ca1a1 100644 (file)
@@ -168,7 +168,7 @@ int Module_int_Initialise(tModule *Module, const char *ArgString)
                        Log_Warning("Module", "Unable to load, reason: Miscelanious");
                        break;
                case MODULE_ERR_NOTNEEDED:
-                       Log_Warning("Module", "Unable to load, reason: Module not needed");
+                       Log_Debug("Module", "Unable to load, reason: Module not needed");
                        break;
                case MODULE_ERR_MALLOC:
                        Log_Warning("Module", "Unable to load, reason: Error in malloc/realloc/calloc, probably not good");
index 4b4c4e4..597242b 100644 (file)
@@ -27,7 +27,7 @@ int Mutex_Acquire(tMutex *Mutex)
        // Get protector
        SHORTLOCK( &Mutex->Protector );
        
-       //Log("Mutex_Acquire: (%p)", Mutex);
+//     Log("Mutex_Acquire: (%p)", Mutex);
        
        // Check if the lock is already held
        if( Mutex->Owner ) {
@@ -94,17 +94,12 @@ void Mutex_Release(tMutex *Mutex)
                Mutex->Owner = Mutex->Waiting;  // Set owner
                Mutex->Waiting = Mutex->Waiting->Next;  // Next!
                // Reset ->LastWaiting to NULL if we have just removed the last waiting thread
-               // 2010-10-02 21:50 - Comemerating the death of the longest single
-               //                    blocker in the Acess2 history. REMEMBER TO
-               //                    FUCKING MAINTAIN YOUR FUCKING LISTS DIPWIT
                if( Mutex->LastWaiting == Mutex->Owner )
                        Mutex->LastWaiting = NULL;
                
                // Wake new owner
-               SHORTLOCK( &glThreadListLock );
                if( Mutex->Owner->Status != THREAD_STAT_ACTIVE )
                        Threads_AddActive(Mutex->Owner);
-               SHORTREL( &glThreadListLock );
        }
        else {
                Mutex->Owner = NULL;
index 35e4890..5580187 100644 (file)
@@ -10,6 +10,7 @@
 #include <hal_proc.h>
 #include <errno.h>
 #include <threads.h>
+#include <events.h>
 
 #define CHECK_NUM_NULLOK(v,size)       \
        if((v)&&!Syscall_Valid((size),(v))){ret=-1;err=-EINVAL;break;}
        if(!(v)||!Syscall_Valid((size),(v))){ret=-1;err=-EINVAL;break;}
 #define CHECK_STR_NONULL(v)    \
        if(!(v)||!Syscall_ValidString((v))){ret=-1;err=-EINVAL;break;}
+#define CHECK_STR_ARRAY(arr)   do {\
+        int    i;\
+       char    **tmp = (char**)arr; \
+       CHECK_NUM_NONULL( tmp, sizeof(char**) ); \
+       for(i=0;tmp[i];i++) { \
+               CHECK_STR_NONULL( tmp[i] ); \
+               CHECK_NUM_NONULL( &tmp[i+1], sizeof(char*) ); \
+       }\
+       if(tmp[i]) break;\
+} while(0)
 
 // === IMPORTS ===
-extern int     Proc_Execve(char *File, char **ArgV, char **EnvP);
 extern Uint    Binary_Load(const char *file, Uint *entryPoint);
 
 // === PROTOTYPES ===
@@ -75,7 +85,13 @@ void SyscallHandler(tSyscallRegs *Regs)
                err = -ENOSYS;
                ret = -1;
                break;
-       
+
+       // -- Wait fr an event  
+       case SYS_WAITEVENT:
+               // Message mask
+               ret = Threads_WaitEvents(Regs->Arg1);
+               break;
+
        // -- Wait for a thread
        case SYS_WAITTID:
                // Sanity Check (Status can be NULL)
@@ -107,14 +123,14 @@ void SyscallHandler(tSyscallRegs *Regs)
        case SYS_GETGID:        ret = Threads_GetGID(); break;
        
        // -- Set User/Group IDs
-       case SYS_SETUID:        ret = Threads_SetUID(&err, Regs->Arg1); break;
-       case SYS_SETGID:        ret = Threads_SetGID(&err, Regs->Arg1); break;
+       case SYS_SETUID:        ret = Threads_SetUID(Regs->Arg1);       break;
+       case SYS_SETGID:        ret = Threads_SetGID(Regs->Arg1);       break;
        
        // -- Send Message
        case SYS_SENDMSG:
                CHECK_NUM_NONULL( (void*)Regs->Arg3, Regs->Arg2 );
                // Destination, Size, *Data
-               ret = Proc_SendMessage(&err, Regs->Arg1, Regs->Arg2, (void*)Regs->Arg3);
+               ret = Proc_SendMessage(Regs->Arg1, Regs->Arg2, (void*)Regs->Arg3);
                break;
        // -- Check for messages
        case SYS_GETMSG:
@@ -125,7 +141,7 @@ void SyscallHandler(tSyscallRegs *Regs)
                        err = -EINVAL;  ret = -1;       break;
                }
                // *Source, *Data
-               ret = Proc_GetMessage(&err, (Uint*)Regs->Arg1, (void*)Regs->Arg2);
+               ret = Proc_GetMessage((Uint*)Regs->Arg1, (void*)Regs->Arg2);
                break;
        
        // -- Get the current timestamp
@@ -142,46 +158,34 @@ void SyscallHandler(tSyscallRegs *Regs)
        // ---
        // Binary Control
        // ---
+       // -- Create a new process
+       case SYS_SPAWN:
+               CHECK_STR_NONULL((const char*)Regs->Arg1);
+               CHECK_STR_ARRAY((const char**)Regs->Arg2);
+               CHECK_STR_ARRAY((const char**)Regs->Arg3);
+               CHECK_NUM_NONULL((void*)Regs->Arg5, Regs->Arg4*sizeof(int));
+               ret = Proc_SysSpawn(
+                       (const char*)Regs->Arg1, (const char**)Regs->Arg2, (const char**)Regs->Arg3,
+                       Regs->Arg4, (int*)Regs->Arg5
+                       );
+               break;
        // -- Replace the current process with another
        case SYS_EXECVE:
                CHECK_STR_NONULL((char*)Regs->Arg1);
-               // Check the argument arrays
-               {
-                        int    i;
-                       char    **tmp = (char**)Regs->Arg2;
-                       // Check ArgV (traverse array checking all string pointers)
-                       CHECK_NUM_NONULL( tmp, sizeof(char**) );
-                       //Log("tmp = %p", tmp);
-                       for(i=0;tmp[i];i++) {
-                               CHECK_NUM_NONULL( &tmp[i], sizeof(char*) );
-                               CHECK_STR_NONULL( tmp[i] );
-                       }
-                       if(ret == -1) break;
-                       // Check EnvP also
-                       // - EnvP can be NULL
-                       if( Regs->Arg3 )
-                       {
-                               tmp = (char**)Regs->Arg3;
-                               CHECK_NUM_NONULL(tmp, sizeof(char**));
-                               for(i=0;tmp[i];i++) {
-                                       CHECK_NUM_NONULL( &tmp[i], sizeof(char*) );
-                                       CHECK_STR_NONULL( tmp[i] );
-                               }
-                               if(ret == -1) break;
-                       }
-               }
+               CHECK_STR_ARRAY( (char**)Regs->Arg2 );
+               if( Regs->Arg3 )
+                       CHECK_STR_ARRAY( (char**)Regs->Arg3 );
                LEAVE('s', "Assuming 0");
-               // Path, **Argv, **Envp
-               ret = Proc_Execve( (char*)Regs->Arg1, (char**)Regs->Arg2, (char**)Regs->Arg3 );
+               // Path, **Argv, **Envp, DataSize (=0 to tell it to create a copy)
+               ret = Proc_Execve(
+                       (const char*)Regs->Arg1, (const char**)Regs->Arg2, (const char**)Regs->Arg3,
+                       0
+                       );
                break;
        // -- Load a binary into the current process
        case SYS_LOADBIN:
-               if( !Syscall_ValidString( (char*) Regs->Arg1)
-               ||  !Syscall_Valid(sizeof(Uint), (Uint*)Regs->Arg2) ) {
-                       err = -EINVAL;
-                       ret = 0;
-                       break;
-               }
+               CHECK_STR_NONULL( (char*)Regs->Arg1 );
+               CHECK_NUM_NONULL( (Uint*)Regs->Arg2, sizeof(Uint) );
                // Path, *Entrypoint
                ret = Binary_Load((char*)Regs->Arg1, (Uint*)Regs->Arg2);
                break;
@@ -245,7 +249,7 @@ void SyscallHandler(tSyscallRegs *Regs)
        // Open a file that is a entry in an open directory
        case SYS_OPENCHILD:
                CHECK_STR_NONULL( (char*)Regs->Arg2 );
-               ret = VFS_OpenChild( Regs->Arg1, (char*)Regs->Arg2, Regs->Arg3);
+               ret = VFS_OpenChild( Regs->Arg1, (char*)Regs->Arg2, Regs->Arg3 | VFS_OPENFLAG_USER);
                break;
        
        // Change Directory
@@ -307,6 +311,7 @@ void SyscallHandler(tSyscallRegs *Regs)
                        (fd_set *)Regs->Arg3,   // Write
                        (fd_set *)Regs->Arg4,   // Errors
                        (tTime *)Regs->Arg5,    // Timeout
+                       (Uint32)Regs->Arg6,     // Extra wakeup events
                        0       // User handles
                        );
                break;
index 826249d..283caf9 100644 (file)
@@ -6,11 +6,11 @@ SYS_KILL      Send a signal
 SYS_SETFAULTHANDLER    Set signal Handler
 SYS_YIELD      Yield remainder of timestamp
 SYS_SLEEP      Sleep until messaged or signaled
-SYS_WAIT       Wait for a time or a message
+SYS_WAITEVENT  Wait for an event
 SYS_WAITTID    Wait for a thread to do something
 
-SYS_SETNAME    Set's the name of the current thread
-SYS_GETNAME    Get's the name of a thread
+SYS_SETNAME    Sets the name of the current thread
+SYS_GETNAME    Gets the name of a thread
 SYS_GETTID     Get current thread ID
 SYS_GETPID     Get current thread group ID
 SYS_SETPRI     Set process priority
index 879fbdd..956eede 100644 (file)
@@ -9,6 +9,7 @@
 #include <errno.h>
 #include <hal_proc.h>
 #include <semaphore.h>
+#include <vfs_threads.h>       // VFS Handle maintainence
 
 // Configuration
 #define DEBUG_TRACE_TICKETS    0       // Trace ticket counts
 #define        DEFAULT_QUANTUM 5
 #define        DEFAULT_PRIORITY        5
 #define MIN_PRIORITY           10
-const enum eConfigTypes        cCONFIG_TYPES[NUM_CFG_ENTRIES] = {
-       CFGT_HEAPSTR,   // e.g. CFG_VFS_CWD
-       CFGT_INT,       // e.g. CFG_VFS_MAXFILES
-       CFGT_NULL
-};
 
 // === IMPORTS ===
 
+// === TYPE ===
+typedef struct
+{
+       tThread *Head;
+       tThread *Tail;
+} tThreadList;
+
 // === PROTOTYPES ===
 void   Threads_Init(void);
 #if 0
 void   Threads_Delete(tThread *Thread);
  int   Threads_SetName(const char *NewName);
 #endif
-char   *Threads_GetName(int ID);
+char   *Threads_GetName(tTID ID);
 #if 0
 void   Threads_SetPriority(tThread *Thread, int Pri);
 tThread        *Threads_CloneTCB(Uint *Err, Uint Flags);
  int   Threads_WaitTID(int TID, int *status);
 tThread        *Threads_GetThread(Uint TID);
 #endif
-tThread        *Threads_int_DelFromQueue(tThread **List, tThread *Thread);
+tThread        *Threads_int_DelFromQueue(tThreadList *List, tThread *Thread);
+void   Threads_int_AddToList(tThreadList *List, tThread *Thread);
 #if 0
 void   Threads_Exit(int TID, int Status);
 void   Threads_Kill(tThread *Thread, int Status);
@@ -73,6 +77,8 @@ void  Threads_DumpActive(void);
 
 // === GLOBALS ===
 // -- Core Thread --
+struct sProcess        gProcessZero = {
+       };
 // Only used for the core kernel
 tThread        gThreadZero = {
        .Status         = THREAD_STAT_ACTIVE,   // Status
@@ -89,18 +95,18 @@ volatile int        giNumActiveThreads = 0; // Number of threads on the active queue
 volatile Uint  giNextTID = 1;  // Next TID to allocate
 // --- Thread Lists ---
 tThread        *gAllThreads = NULL;            // All allocated threads
-tThread        *gSleepingThreads = NULL;       // Sleeping Threads
+tThreadList    gSleepingThreads;       // Sleeping Threads
  int   giNumCPUs = 1;  // Number of CPUs
 BOOL     gaThreads_NoTaskSwitch[MAX_CPUS];     // Disables task switches for each core (Pseudo-IF)
 // --- Scheduler Types ---
 #if SCHEDULER_TYPE == SCHED_LOTTERY
 const int      caiTICKET_COUNTS[MIN_PRIORITY+1] = {100,81,64,49,36,25,16,9,4,1,0};
 volatile int   giFreeTickets = 0;      // Number of tickets held by non-scheduled threads
-tThread        *gActiveThreads = NULL;         // Currently Running Threads
+tThreadList    gActiveThreads;         // Currently Running Threads
 #elif SCHEDULER_TYPE == SCHED_RR_SIM
-tThread        *gActiveThreads = NULL;         // Currently Running Threads
+tThreadList    gActiveThreads;         // Currently Running Threads
 #elif SCHEDULER_TYPE == SCHED_RR_PRI
-tThread        *gaActiveThreads[MIN_PRIORITY+1];       // Active threads for each priority level
+tThreadList    gaActiveThreads[MIN_PRIORITY+1];        // Active threads for each priority level
 #else
 # error "Unkown scheduler type"
 #endif
@@ -119,14 +125,17 @@ void Threads_Init(void)
        Log_Debug("Threads", ".KernelStack = %i", offsetof(tThread, KernelStack));
        
        // Create Initial Task
-       #if SCHEDULER_TYPE == SCHED_RR_PRI
-       gaActiveThreads[gThreadZero.Priority] = &gThreadZero;
-       #else
-       gActiveThreads = &gThreadZero;
-       #endif
+//     #if SCHEDULER_TYPE == SCHED_RR_PRI
+//     gaActiveThreads[gThreadZero.Priority].Head = &gThreadZero;
+//     gaActiveThreads[gThreadZero.Priority].Tail = &gThreadZero;
+//     #else
+//     gActiveThreads.Head = &gThreadZero;
+//     gActiveThreads.Tail = &gThreadZero;
+//     #endif
        
        gAllThreads = &gThreadZero;
        giNumActiveThreads = 1;
+       gThreadZero.Process = &gProcessZero;
                
        Proc_Start();
 }
@@ -135,6 +144,26 @@ void Threads_Delete(tThread *Thread)
 {
        // Set to dead
        Thread->Status = THREAD_STAT_BURIED;
+
+       // Clear out process state
+       Proc_ClearThread(Thread);                       
+
+       Thread->Process->nThreads --;
+       if( Thread->Process->nThreads == 0 )
+       {
+               tProcess        *proc = Thread->Process;
+               // VFS Cleanup
+               VFS_CloseAllUserHandles();
+               // Architecture cleanup
+               Proc_ClearProcess( proc );
+               // VFS Configuration strings
+               if( proc->CurrentWorkingDir)
+                       free( proc->CurrentWorkingDir );
+               if( proc->RootDir )
+                       free( proc->RootDir );
+               // Process descriptor
+               free( proc );
+       }
        
        // Free name
        if( IsHeap(Thread->ThreadName) )
@@ -166,9 +195,11 @@ int Threads_SetName(const char *NewName)
        
        cur->ThreadName = NULL;
        
-       if( IsHeap(oldname) )   free( oldname );
-       
+       if( IsHeap(oldname) )   free( oldname );        
        cur->ThreadName = strdup(NewName);
+
+       Log_Debug("Threads", "Thread renamed to '%s'", NewName);        
+
        return 0;
 }
 
@@ -207,14 +238,18 @@ void Threads_SetPriority(tThread *Thread, int Pri)
        if( Pri == Thread->Priority )   return;
        
        #if SCHEDULER_TYPE == SCHED_RR_PRI
-       SHORTLOCK( &glThreadListLock );
-       // Remove from old priority
-       Threads_int_DelFromQueue( &gaActiveThreads[Thread->Priority], Thread );
-       // And add to new
-       Thread->Next = gaActiveThreads[Pri];
-       gaActiveThreads[Pri] = Thread;
-       Thread->Priority = Pri;
-       SHORTREL( &glThreadListLock );
+       if( Thread != Proc_GetCurThread() )
+       {
+               SHORTLOCK( &glThreadListLock );
+               // Remove from old priority
+               Threads_int_DelFromQueue( &gaActiveThreads[Thread->Priority], Thread );
+               // And add to new
+               Threads_int_AddToList( &gaActiveThreads[Pri], Thread );
+               Thread->Priority = Pri;
+               SHORTREL( &glThreadListLock );
+       }
+       else
+               Thread->Priority = Pri;
        #else
        // If this isn't the current thread, we need to lock
        if( Thread != Proc_GetCurThread() )
@@ -250,7 +285,6 @@ void Threads_SetPriority(tThread *Thread, int Pri)
 tThread *Threads_CloneTCB(Uint Flags)
 {
        tThread *cur, *new;
-        int    i;
        cur = Proc_GetCurThread();
        
        // Allocate and duplicate
@@ -273,10 +307,30 @@ tThread *Threads_CloneTCB(Uint Flags)
        new->ThreadName = strdup(cur->ThreadName);
        
        // Set Thread Group ID (PID)
-       if(Flags & CLONE_VM)
-               new->TGID = new->TID;
-       else
-               new->TGID = cur->TGID;
+       if(Flags & CLONE_VM) {
+               tProcess        *newproc, *oldproc;
+               oldproc = cur->Process;
+               new->Process = malloc( sizeof(struct sProcess) );
+               newproc = new->Process;
+               newproc->PID = new->TID;
+               newproc->UID = oldproc->UID;
+               newproc->GID = oldproc->GID;
+               newproc->MaxFD = oldproc->MaxFD;
+               if( oldproc->CurrentWorkingDir )
+                       newproc->CurrentWorkingDir = strdup( oldproc->CurrentWorkingDir );
+               else
+                       newproc->CurrentWorkingDir = NULL;
+               if( oldproc->RootDir )
+                       newproc->RootDir = strdup( oldproc->RootDir );
+               else
+                       newproc->RootDir = NULL;
+               newproc->nThreads = 1;
+               // Reference all handles in the VFS
+               VFS_ReferenceUserHandles();
+       }
+       else {
+               new->Process->nThreads ++;
+       }
        
        // Messages are not inherited
        new->Messages = NULL;
@@ -285,27 +339,12 @@ tThread *Threads_CloneTCB(Uint Flags)
        // Set State
        new->Remaining = new->Quantum = cur->Quantum;
        new->Priority = cur->Priority;
+       new->_errno = 0;
        
        // Set Signal Handlers
        new->CurFaultNum = 0;
        new->FaultHandler = cur->FaultHandler;
        
-       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;
-               }
-       }
-       
        // Maintain a global list of threads
        SHORTLOCK( &glThreadListLock );
        new->GlobalPrev = NULL; // Protect against bugs
@@ -323,7 +362,6 @@ tThread *Threads_CloneTCB(Uint Flags)
 tThread *Threads_CloneThreadZero(void)
 {
        tThread *new;
-        int    i;
        
        // Allocate and duplicate
        new = malloc(sizeof(tThread));
@@ -331,6 +369,8 @@ tThread *Threads_CloneThreadZero(void)
                return NULL;
        }
        memcpy(new, &gThreadZero, sizeof(tThread));
+
+       new->Process->nThreads ++;
        
        new->CurCPU = -1;
        new->Next = NULL;
@@ -358,11 +398,6 @@ tThread *Threads_CloneThreadZero(void)
        new->CurFaultNum = 0;
        new->FaultHandler = 0;
        
-       for( i = 0; i < NUM_CFG_ENTRIES; i ++ )
-       {
-               new->Config[i] = 0;
-       }
-       
        // Maintain a global list of threads
        SHORTLOCK( &glThreadListLock );
        new->GlobalPrev = NULL; // Protect against bugs
@@ -374,21 +409,6 @@ tThread *Threads_CloneThreadZero(void)
        return new;
 }
 
-/**
- * \brief Get a configuration pointer from the Per-Thread data area
- * \param ID   Config slot ID
- * \return Pointer at 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];
-}
-
 /**
  * \brief Wait for a task to change state
  * \param TID  Thread ID to wait on (-1: Any child thread, 0: Any Child/Sibling, <-1: -PID)
@@ -418,22 +438,17 @@ tTID Threads_WaitTID(int TID, int *Status)
        // Specific Thread
        if(TID > 0) {
                tThread *t = Threads_GetThread(TID);
-                int    initStatus = t->Status;
                tTID    ret;
                
                // Wait for the thread to die!
-               if(initStatus != THREAD_STAT_ZOMBIE) {
-                       // TODO: Handle child also being suspended if wanted
-                       while(t->Status != THREAD_STAT_ZOMBIE) {
-                               Threads_Sleep();
-                               Log_Debug("Threads", "%i waiting for %i, t->Status = %i",
-                                       Threads_GetTID(), t->TID, t->Status);
-                       }
+               // TODO: Handle child also being suspended if wanted
+               while(t->Status != THREAD_STAT_ZOMBIE) {
+                       Threads_Sleep();
+                       Log_Debug("Threads", "%i waiting for %i, t->Status = %i",
+                               Threads_GetTID(), t->TID, t->Status);
                }
                
                // Set return status
-               Log_Debug("Threads", "%i waiting for %i, t->Status = %i",
-                       Threads_GetTID(), t->TID, t->Status);
                ret = t->TID;
                switch(t->Status)
                {
@@ -484,11 +499,11 @@ tThread *Threads_GetThread(Uint TID)
  * \param Thread       Thread to find
  * \return \a Thread
  */
-tThread *Threads_int_DelFromQueue(tThread **List, tThread *Thread)
+tThread *Threads_int_DelFromQueue(tThreadList *List, tThread *Thread)
 {
        tThread *ret, *prev = NULL;
        
-       for(ret = *List;
+       for(ret = List->Head;
                ret && ret != Thread;
                prev = ret, ret = ret->Next
                );
@@ -500,17 +515,29 @@ tThread *Threads_int_DelFromQueue(tThread **List, tThread *Thread)
        }
        
        if( !prev ) {
-               *List = Thread->Next;
+               List->Head = Thread->Next;
                //LogF("%p(%s) removed from head of %p\n", Thread, Thread->ThreadName, List);
        }
        else {
                prev->Next = Thread->Next;
                //LogF("%p(%s) removed from %p (prev=%p)\n", Thread, Thread->ThreadName, List, prev);
        }
+       if( Thread->Next == NULL )
+               List->Tail = prev;
        
        return Thread;
 }
 
+void Threads_int_AddToList(tThreadList *List, tThread *Thread)
+{
+       if( List->Head )
+               List->Tail->Next = Thread;
+       else
+               List->Head = Thread;
+       List->Tail = Thread;
+       Thread->Next = NULL;
+}
+
 /**
  * \brief Exit the current process (or another?)
  * \param TID  Thread ID to kill
@@ -576,30 +603,33 @@ void Threads_Kill(tThread *Thread, int Status)
        
        // Currently active thread
        case THREAD_STAT_ACTIVE:
-               #if SCHEDULER_TYPE == SCHED_RR_PRI
-               if( Threads_int_DelFromQueue( &gaActiveThreads[Thread->Priority], Thread ) )
-               #else
-               if( Threads_int_DelFromQueue( &gActiveThreads, Thread ) )
-               #endif
+               if( Thread != Proc_GetCurThread() )
                {
-                       // Ensure that we are not rescheduled
-                       Thread->Remaining = 0;  // Clear Remaining Quantum
-                       Thread->Quantum = 0;    // Clear Quantum to indicate dead thread
-                       
-                       // Update bookkeeping
-                       giNumActiveThreads --;
+                       #if SCHEDULER_TYPE == SCHED_RR_PRI
+                       tThreadList     *list = &gaActiveThreads[Thread->Priority];
+                       #else
+                       tThreadList     *list = &gActiveThreads;
+                       #endif
+                       if( Threads_int_DelFromQueue( list, Thread ) )
+                       {
+                       }
+                       else
+                       {
+                               Log_Warning("Threads",
+                                       "Threads_Kill - Thread %p(%i,%s) marked as active, but not on list",
+                                       Thread, Thread->TID, Thread->ThreadName
+                                       );
+                       }
                        #if SCHEDULER_TYPE == SCHED_LOTTERY
-                       if( Thread != Proc_GetCurThread() )
-                               giFreeTickets -= caiTICKET_COUNTS[ Thread->Priority ];
+                       giFreeTickets -= caiTICKET_COUNTS[ Thread->Priority ];
                        #endif
                }
-               else
-               {
-                       Log_Warning("Threads",
-                               "Threads_Kill - Thread %p(%i,%s) marked as active, but not on list",
-                               Thread, Thread->TID, Thread->ThreadName
-                               );
-               }
+               // Ensure that we are not rescheduled
+               Thread->Remaining = 0;  // Clear Remaining Quantum
+               Thread->Quantum = 0;    // Clear Quantum to indicate dead thread
+                       
+               // Update bookkeeping
+               giNumActiveThreads --;
                break;
        // Kill it while it sleeps!
        case THREAD_STAT_SLEEPING:
@@ -630,8 +660,6 @@ void Threads_Kill(tThread *Thread, int Status)
        Thread->RetStatus = Status;
 
        SHORTREL( &Thread->IsLocked );
-       // Clear out process state
-       Proc_ClearThread(Thread);                       
 
        Thread->Status = THREAD_STAT_ZOMBIE;
        SHORTREL( &glThreadListLock );
@@ -680,9 +708,7 @@ void Threads_Sleep(void)
        cur->Status = THREAD_STAT_SLEEPING;
        
        // Add to Sleeping List (at the top)
-       cur->Next = gSleepingThreads;
-       gSleepingThreads = cur;
-       
+       Threads_int_AddToList( &gSleepingThreads, cur );
        
        #if DEBUG_TRACE_STATE
        Log("Threads_Sleep: %p (%i %s) sleeping", cur, cur->TID, cur->ThreadName);
@@ -836,21 +862,12 @@ void Threads_AddActive(tThread *Thread)
 //     Thread->CurCPU = -1;
        // Add to active list
        {
-               tThread *tmp, *prev = NULL;
                #if SCHEDULER_TYPE == SCHED_RR_PRI
-               for( tmp = gaActiveThreads[Thread->Priority]; tmp; prev = tmp, tmp = tmp->Next );
-               if(prev)
-                       prev->Next = Thread;
-               else
-                       gaActiveThreads[Thread->Priority] = Thread;
+               tThreadList     *list = &gaActiveThreads[Thread->Priority];
                #else
-               for( tmp = gActiveThreads; tmp; prev = tmp, tmp = tmp->Next );
-               if(prev)
-                       prev->Next = Thread;
-               else
-                       gActiveThreads = Thread;
+               tThreadList     *list = &gActiveThreads;
                #endif
-               Thread->Next = NULL;
+               Threads_int_AddToList( list, Thread );
        }
        
        // Update bookkeeping
@@ -885,6 +902,7 @@ void Threads_AddActive(tThread *Thread)
  */
 tThread *Threads_RemActive(void)
 {
+       #if 0
        tThread *ret = Proc_GetCurThread();
 
        if( !IS_LOCKED(&glThreadListLock) ) {
@@ -899,7 +917,6 @@ tThread *Threads_RemActive(void)
        if( !Threads_int_DelFromQueue(&gActiveThreads, ret) )
        #endif
        {
-               SHORTREL( &glThreadListLock );
                Log_Warning("Threads", "Current thread %p(%i %s) is not on active queue",
                        ret, ret->TID, ret->ThreadName
                        );
@@ -918,6 +935,9 @@ tThread *Threads_RemActive(void)
        #endif
        
        return ret;
+       #else
+       return Proc_GetCurThread();
+       #endif
 }
 
 /**
@@ -983,7 +1003,7 @@ void Threads_SegFault(tVAddr Addr)
 // --- Process Structure Access Functions ---
 tPID Threads_GetPID(void)
 {
-       return Proc_GetCurThread()->TGID;
+       return Proc_GetCurThread()->Process->PID;
 }
 tTID Threads_GetTID(void)
 {
@@ -991,43 +1011,65 @@ tTID Threads_GetTID(void)
 }
 tUID Threads_GetUID(void)
 {
-       return Proc_GetCurThread()->UID;
+       return Proc_GetCurThread()->Process->UID;
 }
 tGID Threads_GetGID(void)
 {
-       return Proc_GetCurThread()->GID;
+       return Proc_GetCurThread()->Process->GID;
 }
 
-int Threads_SetUID(Uint *Errno, tUID ID)
+int Threads_SetUID(tUID ID)
 {
        tThread *t = Proc_GetCurThread();
-       if( t->UID != 0 ) {
-               *Errno = -EACCES;
+       if( t->Process->UID != 0 ) {
+               errno = -EACCES;
                return -1;
        }
-       Log_Debug("Threads", "TID %i's UID set to %i", t->TID, ID);
-       t->UID = ID;
+       Log_Debug("Threads", "PID %i's UID set to %i", t->Process->PID, ID);
+       t->Process->UID = ID;
        return 0;
 }
 
-int Threads_SetGID(Uint *Errno, tGID ID)
+int Threads_SetGID(tGID ID)
 {
        tThread *t = Proc_GetCurThread();
-       if( t->UID != 0 ) {
-               *Errno = -EACCES;
+       if( t->Process->UID != 0 ) {
+               errno = -EACCES;
                return -1;
        }
-       Log_Debug("Threads", "TID %i's GID set to %i", t->TID, ID);
-       t->GID = ID;
+       Log_Debug("Threads", "PID %i's GID set to %i", t->Process->PID, ID);
+       t->Process->GID = ID;
        return 0;
 }
 
+// --- Per-thread storage ---
+int *Threads_GetErrno(void)
+{
+       return &Proc_GetCurThread()->_errno;
+}
+
+// --- Configuration ---
+int *Threads_GetMaxFD(void)
+{
+       return &Proc_GetCurThread()->Process->MaxFD;
+}
+char **Threads_GetChroot(void)
+{
+       return &Proc_GetCurThread()->Process->RootDir;
+}
+char **Threads_GetCWD(void)
+{
+       return &Proc_GetCurThread()->Process->CurrentWorkingDir;
+}
+// ---
+
 /**
  * \fn void Threads_Dump(void)
  */
 void Threads_DumpActive(void)
 {
        tThread *thread;
+       tThreadList     *list;
        #if SCHEDULER_TYPE == SCHED_RR_PRI
         int    i;
        #endif
@@ -1037,15 +1079,17 @@ void Threads_DumpActive(void)
        #if SCHEDULER_TYPE == SCHED_RR_PRI
        for( i = 0; i < MIN_PRIORITY+1; i++ )
        {
-               for(thread=gaActiveThreads[i];thread;thread=thread->Next)
+               list = &gaActiveThreads[i];
        #else
-               for(thread=gActiveThreads;thread;thread=thread->Next)
+               list = &gActiveThreads;
        #endif
+               for(thread=list->Head;thread;thread=thread->Next)
                {
                        Log(" %p %i (%i) - %s (CPU %i)",
-                               thread, thread->TID, thread->TGID, thread->ThreadName, thread->CurCPU);
+                               thread, thread->TID, thread->Process->PID, thread->ThreadName, thread->CurCPU);
                        if(thread->Status != THREAD_STAT_ACTIVE)
-                               Log("  ERROR State (%i) != THREAD_STAT_ACTIVE (%i)", thread->Status, THREAD_STAT_ACTIVE);
+                               Log("  ERROR State (%i) != THREAD_STAT_ACTIVE (%i)",
+                                       thread->Status, THREAD_STAT_ACTIVE);
                        Log("  Priority %i, Quantum %i", thread->Priority, thread->Quantum);
                        Log("  KStack 0x%x", thread->KernelStack);
                        if( thread->bInstrTrace )
@@ -1073,7 +1117,7 @@ void Threads_Dump(void)
        for(thread=gAllThreads;thread;thread=thread->GlobalNext)
        {
                Log(" %p %i (%i) - %s (CPU %i)",
-                       thread, thread->TID, thread->TGID, thread->ThreadName, thread->CurCPU);
+                       thread, thread->TID, thread->Process->PID, thread->ThreadName, thread->CurCPU);
                Log("  State %i (%s)", thread->Status, casTHREAD_STAT[thread->Status]);
                switch(thread->Status)
                {
@@ -1131,25 +1175,28 @@ tThread *Threads_GetNextToRun(int CPU, tThread *Last)
                #endif
                return NULL;
        }
-       
+
+       #if 0   
        #if SCHEDULER_TYPE != SCHED_RR_PRI
        // Special case: 1 thread
        if(giNumActiveThreads == 1) {
-               if( gActiveThreads->CurCPU == -1 )
-                       gActiveThreads->CurCPU = CPU;
+               if( gActiveThreads.Head->CurCPU == -1 )
+                       gActiveThreads.Head->CurCPU = CPU;
                
                SHORTREL( &glThreadListLock );
                
-               if( gActiveThreads->CurCPU == CPU )
-                       return gActiveThreads;
+               if( gActiveThreads.Head->CurCPU == CPU )
+                       return gActiveThreads.Head;
                
                return NULL;    // CPU has nothing to do
        }
        #endif
-       
+       #endif  
+
        // Allow the old thread to be scheduled again
        if( Last ) {
                if( Last->Status == THREAD_STAT_ACTIVE ) {
+                       tThreadList     *list;
                        #if SCHEDULER_TYPE == SCHED_LOTTERY
                        giFreeTickets += caiTICKET_COUNTS[ Last->Priority ];
                        # if DEBUG_TRACE_TICKETS
@@ -1158,6 +1205,14 @@ tThread *Threads_GetNextToRun(int CPU, tThread *Last)
                                caiTICKET_COUNTS[ Last->Priority ]);
                        # endif
                        #endif
+                       
+                       #if SCHEDULER_TYPE == SCHED_RR_PRI
+                       list = &gaActiveThreads[ Last->Priority ];
+                       #else
+                       list = &gActiveThreads;
+                       #endif
+                       // Add to end of list
+                       Threads_int_AddToList( list, Last );
                }
                #if SCHEDULER_TYPE == SCHED_LOTTERY && DEBUG_TRACE_TICKETS
                else
@@ -1175,8 +1230,8 @@ tThread *Threads_GetNextToRun(int CPU, tThread *Last)
                 int    ticket, number;
                # if 1
                number = 0;
-               for(thread = gActiveThreads; thread; thread = thread->Next) {
-                       if(thread->CurCPU >= 0) continue;
+               for(thread = gActiveThreads.Head; thread; thread = thread->Next)
+               {
                        if(thread->Status != THREAD_STAT_ACTIVE)
                                Panic("Bookkeeping fail - %p %i(%s) is on the active queue with a status of %i",
                                        thread, thread->TID, thread->ThreadName, thread->Status);
@@ -1202,9 +1257,8 @@ tThread *Threads_GetNextToRun(int CPU, tThread *Last)
                ticket = number = rand() % giFreeTickets;
                
                // Find the next thread
-               for(thread=gActiveThreads;thread;thread=thread->Next)
+               for(thread = gActiveThreads.Head; thread; prev = thread, thread = thread->Next )
                {
-                       if(thread->CurCPU >= 0) continue;
                        if( caiTICKET_COUNTS[ thread->Priority ] > number)      break;
                        number -= caiTICKET_COUNTS[ thread->Priority ];
                }
@@ -1220,7 +1274,15 @@ tThread *Threads_GetNextToRun(int CPU, tThread *Last)
                        Panic("Bookeeping Failed - giFreeTickets(%i) > true count (%i)",
                                giFreeTickets, number);
                }
-               
+
+               // Remove
+               if(prev)
+                       prev->Next = thread->Next;
+               else
+                       gActiveThreads.Head = thread->Next;
+               if(!thread->Next)
+                       gActiveThreads.Tail = prev;             
+
                giFreeTickets -= caiTICKET_COUNTS[ thread->Priority ];
                # if DEBUG_TRACE_TICKETS
                LogF("Log: CPU%i allocated %p (%i %s), (%i [-%i] tickets in pool), \n",
@@ -1235,28 +1297,20 @@ tThread *Threads_GetNextToRun(int CPU, tThread *Last)
        #elif SCHEDULER_TYPE == SCHED_RR_PRI
        {
                 int    i;
+               thread = NULL;
                for( i = 0; i < MIN_PRIORITY + 1; i ++ )
                {
-                       for(thread = gaActiveThreads[i]; thread; thread = thread->Next)
-                       {
-                               if( thread->CurCPU == -1 )      break;
-                       }
-                       // If we fall onto the same queue again, special handling is
-                       // needed
-                       if( Last && Last->Status == THREAD_STAT_ACTIVE && i == Last->Priority ) {
-                               tThread *savedThread = thread;
-                               
-                               // Find the next unscheduled thread in the list
-                               for( thread = Last->Next; thread; thread = thread->Next )
-                               {
-                                       if( thread->CurCPU == -1 )      break;
-                               }
-                               // If we don't find anything after, just use the one 
-                               // found above.
-                               if( !thread )   thread = savedThread;
-                       }
-                       // Found a thread? Schedule it!
-                       if( thread )    break;
+                       if( !gaActiveThreads[i].Head )
+                               continue ;
+       
+                       thread = gaActiveThreads[i].Head;
+                       
+                       // Remove from head
+                       gaActiveThreads[i].Head = thread->Next;
+                       if(!thread->Next)
+                               gaActiveThreads[i].Tail = NULL;
+                       thread->Next = NULL;
+                       break;
                }
                
                // Anything to do?
@@ -1269,20 +1323,13 @@ tThread *Threads_GetNextToRun(int CPU, tThread *Last)
                }
        }
        #elif SCHEDULER_TYPE == SCHED_RR_SIM
-       {               
-               // Find the next unscheduled thread in the list
-               for( thread = Last->Next; thread; thread = thread->Next )
-               {
-                       if( thread->CurCPU == -1 )      break;
-               }
-               // If we don't find anything after, search from the beginning
-               if( !thread )
-               {
-                       for(thread = gActiveThreads; thread; thread = thread->Next)
-                       {
-                               if( thread->CurCPU == -1 )      break;
-                       }       
-               }
+       {
+               // Get the next thread off the list
+               thread = gActiveThreads.Head;   
+               gActiveThreads.Head = thread->Next;
+               if(!thread->Next)
+                       gaActiveThreads.Tail = NULL;
+               thread->Next = NULL;
                
                // Anything to do?
                if( !thread ) {
index 3d4018f..aee7a60 100644 (file)
@@ -73,7 +73,7 @@ int VFS_MkNod(const char *Path, Uint Flags)
        
        // Permissions Check
        if( !VFS_CheckACL(parent, VFS_PERM_EXECUTE|VFS_PERM_WRITE) ) {
-               if(parent->Close)       parent->Close( parent );
+               _CloseNode(parent);
                free(absPath);
                LEAVE('i', -1);
                return -1;
@@ -81,20 +81,20 @@ int VFS_MkNod(const char *Path, Uint Flags)
        
        LOG("parent = %p", parent);
        
-       if(parent->MkNod == NULL) {
+       if(!parent->Type || !parent->Type->MkNod) {
                Warning("VFS_MkNod - Directory has no MkNod method");
                LEAVE('i', -1);
                return -1;
        }
        
        // Create node
-       ret = parent->MkNod(parent, name, Flags);
+       ret = parent->Type->MkNod(parent, name, Flags);
        
        // Free allocated string
        free(absPath);
        
        // Free Parent
-       if(parent->Close)       parent->Close( parent );
+       _CloseNode(parent);
        
        // Error Check
        if(ret == 0) {
@@ -116,48 +116,23 @@ int VFS_Symlink(const char *Name, const char *Link)
 {
        char    *realLink;
         int    fp;
-       char    *_link;
        
        ENTER("sName sLink", Name, Link);
        
        // Get absolue path name
-       _link = VFS_GetAbsPath( Link );
-       if(!_link) {
+       realLink = VFS_GetAbsPath( Link );
+       if(!realLink) {
                Log_Warning("VFS", "Path '%s' is badly formed", Link);
                LEAVE('i', -1);
                return -1;
        }
 
-       LOG("_link = '%s'", _link);
-       
-       #if 1
-       {
-       tVFS_Node *destNode = VFS_ParsePath( _link, &realLink, NULL );
-       #if 0
-       // Get true path and node
-       free(_link);
-       _link = NULL;
-       #else
-       realLink = _link;
-       #endif
-       
-       // Check if destination exists
-       if(!destNode) {
-               Log_Warning("VFS", "File '%s' does not exist, symlink not created", Link);
-               return -1;
-       }
-       
-       // Derefence the destination
-       if(destNode->Close)     destNode->Close(destNode);
-       }
-       #else
-       realLink = _link;
-       #endif  
        LOG("realLink = '%s'", realLink);
 
        // Make node
        if( VFS_MkNod(Name, VFS_FFLAG_SYMLINK) != 0 ) {
                Log_Warning("VFS", "Unable to create link node '%s'", Name);
+               free(realLink);
                LEAVE('i', -2);
                return -2;      // Make link node
        }
@@ -184,7 +159,7 @@ int VFS_ReadDir(int FD, char *Dest)
        
        //ENTER("ph pDest", h, Dest);
        
-       if(!h || h->Node->ReadDir == NULL) {
+       if(!h || !h->Node->Type || !h->Node->Type->ReadDir) {
                //LEAVE('i', 0);
                return 0;
        }
@@ -195,7 +170,7 @@ int VFS_ReadDir(int FD, char *Dest)
        }
        
        do {
-               tmp = h->Node->ReadDir(h->Node, h->Position);
+               tmp = h->Node->Type->ReadDir(h->Node, h->Position);
                if((Uint)tmp < (Uint)VFS_MAXSKIP)
                        h->Position += (Uint)tmp;
                else
index 162f111..b3f4a57 100644 (file)
@@ -20,13 +20,17 @@ tVFS_Node   *DevFS_FindDir(tVFS_Node *Node, const char *Name);
 tVFS_Driver    gDevFS_Info = {
        "devfs", 0, DevFS_InitDevice, NULL, NULL
        };
+tVFS_NodeType  gDevFS_DirType = {
+       .TypeName = "DevFS-Dir",
+       .ReadDir = DevFS_ReadDir,
+       .FindDir = DevFS_FindDir
+       };
 tVFS_Node      gDevFS_RootNode = {
        .Size = 0,
        .Flags = VFS_FFLAG_DIRECTORY,
        .NumACLs = 1,
        .ACLs = &gVFS_ACL_EveryoneRX,
-       .ReadDir = DevFS_ReadDir,
-       .FindDir = DevFS_FindDir
+       .Type = &gDevFS_DirType
        };
 tDevFS_Driver  *gDevFS_Drivers = NULL;
  int   giDevFS_NextID = 1;
index a12d154..9fa1732 100644 (file)
@@ -17,7 +17,7 @@ tVFS_Node     *Root_InitDevice(const char *Device, const char **Options);
 tVFS_Node      *Root_FindDir(tVFS_Node *Node, const char *Name);
 char   *Root_ReadDir(tVFS_Node *Node, int Pos);
 Uint64 Root_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
-Uint64 Root_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+Uint64 Root_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer);
 tRamFS_File    *Root_int_AllocFile(void);
 
 // === GLOBALS ===
@@ -35,6 +35,17 @@ tVFS_ACL     RootFS_FileACLs[3] = {
        {{1,0}, {0,VFS_PERM_ALL^VFS_PERM_EXECUTE}},     // Group (Root)
        {{0,-1}, {0,VFS_PERM_READ}}     // World (Nobody)
 };
+tVFS_NodeType  gRootFS_DirType = {
+       .TypeName = "RootFS-Dir",
+       .ReadDir = Root_ReadDir,
+       .FindDir = Root_FindDir,
+       .MkNod = Root_MkNod
+};
+tVFS_NodeType  gRootFS_FileType = {
+       .TypeName = "RootFS-File",
+       .Read = Root_Read,
+       .Write = Root_Write,
+};
 
 // === CODE ===
 /**
@@ -57,12 +68,8 @@ tVFS_Node *Root_InitDevice(const char *Device, const char **Options)
                = root->Node.ATime = now();
        root->Node.NumACLs = 3;
        root->Node.ACLs = RootFS_DirACLs;
-       
-       //root->Node.Close = Root_CloseFile;    // Not Needed (It's a RAM Disk!)
-       //root->Node.Relink = Root_RelinkRoot;  // Not Needed (Why relink the root of the tree)
-       root->Node.FindDir = Root_FindDir;
-       root->Node.ReadDir = Root_ReadDir;
-       root->Node.MkNod = Root_MkNod;
+
+       root->Node.Type = &gRootFS_DirType;
        
        return &root->Node;
 }
@@ -109,16 +116,13 @@ int Root_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
        if(Flags & VFS_FFLAG_DIRECTORY)
        {
                child->Node.ACLs = RootFS_DirACLs;
-               child->Node.ReadDir = Root_ReadDir;
-               child->Node.FindDir = Root_FindDir;
-               child->Node.MkNod = Root_MkNod;
+               child->Node.Type = &gRootFS_DirType;
        } else {
                if(Flags & VFS_FFLAG_SYMLINK)
                        child->Node.ACLs = RootFS_DirACLs;
                else
                        child->Node.ACLs = RootFS_FileACLs;
-               child->Node.Read = Root_Read;
-               child->Node.Write = Root_Write;
+               child->Node.Type = &gRootFS_FileType;
        }
        
        prev->Next = child;
@@ -194,7 +198,7 @@ Uint64 Root_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
  * \fn Uint64 Root_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
  * \brief Write to a file in the root directory
  */
-Uint64 Root_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+Uint64 Root_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
 {
        tRamFS_File     *file = Node->ImplPtr;
 
index 55c841e..d22f965 100644 (file)
@@ -8,6 +8,8 @@
 #include "vfs.h"
 #include "vfs_int.h"
 #include "vfs_ext.h"
+#include <threads.h>   // GetMaxFD
+#include <vfs_threads.h>       // Handle maintainance
 
 // === CONSTANTS ===
 #define MAX_KERNEL_FILES       128
@@ -40,7 +42,7 @@ tVFS_Handle *VFS_GetHandle(int FD)
                if(FD >= MAX_KERNEL_FILES)      return NULL;
                h = &gaKernelHandles[ FD ];
        } else {
-               if(FD >= CFGINT(CFG_VFS_MAXFILES))      return NULL;
+               if(FD >= *Threads_GetMaxFD())   return NULL;
                h = &gaUserHandles[ FD ];
        }
        
@@ -56,14 +58,15 @@ int VFS_AllocHandle(int bIsUser, tVFS_Node *Node, int Mode)
        // Check for a user open
        if(bIsUser)
        {
+                int    max_handles = *Threads_GetMaxFD();
                // Allocate Buffer
-               if( MM_GetPhysAddr( (Uint)gaUserHandles ) == 0 )
+               if( MM_GetPhysAddr( (tVAddr)gaUserHandles ) == 0 )
                {
                        Uint    addr, size;
-                       size = CFGINT(CFG_VFS_MAXFILES) * sizeof(tVFS_Handle);
+                       size = max_handles * sizeof(tVFS_Handle);
                        for(addr = 0; addr < size; addr += 0x1000)
                        {
-                               if( !MM_Allocate( (Uint)gaUserHandles + addr ) )
+                               if( !MM_Allocate( (tVAddr)gaUserHandles + addr ) )
                                {
                                        Warning("OOM - VFS_AllocHandle");
                                        Threads_Exit(0, 0xFF);  // Terminate user
@@ -72,7 +75,7 @@ int VFS_AllocHandle(int bIsUser, tVFS_Node *Node, int Mode)
                        memset( gaUserHandles, 0, size );
                }
                // Get a handle
-               for(i=0;i<CFGINT(CFG_VFS_MAXFILES);i++)
+               for( i = 0; i < max_handles; i ++ )
                {
                        if(gaUserHandles[i].Node)       continue;
                        gaUserHandles[i].Node = Node;
@@ -84,13 +87,13 @@ int VFS_AllocHandle(int bIsUser, tVFS_Node *Node, int Mode)
        else
        {
                // Allocate space if not already
-               if( MM_GetPhysAddr( (Uint)gaKernelHandles ) == 0 )
+               if( MM_GetPhysAddr( (tVAddr)gaKernelHandles ) == 0 )
                {
                        Uint    addr, size;
                        size = MAX_KERNEL_FILES * sizeof(tVFS_Handle);
                        for(addr = 0; addr < size; addr += 0x1000)
                        {
-                               if( !MM_Allocate( (Uint)gaKernelHandles + addr ) )
+                               if( !MM_Allocate( (tVAddr)gaKernelHandles + addr ) )
                                {
                                        Panic("OOM - VFS_AllocHandle");
                                        Threads_Exit(0, 0xFF);  // Terminate application (get some space back)
@@ -111,3 +114,157 @@ int VFS_AllocHandle(int bIsUser, tVFS_Node *Node, int Mode)
        
        return -1;
 }
+
+void VFS_ReferenceUserHandles(void)
+{
+        int    i;
+        int    max_handles = *Threads_GetMaxFD();
+
+       // Check if this process has any handles
+       if( MM_GetPhysAddr( (tVAddr)gaUserHandles ) == 0 )
+               return ;
+       
+       for( i = 0; i < max_handles; i ++ )
+       {
+               tVFS_Handle     *h;
+               h = &gaUserHandles[i];
+               if( !h->Node )
+                       continue ;
+               if( h->Node->Type && h->Node->Type->Reference )
+                       h->Node->Type->Reference( h->Node );
+       }
+}
+
+void VFS_CloseAllUserHandles(void)
+{
+        int    i;
+        int    max_handles = *Threads_GetMaxFD();
+
+       // Check if this process has any handles
+       if( MM_GetPhysAddr( (tVAddr)gaUserHandles ) == 0 )
+               return ;
+       
+       for( i = 0; i < max_handles; i ++ )
+       {
+               tVFS_Handle     *h;
+               h = &gaUserHandles[i];
+               if( !h->Node )
+                       continue ;
+               if( h->Node->Type && h->Node->Type->Close )
+                       h->Node->Type->Close( h->Node );
+       }
+}
+
+/**
+ * \brief Take a backup of a set of file descriptors
+ */
+void *VFS_SaveHandles(int NumFDs, int *FDs)
+{
+       tVFS_Handle     *ret;
+        int    i;
+        int    max_handles = *Threads_GetMaxFD();
+       
+       // Check if this process has any handles
+       if( MM_GetPhysAddr( (tVAddr)gaUserHandles ) == 0 )
+               return NULL;
+
+       // Allocate
+       ret = malloc( NumFDs * sizeof(tVFS_Handle) );
+       if( !ret )
+               return NULL;    
+
+       if( NumFDs > max_handles )
+               NumFDs = max_handles;
+
+       // Take copies of the handles
+       for( i = 0; i < NumFDs; i ++ )
+       {
+               tVFS_Handle     *h;
+               if( FDs == NULL )
+                       h = &gaUserHandles[i];
+               else {
+                       h = VFS_GetHandle(FDs[i] & (VFS_KERNEL_FLAG - 1));
+                       if(!h) {
+                               Log_Warning("VFS", "VFS_SaveHandles - Invalid FD %i",
+                                       FDs[i] & (VFS_KERNEL_FLAG - 1) );
+                               free(ret);
+                               return NULL;
+                       }
+               }
+               memcpy( &ret[i], h, sizeof(tVFS_Handle) );
+               
+               // Reference node
+               if( !h->Node )
+                       continue ;
+               if( h->Node->Type && h->Node->Type->Reference )
+                       h->Node->Type->Reference( h->Node );
+       }       
+
+       return ret;
+}
+
+void VFS_RestoreHandles(int NumFDs, void *Handles)
+{
+       tVFS_Handle     *handles = Handles;
+        int    i;
+
+       // NULL = nothing to do
+       if( !Handles )
+               return ;        
+
+       // Check if there is already a set of handles
+       if( MM_GetPhysAddr( (tVAddr)gaUserHandles ) != 0 )
+               return ;
+       
+       
+       // Allocate user handle area
+       {
+               Uint    addr, size;
+                int    max_handles = *Threads_GetMaxFD();
+               size = max_handles * sizeof(tVFS_Handle);
+               for(addr = 0; addr < size; addr += 0x1000)
+               {
+                       if( !MM_Allocate( (tVAddr)gaUserHandles + addr ) )
+                       {
+                               Warning("OOM - VFS_AllocHandle");
+                               Threads_Exit(0, 0xFF);  // Terminate user
+                       }
+               }
+               memset( gaUserHandles, 0, size );
+       }
+       
+       // Restore handles
+       memcpy( gaUserHandles, handles, NumFDs * sizeof(tVFS_Handle) );
+       // Reference when copied
+       for( i = 0; i < NumFDs; i ++ )
+       {
+               tVFS_Handle     *h = &handles[i];
+       
+               if( !h->Node )
+                       continue ;
+               if( h->Node->Type && h->Node->Type->Reference )
+                       h->Node->Type->Reference( h->Node );
+       }
+}
+
+void VFS_FreeSavedHandles(int NumFDs, void *Handles)
+{
+       tVFS_Handle     *handles = Handles;
+        int    i;
+
+       // NULL = nothing to do
+       if( !Handles )
+               return ;        
+       
+       // Dereference all saved nodes
+       for( i = 0; i < NumFDs; i ++ )
+       {
+               tVFS_Handle     *h = &handles[i];
+       
+               if( !h->Node )
+                       continue ;
+               if( h->Node->Type && h->Node->Type->Close )
+                       h->Node->Type->Close( h->Node );
+       }
+       free( Handles );
+}
index 358d703..e7a2a06 100644 (file)
@@ -25,9 +25,9 @@ Uint64 VFS_Read(int FD, Uint64 Length, void *Buffer)
        if( !(h->Mode & VFS_OPENFLAG_READ) || h->Node->Flags & VFS_FFLAG_DIRECTORY )
                LEAVE_RET('i', -1);
 
-       if(!h->Node->Read)      LEAVE_RET('i', 0);
+       if(!h->Node->Type || !h->Node->Type->Read)      LEAVE_RET('i', 0);
        
-       ret = h->Node->Read(h->Node, h->Position, Length, Buffer);
+       ret = h->Node->Type->Read(h->Node, h->Position, Length, Buffer);
        if(ret == -1)   LEAVE_RET('i', -1);
        
        h->Position += ret;
@@ -50,11 +50,11 @@ Uint64 VFS_ReadAt(int FD, Uint64 Offset, Uint64 Length, void *Buffer)
        if( !(h->Mode & VFS_OPENFLAG_READ) )    return -1;
        if( h->Node->Flags & VFS_FFLAG_DIRECTORY )      return -1;
 
-       if(!h->Node->Read) {
+       if( !h->Node->Type || !h->Node->Type->Read) {
                Warning("VFS_ReadAt - Node %p, does not have a read method", h->Node);
                return 0;
        }
-       ret = h->Node->Read(h->Node, Offset, Length, Buffer);
+       ret = h->Node->Type->Read(h->Node, Offset, Length, Buffer);
        if(ret == -1)   return -1;
        return ret;
 }
@@ -74,11 +74,11 @@ Uint64 VFS_Write(int FD, Uint64 Length, const void *Buffer)
        if( !(h->Mode & VFS_OPENFLAG_WRITE) )   return -1;
        if( h->Node->Flags & VFS_FFLAG_DIRECTORY )      return -1;
 
-       if(!h->Node->Write)     return 0;
+       if( !h->Node->Type || !h->Node->Type->Write )   return 0;
        
-       // TODO: This is a hack, I need to change VFS_Node to have "const void*"
-       ret = h->Node->Write(h->Node, h->Position, Length, (void*)Buffer);
+       ret = h->Node->Type->Write(h->Node, h->Position, Length, Buffer);
        if(ret == -1)   return -1;
+
        h->Position += ret;
        return ret;
 }
@@ -98,9 +98,9 @@ Uint64 VFS_WriteAt(int FD, Uint64 Offset, Uint64 Length, const void *Buffer)
        if( !(h->Mode & VFS_OPENFLAG_WRITE) )   return -1;
        if( h->Node->Flags & VFS_FFLAG_DIRECTORY )      return -1;
 
-       if(!h->Node->Write)     return 0;
-       // TODO: This is a hack, I need to change VFS_Node to have "const void*"
-       ret = h->Node->Write(h->Node, Offset, Length, (void*)Buffer);
+       if(!h->Node->Type || !h->Node->Type->Write)     return 0;
+       ret = h->Node->Type->Write(h->Node, Offset, Length, Buffer);
+
        if(ret == -1)   return -1;
        return ret;
 }
@@ -166,8 +166,8 @@ int VFS_IOCtl(int FD, int ID, void *Buffer)
        h = VFS_GetHandle(FD);
        if(!h)  return -1;
 
-       if(!h->Node->IOCtl)     return -1;
-       return h->Node->IOCtl(h->Node, ID, Buffer);
+       if(!h->Node->Type || !h->Node->Type->IOCtl)     return -1;
+       return h->Node->Type->IOCtl(h->Node, ID, Buffer);
 }
 
 /**
index cb798c1..5ff0e7c 100644 (file)
@@ -4,9 +4,10 @@
  */
 #include <acess.h>
 #include <fs_sysfs.h>
-#include "vfs.h"
-#include "vfs_int.h"
-#include "vfs_ext.h"
+#include <threads.h>
+#include <vfs.h>
+#include <vfs_int.h>
+#include <vfs_ext.h>
 
 // === IMPORTS ===
 extern tVFS_Driver     gRootFS_Info;
@@ -60,7 +61,7 @@ int VFS_Init(void)
        VFS_Mount("dev", "/Devices", "devfs", "");
                
        Log_Debug("VFS", "Setting max files");
-       CFGINT(CFG_VFS_MAXFILES) = 32;
+       *Threads_GetMaxFD() = 32;
        return 0;
 }
 
@@ -81,7 +82,7 @@ char *VFS_GetTruePath(const char *Path)
        //Log(" VFS_GetTruePath: node=%p, ret='%s'", node, ret);
        
        if(!node)       return NULL;
-       if(node->Close) node->Close(node);
+       if(node->Type->Close)   node->Type->Close(node);
        
        return ret;
 }
index c197626..14b3948 100644 (file)
@@ -7,24 +7,23 @@
 #include <vfs.h>
 
 // === PROTOTYPES ===
-tVFS_Node      *VFS_MemFile_Create(tVFS_Node *Unused, const char *Path);
+tVFS_Node      *VFS_MemFile_Create(const char *Path);
 void   VFS_MemFile_Close(tVFS_Node *Node);
 Uint64 VFS_MemFile_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
-Uint64 VFS_MemFile_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+Uint64 VFS_MemFile_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer);
 
 // === GLOBALS ===
-tVFS_Node      gVFS_MemRoot = {
-       .Flags = VFS_FFLAG_DIRECTORY,
-       .NumACLs = 0,
-       .FindDir = VFS_MemFile_Create
+tVFS_NodeType  gVFS_MemFileType = {
+       .Close = VFS_MemFile_Close,
+       .Read = VFS_MemFile_Read,
+       .Write = VFS_MemFile_Write
        };
 
 // === CODE ===
 /**
- * \fn tVFS_Node *VFS_MemFile_Create(tVFS_Node *Unused, const char *Path)
- * \note Treated as finddir by VFS_ParsePath
+ * \fn tVFS_Node *VFS_MemFile_Create(const char *Path)
  */
-tVFS_Node *VFS_MemFile_Create(tVFS_Node *Unused, const char *Path)
+tVFS_Node *VFS_MemFile_Create(const char *Path)
 {
        Uint    base, size;
        const char      *str = Path;
@@ -73,9 +72,7 @@ tVFS_Node *VFS_MemFile_Create(tVFS_Node *Unused, const char *Path)
        ret->ACLs = &gVFS_ACL_EveryoneRWX;
        
        // Functions
-       ret->Close = VFS_MemFile_Close;
-       ret->Read = VFS_MemFile_Read;
-       ret->Write = VFS_MemFile_Write;
+       ret->Type = &gVFS_MemFileType;
        
        return ret;
 }
@@ -119,7 +116,7 @@ Uint64 VFS_MemFile_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buf
  * \fn Uint64 VFS_MemFile_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
  * \brief Write to a memory file
  */
-Uint64 VFS_MemFile_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+Uint64 VFS_MemFile_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
 {
        // Check for use of free'd file
        if(Node->ImplPtr == NULL)       return 0;
index f4132d5..9fe9282 100644 (file)
@@ -114,8 +114,13 @@ void *VFS_MMap(void *DestHint, size_t Length, int Protection, int Flags, int FD,
                {
                        if( pb->PhysAddrs[pagenum - pb->BaseOffset] == 0 )
                        {
-                               if( h->Node->MMap )
-                                       h->Node->MMap(h->Node, pagenum*PAGE_SIZE, PAGE_SIZE, (void*)mapping_dest);
+                               tVFS_NodeType   *nt = h->Node->Type;
+                               if( !nt ) 
+                               {
+                                       // TODO: error
+                               }
+                               else if( nt->MMap )
+                                       nt->MMap(h->Node, pagenum*PAGE_SIZE, PAGE_SIZE, (void*)mapping_dest);
                                else
                                {
                                         int    read_len;
@@ -127,7 +132,7 @@ void *VFS_MMap(void *DestHint, size_t Length, int Protection, int Flags, int FD,
                                                return NULL;
                                        }
                                        // TODO: Clip read length
-                                       read_len = h->Node->Read(h->Node, pagenum*PAGE_SIZE, PAGE_SIZE, (void*)mapping_dest);
+                                       read_len = nt->Read(h->Node, pagenum*PAGE_SIZE, PAGE_SIZE, (void*)mapping_dest);
 //                                     if( read_len != PAGE_SIZE ) {
 //                                             memset( (void*)(mapping_dest+read_len), 0, PAGE_SIZE-read_len );
 //                                     }
index ad85ac3..d2796c1 100644 (file)
@@ -178,8 +178,8 @@ void Inode_ClearCache(int Handle)
                ent->Node.ReferenceCount = 1;
                next = ent->Next;
                
-               if(ent->Node.Close)
-                       ent->Node.Close( &ent->Node );
+               if(ent->Node.Type && ent->Node.Type->Close)
+                       ent->Node.Type->Close( &ent->Node );
                free(ent);
                
                ent = next;
index a886c45..1536d1a 100644 (file)
@@ -7,6 +7,7 @@
 #include "vfs.h"
 #include "vfs_int.h"
 #include "vfs_ext.h"
+#include <threads.h>
 
 // === CONSTANTS ===
 #define        OPEN_MOUNT_ROOT 1
@@ -15,9 +16,9 @@
 #define MAX_PATH_LEN   255
 
 // === IMPORTS ===
-extern tVFS_Node       gVFS_MemRoot;
 extern tVFS_Mount      *gVFS_RootMount;
 extern int     VFS_AllocHandle(int bIsUser, tVFS_Node *Node, int Mode);
+extern tVFS_Node       *VFS_MemFile_Create(const char *Path);
 
 // === PROTOTYPES ===
  int   VFS_int_CreateHandle( tVFS_Node *Node, tVFS_Mount *Mount, int Mode );
@@ -35,9 +36,9 @@ char *VFS_GetAbsPath(const char *Path)
        char    *tmpStr;
        int             iPos = 0;
        int             iPos2 = 0;
-       const char      *chroot = CFGPTR(CFG_VFS_CHROOT);
+       const char      *chroot = *Threads_GetChroot();
         int    chrootLen;
-       const char      *cwd = CFGPTR(CFG_VFS_CWD);
+       const char      *cwd = *Threads_GetCWD();
         int    cwdLen;
        
        ENTER("sPath", Path);
@@ -176,13 +177,13 @@ tVFS_Node *VFS_ParsePath(const char *Path, char **TruePath, tVFS_Mount **MountPo
        
        ENTER("sPath pTruePath", Path, TruePath);
        
-       // Memory File
-       if(Path[0] == '$') {
+       // HACK: Memory File
+       if(Threads_GetUID() == 0 && Path[0] == '$') {
                if(TruePath) {
                        *TruePath = malloc(strlen(Path)+1);
                        strcpy(*TruePath, Path);
                }
-               curNode = gVFS_MemRoot.FindDir(&gVFS_MemRoot, Path);
+               curNode = VFS_MemFile_Create(Path);
                if(MountPoint) {
                        *MountPoint = NULL;
                }
@@ -268,48 +269,27 @@ restart_parse:
        
                // Check permissions on root of filesystem
                if( !VFS_CheckACL(curNode, VFS_PERM_EXECUTE) ) {
-                       if(curNode->Close)      curNode->Close( curNode );
-                       if(TruePath) {
-                               free(*TruePath);
-                               *TruePath = NULL;
-                       }
                        //Log("Permissions fail on '%s'", Path);
-                       LEAVE('n');
-                       return NULL;
+                       goto _error;
                }
                
                // Check if the node has a FindDir method
-               if( !curNode->FindDir )
+               if( !curNode->Type->FindDir )
                {
-                       if(curNode->Close)      curNode->Close(curNode);
-                       if(TruePath) {
-                               free(*TruePath);
-                               *TruePath = NULL;
-                       }
                        //Log("FindDir fail on '%s'", Path);
-                       LEAVE('n');
-                       return NULL;
+                       goto _error;
                }
-               LOG("FindDir{=%p}(%p, '%s')", curNode->FindDir, curNode, pathEle);
+               LOG("FindDir{=%p}(%p, '%s')", curNode->Type->FindDir, curNode, pathEle);
                // Get Child Node
-               tmpNode = curNode->FindDir(curNode, pathEle);
+               tmpNode = curNode->Type->FindDir(curNode, pathEle);
                LOG("tmpNode = %p", tmpNode);
-               if(curNode->Close) {
-                       //LOG2("curNode->Close = %p", curNode->Close);
-                       curNode->Close(curNode);
-               }
+               _CloseNode( curNode );
                curNode = tmpNode;
                
                // Error Check
                if(!curNode) {
                        LOG("Node '%s' not found in dir '%s'", pathEle, Path);
-                       if(TruePath) {
-                               free(*TruePath);
-                               *TruePath = NULL;
-                       }
-                       //Log("Child fail on '%s' ('%s)", Path, pathEle);
-                       LEAVE('n');
-                       return NULL;
+                       goto _error;
                }
                
                // Handle Symbolic Links
@@ -318,19 +298,15 @@ restart_parse:
                                free(*TruePath);
                                *TruePath = NULL;
                        }
-                       if(!curNode->Read) {
+                       if(!curNode->Type || !curNode->Type->Read) {
                                Log_Warning("VFS", "VFS_ParsePath - Read of symlink node %p'%s' is NULL",
                                        curNode, Path);
-                               if(curNode->Close)      curNode->Close(curNode);
-                               // No need to free *TruePath, it should already be NULL
-                               LEAVE('n');
-                               return NULL;
+                               goto _error;
                        }
                        
                        if(iNestedLinks > MAX_NESTED_LINKS) {
-                               if(curNode->Close)      curNode->Close(curNode);
-                               LEAVE('n');
-                               return NULL;
+                               Log_Notice("VFS", "VFS_ParsePath - Nested link limit exceeded");
+                               goto _error;
                        }
                        
                        // Parse Symlink Path
@@ -339,12 +315,10 @@ restart_parse:
                        {
                                 int    remlen = strlen(Path) - (ofs + nextSlash);
                                if( curNode->Size + remlen > MAX_PATH_LEN ) {
-                                       if(curNode->Close)      curNode->Close(curNode);
                                        Log_Warning("VFS", "VFS_ParsePath - Symlinked path too long");
-                                       LEAVE('n');
-                                       return NULL;
+                                       goto _error;
                                }
-                               curNode->Read( curNode, 0, curNode->Size, path_buffer );
+                               curNode->Type->Read( curNode, 0, curNode->Size, path_buffer );
                                path_buffer[ curNode->Size ] = '\0';
                                LOG("path_buffer = '%s'", path_buffer);
                                strcat(path_buffer, Path + ofs+nextSlash);
@@ -363,9 +337,7 @@ restart_parse:
                if( !(curNode->Flags & VFS_FFLAG_DIRECTORY) )
                {
                        Log_Warning("VFS", "VFS_ParsePath - Path segment is not a directory");
-                       if(TruePath)    free(*TruePath);
-                       LEAVE('n');
-                       return NULL;
+                       goto _error;
                }
                
                // Check if path needs extending
@@ -376,11 +348,7 @@ restart_parse:
                // Check if allocation succeeded
                if(!tmp) {
                        Log_Warning("VFS", "VFS_ParsePath - Unable to reallocate true path buffer");
-                       free(*TruePath);
-                       *TruePath = NULL;
-                       if(curNode->Close)      curNode->Close(curNode);
-                       LEAVE('n');
-                       return NULL;
+                       goto _error;
                }
                *TruePath = tmp;
                // Append to path
@@ -392,32 +360,23 @@ restart_parse:
                // - Extend Path
                retLength += nextSlash + 1;
        }
-       
-       if( !curNode->FindDir ) {
-               if(curNode->Close)      curNode->Close(curNode);
-               if(TruePath) {
-                       free(*TruePath);
-                       *TruePath = NULL;
-               }
+
+       // Check final finddir call     
+       if( !curNode->Type || !curNode->Type->FindDir ) {
                Log_Warning("VFS", "VFS_ParsePath - FindDir doesn't exist for element of '%s'", Path);
-               LEAVE('n');
-               return NULL;
+               goto _error;
        }
        
        // Get last node
        LOG("FindDir(%p, '%s')", curNode, &Path[ofs]);
-       tmpNode = curNode->FindDir(curNode, &Path[ofs]);
+       tmpNode = curNode->Type->FindDir(curNode, &Path[ofs]);
        LOG("tmpNode = %p", tmpNode);
-       if(curNode->Close)      curNode->Close(curNode);
        // Check if file was found
        if(!tmpNode) {
                LOG("Node '%s' not found in dir '%s'", &Path[ofs], Path);
-               //Log("Child fail '%s' ('%s')", Path, &Path[ofs]);
-               if(TruePath)    free(*TruePath);
-               if(curNode->Close)      curNode->Close(curNode);
-               LEAVE('n');
-               return NULL;
+               goto _error;
        }
+       _CloseNode( curNode );
        
        if(TruePath)
        {
@@ -426,10 +385,7 @@ restart_parse:
                // Check if allocation succeeded
                if(!tmp) {
                        Log_Warning("VFS", "VFS_ParsePath -  Unable to reallocate true path buffer");
-                       free(*TruePath);
-                       if(tmpNode->Close)      tmpNode->Close(curNode);
-                       LEAVE('n');
-                       return NULL;
+                       goto _error;
                }
                *TruePath = tmp;
                // Append to path
@@ -445,6 +401,16 @@ restart_parse:
        
        LEAVE('p', tmpNode);
        return tmpNode;
+
+_error:
+       _CloseNode( curNode );
+       
+       if(TruePath && *TruePath) {
+               free(*TruePath);
+               *TruePath = NULL;
+       }
+       LEAVE('n');
+       return NULL;
 }
 
 /**
@@ -465,7 +431,7 @@ int VFS_int_CreateHandle( tVFS_Node *Node, tVFS_Mount *Mount, int Mode )
        
        // Permissions Check
        if( !VFS_CheckACL(Node, i) ) {
-               if(Node->Close) Node->Close( Node );
+               _CloseNode( Node );
                Log_Log("VFS", "VFS_int_CreateHandle: Permissions Failed");
                errno = EACCES;
                LEAVE_RET('i', -1);
@@ -487,13 +453,18 @@ int VFS_int_CreateHandle( tVFS_Node *Node, tVFS_Mount *Mount, int Mode )
  * \fn int VFS_Open(const char *Path, Uint Mode)
  * \brief Open a file
  */
-int VFS_Open(const char *Path, Uint Mode)
+int VFS_Open(const char *Path, Uint Flags)
+{
+       return VFS_OpenEx(Path, Flags, 0);
+}
+
+int VFS_OpenEx(const char *Path, Uint Flags, Uint Mode)
 {
        tVFS_Node       *node;
        tVFS_Mount      *mnt;
        char    *absPath;
        
-       ENTER("sPath xMode", Path, Mode);
+       ENTER("sPath xFlags oMode", Path, Flags);
        
        // Get absolute path
        absPath = VFS_GetAbsPath(Path);
@@ -502,33 +473,46 @@ int VFS_Open(const char *Path, Uint Mode)
                LEAVE_RET('i', -1);
        }
        LOG("absPath = \"%s\"", absPath);
+       
        // Parse path and get mount point
        node = VFS_ParsePath(absPath, NULL, &mnt);
+       
+       // Create file if requested and it doesn't exist
+       if( !node && (Flags & VFS_OPENFLAG_CREATE) )
+       {
+               // TODO: Translate `Mode` into ACL and node flags
+               // Get parent, create node
+               VFS_MkNod(absPath, 0);
+               node = VFS_ParsePath(absPath, NULL, &mnt);
+       }
+       
        // Free generated path
        free(absPath);
        
-       if(!node) {
+       // Check for error
+       if(!node)
+       {
                LOG("Cannot find node");
                errno = ENOENT;
                LEAVE_RET('i', -1);
        }
        
        // Check for symlinks
-       if( !(Mode & VFS_OPENFLAG_NOLINK) && (node->Flags & VFS_FFLAG_SYMLINK) )
+       if( !(Flags & VFS_OPENFLAG_NOLINK) && (node->Flags & VFS_FFLAG_SYMLINK) )
        {
                char    tmppath[node->Size+1];
                if( node->Size > MAX_PATH_LEN ) {
                        Log_Warning("VFS", "VFS_Open - Symlink is too long (%i)", node->Size);
                        LEAVE_RET('i', -1);
                }
-               if( !node->Read ) {
+               if( !node->Type || !node->Type->Read ) {
                        Log_Warning("VFS", "VFS_Open - No read method on symlink");
                        LEAVE_RET('i', -1);
                }
                // Read symlink's path
-               node->Read( node, 0, node->Size, tmppath );
+               node->Type->Read( node, 0, node->Size, tmppath );
                tmppath[ node->Size ] = '\0';
-               if(node->Close) node->Close( node );
+               _CloseNode( node );
                // Open the target
                node = VFS_ParsePath(tmppath, NULL, &mnt);
                if(!node) {
@@ -538,7 +522,7 @@ int VFS_Open(const char *Path, Uint Mode)
                }
        }
 
-       LEAVE_RET('x', VFS_int_CreateHandle(node, mnt, Mode));
+       LEAVE_RET('x', VFS_int_CreateHandle(node, mnt, Flags));
 }
 
 
@@ -562,13 +546,20 @@ int VFS_OpenChild(int FD, const char *Name, Uint Mode)
        
        // Check for directory
        if( !(h->Node->Flags & VFS_FFLAG_DIRECTORY) ) {
-               Log_Warning("VFS", "VFS_OpenChild - Passed handle is not a directory", FD);
+               Log_Warning("VFS", "VFS_OpenChild - Passed handle is not a directory");
+               errno = ENOTDIR;
+               LEAVE_RET('i', -1);
+       }
+
+       // Sanity check
+       if( !h->Node->Type || !h->Node->Type->FindDir ) {
+               Log_Error("VFS", "VFS_OpenChild - Node does not have a type/is missing FindDir");
                errno = ENOTDIR;
                LEAVE_RET('i', -1);
        }
        
        // Find Child
-       node = h->Node->FindDir(h->Node, Name);
+       node = h->Node->Type->FindDir(h->Node, Name);
        if(!node) {
                errno = ENOENT;
                LEAVE_RET('i', -1);
@@ -633,8 +624,7 @@ void VFS_Close(int FD)
        }
        #endif
        
-       if(h->Node->Close)
-               h->Node->Close( h->Node );
+       _CloseNode(h->Node);
        
        h->Node = NULL;
 }
@@ -673,11 +663,13 @@ int VFS_ChDir(const char *Dest)
        // Close file
        VFS_Close(fd);
        
-       // Free old working directory
-       if( CFGPTR(CFG_VFS_CWD) )
-               free( CFGPTR(CFG_VFS_CWD) );
-       // Set new
-       CFGPTR(CFG_VFS_CWD) = buf;
+       {
+               char    **cwdptr = Threads_GetCWD();
+               // Free old working directory
+               if( *cwdptr )   free( *cwdptr );
+               // Set new
+               *cwdptr = buf;
+       }
        
        Log("Updated CWD to '%s'", buf);
        
@@ -721,12 +713,13 @@ int VFS_ChRoot(const char *New)
        
        // Close file
        VFS_Close(fd);
-       
-       // Free old working directory
-       if( CFGPTR(CFG_VFS_CHROOT) )
-               free( CFGPTR(CFG_VFS_CHROOT) );
-       // Set new
-       CFGPTR(CFG_VFS_CHROOT) = buf;
+
+       // Update       
+       {
+               char    **chroot_ptr = Threads_GetChroot();
+               if( *chroot_ptr )       free( *chroot_ptr );
+               *chroot_ptr = buf;
+       }
        
        LOG("Updated Root to '%s'", buf);
        
index ed99492..439afc0 100644 (file)
@@ -4,6 +4,9 @@
  * 
  * select.c
  * - Implements the select() system call (and supporting code)
+ *
+ * TODO: Implment timeouts (via an alarm event?)
+ * TODO: Remove malloc for read/write queues
  */
 #define DEBUG  0
 #include <acess.h>
 #include "vfs_int.h"
 #include "vfs_ext.h"
 #include <semaphore.h>
+#include <threads.h>
+#include <events.h>
 
 // === CONSTANTS ===
 #define        NUM_THREADS_PER_ALLOC   4
 
+// === IMPORTS ===
+extern tThread *Proc_GetCurThread(void);
+
 // === TYPES ===
-typedef struct sVFS_SelectThread       tVFS_SelectThread;
 typedef struct sVFS_SelectListEnt      tVFS_SelectListEnt;
 
 // === STRUCTURES ===
 struct sVFS_SelectListEnt
 {
        tVFS_SelectListEnt      *Next;
-       tVFS_SelectThread       *Threads[NUM_THREADS_PER_ALLOC];
+       tThread *Threads[NUM_THREADS_PER_ALLOC];
 };
 
+// NOTE: Typedef is in vfs.h
 struct sVFS_SelectList
 {
        tMutex  Lock;
        tVFS_SelectListEnt      FirstEnt;
 };
 
-struct sVFS_SelectThread
-{
-       //! \brief Semaphore to atomically put the listener to sleep
-       tSemaphore      SleepHandle;    // TODO: Allow timeouts (by setting an alarm?)
-};
-
 // === PROTOTYPES ===
 // int VFS_SelectNode(tVFS_Node *Node, enum eVFS_SelectTypes Type, tTime *Timeout);
-// int VFS_Select(int MaxHandle, fd_set *ReadHandles, fd_set *WriteHandles, fd_set *ErrHandles, tTime *Timeout, BOOL IsKernel);
+// int VFS_Select(int MaxHandle, fd_set *ReadHandles, fd_set *WriteHandles, fd_set *ErrHandles, tTime *Timeout, Uint32 ExtraEvents, BOOL IsKernel);
 // int VFS_MarkFull(tVFS_Node *Node, BOOL IsBufferFull);
 // int VFS_MarkAvaliable(tVFS_Node *Node, BOOL IsDataAvaliable);
 // int VFS_MarkError(tVFS_Node *Node, BOOL IsErrorState);
  int   VFS_int_Select_GetType(int Type, tVFS_Node *Node, tVFS_SelectList ***List, int **Flag, int *WantedFlag, int *MaxAllowed);
- int   VFS_int_Select_Register(tVFS_SelectThread *Thread, int MaxHandle, fd_set *Handles, int Type, BOOL IsKernel);
- int   VFS_int_Select_Deregister(tVFS_SelectThread *Thread, int MaxHandle, fd_set *Handles, int Type, BOOL IsKernel);
- int   VFS_int_Select_AddThread(tVFS_SelectList *List, tVFS_SelectThread *Thread, int MaxAllowed);
-void   VFS_int_Select_RemThread(tVFS_SelectList *List, tVFS_SelectThread *Thread);
+ int   VFS_int_Select_Register(tThread *Thread, int MaxHandle, fd_set *Handles, int Type, BOOL IsKernel);
+ int   VFS_int_Select_Deregister(tThread *Thread, int MaxHandle, fd_set *Handles, int Type, BOOL IsKernel);
+ int   VFS_int_Select_AddThread(tVFS_SelectList *List, tThread *Thread, int MaxAllowed);
+void   VFS_int_Select_RemThread(tVFS_SelectList *List, tThread *Thread);
 void   VFS_int_Select_SignalAll(tVFS_SelectList *List);
 
 // === GLOBALS ===
@@ -56,15 +58,10 @@ void        VFS_int_Select_SignalAll(tVFS_SelectList *List);
 // === FUNCTIONS ===
 int VFS_SelectNode(tVFS_Node *Node, int TypeFlags, tTime *Timeout, const char *Name)
 {
-       tVFS_SelectThread       *thread_info;
+       tThread *thisthread = Proc_GetCurThread();
         int    ret, type;
        
-       ENTER("pNode iTypeFlags pTimeout", Node, TypeFlags, Timeout);
-       
-       thread_info = malloc(sizeof(tVFS_SelectThread));
-       if(!thread_info)        LEAVE_RET('i', -1);
-
-       Semaphore_Init(&thread_info->SleepHandle, 0, 0, "VFS_SelectNode()", Name);
+       ENTER("pNode iTypeFlags pTimeout sName", Node, TypeFlags, Timeout, Name);
        
        // Initialise
        for( type = 0; type < 3; type ++ )
@@ -73,7 +70,6 @@ int VFS_SelectNode(tVFS_Node *Node, int TypeFlags, tTime *Timeout, const char *N
                 int    *flag, wanted, maxAllowed;
                if( !(TypeFlags & (1 << type)) )        continue;
                if( VFS_int_Select_GetType(type, Node, &list, &flag, &wanted, &maxAllowed) ) {
-                       free(thread_info);
                        LEAVE('i', -1);
                        return -1;
                }
@@ -81,11 +77,10 @@ int VFS_SelectNode(tVFS_Node *Node, int TypeFlags, tTime *Timeout, const char *N
                // Alloc if needed
                if( !*list )    *list = calloc(1, sizeof(tVFS_SelectList));
        
-               VFS_int_Select_AddThread(*list, thread_info, maxAllowed);
+               VFS_int_Select_AddThread(*list, thisthread, maxAllowed);
                if( *flag == wanted )
                {
-                       VFS_int_Select_RemThread(*list, thread_info);
-                       free(thread_info);
+                       VFS_int_Select_RemThread(*list, thisthread);
                        LEAVE('i', 1);
                        return 1;
                }
@@ -99,7 +94,7 @@ int VFS_SelectNode(tVFS_Node *Node, int TypeFlags, tTime *Timeout, const char *N
        {
                LOG("Semaphore_Wait()");
                // TODO: Actual timeout
-               Semaphore_Wait(&thread_info->SleepHandle, 1);
+               Threads_WaitEvents( THREAD_EVENT_VFS );
        }
        
        // Get return value
@@ -111,30 +106,23 @@ int VFS_SelectNode(tVFS_Node *Node, int TypeFlags, tTime *Timeout, const char *N
                if( !(TypeFlags & (1 << type)) )        continue;
                VFS_int_Select_GetType(type, Node, &list, &flag, &wanted, &maxAllowed);
                LOG("VFS_int_Select_RemThread()");
-               VFS_int_Select_RemThread(*list, thread_info);
+               VFS_int_Select_RemThread(*list, thisthread);
                ret = ret || *flag == wanted;
        }
        
-       free(thread_info);
-       
        LEAVE('i', ret);
        return ret;
 }
 
-int VFS_Select(int MaxHandle, fd_set *ReadHandles, fd_set *WriteHandles, fd_set *ErrHandles, tTime *Timeout, BOOL IsKernel)
+int VFS_Select(int MaxHandle, fd_set *ReadHandles, fd_set *WriteHandles, fd_set *ErrHandles, tTime *Timeout, Uint32 ExtraEvents, BOOL IsKernel)
 {
-       tVFS_SelectThread       *thread_info;
+       tThread *thisthread = Proc_GetCurThread();
         int    ret;
        
-       thread_info = malloc(sizeof(tVFS_SelectThread));
-       if(!thread_info)        return -1;
-       
        ENTER("iMaxHandle pReadHandles pWriteHandles pErrHandles pTimeout bIsKernel",
                MaxHandle, ReadHandles, WriteHandles, ErrHandles, Timeout, IsKernel);
        
-       Semaphore_Init(&thread_info->SleepHandle, 0, 0, "VFS_Select()", "");
-       
-       // Notes: The idea is to make sure we only enter wait (on the semaphore)
+       // Notes: The idea is to make sure we only enter wait (Threads_WaitEvents)
        // if we are going to be woken up (either by an event at a later time,
        // or by an event that happened while or before we were registering).
        // Hence, register must happen _before_ we check the state flag
@@ -142,19 +130,18 @@ int VFS_Select(int MaxHandle, fd_set *ReadHandles, fd_set *WriteHandles, fd_set
        // or the semaphore is incremeneted (or both, but never none)
        
        // Register with nodes
-       ret  = VFS_int_Select_Register(thread_info, MaxHandle, ReadHandles, 0, IsKernel);
-       ret += VFS_int_Select_Register(thread_info, MaxHandle, WriteHandles, 1, IsKernel);
-       ret += VFS_int_Select_Register(thread_info, MaxHandle, ErrHandles, 2, IsKernel);
+       ret  = VFS_int_Select_Register(thisthread, MaxHandle, ReadHandles, 0, IsKernel);
+       ret += VFS_int_Select_Register(thisthread, MaxHandle, WriteHandles, 1, IsKernel);
+       ret += VFS_int_Select_Register(thisthread, MaxHandle, ErrHandles, 2, IsKernel);
        
        LOG("Register ret = %i", ret);
        
        // If there were events waiting, de-register and return
        if( ret > 0 )
        {
-               ret  = VFS_int_Select_Deregister(thread_info, MaxHandle, ReadHandles, 0, IsKernel);
-               ret += VFS_int_Select_Deregister(thread_info, MaxHandle, WriteHandles, 1, IsKernel);
-               ret += VFS_int_Select_Deregister(thread_info, MaxHandle, ErrHandles, 2, IsKernel);
-               free(thread_info);
+               ret  = VFS_int_Select_Deregister(thisthread, MaxHandle, ReadHandles, 0, IsKernel);
+               ret += VFS_int_Select_Deregister(thisthread, MaxHandle, WriteHandles, 1, IsKernel);
+               ret += VFS_int_Select_Deregister(thisthread, MaxHandle, ErrHandles, 2, IsKernel);
                LEAVE('i', ret);
                return ret;
        }
@@ -165,16 +152,16 @@ int VFS_Select(int MaxHandle, fd_set *ReadHandles, fd_set *WriteHandles, fd_set
        // Wait (only if there is no timeout, or it is greater than zero
        if( !Timeout || *Timeout > 0 )
        {
-               ret = Semaphore_Wait(&thread_info->SleepHandle, 1);
-               // TODO: Do something with ret?
+               // TODO: Timeout
+               // TODO: Allow extra events to be waited upon
+               Threads_WaitEvents( THREAD_EVENT_VFS|ExtraEvents );
        }
        
        // Fill output (modify *Handles)
        // - Also, de-register
-       ret  = VFS_int_Select_Deregister(thread_info, MaxHandle, ReadHandles, 0, IsKernel);
-       ret += VFS_int_Select_Deregister(thread_info, MaxHandle, WriteHandles, 1, IsKernel);
-       ret += VFS_int_Select_Deregister(thread_info, MaxHandle, ErrHandles, 2, IsKernel);
-       free(thread_info);
+       ret  = VFS_int_Select_Deregister(thisthread, MaxHandle, ReadHandles, 0, IsKernel);
+       ret += VFS_int_Select_Deregister(thisthread, MaxHandle, WriteHandles, 1, IsKernel);
+       ret += VFS_int_Select_Deregister(thisthread, MaxHandle, ErrHandles, 2, IsKernel);
        LEAVE('i', ret);
        return ret;
 }
@@ -193,7 +180,7 @@ int VFS_MarkAvaliable(tVFS_Node *Node, BOOL IsDataAvaliable)
 // Mark a node as having a full buffer
 int VFS_MarkFull(tVFS_Node *Node, BOOL IsBufferFull)
 {
-       ENTER("pNode bIsDataAvaliable", Node, IsBufferFull);
+       ENTER("pNode bIsBufferFull", Node, IsBufferFull);
        Node->BufferFull = !!IsBufferFull;
        if( !Node->BufferFull )
                VFS_int_Select_SignalAll(Node->WriteThreads);
@@ -204,7 +191,7 @@ int VFS_MarkFull(tVFS_Node *Node, BOOL IsBufferFull)
 // Mark a node as errored
 int VFS_MarkError(tVFS_Node *Node, BOOL IsErrorState)
 {
-       ENTER("pNode bIsDataAvaliable", Node, IsErrorState);
+       ENTER("pNode bIsErrorState", Node, IsErrorState);
        Node->ErrorOccurred = !!IsErrorState;
        if( Node->ErrorOccurred )
                VFS_int_Select_SignalAll(Node->ErrorThreads);
@@ -246,7 +233,7 @@ int VFS_int_Select_GetType(int Type, tVFS_Node *Node, tVFS_SelectList ***List, i
 /**
  * \return Number of files with an action
  */
-int VFS_int_Select_Register(tVFS_SelectThread *Thread, int MaxHandle, fd_set *Handles, int Type, BOOL IsKernel)
+int VFS_int_Select_Register(tThread *Thread, int MaxHandle, fd_set *Handles, int Type, BOOL IsKernel)
 {
         int    i, numFlagged = 0;
        tVFS_SelectList **list;
@@ -308,7 +295,7 @@ int VFS_int_Select_Register(tVFS_SelectThread *Thread, int MaxHandle, fd_set *Ha
 /**
  * \return Number of files with an action
  */
-int VFS_int_Select_Deregister(tVFS_SelectThread *Thread, int MaxHandle, fd_set *Handles, int Type, BOOL IsKernel)
+int VFS_int_Select_Deregister(tThread *Thread, int MaxHandle, fd_set *Handles, int Type, BOOL IsKernel)
 {
         int    i, numFlagged = 0;
        tVFS_SelectList **list;
@@ -367,7 +354,7 @@ int VFS_int_Select_Deregister(tVFS_SelectThread *Thread, int MaxHandle, fd_set *
 /**
  * \return Boolean failure
  */
-int VFS_int_Select_AddThread(tVFS_SelectList *List, tVFS_SelectThread *Thread, int MaxAllowed)
+int VFS_int_Select_AddThread(tVFS_SelectList *List, tThread *Thread, int MaxAllowed)
 {
         int    i, count = 0;
        tVFS_SelectListEnt      *block, *prev;
@@ -428,7 +415,7 @@ int VFS_int_Select_AddThread(tVFS_SelectList *List, tVFS_SelectThread *Thread, i
        return 0;
 }
 
-void VFS_int_Select_RemThread(tVFS_SelectList *List, tVFS_SelectThread *Thread)
+void VFS_int_Select_RemThread(tVFS_SelectList *List, tThread *Thread)
 {
         int    i;
        tVFS_SelectListEnt      *block, *prev = NULL;
@@ -507,7 +494,7 @@ void VFS_int_Select_SignalAll(tVFS_SelectList *List)
                        if( block->Threads[i]  )
                        {
                                LOG("block(%p)->Threads[%i] = %p", block, i, block->Threads[i]);
-                               Semaphore_Signal( &block->Threads[i]->SleepHandle, 1 );
+                               Threads_PostEvent( block->Threads[i], THREAD_EVENT_VFS );
                        }
                }
                
index dea5cf2..e3d7532 100755 (executable)
@@ -5,8 +5,19 @@ if [ $# -ge 1 ]; then
 else
        ARCH=x86
 fi
+
+if [ $# -ge 2 ]; then
+       PLATFORM=$2
+else
+       PLATFORM=default
+fi
+
 mkdir -p Releases/
 BUILD_DIST=y ARCH=$ARCH make clean all-install
+while [ $# -ge 2 ]; do
+       BUILD_DIST=y ARCH=$ARCH PLATFORM=$2 make
+       shift
+done
 tar --transform="s|Dist/($ARCH/)*|Acess/|x" -zcf Releases/Acess2_latest_${ARCH}_bin.tar.gz Dist/$ARCH Dist/Acess2.$ARCH.gz
 mdeltree b:/Acess2 2>&1 >/dev/null || true
 mcopy -s Dist/$ARCH/ b:/Acess2
index d343708..4597d87 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -15,7 +15,7 @@ USRLIBS += libreadline.so libnet.so liburi.so
 USRLIBS += libimage_sif.so
 
 USRAPPS := init login CLIShell cat ls mount
-USRAPPS += bomb
+USRAPPS += bomb dhcpclient
 USRAPPS += ifconfig ping telnet irc
 USRAPPS += axwin3
 
index 292934a..e229893 100644 (file)
@@ -1,7 +1,7 @@
 
-ACESS_VERSION = 0.14
+ACESS_VERSION = 0.15
 
-ifeq ($(BUILD_DIST),y)
-       ACESS_VERSION := $(ACESS_VERSION)-rel
+ifneq ($(BUILD_DIST),y)
+       ACESS_VERSION := $(ACESS_VERSION)-pr
 endif
 
index 58a024f..806c1c1 100644 (file)
@@ -64,19 +64,20 @@ void        BGA_int_SetMode(Uint16 width, Uint16 height);
  int   BGA_int_MapFB(void *Dest);\r
 // Filesystem\r
 Uint64 BGA_Read(tVFS_Node *Node, Uint64 off, Uint64 len, void *buffer);\r
-Uint64 BGA_Write(tVFS_Node *Node, Uint64 off, Uint64 len, void *buffer);\r
+Uint64 BGA_Write(tVFS_Node *Node, Uint64 off, Uint64 len, const void *buffer);\r
  int   BGA_IOCtl(tVFS_Node *Node, int ID, void *Data);\r
 \r
 // === GLOBALS ===\r
 MODULE_DEFINE(0, VERSION, BochsGA, BGA_Install, NULL, "PCI", NULL);\r
-tDevFS_Driver  gBGA_DriverStruct = {\r
-       NULL, "BochsGA",\r
-       {\r
+tVFS_NodeType  gBGA_NodeType = {\r
        .Read = BGA_Read,\r
        .Write = BGA_Write,\r
        .IOCtl = BGA_IOCtl\r
-       }\r
-};\r
+       };\r
+tDevFS_Driver  gBGA_DriverStruct = {\r
+       NULL, "BochsGA",\r
+       {.Type = &gBGA_NodeType}\r
+       };\r
  int   giBGA_CurrentMode = -1;\r
 tVideo_IOCtl_Pos       gBGA_CursorPos = {-1,-1};\r
 Uint   *gBGA_Framebuffer;\r
@@ -160,7 +161,7 @@ Uint64 BGA_Read(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer)
 /**\r
  * \brief Write to the framebuffer\r
  */\r
-Uint64 BGA_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)\r
+Uint64 BGA_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)\r
 {\r
        if( giBGA_CurrentMode == -1 )   BGA_int_UpdateMode(0);\r
        return DrvUtil_Video_WriteLFB(&gBGA_DrvUtil_BufInfo, Offset, Length, Buffer);\r
index 4d7b938..c3b6e52 100644 (file)
@@ -65,20 +65,21 @@ void        PL110_Uninstall();
 // Internal\r
 // Filesystem\r
 Uint64 PL110_Read(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer);\r
-Uint64 PL110_Write(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer);\r
+Uint64 PL110_Write(tVFS_Node *node, Uint64 off, Uint64 len, const void *buffer);\r
  int   PL110_IOCtl(tVFS_Node *node, int id, void *data);\r
 // -- Internals\r
  int   PL110_int_SetResolution(int W, int H);\r
 \r
 // === GLOBALS ===\r
 MODULE_DEFINE(0, VERSION, PL110, PL110_Install, NULL, NULL);\r
-tDevFS_Driver  gPL110_DriverStruct = {\r
-       NULL, "PL110",\r
-       {\r
+tVFS_NodeType  gPL110_DevNodeType = {\r
        .Read = PL110_Read,\r
        .Write = PL110_Write,\r
        .IOCtl = PL110_IOCtl\r
-       }\r
+       };\r
+tDevFS_Driver  gPL110_DriverStruct = {\r
+       NULL, "PL110",\r
+       {.Type = &gPL110_DevNodeType}\r
 };\r
 // -- Options\r
 tPAddr gPL110_PhysBase = PL110_BASE;\r
@@ -139,7 +140,7 @@ Uint64 PL110_Read(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer)
 /**\r
  * \brief Write to the framebuffer\r
  */\r
-Uint64 PL110_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)\r
+Uint64 PL110_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)\r
 {\r
        gPL110_DrvUtil_BufInfo.BufferFormat = giPL110_BufferMode;\r
        return DrvUtil_Video_WriteLFB(&gPL110_DrvUtil_BufInfo, Offset, Length, Buffer);\r
index 55083b0..a85d313 100644 (file)
@@ -24,7 +24,7 @@
 // === PROTOTYPES ===\r
  int   Vesa_Install(char **Arguments);\r
 Uint64 Vesa_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);\r
-Uint64 Vesa_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);\r
+Uint64 Vesa_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer);\r
  int   Vesa_IOCtl(tVFS_Node *Node, int ID, void *Data);\r
  int   Vesa_Int_SetMode(int Mode);\r
  int   Vesa_Int_FindMode(tVideo_IOCtl_Mode *data);\r
@@ -35,14 +35,15 @@ void        Vesa_FlipCursor(void *Arg);
 \r
 // === GLOBALS ===\r
 MODULE_DEFINE(0, VERSION, Vesa, Vesa_Install, NULL, "PCI", "VM8086", NULL);\r
-tDevFS_Driver  gVesa_DriverStruct = {\r
-       NULL, "Vesa",\r
-       {\r
+tVFS_NodeType  gVesa_NodeType = {\r
        .Read = Vesa_Read,\r
        .Write = Vesa_Write,\r
        .IOCtl = Vesa_IOCtl\r
-       }\r
-};\r
+       };\r
+tDevFS_Driver  gVesa_DriverStruct = {\r
+       NULL, "Vesa",\r
+       {.Type = &gVesa_NodeType}\r
+       };\r
 tMutex glVesa_Lock;\r
 tVM8086        *gpVesa_BiosState;\r
  int   giVesaDriverId = -1;\r
@@ -178,7 +179,7 @@ Uint64 Vesa_Read(tVFS_Node *Node, Uint64 off, Uint64 len, void *buffer)
 /**\r
  * \brief Write to the framebuffer\r
  */\r
-Uint64 Vesa_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)\r
+Uint64 Vesa_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)\r
 {\r
        if( gVesa_Modes[giVesaCurrentMode].framebuffer == 0 ) {\r
                Log_Warning("VESA", "Vesa_Write - Non-LFB Modes not yet supported.");\r
index c7d8dd8..5eb476f 100644 (file)
@@ -23,6 +23,23 @@ tVFS_Node    *Ext2_FindDir(tVFS_Node *Node, const char *FileName);
 // --- Helpers ---
 tVFS_Node      *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeId);
 
+// === GLOBALS ===
+tVFS_NodeType  gExt2_DirType = {
+       .TypeName = "ext2-dir",
+       .ReadDir = Ext2_ReadDir,
+       .FindDir = Ext2_FindDir,
+       .MkNod = Ext2_MkNod,
+       .Relink = Ext2_Relink,
+       .Link = Ext2_Link,
+       .Close = Ext2_CloseFile
+       };
+tVFS_NodeType  gExt2_FileType = {
+       .TypeName = "ext2-file",
+       .Read = Ext2_Read,
+       .Write = Ext2_Write,
+       .Close = Ext2_CloseFile
+       };
+
 // === CODE ===
 /**
  * \brief Reads a directory entry
@@ -345,9 +362,7 @@ tVFS_Node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeID)
        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;
+       retNode.Type = &gExt2_FileType;
        
        switch(inode.i_mode & EXT2_S_IFMT)
        {
@@ -362,11 +377,7 @@ tVFS_Node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeID)
                break;
        // Directory
        case EXT2_S_IFDIR:
-               retNode.ReadDir = Ext2_ReadDir;
-               retNode.FindDir = Ext2_FindDir;
-               retNode.MkNod = Ext2_MkNod;
-               retNode.Relink = Ext2_Relink;
-               retNode.Link = Ext2_Link;
+               retNode.Type = &gExt2_DirType;
                retNode.Flags = VFS_FFLAG_DIRECTORY;
                retNode.Data = calloc( sizeof(Uint16), DivUp(retNode.Size, Disk->BlockSize) );
                break;
index ad96cc8..7c4bf97 100644 (file)
@@ -12,6 +12,9 @@
 #include "ext2_common.h"\r
 #include <modules.h>\r
 \r
+// === IMPORTS ===\r
+extern tVFS_NodeType   gExt2_DirType;\r
+\r
 // === PROTOTYPES ===\r
  int   Ext2_Install(char **Arguments);\r
 // Interface Functions\r
@@ -130,10 +133,8 @@ tVFS_Node *Ext2_InitDevice(const char *Device, const char **Options)
        disk->RootNode.ImplPtr = disk;  // Save disk pointer\r
        disk->RootNode.Size = -1;       // Fill in later (on readdir)\r
        disk->RootNode.Flags = VFS_FFLAG_DIRECTORY;\r
-       \r
-       disk->RootNode.ReadDir = Ext2_ReadDir;\r
-       disk->RootNode.FindDir = Ext2_FindDir;\r
-       //disk->RootNode.Relink = Ext2_Relink;\r
+\r
+       disk->RootNode.Type = &gExt2_DirType;\r
        \r
        // Complete root node\r
        disk->RootNode.UID = inode.i_uid;\r
index be4ae39..6ef9d7c 100644 (file)
@@ -42,6 +42,6 @@ extern int    Ext2_Link(tVFS_Node *Parent, tVFS_Node *Node, const char *Name);
 // --- Read ---
 extern Uint64  Ext2_Read(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer);
 // --- Write ---
-extern Uint64  Ext2_Write(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer);
+extern Uint64  Ext2_Write(tVFS_Node *node, Uint64 offset, Uint64 length, const void *buffer);
 
 #endif
index 5a7cfc0..03109e8 100644 (file)
@@ -12,7 +12,6 @@
 #include "ext2_common.h"
 
 // === PROTOYPES ===
-Uint64         Ext2_Write(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer);
 Uint32         Ext2_int_AllocateBlock(tExt2_Disk *Disk, Uint32 PrevBlock);
 void   Ext2_int_DeallocateBlock(tExt2_Disk *Disk, Uint32 Block);
  int   Ext2_int_AppendBlock(tExt2_Disk *Disk, tExt2_Inode *Inode, Uint32 Block);
@@ -22,7 +21,7 @@ void  Ext2_int_DeallocateBlock(tExt2_Disk *Disk, Uint32 Block);
  * \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)
+Uint64 Ext2_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
 {
        tExt2_Disk      *disk = Node->ImplPtr;
        tExt2_Inode     inode;
index af73322..f5d1916 100644 (file)
@@ -90,6 +90,24 @@ MODULE_DEFINE(0, (0<<8)|50 /*v0.50*/, VFAT, FAT_Install, NULL, NULL);
 tFAT_VolInfo   gFAT_Disks[8];\r
  int   giFAT_PartCount = 0;\r
 tVFS_Driver    gFAT_FSInfo = {"fat", 0, FAT_InitDevice, FAT_Unmount, FAT_GetNodeFromINode, NULL};\r
+tVFS_NodeType  gFAT_DirType = {\r
+       .TypeName = "FAT-Dir",\r
+       .ReadDir = FAT_ReadDir,\r
+       .FindDir = FAT_FindDir,\r
+       #if SUPPORT_WRITE\r
+       .MkNod = FAT_Mknod,\r
+       .Relink = FAT_Relink,\r
+       #endif\r
+       .Close = FAT_CloseFile\r
+       };\r
+tVFS_NodeType  gFAT_FileType = {\r
+       .TypeName = "FAT-File",\r
+       .Read = FAT_Read,\r
+       #if SUPPORT_WRITE\r
+       .Write = FAT_Write,\r
+       #endif\r
+       .Close = FAT_CloseFile\r
+       };\r
 \r
 // === CODE ===\r
 /**\r
@@ -273,18 +291,8 @@ tVFS_Node *FAT_InitDevice(const char *Device, const char **Options)
        node->ACLs = &gVFS_ACL_EveryoneRWX;\r
        node->Flags = VFS_FFLAG_DIRECTORY;\r
        node->CTime = node->MTime = node->ATime = now();\r
-       \r
-       node->Read = node->Write = NULL;\r
-       node->ReadDir = FAT_ReadDir;\r
-       node->FindDir = FAT_FindDir;\r
-       #if SUPPORT_WRITE\r
-       node->Relink = FAT_Relink;\r
-       node->MkNod = FAT_Mknod;\r
-       #else\r
-       node->Relink = NULL;\r
-       node->MkNod = NULL;\r
-       #endif\r
-       //node->Close = FAT_Unmount;\r
+\r
+       node->Type = &gFAT_DirType;     \r
        \r
        giFAT_PartCount ++;\r
        return node;\r
@@ -977,21 +985,12 @@ tVFS_Node *FAT_int_CreateNode(tVFS_Node *Parent, fat_filetable *Entry, int Pos)
        // Set pointers\r
        if(node.Flags & VFS_FFLAG_DIRECTORY) {\r
                //Log_Debug("FAT", "Directory %08x has size 0x%x", node.Inode, node.Size);\r
-               node.ReadDir = FAT_ReadDir;\r
-               node.FindDir = FAT_FindDir;\r
-               #if SUPPORT_WRITE\r
-               node.MkNod = FAT_Mknod;\r
-               node.Relink = FAT_Relink;\r
-               #endif\r
+               node.Type = &gFAT_DirType;      \r
                node.Size = -1;\r
        }\r
        else {\r
-               node.Read = FAT_Read;\r
-               #if SUPPORT_WRITE\r
-               node.Write = FAT_Write;\r
-               #endif\r
+               node.Type = &gFAT_FileType;\r
        }\r
-       node.Close = FAT_CloseFile;\r
        \r
        ret = Inode_CacheNode(disk->inodeHandle, &node);\r
        LEAVE('p', ret);\r
index af967d5..e7cd4f7 100644 (file)
@@ -98,8 +98,7 @@ tVFS_Node {$prefix}_{$i} = {
        .Size = $size,
        .Inode = {$inode},
        .ImplPtr = {$prefix}_{$i}_entries,
-       .ReadDir = InitRD_ReadDir,
-       .FindDir = InitRD_FindDir
+       .Type = &gInitRD_DirType
 };
 
 EOF;
@@ -161,7 +160,7 @@ tVFS_Node {$prefix}_{$i} = {
        .Size = $size,
        .Inode = {$inode},
        .ImplPtr = $_sym,
-       .Read = InitRD_ReadFile
+       .Type = &gInitRD_FileType
 };
 
 EOF;
@@ -189,8 +188,7 @@ tVFS_Node gInitRD_RootNode = {
        .Flags = VFS_FFLAG_DIRECTORY,
        .Size = $nRootFiles,
        .ImplPtr = gInitRD_Root_Files,
-       .ReadDir = InitRD_ReadDir,
-       .FindDir = InitRD_FindDir
+       .Type = &gInitRD_DirType
 };
 EOF;
 
index 8ebabd3..479a841 100644 (file)
@@ -18,4 +18,8 @@ extern Uint64 InitRD_ReadFile(tVFS_Node *Node, Uint64 Offset, Uint64 Size, void
 extern char    *InitRD_ReadDir(tVFS_Node *Node, int ID);
 extern tVFS_Node       *InitRD_FindDir(tVFS_Node *Node, const char *Name);
 
+// === Globals ===
+tVFS_NodeType  gInitRD_DirType;
+tVFS_NodeType  gInitRD_FileType;
+
 #endif
index b2ed2b3..b52ab8d 100644 (file)
@@ -27,6 +27,13 @@ MODULE_DEFINE(0, 0x0A, FS_InitRD, InitRD_Install, NULL);
 tVFS_Driver    gInitRD_FSInfo = {
        "initrd", 0, InitRD_InitDevice, InitRD_Unmount, InitRD_GetNodeFromINode
        };
+tVFS_NodeType  gInitRD_DirType = {
+       .ReadDir = InitRD_ReadFile,
+       .FindDir = InitRD_FindDir
+       };
+tVFS_NodeType  gInitRD_FileType = {
+       .Read = InitRD_ReadFile
+       };
 
 /**
  * \brief Register initrd with the kernel
index f5f99c7..dbda06e 100644 (file)
@@ -24,6 +24,12 @@ void NTFS_DumpEntry(tNTFS_Disk *Disk, Uint32 Entry);
 // === GLOBALS ===
 MODULE_DEFINE(0, 0x0A /*v0.1*/, FS_NTFS, NTFS_Install, NULL);
 tVFS_Driver    gNTFS_FSInfo = {"ntfs", 0, NTFS_InitDevice, NTFS_Unmount, NULL};
+tVFS_NodeType  gNTFS_DirType = {
+       .TypeName = "NTFS-File",
+       .ReadDir = NTFS_ReadDir,
+       .FindDir = NTFS_FindDir,
+       .Close = NULL
+       };
 
 tNTFS_Disk     gNTFS_Disks;
 
@@ -99,12 +105,8 @@ tVFS_Node *NTFS_InitDevice(const char *Device, const char **Options)
        disk->RootNode.NumACLs = 1;
        disk->RootNode.ACLs = &gVFS_ACL_EveryoneRX;
        
-       disk->RootNode.ReadDir = NTFS_ReadDir;
-       disk->RootNode.FindDir = NTFS_FindDir;
-       disk->RootNode.MkNod = NULL;
-       disk->RootNode.Link = NULL;
-       disk->RootNode.Relink = NULL;
-       disk->RootNode.Close = NULL;
+       disk->RootNode.Type = &gNTFS_DirType;
+
        
        NTFS_DumpEntry(disk, 5);
        
index e0912ad..abaea27 100644 (file)
@@ -77,6 +77,14 @@ tMacAddr ARP_Resolve4(tInterface *Interface, tIPv4 Address)
        
        ENTER("pInterface xAddress", Interface, Address);
        
+       // Check for broadcast
+       if( Address.L == -1 )
+       {
+               LOG("Broadcast");
+               LEAVE('-');
+               return cMAC_BROADCAST;
+       }
+
        // Check routing tables if not on this subnet
        if( IPStack_CompareAddress(4, &Address, Interface->Address, Interface->SubnetBits) == 0 )
        {
@@ -86,8 +94,23 @@ tMacAddr ARP_Resolve4(tInterface *Interface, tIPv4 Address)
                if( route && ((tIPv4*)route->NextHop)->L != 0 )
                {
                        // Recursion: see /Recursion/
+                       LOG("Recursing with %s", IPStack_PrintAddress(4, route->NextHop));
+                       LEAVE('-');
                        return ARP_Resolve4(Interface, *(tIPv4*)route->NextHop);
                }
+               // No route, fall though
+       }
+       else
+       {
+               Uint32  netmask;
+               // Check for broadcast
+               netmask = IPv4_Netmask(Interface->SubnetBits);
+               if( (Address.L & ~netmask) == (0xFFFFFFFF & ~netmask) )
+               {
+                       LOG("Local Broadcast");
+                       LEAVE('-');
+                       return cMAC_BROADCAST;
+               }
        }
        
        // Check ARP Cache
index 82d1b8c..b0b63b9 100644 (file)
@@ -32,6 +32,11 @@ tVFS_Node    *IPStack_Iface_FindDir(tVFS_Node *Node, const char *Name);
  int   IPStack_Iface_IOCtl(tVFS_Node *Node, int ID, void *Data);
 
 // === GLOBALS ===
+tVFS_NodeType  gIP_InterfaceNodeType = {
+               .ReadDir = IPStack_Iface_ReadDir,
+               .FindDir = IPStack_Iface_FindDir,
+               .IOCtl = IPStack_Iface_IOCtl
+};
 //! Loopback (127.0.0.0/8, ::1) Pseudo-Interface
 tInterface     gIP_LoopInterface = {
        .Node = {
@@ -40,9 +45,7 @@ tInterface    gIP_LoopInterface = {
                .Size = -1,
                .NumACLs = 1,
                .ACLs = &gVFS_ACL_EveryoneRX,
-               .ReadDir = IPStack_Iface_ReadDir,
-               .FindDir = IPStack_Iface_FindDir,
-               .IOCtl = IPStack_Iface_IOCtl
+               .Type = &gIP_InterfaceNodeType
        },
        .Adapter = NULL,
        .Type = 0
@@ -75,10 +78,12 @@ char *IPStack_Root_ReadDir(tVFS_Node *Node, int Pos)
 
        // Routing Subdir
        if( Pos == 0 ) {
+               LEAVE('s', "routes");
                return strdup("routes");
        }
        // Pseudo Interfaces
        if( Pos == 1 ) {
+               LEAVE('s', "lo");
                return strdup("lo");
        }
        Pos -= 2;
@@ -136,11 +141,13 @@ tVFS_Node *IPStack_Root_FindDir(tVFS_Node *Node, const char *Name)
        
        // Routing subdir
        if( strcmp(Name, "routes") == 0 ) {
+               LEAVE('p', &gIP_RouteNode);
                return &gIP_RouteNode;
        }
        
        // Loopback
        if( strcmp(Name, "lo") == 0 ) {
+               LEAVE('p', &gIP_LoopInterface.Node);
                return &gIP_LoopInterface.Node;
        }
        
@@ -178,6 +185,7 @@ int IPStack_Root_IOCtl(tVFS_Node *Node, int ID, void *Data)
        case 4:
                if( Threads_GetUID() != 0 )     LEAVE_RET('i', -1);
                if( !CheckString( Data ) )      LEAVE_RET('i', -1);
+               LOG("New interface for '%s'", Data);
                {
                        char    name[4] = "";
                        tInterface      *iface = IPStack_AddInterface(Data, name);
@@ -234,13 +242,7 @@ tInterface *IPStack_AddInterface(const char *Device, const char *Name)
        iface->Node.Size = -1;
        iface->Node.NumACLs = 1;
        iface->Node.ACLs = &gVFS_ACL_EveryoneRX;
-       iface->Node.ReadDir = IPStack_Iface_ReadDir;
-       iface->Node.FindDir = IPStack_Iface_FindDir;
-       iface->Node.IOCtl = IPStack_Iface_IOCtl;
-       iface->Node.MkNod = NULL;
-       iface->Node.Link = NULL;
-       iface->Node.Relink = NULL;
-       iface->Node.Close = NULL;
+       iface->Node.Type = &gIP_InterfaceNodeType;
        
        // Set Defaults
        iface->TimeoutDelay = DEFAULT_TIMEOUT;
@@ -367,6 +369,7 @@ int IPStack_Iface_IOCtl(tVFS_Node *Node, int ID, void *Data)
                        
                        // Set type
                        iface->Type = *(int*)Data;
+                       LOG("Interface type set to %i", iface->Type);
                        size = IPStack_GetAddressSize(iface->Type);
                        // Check it's actually valid
                        if( iface->Type != 0 && size == 0 ) {
@@ -402,9 +405,9 @@ int IPStack_Iface_IOCtl(tVFS_Node *Node, int ID, void *Data)
                size = IPStack_GetAddressSize(iface->Type);
                if( !CheckMem( Data, size ) )   LEAVE_RET('i', -1);
                // TODO: Protect against trashing
+               LOG("Interface address set to '%s'", IPStack_PrintAddress(iface->Type, Data));
                memcpy( iface->Address, Data, size );
-               LEAVE('i', 1);
-               return 1;
+               LEAVE_RET('i', 1);
        
        /*
         * getset_subnet
@@ -422,12 +425,11 @@ int IPStack_Iface_IOCtl(tVFS_Node *Node, int ID, void *Data)
                        // Is the mask sane?
                        if( *(int*)Data < 0 || *(int*)Data > IPStack_GetAddressSize(iface->Type)*8-1 )
                                LEAVE_RET('i', -1);
-                       
+                       LOG("Set subnet bits to %i", *(int*)Data);
                        // Ok, set it
                        iface->SubnetBits = *(int*)Data;
                }
-               LEAVE('i', iface->SubnetBits);
-               return iface->SubnetBits;
+               LEAVE_RET('i', iface->SubnetBits);
        
        /*
         * get_device
@@ -441,7 +443,7 @@ int IPStack_Iface_IOCtl(tVFS_Node *Node, int ID, void *Data)
                if( !CheckMem( Data, iface->Adapter->DeviceLen+1 ) )
                        LEAVE_RET('i', -1);
                strcpy( Data, iface->Adapter->Device );
-               return iface->Adapter->DeviceLen;
+               LEAVE_RET('i', iface->Adapter->DeviceLen);
        
        /*
         * ping
@@ -456,8 +458,7 @@ int IPStack_Iface_IOCtl(tVFS_Node *Node, int ID, void *Data)
                case 4:
                        if( !CheckMem( Data, sizeof(tIPv4) ) )  LEAVE_RET('i', -1);
                        tmp = IPv4_Ping(iface, *(tIPv4*)Data);
-                       LEAVE('i', tmp);
-                       return tmp;
+                       LEAVE_RET('i', tmp);
                        
                case 6:
                        LEAVE_RET('i', 1);
index d16cc97..86301e9 100644 (file)
@@ -2,6 +2,7 @@
  * Acess2 IP Stack
  * - IPv4 Protcol Handling
  */
+#define DEBUG  1
 #include "ipstack.h"
 #include "link.h"
 #include "ipv4.h"
@@ -63,12 +64,13 @@ int IPv4_RegisterCallback(int ID, tIPCallback Callback)
  */
 int IPv4_SendPacket(tInterface *Iface, tIPv4 Address, int Protocol, int ID, int Length, const void *Data)
 {
-       tMacAddr        to = ARP_Resolve4(Iface, Address);
+       tMacAddr        to;
         int    bufSize = sizeof(tIPv4Header) + Length;
        char    buf[bufSize];
        tIPv4Header     *hdr = (void*)buf;
         int    ret;
        
+       to = ARP_Resolve4(Iface, Address);
        if( MAC_EQU(to, cMAC_ZERO) ) {
                // No route to host
                Log_Notice("IPv4", "No route to host %i.%i.%i.%i",
@@ -171,6 +173,11 @@ void IPv4_int_GetPacket(tAdapter *Adapter, tMacAddr From, int Length, void *Buff
        // TODO: Handle packet fragmentation
        
        
+       Log_Debug("IPv4", " From %i.%i.%i.%i to %i.%i.%i.%i",
+               hdr->Source.B[0], hdr->Source.B[1], hdr->Source.B[2], hdr->Source.B[3],
+               hdr->Destination.B[0], hdr->Destination.B[1], hdr->Destination.B[2], hdr->Destination.B[3]
+               );
+       
        // Get Data and Data Length
        dataLength = ntohs(hdr->TotalLength) - sizeof(tIPv4Header);
        data = &hdr->Options[0];
@@ -221,13 +228,15 @@ void IPv4_int_GetPacket(tAdapter *Adapter, tMacAddr From, int Length, void *Buff
                Log_Debug("IPv4", "Route the packet");
                // Drop the packet if the TTL is zero
                if( hdr->TTL == 0 ) {
-                       Log_Warning("IPv4", "TODO: Sent ICMP-Timeout when TTL exceeded");
+                       Log_Warning("IPv4", "TODO: Send ICMP-Timeout when TTL exceeded");
                        return ;
                }
                
                hdr->TTL --;
                
                rt = IPStack_FindRoute(4, NULL, &hdr->Destination);     // Get the route (gets the interface)
+               if( !rt || !rt->Interface )
+                       return ;
                to = ARP_Resolve4(rt->Interface, hdr->Destination);     // Resolve address
                if( MAC_EQU(to, cMAC_ZERO) )
                        return ;
@@ -265,27 +274,37 @@ tInterface *IPv4_GetInterface(tAdapter *Adapter, tIPv4 Address, int Broadcast)
        tInterface      *iface = NULL;
        Uint32  netmask;
        Uint32  addr, this;
-       
+
+       ENTER("pAdapter xAddress bBroadcast", Adapter, Address, Broadcast);     
+
        addr = ntohl( Address.L );
+       LOG("addr = 0x%x", addr);
        
        for( iface = gIP_Interfaces; iface; iface = iface->Next)
        {
                if( iface->Adapter != Adapter ) continue;
                if( iface->Type != 4 )  continue;
-               if( IP4_EQU(Address, *(tIPv4*)iface->Address) )
+               if( IP4_EQU(Address, *(tIPv4*)iface->Address) ) {
+                       LOG("Exact match");
+                       LEAVE('p', iface);
                        return iface;
+               }
                
                if( !Broadcast )        continue;
                
-               this = ntohl( ((tIPv4*)iface->Address)->L );
-               
                // Check for broadcast
+               this = ntohl( ((tIPv4*)iface->Address)->L );
                netmask = IPv4_Netmask(iface->SubnetBits);
-               
-               if( (addr & netmask) == (this & netmask)
-                && (addr & ~netmask) == (0xFFFFFFFF & ~netmask) )
+               LOG("iface addr = 0x%x, netmask = 0x%x (bits = %i)", this, netmask, iface->SubnetBits);
+
+               if( (addr & netmask) == (this & netmask) && (addr & ~netmask) == (0xFFFFFFFF & ~netmask) )
+               {
+                       LOG("Broadcast match");
+                       LEAVE('p', iface);
                        return iface;
+               }
        }
+       LEAVE('n');
        return NULL;
 }
 
@@ -298,8 +317,13 @@ tInterface *IPv4_GetInterface(tAdapter *Adapter, tIPv4 Address, int Broadcast)
 Uint32 IPv4_Netmask(int FixedBits)
 {
        Uint32  ret = 0xFFFFFFFF;
-       ret >>= (32-FixedBits);
-       ret <<= (32-FixedBits);
+       if( FixedBits == 0 )
+               return 0;
+       if( FixedBits < 32 )
+       {
+               ret >>= (32-FixedBits);
+               ret <<= (32-FixedBits);
+       }
        // Returns a native endian netmask
        return ret;
 }
index 5f650b3..d5d1ebc 100644 (file)
@@ -30,6 +30,11 @@ extern tRoute        *IPStack_AddRoute(const char *Interface, void *Network, int Subnet
 
 // === GLOBALS ===
 MODULE_DEFINE(0, VERSION, IPStack, IPStack_Install, NULL, NULL);
+tVFS_NodeType  gIP_RootNodeType = {
+       .ReadDir = IPStack_Root_ReadDir,
+       .FindDir = IPStack_Root_FindDir,
+       .IOCtl = IPStack_Root_IOCtl
+};
 tDevFS_Driver  gIP_DriverInfo = {
        NULL, "ip",
        {
@@ -37,9 +42,7 @@ tDevFS_Driver gIP_DriverInfo = {
        .NumACLs = 1,
        .ACLs = &gVFS_ACL_EveryoneRX,
        .Flags = VFS_FFLAG_DIRECTORY,
-       .ReadDir = IPStack_Root_ReadDir,
-       .FindDir = IPStack_Root_FindDir,
-       .IOCtl = IPStack_Root_IOCtl
+       .Type = &gIP_RootNodeType
        }
 };
 
@@ -263,8 +266,8 @@ const char *IPStack_PrintAddress(int AddressType, const void *Address)
                static char     ret[8*4+7+1];
                const Uint16    *addr = Address;
                sprintf(ret, "%x:%x:%x:%x:%x:%x:%x:%x",
-                       addr[0], addr[1], addr[2], addr[3],
-                       addr[4], addr[5], addr[6], addr[7]
+                       ntohs(addr[0]), ntohs(addr[1]), ntohs(addr[2]), ntohs(addr[3]),
+                       ntohs(addr[4]), ntohs(addr[5]), ntohs(addr[6]), ntohs(addr[7])
                        );
                return ret;
                }
index 1cde444..7173d1f 100644 (file)
@@ -19,9 +19,13 @@ extern tVFS_Node     *IPStack_Root_FindDir(tVFS_Node *Node, const char *Filename);
 // - Routes directory
 char   *IPStack_RouteDir_ReadDir(tVFS_Node *Node, int Pos);
 tVFS_Node      *IPStack_RouteDir_FindDir(tVFS_Node *Node, const char *Name);
+ int   IPStack_RouteDir_MkNod(tVFS_Node *Node, const char *Name, Uint Flags);
+ int   IPStack_RouteDir_Relink(tVFS_Node *Node, const char *OldName, const char *NewName);
+tRoute *_Route_FindExactRoute(int Type, void *Network, int Subnet, int Metric);
+ int   _Route_ParseRouteName(const char *Name, void *Addr, int *SubnetBits, int *Metric);
  int   IPStack_RouteDir_IOCtl(tVFS_Node *Node, int ID, void *Data);
 // - Route Management
-tRoute *IPStack_Route_Create(const char *InterfaceName);
+tRoute *IPStack_Route_Create(int AddrType, void *Network, int SubnetBits, int Metric);
 tRoute *IPStack_AddRoute(const char *Interface, void *Network, int SubnetBits, void *NextHop, int Metric);
 tRoute *IPStack_FindRoute(int AddressType, tInterface *Interface, void *Address);
 // - Individual Routes
@@ -31,14 +35,22 @@ tRoute      *IPStack_FindRoute(int AddressType, tInterface *Interface, void *Address)
  int   giIP_NextRouteId = 1;
 tRoute *gIP_Routes;
 tRoute *gIP_RoutesEnd;
+tVFS_NodeType  gIP_RouteNodeType = {
+       .IOCtl = IPStack_Route_IOCtl
+};
+tVFS_NodeType  gIP_RouteDirNodeType = {
+       .ReadDir = IPStack_RouteDir_ReadDir,
+       .FindDir = IPStack_RouteDir_FindDir,
+       .MkNod = IPStack_RouteDir_MkNod,
+       .Relink = IPStack_RouteDir_Relink,
+       .IOCtl = IPStack_RouteDir_IOCtl
+};
 tVFS_Node      gIP_RouteNode = {
        .Flags = VFS_FFLAG_DIRECTORY,
        .Size = -1,
        .NumACLs = 1,
        .ACLs = &gVFS_ACL_EveryoneRX,
-       .ReadDir = IPStack_RouteDir_ReadDir,
-       .FindDir = IPStack_RouteDir_FindDir,
-       .IOCtl = IPStack_RouteDir_IOCtl
+       .Type = &gIP_RouteDirNodeType
 };
 
 // === CODE ===
@@ -50,15 +62,16 @@ char *IPStack_RouteDir_ReadDir(tVFS_Node *Node, int Pos)
        tRoute  *rt;
        
        for(rt = gIP_Routes; rt && Pos --; rt = rt->Next);
-       
-       if( !rt ) {
-               return NULL;
-       }
+       if( !rt )       return NULL;
        
        {
-                int    len = sprintf(NULL, "%i", (int)rt->Node.Inode);
+                int    addrlen = IPStack_GetAddressSize(rt->AddressType);
+                int    len = sprintf(NULL, "%i::%i:%i", rt->AddressType, rt->SubnetBits, rt->Metric) + addrlen*2;
                char    buf[len+1];
-               sprintf(buf, "%i", (int)rt->Node.Inode);
+                int    ofs;
+               ofs = sprintf(buf, "%i:", rt->AddressType);
+               ofs += Hex(buf+ofs, addrlen, rt->Network);
+               sprintf(buf+ofs, ":%i:%i", rt->SubnetBits, rt->Metric);
                return strdup(buf);
        }
 }
@@ -68,48 +81,217 @@ char *IPStack_RouteDir_ReadDir(tVFS_Node *Node, int Pos)
  */
 tVFS_Node *IPStack_RouteDir_FindDir(tVFS_Node *Node, const char *Name)
 {
-        int    num = atoi(Name);
-       tRoute  *rt;
-       
-       // Zero is invalid, sorry :)
-       if( !num )      return NULL;
-       
        // Interpret the name as <type>:<addr>, returning the interface for
        // needed to access that address.
-       //   E.g. '4:0A02000A'  - 10.2.0.10
+       //   E.g. '@4:0A02000A' - 10.2.0.10
        // Hm... It could do with a way to have a better address type representation
-       if( Name[1] == ':' )    // TODO: Allow variable length type codes
+       if( Name[0] == '@' )
        {
-                int    addrSize = IPStack_GetAddressSize(num);
-               Uint8   addrData[addrSize];
+               tRoute  *rt;
+                int    ofs = 1;
+                int    type;
                
-               // Errof if the size is invalid
-               if( strlen(Name) != 2 + addrSize*2 )
+               ofs += ParseInt(Name+ofs, &type);
+                int    addrSize = IPStack_GetAddressSize(type);
+               Uint8   addrData[addrSize];
+
+               // Separator
+               if( Name[ofs] != ':' )  return NULL;
+               ofs ++;
+
+               // Error if the size is invalid
+               if( strlen(Name+ofs) != addrSize*2 )
                        return NULL;
                
                // Parse the address
                // - Error if the address data is not fully hex
-               if( UnHex(addrData, addrSize, Name + 2) != addrSize )
+               if( UnHex(addrData, addrSize, Name + ofs) != addrSize )
                        return NULL;
                
                // Find the route
-               rt = IPStack_FindRoute(num, NULL, addrData);
+               rt = IPStack_FindRoute(type, NULL, addrData);
                if(!rt) return NULL;
+       
+               if( rt->Interface )
+               {       
+                       // Return the interface node
+                       // - Sure it's hijacking it from inteface.c's area, but it's
+                       //   simpler this way
+                       return &rt->Interface->Node;
+               }
+               else
+               {
+                       return NULL;
+               }
+       }
+       else if( Name[0] == '#' )
+       {
+               int num, ofs = 1;
                
-               // Return the interface node
-               // - Sure it's hijacking it from inteface.c's area, but it's
-               //   simpler this way
-               return &rt->Interface->Node;
+               ofs = ParseInt(Name+ofs, &num);
+               if( ofs == 1 )  return NULL;
+               if( Name[ofs] != '\0' ) return NULL;
+               if( num < 0)    return NULL;            
+
+               for( tRoute *rt = gIP_Routes; rt; rt = rt->Next )
+               {
+                       if( rt->Node.Inode > num )      return NULL;
+                       if( rt->Node.Inode == num )     return &rt->Node;
+               }
+               return NULL;
        }
+       else
+       {
+                int    type = _Route_ParseRouteName(Name, NULL, NULL, NULL);
+               if( type <= 0 ) return NULL;
+
+                int    addrSize = IPStack_GetAddressSize(type);
+               Uint8   addrData[addrSize];
+                int    subnet_bits, metric;
+               
+               _Route_ParseRouteName(Name, addrData, &subnet_bits, &metric);
+
+               tRoute *rt = _Route_FindExactRoute(type, addrData, subnet_bits, metric);
+               if(rt)  return &rt->Node;
+               return NULL;
+       }
+}
+
+/**
+ * \brief Create a new route node
+ */
+int IPStack_RouteDir_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
+{
+       if( Flags )     return -EINVAL; 
+       if( Threads_GetUID() != 0 )     return -EACCES;
+
+        int    type = _Route_ParseRouteName(Name, NULL, NULL, NULL);
+       if( type <= 0 ) return -EINVAL;
+
+        int    size = IPStack_GetAddressSize(type);
+       Uint8   addrdata[size]; 
+        int    subnet, metric;
+
+       _Route_ParseRouteName(Name, addrdata, &subnet, &metric);
+
+       // Check for duplicates
+       if( _Route_FindExactRoute(type, addrdata, subnet, metric) )
+               return -EEXIST;
+
+       IPStack_Route_Create(type, addrdata, subnet, metric);
+
+       return 0;
+}
+
+/**
+ * \brief Rename / Delete a route
+ */
+int IPStack_RouteDir_Relink(tVFS_Node *Node, const char *OldName, const char *NewName)
+{
+       tRoute  *rt;
        
-       // The list is inherently sorted, so we can do a quick search
-       for(rt = gIP_Routes; rt && rt->Node.Inode < num; rt = rt->Next);
+       if( Threads_GetUID() != 0 )     return -EACCES;
+
+       // Get the original route entry
+       {
+                int    type = _Route_ParseRouteName(OldName, NULL, NULL, NULL);
+               if(type <= 0)   return -EINVAL;
+               Uint8   addr[IPStack_GetAddressSize(type)];
+                int    subnet, metric;
+               _Route_ParseRouteName(OldName, addr, &subnet, &metric);
+               
+               rt = _Route_FindExactRoute(type, addr, subnet, metric);
+       }       
+
+       if( NewName == NULL )
+       {
+               // Delete the route
+               tRoute  *prev = NULL;
+               for(tRoute *r = gIP_Routes; r && r != rt; prev = r, r = r->Next);
+               
+               if(prev)
+                       prev->Next = rt->Next;
+               else
+                       gIP_Routes = rt->Next;
+               free(rt);
+       }
+       else
+       {
+               // Change the route
+                int    type = _Route_ParseRouteName(NewName, NULL, NULL, NULL);
+               if(type <= 0)   return -EINVAL;
+               Uint8   addr[IPStack_GetAddressSize(type)];
+                int    subnet, metric;
+               _Route_ParseRouteName(NewName, addr, &subnet, &metric);
+       
+               return -ENOTIMPL;       
+       }
+       return 0;
+}
+
+tRoute *_Route_FindExactRoute(int Type, void *Network, int Subnet, int Metric)
+{
+       for(tRoute *rt = gIP_Routes; rt; rt = rt->Next)
+       {
+               if( rt->AddressType != Type )   continue;
+               if( rt->Metric != Metric )      continue;
+               if( rt->SubnetBits != Subnet )  continue;
+               if( IPStack_CompareAddress(Type, rt->Network, Network, -1) == 0 )
+                       continue ;
+               return rt;
+       }
+       return NULL;
+}
+
+int _Route_ParseRouteName(const char *Name, void *Addr, int *SubnetBits, int *Metric)
+{
+        int    type, addrlen;
+        int    ofs = 0, ilen;
        
-       // Fast fail end of list / larger number
-       if( !rt || rt->Node.Inode > num )
-               return NULL;
+       ENTER("sName pAddr pSubnetBits pMetric", Name, Addr, SubnetBits, Metric);
+
+       ilen = ParseInt(Name, &type);
+       if(ilen == 0) {
+               LOG("Type failed to parse");
+               LEAVE_RET('i', -1);
+       }
+       ofs += ilen;
+       
+       if(Name[ofs] != ':')    LEAVE_RET('i', -1);
+       ofs ++;
+
+       addrlen = IPStack_GetAddressSize(type);
+       if( Addr )
+       {
+               if( UnHex(Addr, addrlen, Name + ofs) != addrlen )
+                       return -1;
+       }
+       ofs += addrlen*2;
+       
+       if(Name[ofs] != ':')    LEAVE_RET('i', -1);
+       ofs ++;
+
+       ilen = ParseInt(Name+ofs, SubnetBits);
+       if(ilen == 0) {
+               LOG("Subnet failed to parse");
+               LEAVE_RET('i', -1);
+       }
+       ofs += ilen;
        
-       return &rt->Node;
+       if(Name[ofs] != ':')    LEAVE_RET('i', -1);
+       ofs ++;
+
+       ilen = ParseInt(Name+ofs, Metric);
+       if(ilen == 0) {
+               LOG("Metric failed to parse");
+               LEAVE_RET('i', -1);
+       }
+       ofs += ilen;
+       
+       if(Name[ofs] != '\0')   LEAVE_RET('i', -1);
+
+       LEAVE('i', type);
+       return type;
 }
 
 /**
@@ -117,7 +299,6 @@ tVFS_Node *IPStack_RouteDir_FindDir(tVFS_Node *Node, const char *Name)
  */
 static const char *casIOCtls_RouteDir[] = {
        DRV_IOCTLNAMES,
-       "add_route",    // Add a route - char *InterfaceName
        "locate_route", // Find the best route for an address - struct {int Type, char Address[]} *
        NULL
        };
@@ -127,7 +308,6 @@ static const char *casIOCtls_RouteDir[] = {
  */
 int IPStack_RouteDir_IOCtl(tVFS_Node *Node, int ID, void *Data)
 {
-        int    tmp;
        tRoute  *rt;
        ENTER("pNode iID pData", Node, ID, Data);
        switch(ID)
@@ -135,17 +315,7 @@ int IPStack_RouteDir_IOCtl(tVFS_Node *Node, int ID, void *Data)
        // --- Standard IOCtls (0-3) ---
        BASE_IOCTLS(DRV_TYPE_MISC, STR(IDENT), VERSION, casIOCtls_RouteDir)
        
-       case 4: // Add Route
-               if( !CheckString(Data) )        LEAVE_RET('i', -1);
-               rt = IPStack_Route_Create(Data);
-               if( !rt )
-                       tmp = -1;
-               else
-                       tmp = rt->Node.Inode;
-               LEAVE('i', tmp);
-               return tmp;
-       
-       case 5: // Locate Route
+       case 4: // Locate Route
                {
                        struct {
                                 int    Type;
@@ -177,26 +347,13 @@ int IPStack_RouteDir_IOCtl(tVFS_Node *Node, int ID, void *Data)
  * \brief Create a new route entry
  * \param InterfaceName        Name of the interface using this route
  */
-tRoute *IPStack_Route_Create(const char *InterfaceName)
+tRoute *IPStack_Route_Create(int AddrType, void *Network, int SubnetBits, int Metric)
 {
        tRoute  *rt;
-       tInterface      *iface;
         int    size;
        
-       // Get interface
-       // Note: Oh man! This is such a hack
-       {
-               tVFS_Node       *node = IPStack_Root_FindDir(NULL, InterfaceName);
-               if( !node ) {
-                       Log_Debug("IPStack", "IPStack_Route_Create - Unknown interface '%s'\n", InterfaceName);
-                       return NULL;
-               }
-               iface = node->ImplPtr;
-               if(node->Close) node->Close(node);
-       }
-       
        // Get the size of the specified address type
-       size = IPStack_GetAddressSize(iface->Type);
+       size = IPStack_GetAddressSize(AddrType);
        if( size == 0 ) {
                return NULL;
        }
@@ -210,18 +367,31 @@ tRoute *IPStack_Route_Create(const char *InterfaceName)
        rt->Node.Size = 0;
        rt->Node.NumACLs = 1,
        rt->Node.ACLs = &gVFS_ACL_EveryoneRO;
-       rt->Node.IOCtl = IPStack_Route_IOCtl;
+       rt->Node.Type = &gIP_RouteNodeType;
        
        // Set up state
-       rt->AddressType = iface->Type;
+       rt->AddressType = AddrType;
        rt->Network = (void *)( (tVAddr)rt + sizeof(tRoute) );
-       rt->SubnetBits = 0;
+       rt->SubnetBits = SubnetBits;
        rt->NextHop = (void *)( (tVAddr)rt + sizeof(tRoute) + size );
-       rt->Interface = iface;
-       rt->Metric = DEFAUTL_METRIC;
-       memset(rt->Network, 0, size);
+       rt->Interface = NULL;
+       rt->Metric = Metric;
+       memcpy(rt->Network, Network, size);
        memset(rt->NextHop, 0, size);
        
+       // Clear non-fixed bits
+       {
+               Uint8   *data = rt->Network;
+                int    i;
+               i = SubnetBits / 8;
+               if( SubnetBits % 8 ) {
+                       data[i] &= ~((1 << (8 - SubnetBits % 8)) - 1);
+                       i ++;
+               }
+               memset(data + i, 0, size - i);
+       }       
+
+
        // Add to list
        if( gIP_RoutesEnd ) {
                gIP_RoutesEnd->Next = rt;
@@ -231,7 +401,7 @@ tRoute *IPStack_Route_Create(const char *InterfaceName)
                gIP_Routes = gIP_RoutesEnd = rt;
        }
        
-       Log_Log("IPStack", "Route entry for '%s' created", InterfaceName);
+//     Log_Log("IPStack", "Route entry for '%s' created", InterfaceName);
        
        return rt;
 }
@@ -241,19 +411,26 @@ tRoute *IPStack_Route_Create(const char *InterfaceName)
  */
 tRoute *IPStack_AddRoute(const char *Interface, void *Network, int SubnetBits, void *NextHop, int Metric)
 {
-       tRoute  *rt = IPStack_Route_Create(Interface);
+       tInterface      *iface;
+       tRoute  *rt;
         int    addrSize;
        
+       {
+               tVFS_Node       *tmp;
+               tmp = IPStack_Root_FindDir(NULL, Interface);
+               if(!tmp)        return NULL;
+               iface = tmp->ImplPtr;
+               if(tmp->Type->Close)    tmp->Type->Close(tmp);
+       }
+
+       rt = IPStack_Route_Create(iface->Type, Network, SubnetBits, Metric);
        if( !rt )       return NULL;
        
-       addrSize = IPStack_GetAddressSize(rt->Interface->Type);
+       addrSize = IPStack_GetAddressSize(iface->Type);
+       rt->Interface = iface;
        
-       memcpy(rt->Network, Network, addrSize);
        if( NextHop )
                memcpy(rt->NextHop, NextHop, addrSize);
-       rt->SubnetBits = SubnetBits;
-       if( Metric )
-               rt->Metric = Metric;
        
        return rt;
 }
@@ -368,14 +545,10 @@ tRoute *IPStack_FindRoute(int AddressType, tInterface *Interface, void *Address)
  */
 static const char *casIOCtls_Route[] = {
        DRV_IOCTLNAMES,
-       "get_type",     // Get address type - (void), returns integer type
-       "get_network",  // Get network - (void *Data), returns boolean success
-       "set_network",  // Set network - (void *Data), returns boolean success
        "get_nexthop",  // Get next hop - (void *Data), returns boolean success
        "set_nexthop",  // Set next hop - (void *Data), returns boolean success
-       "getset_subnetbits",    // Get/Set subnet bits - (int *Bits), returns current value
-       "getset_metric",        // Get/Set metric - (int *Metric), returns current value
        "get_interface",        // Get interface name - (char *Name), returns name length, NULL OK
+       "set_interface",        // Set interface - (const char *Name)
        NULL
        };
 
@@ -384,7 +557,6 @@ static const char *casIOCtls_Route[] = {
  */
 int IPStack_Route_IOCtl(tVFS_Node *Node, int ID, void *Data)
 {
-        int    *iData = Data;
        tRoute  *rt = Node->ImplPtr;
         int    addrSize = IPStack_GetAddressSize(rt->AddressType);
        
@@ -393,60 +565,58 @@ int IPStack_Route_IOCtl(tVFS_Node *Node, int ID, void *Data)
        // --- Standard IOCtls (0-3) ---
        BASE_IOCTLS(DRV_TYPE_MISC, STR(IDENT), VERSION, casIOCtls_Route)
        
-       // Get address type
-       case 4:
-               return rt->AddressType;
-       
-       // Get Network
-       case 5:
-               if( !CheckMem(Data, addrSize) ) return -1;
-               memcpy(Data, rt->Network, addrSize);
-               return 1;
-       // Set Network
-       case 6:
-               if( !CheckMem(Data, addrSize) ) return -1;
-               memcpy(rt->Network, Data, addrSize);
-               return 1;
-       
        // Get Next Hop
-       case 7:
+       case 4:
                if( !CheckMem(Data, addrSize) ) return -1;
                memcpy(Data, rt->NextHop, addrSize);
                return 1;
        // Set Next Hop
-       case 8:
+       case 5:
+               if( Threads_GetUID() != 0 )     return -1;
                if( !CheckMem(Data, addrSize) ) return -1;
                memcpy(rt->NextHop, Data, addrSize);
                return 1;
-       
-       // Get/Set Subnet Bits
-       case 9:
-               if( Data ) {
-                       if( !CheckMem(Data, sizeof(int)) )      return -1;
-                       if( *iData < 0 || *iData > addrSize*8 )
+
+       // Get interface name
+       case 6:
+               if( !rt->Interface ) {
+                       if(Data && !CheckMem(Data, 1) )
                                return -1;
-                       rt->SubnetBits = *iData;
+                       if(Data)
+                               *(char*)Data = 0;
+                       return 0;
                }
-               return rt->SubnetBits;
-       
-       // Get/Set Metric
-       case 10:
-               if( Data ) {
-                       if( !CheckMem(Data, sizeof(int)) )      return -1;
-                       if( *iData < 0 )        return -1;
-                       rt->Metric = *iData;
-               }
-               return rt->Metric;
-       
-       // Get interface name
-       case 11:
                if( Data ) {
                        if( !CheckMem(Data, strlen(rt->Interface->Name) + 1) )
                                return -1;
                        strcpy(Data, rt->Interface->Name);
                }
                return strlen(rt->Interface->Name);
+       // Set interface name
+       case 7:
+               if( Threads_GetUID() != 0 )
+                       return -1;
+               if( !CheckString(Data) )
+                       return -1;
+               else
+               {
+                       tInterface      *iface;
+                       tVFS_Node       *tmp;
+                       tmp = IPStack_Root_FindDir(NULL, Data);
+                       if(!tmp)
+                               return -1;
+                       iface = tmp->ImplPtr;
+                       if(tmp->Type->Close)    tmp->Type->Close(tmp);
+                       
+                       if( iface->Type != rt->AddressType )
+                               return -1;
+
+                       // TODO: Other checks?          
        
+                       rt->Interface = iface;
+               }
+               return 0;
+
        default:
                return -1;
        }
index bb71fdb..e9c3de9 100644 (file)
@@ -40,7 +40,7 @@ void  TCP_Server_Close(tVFS_Node *Node);
 // --- Client
 tVFS_Node      *TCP_Client_Init(tInterface *Interface);
 Uint64 TCP_Client_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
-Uint64 TCP_Client_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+Uint64 TCP_Client_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer);
  int   TCP_Client_IOCtl(tVFS_Node *Node, int ID, void *Data);
 void   TCP_Client_Close(tVFS_Node *Node);
 // --- Helpers
@@ -49,6 +49,20 @@ void TCP_Client_Close(tVFS_Node *Node);
 // === TEMPLATES ===
 tSocketFile    gTCP_ServerFile = {NULL, "tcps", TCP_Server_Init};
 tSocketFile    gTCP_ClientFile = {NULL, "tcpc", TCP_Client_Init};
+tVFS_NodeType  gTCP_ServerNodeType = {
+       .TypeName = "TCP Server",
+       .ReadDir = TCP_Server_ReadDir,
+       .FindDir = TCP_Server_FindDir,
+       .IOCtl   = TCP_Server_IOCtl,
+       .Close   = TCP_Server_Close
+       };
+tVFS_NodeType  gTCP_ClientNodeType = {
+       .TypeName = "TCP Client/Connection",
+       .Read  = TCP_Client_Read,
+       .Write = TCP_Client_Write,
+       .IOCtl = TCP_Client_IOCtl,
+       .Close = TCP_Client_Close
+       };
 
 // === GLOBALS ===
  int   giTCP_NumHalfopen = 0;
@@ -136,9 +150,9 @@ void TCP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffe
        tTCPConnection  *conn;
 
        Log_Log("TCP", "TCP_GetPacket: <Local>:%i from [%s]:%i, Flags= %s%s%s%s%s%s%s%s",
-               ntohs(hdr->SourcePort),
-               IPStack_PrintAddress(Interface->Type, Address),
                ntohs(hdr->DestPort),
+               IPStack_PrintAddress(Interface->Type, Address),
+               ntohs(hdr->SourcePort),
                (hdr->Flags & TCP_FLAG_CWR) ? "CWR " : "",
                (hdr->Flags & TCP_FLAG_ECE) ? "ECE " : "",
                (hdr->Flags & TCP_FLAG_URG) ? "URG " : "",
@@ -185,7 +199,11 @@ void TCP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffe
                                if(conn->RemotePort != ntohs(hdr->SourcePort))  continue;
 
                                // Check Source IP
-                               if( IPStack_CompareAddress(conn->Interface->Type, &conn->RemoteIP, Address, -1) != 0 )
+                               Log_Debug("TCP", "TCP_GetPacket: conn->RemoteIP(%s)",
+                                       IPStack_PrintAddress(conn->Interface->Type, &conn->RemoteIP));
+                               Log_Debug("TCP", "                == Address(%s)",
+                                       IPStack_PrintAddress(conn->Interface->Type, Address));
+                               if( IPStack_CompareAddress(conn->Interface->Type, &conn->RemoteIP, Address, -1) == 0 )
                                        continue ;
 
                                Log_Log("TCP", "TCP_GetPacket: Matches connection %p", conn);
@@ -226,9 +244,7 @@ void TCP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffe
                        conn->Node.ACLs = &gVFS_ACL_EveryoneRW;
                        conn->Node.ImplPtr = conn;
                        conn->Node.ImplInt = srv->NextID ++;
-                       conn->Node.Read = TCP_Client_Read;
-                       conn->Node.Write = TCP_Client_Write;
-                       //conn->Node.Close = TCP_SrvConn_Close;
+                       conn->Node.Type = &gTCP_ClientNodeType; // TODO: Special type for the server end?
                        
                        // Hmm... Theoretically, this lock will never have to wait,
                        // as the interface is locked to the watching thread, and this
@@ -244,6 +260,7 @@ void TCP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffe
                        srv->ConnectionsTail = conn;
                        if(!srv->NewConnections)
                                srv->NewConnections = conn;
+                       VFS_MarkAvaliable( &srv->Node, 1 );
                        SHORTREL(&srv->lConnections);
 
                        // Send the SYN ACK
@@ -764,7 +781,7 @@ Uint16 TCP_GetUnusedPort()
 
        // Get Next outbound port
        ret = giTCP_NextOutPort++;
-       while( gaTCP_PortBitmap[ret/32] & (1 << (ret%32)) )
+       while( gaTCP_PortBitmap[ret/32] & (1UL << (ret%32)) )
        {
                ret ++;
                giTCP_NextOutPort++;
@@ -816,7 +833,7 @@ tVFS_Node *TCP_Server_Init(tInterface *Interface)
 {
        tTCPListener    *srv;
        
-       srv = malloc( sizeof(tTCPListener) );
+       srv = calloc( 1, sizeof(tTCPListener) );
 
        if( srv == NULL ) {
                Log_Warning("TCP", "malloc failed for listener (%i) bytes", sizeof(tTCPListener));
@@ -835,10 +852,7 @@ tVFS_Node *TCP_Server_Init(tInterface *Interface)
        srv->Node.ImplPtr = srv;
        srv->Node.NumACLs = 1;
        srv->Node.ACLs = &gVFS_ACL_EveryoneRW;
-       srv->Node.ReadDir = TCP_Server_ReadDir;
-       srv->Node.FindDir = TCP_Server_FindDir;
-       srv->Node.IOCtl = TCP_Server_IOCtl;
-       srv->Node.Close = TCP_Server_Close;
+       srv->Node.Type = &gTCP_ServerNodeType;
 
        SHORTLOCK(&glTCP_Listeners);
        srv->Next = gTCP_Listeners;
@@ -869,7 +883,6 @@ char *TCP_Server_ReadDir(tVFS_Node *Node, int Pos)
                if( srv->NewConnections != NULL )       break;
                SHORTREL( &srv->lConnections );
                Threads_Yield();        // TODO: Sleep until poked
-               continue;
        }
        
 
@@ -877,6 +890,9 @@ char *TCP_Server_ReadDir(tVFS_Node *Node, int Pos)
        // normal list)
        conn = srv->NewConnections;
        srv->NewConnections = conn->Next;
+
+       if( srv->NewConnections == NULL )
+               VFS_MarkAvaliable( Node, 0 );
        
        SHORTREL( &srv->lConnections );
        
@@ -905,37 +921,56 @@ tVFS_Node *TCP_Server_FindDir(tVFS_Node *Node, const char *Name)
         int    id = atoi(Name);
        
        ENTER("pNode sName", Node, Name);
-       
-       // Sanity Check
-       itoa(tmp, id, 16, 8, '0');
-       if(strcmp(tmp, Name) != 0) {
-               LOG("'%s' != '%s' (%08x)", Name, tmp, id);
-               LEAVE('n');
-               return NULL;
+
+       // Check for a non-empty name
+       if( Name[0] ) 
+       {       
+               // Sanity Check
+               itoa(tmp, id, 16, 8, '0');
+               if(strcmp(tmp, Name) != 0) {
+                       LOG("'%s' != '%s' (%08x)", Name, tmp, id);
+                       LEAVE('n');
+                       return NULL;
+               }
+               
+               Log_Debug("TCP", "srv->Connections = %p", srv->Connections);
+               Log_Debug("TCP", "srv->NewConnections = %p", srv->NewConnections);
+               Log_Debug("TCP", "srv->ConnectionsTail = %p", srv->ConnectionsTail);
+               
+               // Search
+               SHORTLOCK( &srv->lConnections );
+               for(conn = srv->Connections;
+                       conn;
+                       conn = conn->Next)
+               {
+                       LOG("conn->Node.ImplInt = %i", conn->Node.ImplInt);
+                       if(conn->Node.ImplInt == id)    break;
+               }
+               SHORTREL( &srv->lConnections );
+
+               // If not found, ret NULL
+               if(!conn) {
+                       LOG("Connection %i not found", id);
+                       LEAVE('n');
+                       return NULL;
+               }
        }
-       
-       Log_Debug("TCP", "srv->Connections = %p", srv->Connections);
-       Log_Debug("TCP", "srv->NewConnections = %p", srv->NewConnections);
-       Log_Debug("TCP", "srv->ConnectionsTail = %p", srv->ConnectionsTail);
-       
-       // Search
-       SHORTLOCK( &srv->lConnections );
-       for(conn = srv->Connections;
-               conn;
-               conn = conn->Next)
+       // Empty Name - Check for a new connection and if it's there, open it
+       else
        {
-               LOG("conn->Node.ImplInt = %i", conn->Node.ImplInt);
-               if(conn->Node.ImplInt == id)    break;
-       }
-       SHORTREL( &srv->lConnections );
-       
-       // If not found, ret NULL
-       if(!conn) {
-               LOG("Connection %i not found", id);
-               LEAVE('n');
-               return NULL;
+               SHORTLOCK( &srv->lConnections );
+               conn = srv->NewConnections;
+               if( conn != NULL )
+                       srv->NewConnections = conn->Next;
+               VFS_MarkAvaliable( Node, srv->NewConnections != NULL );
+               SHORTREL( &srv->lConnections );
+               if( !conn ) {
+                       LOG("No new connections");
+                       LEAVE('n');
+                       return NULL;
+               }
        }
-       
+               
        // Return node
        LEAVE('p', &conn->Node);
        return &conn->Node;
@@ -1003,10 +1038,7 @@ tVFS_Node *TCP_Client_Init(tInterface *Interface)
        conn->Node.ImplPtr = conn;
        conn->Node.NumACLs = 1;
        conn->Node.ACLs = &gVFS_ACL_EveryoneRW;
-       conn->Node.Read = TCP_Client_Read;
-       conn->Node.Write = TCP_Client_Write;
-       conn->Node.IOCtl = TCP_Client_IOCtl;
-       conn->Node.Close = TCP_Client_Close;
+       conn->Node.Type = &gTCP_ClientNodeType;
 
        conn->RecievedBuffer = RingBuffer_Create( TCP_RECIEVE_BUFFER_SIZE );
        #if 0
@@ -1086,7 +1118,7 @@ Uint64 TCP_Client_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buff
 /**
  * \brief Send a data packet on a connection
  */
-void TCP_INT_SendDataPacket(tTCPConnection *Connection, size_t Length, void *Data)
+void TCP_INT_SendDataPacket(tTCPConnection *Connection, size_t Length, const void *Data)
 {
        char    buf[sizeof(tTCPHeader)+Length];
        tTCPHeader      *packet = (void*)buf;
@@ -1115,7 +1147,7 @@ void TCP_INT_SendDataPacket(tTCPConnection *Connection, size_t Length, void *Dat
 /**
  * \brief Send some bytes on a connection
  */
-Uint64 TCP_Client_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+Uint64 TCP_Client_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
 {
        tTCPConnection  *conn = Node->ImplPtr;
        size_t  rem = Length;
index c75aab0..cbdcd56 100644 (file)
 void   UDP_Initialise();
 void   UDP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer);
 void   UDP_Unreachable(tInterface *Interface, int Code, void *Address, int Length, void *Buffer);
-void   UDP_SendPacketTo(tUDPChannel *Channel, int AddrType, void *Address, Uint16 Port, void *Data, size_t Length);
+void   UDP_SendPacketTo(tUDPChannel *Channel, int AddrType, const void *Address, Uint16 Port, const void *Data, size_t Length);
 // --- Client Channels
 tVFS_Node      *UDP_Channel_Init(tInterface *Interface);
 Uint64 UDP_Channel_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
-Uint64 UDP_Channel_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+Uint64 UDP_Channel_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer);
  int   UDP_Channel_IOCtl(tVFS_Node *Node, int ID, void *Data);
 void   UDP_Channel_Close(tVFS_Node *Node);
 // --- Helpers
@@ -25,6 +25,12 @@ Uint16       UDP_int_AllocatePort();
 void   UDP_int_FreePort(Uint16 Port);
 
 // === GLOBALS ===
+tVFS_NodeType  gUDP_NodeType = {
+       .Read = UDP_Channel_Read,
+       .Write = UDP_Channel_Write,
+       .IOCtl = UDP_Channel_IOCtl,
+       .Close = UDP_Channel_Close
+};
 tMutex glUDP_Channels;
 tUDPChannel    *gpUDP_Channels;
 
@@ -85,6 +91,7 @@ int UDP_int_ScanList(tUDPChannel *List, tInterface *Interface, void *Address, in
                pack->Next = NULL;
                memcpy(&pack->Remote.Addr, Address, IPStack_GetAddressSize(Interface->Type));
                pack->Remote.Port = ntohs(hdr->SourcePort);
+               pack->Remote.AddrType = Interface->Type;
                pack->Length = len;
                memcpy(pack->Data, hdr->Data, len);
                
@@ -135,7 +142,7 @@ void UDP_Unreachable(tInterface *Interface, int Code, void *Address, int Length,
  * \param Data Packet data
  * \param Length       Length in bytes of packet data
  */
-void UDP_SendPacketTo(tUDPChannel *Channel, int AddrType, void *Address, Uint16 Port, void *Data, size_t Length)
+void UDP_SendPacketTo(tUDPChannel *Channel, int AddrType, const void *Address, Uint16 Port, const void *Data, size_t Length)
 {
        tUDPHeader      *hdr;
 
@@ -169,10 +176,7 @@ tVFS_Node *UDP_Channel_Init(tInterface *Interface)
        new->Node.ImplPtr = new;
        new->Node.NumACLs = 1;
        new->Node.ACLs = &gVFS_ACL_EveryoneRW;
-       new->Node.Read = UDP_Channel_Read;
-       new->Node.Write = UDP_Channel_Write;
-       new->Node.IOCtl = UDP_Channel_IOCtl;
-       new->Node.Close = UDP_Channel_Close;
+       new->Node.Type = &gUDP_NodeType;
        
        Mutex_Acquire(&glUDP_Channels);
        new->Next = gpUDP_Channels;
@@ -190,7 +194,7 @@ Uint64 UDP_Channel_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buf
        tUDPChannel     *chan = Node->ImplPtr;
        tUDPPacket      *pack;
        tUDPEndpoint    *ep;
-        int    ofs;
+        int    ofs, addrlen;
        
        if(chan->LocalPort == 0) {
                Log_Notice("UDP", "Channel %p sent with no local port", chan);
@@ -218,8 +222,9 @@ Uint64 UDP_Channel_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buf
        }
 
        // Check that the header fits
+       addrlen = IPStack_GetAddressSize(pack->Remote.AddrType);
        ep = Buffer;
-       ofs = 4 + IPStack_GetAddressSize(pack->Remote.AddrType);
+       ofs = 4 + addrlen;
        if(Length < ofs) {
                free(pack);
                Log_Notice("UDP", "Insuficient space for header in buffer (%i < %i)", (int)Length, ofs);
@@ -229,7 +234,7 @@ Uint64 UDP_Channel_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buf
        // Fill header
        ep->Port = pack->Remote.Port;
        ep->AddrType = pack->Remote.AddrType;
-       memcpy(&ep->Addr, &pack->Remote.Addr, IPStack_GetAddressSize(pack->Remote.AddrType));
+       memcpy(&ep->Addr, &pack->Remote.Addr, addrlen);
        
        // Copy packet data
        if(Length > ofs + pack->Length) Length = ofs + pack->Length;
@@ -244,18 +249,18 @@ Uint64 UDP_Channel_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buf
 /**
  * \brief Write to the channel file (send a packet)
  */
-Uint64 UDP_Channel_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+Uint64 UDP_Channel_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
 {
        tUDPChannel     *chan = Node->ImplPtr;
-       tUDPEndpoint    *ep;
-       void    *data;
+       const tUDPEndpoint      *ep;
+       const void      *data;
         int    ofs;
        if(chan->LocalPort == 0)        return 0;
        
        ep = Buffer;    
        ofs = 2 + 2 + IPStack_GetAddressSize( ep->AddrType );
 
-       data = (char*)Buffer + ofs;
+       data = (const char *)Buffer + ofs;
 
        UDP_SendPacketTo(chan, ep->AddrType, &ep->Addr, ep->Port, data, (size_t)Length - ofs);
        
index 56c98c2..a121b61 100644 (file)
@@ -25,13 +25,12 @@ void        KB_UpdateLEDs(void);
  int   KB_IOCtl(tVFS_Node *Node, int Id, void *Data);
 
 // === GLOBALS ===
+tVFS_NodeType  gKB_NodeType = {
+       .IOCtl = KB_IOCtl
+};
 tDevFS_Driver  gKB_DevInfo = {
        NULL, "PS2Keyboard",
-       {
-       .NumACLs = 0,
-       .Size = 0,
-       .IOCtl = KB_IOCtl
-       }
+       { .Type = &gKB_NodeType }
 };
 tKeybardCallback       gKB_Callback = NULL;
 Uint32 **gpKB_Map = gpKBDUS;
index e80a141..44be3b7 100644 (file)
@@ -39,11 +39,15 @@ tJoystick_Callback  gMouse_Callback;
  int   giMouse_Cycle = 0;      // IRQ Position\r
 Uint8  gaMouse_Bytes[4] = {0,0,0,0};\r
 // - Driver definition\r
+tVFS_NodeType  gMouse_NodeType = {\r
+       .Read = PS2Mouse_Read,\r
+       .IOCtl = PS2Mouse_IOCtl\r
+};\r
 tDevFS_Driver  gMouse_DriverStruct = {\r
        NULL, "PS2Mouse",\r
        {\r
        .NumACLs = 1, .ACLs = &gVFS_ACL_EveryoneRX,\r
-       .Read = PS2Mouse_Read, .IOCtl = PS2Mouse_IOCtl\r
+       .Type = &gMouse_NodeType\r
        }\r
 };\r
 \r
index 37d9c5a..d05b2a3 100644 (file)
@@ -86,7 +86,7 @@ typedef struct sNe2k_Card {
 char   *Ne2k_ReadDir(tVFS_Node *Node, int Pos);
 tVFS_Node      *Ne2k_FindDir(tVFS_Node *Node, const char *Name);
  int   Ne2k_IOCtl(tVFS_Node *Node, int ID, void *Data);
-Uint64 Ne2k_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+Uint64 Ne2k_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer);
 Uint64 Ne2k_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
 
  int   Ne2k_int_ReadDMA(tCard *Card, int FirstPage, int NumPages, void *Buffer);
@@ -95,15 +95,23 @@ void        Ne2k_IRQHandler(int IntNum, void *Ptr);
 
 // === GLOBALS ===
 MODULE_DEFINE(0, VERSION, Ne2k, Ne2k_Install, NULL, NULL);
+tVFS_NodeType  gNe2K_RootNodeType = {
+       .ReadDir = Ne2k_ReadDir,
+       .FindDir = Ne2k_FindDir,
+       .IOCtl = Ne2k_IOCtl
+       };
+tVFS_NodeType  gNe2K_DevNodeType = {
+       .Write = Ne2k_Write,
+       .Read = Ne2k_Read,
+       .IOCtl = Ne2k_IOCtl     
+       };
 tDevFS_Driver  gNe2k_DriverInfo = {
        NULL, "ne2k",
        {
        .NumACLs = 1,
        .ACLs = &gVFS_ACL_EveryoneRX,
        .Flags = VFS_FFLAG_DIRECTORY,
-       .ReadDir = Ne2k_ReadDir,
-       .FindDir = Ne2k_FindDir,
-       .IOCtl = Ne2k_IOCtl
+       .Type = &gNe2K_RootNodeType
        }
 };
 Uint16 gNe2k_BaseAddress;
@@ -202,9 +210,7 @@ int Ne2k_Install(char **Options)
                        gpNe2k_Cards[ k ].Node.ImplPtr = &gpNe2k_Cards[ k ];
                        gpNe2k_Cards[ k ].Node.NumACLs = 0;     // Root Only
                        gpNe2k_Cards[ k ].Node.CTime = now();
-                       gpNe2k_Cards[ k ].Node.Write = Ne2k_Write;
-                       gpNe2k_Cards[ k ].Node.Read = Ne2k_Read;
-                       gpNe2k_Cards[ k ].Node.IOCtl = Ne2k_IOCtl;
+                       gpNe2k_Cards[ k ].Node.Type = &gNe2K_DevNodeType;
                        
                        // Initialise packet semaphore
                        // - Start at zero, no max
@@ -275,13 +281,13 @@ int Ne2k_IOCtl(tVFS_Node *Node, int ID, void *Data)
 }
 
 /**
- * \fn Uint64 Ne2k_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+ * \fn Uint64 Ne2k_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
  * \brief Send a packet from the network card
  */
-Uint64 Ne2k_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+Uint64 Ne2k_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
 {
        tCard   *Card = (tCard*)Node->ImplPtr;
-       Uint16  *buf = Buffer;
+       const Uint16    *buf = Buffer;
         int    rem = Length;
         int    page;
        
index eb77812..1e9ac89 100644 (file)
@@ -95,21 +95,29 @@ char        *RTL8139_ReadDir(tVFS_Node *Node, int Pos);
 tVFS_Node      *RTL8139_FindDir(tVFS_Node *Node, const char *Filename);
  int   RTL8139_RootIOCtl(tVFS_Node *Node, int ID, void *Arg);
 Uint64 RTL8139_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
-Uint64 RTL8139_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+Uint64 RTL8139_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer);
  int   RTL8139_IOCtl(tVFS_Node *Node, int ID, void *Arg);
 void   RTL8139_IRQHandler(int Num, void *Ptr);
 
 // === GLOBALS ===
 MODULE_DEFINE(0, VERSION, RTL8139, RTL8139_Install, NULL, NULL);
+tVFS_NodeType  gRTL8139_RootNodeType = {
+       .ReadDir = RTL8139_ReadDir,
+       .FindDir = RTL8139_FindDir,
+       .IOCtl = RTL8139_IOCtl
+       };
+tVFS_NodeType  gRTL8139_DevNodeType = {
+       .Write = RTL8139_Write,
+       .Read = RTL8139_Read,
+       .IOCtl = RTL8139_IOCtl  
+       };
 tDevFS_Driver  gRTL8139_DriverInfo = {
        NULL, "RTL8139",
        {
        .NumACLs = 1,
        .ACLs = &gVFS_ACL_EveryoneRX,
        .Flags = VFS_FFLAG_DIRECTORY,
-       .ReadDir = RTL8139_ReadDir,
-       .FindDir = RTL8139_FindDir,
-       .IOCtl = RTL8139_RootIOCtl
+       .Type = &gRTL8139_RootNodeType
        }
 };
  int   giRTL8139_CardCount;
@@ -206,9 +214,7 @@ int RTL8139_Install(char **Options)
                card->Node.ImplPtr = card;
                card->Node.NumACLs = 0;
                card->Node.CTime = now();
-               card->Node.Write = RTL8139_Write;
-               card->Node.Read = RTL8139_Read;
-               card->Node.IOCtl = RTL8139_IOCtl;
+               card->Node.Type = &gRTL8139_DevNodeType;
                
                Log_Log("RTL8139", "Card %i 0x%04x, IRQ %i %02x:%02x:%02x:%02x:%02x:%02x",
                        i, card->IOBase, card->IRQ,
@@ -307,7 +313,7 @@ retry:
        return Length;
 }
 
-Uint64 RTL8139_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+Uint64 RTL8139_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
 {
         int    td;
        Uint32  status;
index 958855f..41228d8 100644 (file)
@@ -27,14 +27,25 @@ Uint16      ATA_GetBasePort(int Disk);
 char   *ATA_ReadDir(tVFS_Node *Node, int Pos);
 tVFS_Node      *ATA_FindDir(tVFS_Node *Node, const char *Name);
 Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
-Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer);
  int   ATA_IOCtl(tVFS_Node *Node, int Id, void *Data);
 // Read/Write Interface/Quantiser
 Uint   ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk);
-Uint   ATA_WriteRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk);
+Uint   ATA_WriteRaw(Uint64 Address, Uint Count, const void *Buffer, Uint Disk);
 
 // === GLOBALS ===
 MODULE_DEFINE(0, VERSION, i386ATA, ATA_Install, NULL, "PCI", NULL);
+tVFS_NodeType  gATA_RootNodeType = {
+       .TypeName = "ATA Root Node",
+       .ReadDir = ATA_ReadDir,
+       .FindDir = ATA_FindDir
+       };
+tVFS_NodeType  gATA_DiskNodeType = {
+       .TypeName = "ATA Volume",
+       .Read = ATA_ReadFS,
+       .Write = ATA_WriteFS,
+       .IOCtl = ATA_IOCtl
+       };
 tDevFS_Driver  gATA_DriverInfo = {
        NULL, "ata",
        {
@@ -42,8 +53,7 @@ tDevFS_Driver gATA_DriverInfo = {
                .Size = -1,
                .Flags = VFS_FFLAG_DIRECTORY,
                .ACLs = &gVFS_ACL_EveryoneRX,
-               .ReadDir = ATA_ReadDir,
-               .FindDir = ATA_FindDir
+               .Type = &gATA_RootNodeType
        }
 };
 tATA_Disk      gATA_Disks[MAX_ATA_DISKS];
@@ -171,12 +181,9 @@ int ATA_ScanDisk(int Disk)
        node->Inode = (Disk << 8) | 0xFF;
        node->ImplPtr = gATA_Disks[ Disk ].Name;
 
-       node->ATime = node->MTime
-               = node->CTime = now();
+       node->ATime = node->MTime = node->CTime = now();
 
-       node->Read = ATA_ReadFS;
-       node->Write = ATA_WriteFS;
-       node->IOCtl = ATA_IOCtl;
+       node->Type = &gATA_DiskNodeType;
 
        // --- Scan Partitions ---
        LOG("Reading MBR");
@@ -224,9 +231,7 @@ void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start
        Part->Node.Inode = (Disk << 8) | Num;
        Part->Node.ImplPtr = Part->Name;
 
-       Part->Node.Read = ATA_ReadFS;
-       Part->Node.Write = ATA_WriteFS;
-       Part->Node.IOCtl = ATA_IOCtl;
+       Part->Node.Type = &gATA_DiskNodeType;
        Log_Notice("ATA", "Partition %s at 0x%llx+0x%llx", Part->Name, Part->Start, Part->Length);
        LOG("Made '%s' (&Node=%p)", Part->Name, &Part->Node);
        LEAVE('-');
@@ -330,9 +335,9 @@ Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
 }
 
 /**
- * \fn Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+ * \fn Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
  */
-Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
 {
         int    disk = Node->Inode >> 8;
         int    part = Node->Inode & 0xFF;
@@ -417,9 +422,9 @@ Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
 }
 
 /**
- * \fn Uint ATA_WriteRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
+ * \fn Uint ATA_WriteRaw(Uint64 Address, Uint Count, const void *Buffer, Uint Disk)
  */
-Uint ATA_WriteRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
+Uint ATA_WriteRaw(Uint64 Address, Uint Count, const void *Buffer, Uint Disk)
 {
         int    ret;
        Uint    offset;
index 0821a58..bec157c 100644 (file)
@@ -32,6 +32,17 @@ Uint64       FDD_ReadFS(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer);
 MODULE_DEFINE(0, FDD_VERSION, Storage_FDDv2, FDD_Install, NULL, "x86_ISADMA", NULL);
 tDrive gaFDD_Disks[MAX_DISKS];
 tVFS_Node      gaFDD_DiskNodes[MAX_DISKS];
+tVFS_NodeType  gFDD_RootNodeType = {
+       .TypeName = "FDD Root Node",
+       .ReadDir = FDD_ReadDir,
+       .FindDir = FDD_FindDir,
+       .IOCtl = FDD_IOCtl
+       };
+tVFS_NodeType  gFDD_DevNodeType = {
+       .TypeName = "FDD Device",
+       .Read = FDD_ReadFS,
+       .Write = NULL   // FDD_WriteFS?
+       };
 tDevFS_Driver  gFDD_DriverInfo = {
        NULL, "fdd",
        {
@@ -39,9 +50,7 @@ tDevFS_Driver gFDD_DriverInfo = {
        .NumACLs = 1,
        .ACLs = &gVFS_ACL_EveryoneRX,
        .Flags = VFS_FFLAG_DIRECTORY,
-       .ReadDir = FDD_ReadDir,
-       .FindDir = FDD_FindDir,
-       .IOCtl = FDD_IOCtl
+       .Type = &gFDD_RootNodeType
        }
        };
 
@@ -88,8 +97,7 @@ int FDD_RegisterFS(void)
                gaFDD_DiskNodes[i].Inode = i;
                gaFDD_DiskNodes[i].Flags = 0;
                gaFDD_DiskNodes[i].NumACLs = 0;
-               gaFDD_DiskNodes[i].Read = FDD_ReadFS;
-               gaFDD_DiskNodes[i].Write = NULL;//FDD_WriteFS;
+               gaFDD_DiskNodes[i].Type = &gFDD_DevNodeType;
                gaFDD_DiskNodes[i].Size = 1440*1024;    // TODO: Non 1.44 disks
        }
        
index 9ef8b0b..7b40b14 100644 (file)
@@ -151,8 +151,16 @@ tUHCI_TD *UHCI_int_GetTDFromPhys(tPAddr PAddr)
 {
        // TODO: Fix this to work with a non-contiguous pool
        static tPAddr   td_pool_base;
+       const int pool_size = NUM_TDs;
+        int    offset;
        if(!td_pool_base)       td_pool_base = MM_GetPhysAddr( (tVAddr)gaUHCI_TDPool );
-       return gaUHCI_TDPool + (PAddr - td_pool_base) / sizeof(gaUHCI_TDPool[0]);
+       offset = (PAddr - td_pool_base) / sizeof(gaUHCI_TDPool[0]);
+       if( offset < 0 || offset >= pool_size )
+       {
+               Log_Error("UHCI", "TD PAddr %P not from pool", PAddr);
+               return NULL;
+       }
+       return gaUHCI_TDPool + offset;
 }
 
 void UHCI_int_AppendTD(tUHCI_Controller *Cont, tUHCI_TD *TD)
@@ -375,7 +383,7 @@ void UHCI_InterruptHandler(int IRQ, void *Ptr)
                {
                        link = Host->FrameList[frame];
                        Host->FrameList[frame] = 1;
-                       while( !(link & 1) )
+                       while( link && !(link & 1) )
                        {
                                tUHCI_TD *td = UHCI_int_GetTDFromPhys(link);
                                 int    byte_count = (td->Control&0x7FF)+1;
@@ -385,6 +393,7 @@ void UHCI_InterruptHandler(int IRQ, void *Ptr)
                                if(td->_info.bCopyData)
                                {
                                        void *ptr = (void*)MM_MapTemp(td->BufferPointer);
+                                       Log_Debug("UHCI", "td->_info.DataPtr = %p", td->_info.DataPtr);
                                        memcpy(td->_info.DataPtr, ptr, byte_count);
                                        MM_FreeTemp((tVAddr)ptr);
                                }
index d958956..41f0bd0 100644 (file)
 
 // === PROTOTYPES ===
  int   VGA_Install(char **Arguments);
-Uint64 VGA_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+Uint64 VGA_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer);
  int   VGA_IOCtl(tVFS_Node *Node, int Id, void *Data);
 Uint8  VGA_int_GetColourNibble(Uint16 col);
-Uint16 VGA_int_GetWord(tVT_Char *Char);
+Uint16 VGA_int_GetWord(const tVT_Char *Char);
 void   VGA_int_SetCursor(Sint16 x, Sint16 y);
 // --- 2D Acceleration Functions --
 void   VGA_2D_Fill(void *Ent, Uint16 X, Uint16 Y, Uint16 W, Uint16 H, Uint32 Colour);
@@ -24,14 +24,17 @@ void        VGA_2D_Blit(void *Ent, Uint16 DstX, Uint16 DstY, Uint16 SrcX, Uint16 SrcY,
 
 // === GLOBALS ===
 MODULE_DEFINE(0, 0x000A, x86_VGAText, VGA_Install, NULL, NULL);
+tVFS_NodeType  gVGA_NodeType = {
+       //.Read = VGA_Read,
+       .Write = VGA_Write,
+       .IOCtl = VGA_IOCtl
+       };
 tDevFS_Driver  gVGA_DevInfo = {
        NULL, "x86_VGAText",
        {
        .NumACLs = 0,
        .Size = VGA_WIDTH*VGA_HEIGHT*sizeof(tVT_Char),
-       //.Read = VGA_Read,
-       .Write = VGA_Write,
-       .IOCtl = VGA_IOCtl
+       .Type = &gVGA_NodeType
        }
 };
 Uint16 *gVGA_Framebuffer = (void*)( KERNEL_BASE|0xB8000 );
@@ -65,17 +68,16 @@ int VGA_Install(char **Arguments)
 }
 
 /**
- * \fn Uint64 VGA_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
  * \brief Writes a string of bytes to the VGA controller
  */
-Uint64 VGA_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+Uint64 VGA_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
 {
        if( giVGA_BufferFormat == VIDEO_BUFFMT_TEXT )
        {
                 int    num = Length / sizeof(tVT_Char);
                 int    ofs = Offset / sizeof(tVT_Char);
                 int    i = 0;
-               tVT_Char        *chars = Buffer;
+               const tVT_Char  *chars = Buffer;
                Uint16  word;
                
                //ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
@@ -197,7 +199,7 @@ Uint8 VGA_int_GetColourNibble(Uint16 col)
  * \fn Uint16 VGA_int_GetWord(tVT_Char *Char)
  * \brief Convers a character structure to a VGA character word
  */
-Uint16 VGA_int_GetWord(tVT_Char *Char)
+Uint16 VGA_int_GetWord(const tVT_Char *Char)
 {
        Uint16  ret;
        Uint16  col;
diff --git a/Notes/20120122-Events.txt b/Notes/20120122-Events.txt
new file mode 100644 (file)
index 0000000..b44e846
--- /dev/null
@@ -0,0 +1,16 @@
+Per-thread event system
+
+enum eEvents
+{
+       EVENT_VFS,
+       EVENT_IPCMESSAGE,
+       ...
+};
+
+Uint32 tThread.ActiveEvents
+tSemaphore     tThread.EventSemaphore
+
+
+Threads_PostEvent(tThread *, int EventID);
+Threads_WaitEvents(Uint32 Mask);
+- Clears events watched when wait is over
diff --git a/Notes/20120204-RoutingNames.txt b/Notes/20120204-RoutingNames.txt
new file mode 100644 (file)
index 0000000..b07d033
--- /dev/null
@@ -0,0 +1,19 @@
+Network only?
+- "/Devices/ip/routes/4:0A000200:24"
+Network and Metric?
+- "/Devices/ip/routes/4:0A000200:24:10"
+
+Would it need the interface?
+- "/Devices/ip/routes/0:4:0A000200:24:10"
+
+
+Current model
+- num = "/Devices/ip/routes"->CreateRoute("interface")
+- "/Devices/ip/routes/{num}"->SetNetwork()
+- "/Devices/ip/routes/{num}"->SetSubnetBits()
+- "/Devices/ip/routes/{num}"->SetMetric()
+- "/Devices/ip/routes/{num}"->SetNextHop()
+
+New Model
+- "/Devices/ip/routes/{type}:{network}:{subnet}:{metric}"->SetNextHop()
+- "/Devices/ip/routes/{type}:{network}:{subnet}:{metric}"->SetInterface()?
diff --git a/RunQemu b/RunQemu
index a07a91b..10776d5 100755 (executable)
--- a/RunQemu
+++ b/RunQemu
@@ -31,6 +31,9 @@ while [ $# -ne 0 ]; do
                shift
                QEMU_PARAMS=$QEMU_PARAMS" "$1
                ;;
+       -fwd)
+               _NETTYPE=$_NETTYPE",hostfwd=tcp::10023-10.0.2.10:23"
+               ;;
        -tuntap)
                _NETTYPE="tap"
        esac
index caa174d..33fa974 100644 (file)
@@ -16,7 +16,7 @@ install:
        @$(xMKDIR) $(DISTROOT)/Apps/AxWin ; true
        @$(xMKDIR) $(DISTROOT)/Apps/3.0 ; true
        @$(foreach DIR,$(DIRS), echo --- $(NAME)/$(DIR) && $(SUBMAKE) -C $(DIR) $@ &&) true
-       @$(foreach FILE,$(FILES), $(SUBMAKE) $FILE;) true
+       @$(foreach FILE,$(FILES), $(xCP) $(FILE:-%=%) $(DISTROOT)/Apps/AxWin/3.0/$(FILE:-%=%) &&) true
 
 clean:
        @$(foreach DIR,$(DIRS), $(SUBMAKE) -C $(DIR) $@ &&) true
index 937fb18..6239b76 100644 (file)
@@ -48,7 +48,7 @@ void Decorator_UpdateBorderSize(tWindow *Window)
 
 void Decorator_Redraw(tWindow *Window)
 {
-        int    bActive;
+        int    bActive = 0;
         int    text_width, text_height;
        
        // TODO: This could possibly be expensive, but is there a better way?
index a9c34b7..b8f3065 100644 (file)
@@ -88,7 +88,7 @@ int main(int argc, char *argv[])
                IPC_FillSelect(&nfds, &fds);
                
                nfds ++;
-               if( select(nfds, &fds, NULL, NULL, NULL) == -1 ) {
+               if( _SysSelect(nfds, &fds, NULL, NULL, NULL, THREAD_EVENT_IPCMSG) == -1 ) {
                        _SysDebug("ERROR: select() returned -1");
                        return -1;
                }
index 586a506..7668cbd 100644 (file)
@@ -392,7 +392,7 @@ tElement *Widget_GetElementByPos(tWidgetWin *Info, int X, int Y)
        tElement        *ret, *next, *ele;
        
        next = &Info->RootElement;
-       while(next)
+       do
        {
                ret = next;
                next = NULL;
@@ -405,7 +405,7 @@ tElement *Widget_GetElementByPos(tWidgetWin *Info, int X, int Y)
                        if(Y >= ele->CachedY + ele->CachedH)    continue;
                        next = ele;
                }
-       }
+       } while(next);
        return ret;
 }
 
index 1fc49f8..3220f77 100644 (file)
@@ -22,7 +22,7 @@ tWindow       *gpWM_DownStartWindow[MAX_BUTTONS];
 // === CODE ===
 tWindow *WM_int_GetWindowAtPos(int X, int Y)
 {
-       tWindow *win, *next_win, *ret;
+       tWindow *win, *next_win, *ret = NULL;
        
        next_win = gpWM_RootWindow;
 
index d189e5e..8168c5c 100644 (file)
@@ -171,7 +171,7 @@ tGlyph *_GetGlyph(tFont *Font, uint32_t Codepoint)
                                 prev = next, next = next->Next
                                 );
                        
-                       if( next->Codepoint == Codepoint )
+                       if( next && next->Codepoint == Codepoint )
                                return next;
                        
                }
@@ -185,7 +185,7 @@ tGlyph *_GetGlyph(tFont *Font, uint32_t Codepoint)
                                 prev && prev->Codepoint > Codepoint;
                                 next = prev, prev = prev->Prev
                                 );
-                       if( prev->Codepoint == Codepoint )
+                       if( prev && prev->Codepoint == Codepoint )
                                return prev;
                }
        }
index c1d562f..b03d64d 100644 (file)
@@ -122,7 +122,7 @@ tAxWin_IPCMessage *AxWin3_int_GetIPCMessage(void)
        {
        case CONNTYPE_SENDMESSAGE:
                // TODO: Less hack, I need a version of select for GetMessage etc
-               if(SysGetMessage(NULL, NULL) == 0)      sleep();
+               if(SysGetMessage(NULL, NULL) == 0)      _SysWaitEvent(THREAD_EVENT_IPCMSG);
                while(SysGetMessage(NULL, NULL))
                {
                        pid_t   tid;
diff --git a/Usermode/Applications/dhcpclient_src/Makefile b/Usermode/Applications/dhcpclient_src/Makefile
new file mode 100644 (file)
index 0000000..f14d39e
--- /dev/null
@@ -0,0 +1,11 @@
+# Project: DHCP Client
+
+-include ../Makefile.cfg
+
+LDFLAGS += -lnet
+
+OBJ = main.o
+BIN = dhcpc
+DIR = SBin
+
+-include ../Makefile.tpl
diff --git a/Usermode/Applications/dhcpclient_src/main.c b/Usermode/Applications/dhcpclient_src/main.c
new file mode 100644 (file)
index 0000000..1bd7f1f
--- /dev/null
@@ -0,0 +1,439 @@
+/*
+ */
+#include <unistd.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <net.h>
+
+#define FILENAME_MAX   255
+// --- Translation functions ---
+static inline uint32_t htonl(uint32_t v)
+{
+       return    (((v >> 24) & 0xFF) <<  0)
+               | (((v >> 16) & 0xFF) <<  8)
+               | (((v >>  8) & 0xFF) << 16)
+               | (((v >>  0) & 0xFF) << 24);
+}
+static inline uint16_t htons(uint16_t v)
+{
+       return    (((v >> 8) & 0xFF) <<  0)
+               | (((v >> 0) & 0xFF) <<  8);
+}
+#define htonb(v)       v
+#define ntohl(v)       htonl(v)
+#define ntohs(v)       htons(v)
+
+// === CONSTANTS ===
+enum eStates
+{
+       STATE_PREINIT,
+       STATE_DISCOVER_SENT,
+       STATE_REQUEST_SENT,
+       STATE_COMPLETE
+};
+
+// === STRUCTURES ===
+#define DHCP_MAGIC     0x63825363
+struct sDHCP_Message
+{
+       uint8_t op;
+       uint8_t htype;  // 1 = Ethernet
+       uint8_t hlen;   // 6 bytes for MAC
+       uint8_t hops;   // Hop counting
+       uint32_t        xid;
+       uint16_t        secs;
+       uint16_t        flags;
+       uint32_t        ciaddr;
+       uint32_t        yiaddr;
+       uint32_t        siaddr;
+       uint32_t        giaddr;
+       uint8_t chaddr[16];
+       uint8_t sname[64];
+       uint8_t file[128];
+       uint32_t        dhcp_magic;     // 0x63 0x82 0x53 0x63
+       uint8_t options[];
+};
+
+typedef struct sInterface
+{
+       struct sInterface       *Next;
+       char    *Adapter;
+        int    State;
+        int    Num;
+        int    SocketFD;
+        int    IfaceFD;
+} tInterface;
+
+// === PROTOTYPES ===
+int    main(int argc, char *argv[]);
+void   Scan_Dir(tInterface **IfaceList, const char *Directory);
+int    Start_Interface(tInterface *Iface);
+void   Send_DHCPDISCOVER(tInterface *Iface);
+void   Send_DHCPREQUEST(tInterface *Iface, void *OfferBuffer, int TypeOffset);
+int    Handle_Packet(tInterface *Iface);
+void   SetAddress(tInterface *Iface, void *Addr, void *Mask, void *Router);
+
+// === CODE ===
+int main(int argc, char *argv[])
+{
+       tInterface      *ifaces = NULL, *i;
+
+       // TODO: Scan /Devices and search for network adapters
+       if( argc > 2 ) {
+               fprintf(stderr, "Usage: %s <interface>\n", argv[0]);
+               return -1;
+       }
+       
+       if( argc == 2 ) {
+               ifaces = malloc(sizeof(tInterface));
+               ifaces->Next = NULL;
+               ifaces->Adapter = argv[1];
+       }
+       else {
+               Scan_Dir( &ifaces, "/Devices" );
+       }
+
+       for( i = ifaces; i; i = i->Next )
+       {
+               i->State = STATE_PREINIT;
+               if( Start_Interface(i) < 0 ) {
+                       return -1;
+               }
+               
+               // Send request
+               Send_DHCPDISCOVER(i);
+       }
+
+       while( ifaces ) 
+       {
+                int    maxfd;
+               fd_set  fds;
+       
+               maxfd = 0;
+               FD_ZERO(&fds);
+               for( i = ifaces; i; i = i->Next )
+               {
+                       FD_SET(i->SocketFD, &fds);
+                       if(maxfd < i->SocketFD) maxfd = i->SocketFD;
+               }
+               if( select(maxfd+1, &fds, NULL, NULL, NULL) < 0 )
+               {
+                       // TODO: Check error result
+                       return -1;
+               }
+
+               _SysDebug("select returned");   
+               tInterface      *p;
+               for( p = (void*)&ifaces, i = ifaces; i; p=i,i = i->Next )
+               {
+                       if( FD_ISSET(i->SocketFD, &fds) )
+                       {
+                               if( Handle_Packet( i ) )
+                               {
+                                       close(i->SocketFD);
+                                       close(i->IfaceFD);
+                                       p->Next = i->Next;
+                                       free(i);
+                                       i = p;
+                               }
+                       }
+               }
+       }
+       return 0;
+}
+
+void Scan_Dir(tInterface **IfaceList, const char *Directory)
+{
+       int dp = open(Directory, OPENFLAG_READ);
+       char filename[FILENAME_MAX];
+
+       while( readdir(dp, filename) )
+       {
+                int    pathlen = strlen(Directory) + 1 + strlen(filename) + 1;
+               char    path[pathlen];
+                int    fd;
+               t_sysFInfo      info;
+
+               sprintf(path, "%s/%s", Directory, filename);
+               fd = open(path, 0);
+
+               if( ioctl(fd, 0, NULL) != 9 )
+                       continue ;
+
+               finfo(fd, &info, 0);
+
+               if( info.flags & FILEFLAG_DIRECTORY )
+               {
+                       Scan_Dir(IfaceList, path);
+               }
+               else
+               {
+                       tInterface      *new = malloc(sizeof(tInterface) + pathlen);
+                       new->Adapter = (void*)(new + 1);
+                       strcpy(new->Adapter, path);
+                       new->Next = *IfaceList;
+                       *IfaceList = new;
+               }
+       }
+       close(dp);
+}
+
+// RETURN: Client FD
+int Start_Interface(tInterface *Iface)
+{
+        int    fd, tmp;
+       char    path[] = "/Devices/ip/XXXXX/udpc";
+       char    addr[4] = {0,0,0,0};
+       
+       // TODO: Check that the adapter is not in use
+       
+       // Initialise an interface, with a dummy IP address (zero)
+       fd = open("/Devices/ip", 0);
+       if( fd == -1 ) {
+               fprintf(stderr, "ERROR: Unable to open '/Devices/ip'\n"); 
+               return -1;
+       }
+       Iface->Num = ioctl(fd, 4, (void*)Iface->Adapter);       // Create interface
+       if( Iface->Num == -1 ) {
+               fprintf(stderr, "ERROR: Unable to create new interface\n");
+               return -1;
+       }
+       close(fd);
+       
+       // Open new interface
+       snprintf(path, sizeof(path), "/Devices/ip/%i", Iface->Num);
+       Iface->IfaceFD = fd = open(path, 0);
+       if( fd == -1 ) {
+               fprintf(stderr, "ERROR: Unable to open '%s'\n", path); 
+               return -1;
+       }
+       tmp = 4; ioctl(fd, 4, &tmp);    // Set to IPv4
+       ioctl(fd, 6, addr);     // Set address to 0.0.0.0
+       tmp = 0; ioctl(fd, 7, &tmp);    // Set subnet mask to 0
+
+       // Open UDP Client
+       snprintf(path, sizeof(path), "/Devices/ip/%i/udp", Iface->Num);
+       Iface->SocketFD = fd = open(path, O_RDWR);
+       if( fd == -1 ) {
+               fprintf(stderr, "ERROR: Unable to open '%s'\n", path); 
+               return -1;
+       }
+       tmp = 68; ioctl(fd, 4, &tmp);   // Local port
+       tmp = 67; ioctl(fd, 5, &tmp);   // Remote port
+       tmp = 0;        ioctl(fd, 7, &tmp);     // Remote addr mask - we don't care where the reply comes from
+       addr[0] = addr[1] = addr[2] = addr[3] = 255;    // 255.255.255.255
+       ioctl(fd, 8, addr);     // Remote address
+       
+       return fd;
+}
+
+void Send_DHCPDISCOVER(tInterface *Iface)
+{
+       uint32_t        transaction_id;
+       struct sDHCP_Message    *msg;
+       char    data[8 + sizeof(struct sDHCP_Message) + 3 + 1];
+       msg = (void*)data + 8;
+       
+       transaction_id = rand();
+
+       msg->op    = htonb(1);  // BOOTREQUEST
+       msg->htype = htonb(1);  // 10mb Ethernet
+       msg->hlen  = htonb(6);  // 6 byte MAC
+       msg->hops  = htonb(0);  // Hop count so far
+       msg->xid   = htonl(transaction_id);     // Transaction ID
+       msg->secs  = htons(0);  // secs - No time has elapsed
+       msg->flags = htons(0);  // flags - TODO: Check if broadcast bit need be set
+       msg->ciaddr = htonl(0); // ciaddr - Zero, as we don't have one yet
+       msg->yiaddr = htonl(0); // yiaddr - Zero?
+       msg->siaddr = htonl(0); // siaddr - Zero? maybe -1
+       msg->giaddr = htonl(0); // giaddr - Zero?
+       // Request MAC address from network adapter
+       {
+               int fd = open(Iface->Adapter, 0);
+               // TODO: Check if open() failed
+               ioctl(fd, 4, msg->chaddr);
+               // TODO: Check if ioctl() failed
+               close(fd);
+       }
+       memset(msg->sname, 0, sizeof(msg->sname));      // Nuke the rest
+       memset(msg->file, 0, sizeof(msg->file));        // Nuke the rest
+       msg->dhcp_magic = htonl(DHCP_MAGIC);
+
+       int i = 0;
+       msg->options[i++] =  53;        // DHCP Message Type
+       msg->options[i++] =   1;
+       msg->options[i++] =   1;        // - DHCPDISCOVER
+       msg->options[i++] = 255;        // End of list
+       
+
+       data[0] = 67;   data[1] = 0;    // Port
+       data[2] = 4;    data[3] = 0;    // AddrType
+       data[4] = 255;  data[5] = 255;  data[6] = 255;  data[7] = 255;
+
+       write(Iface->SocketFD, data, sizeof(data));
+       Iface->State = STATE_DISCOVER_SENT;
+}
+
+void Send_DHCPREQUEST(tInterface *Iface, void *OfferPacket, int TypeOffset)
+{
+       struct sDHCP_Message    *msg;
+       msg = (void*) ((char*)OfferPacket) + 8;
+
+       // Reuses old data :)
+       msg->op = 1;
+       msg->options[TypeOffset+2] = 3; // DHCPREQUEST
+       msg->options[TypeOffset+3] = 255;
+       
+       write(Iface->SocketFD, OfferPacket, 8 + sizeof(*msg) + TypeOffset + 4);
+       Iface->State = STATE_REQUEST_SENT;
+}
+
+int Handle_Packet(tInterface *Iface)
+{
+       char    data[8+576];
+       struct sDHCP_Message    *msg = (void*)(data + 8);
+        int    len, i;
+       
+        int    dhcp_msg_type = 0, dhcp_msg_type_ofs;
+       void    *router = NULL;
+       void    *subnet_mask = NULL;
+       
+       _SysDebug("Doing read on %i", Iface->SocketFD);
+       len = read(Iface->SocketFD, data, sizeof(data));
+       _SysDebug("len = %i", len);
+
+       _SysDebug("*msg = {");
+       _SysDebug("  .op = %i", msg->op);
+       _SysDebug("  .htype = %i", msg->htype);
+       _SysDebug("  .ciaddr = 0x%x", ntohl(msg->ciaddr));
+       _SysDebug("  .yiaddr = 0x%x", ntohl(msg->yiaddr));
+       _SysDebug("}");
+       if( msg->op != 2 ) {
+               // Not a response
+               _SysDebug("Not a response message");
+               return 0;
+       }
+
+       if( htonl(msg->dhcp_magic) != DHCP_MAGIC ) {
+               _SysDebug("DHCP magic doesn't match (got 0x%x, expected 0x%x)",
+                       htonl(msg->dhcp_magic), DHCP_MAGIC);
+               return 0;
+       }       
+
+       i = 0;
+       while( i < len - sizeof(*msg) - 8 && msg->options[i] != 255 )
+       {
+               if( msg->options[i] == 0 ) {
+                       i ++;
+                       continue ;
+               }
+               _SysDebug("Option %i, %i bytes long", msg->options[i], msg->options[i+1]);
+               switch(msg->options[i])
+               {
+               case 1:
+                       subnet_mask = &msg->options[i+2];
+                       break;
+               case 3:
+                       router = &msg->options[i+2];
+                       break;
+               case 53:
+                       dhcp_msg_type_ofs = i;
+                       dhcp_msg_type = msg->options[i+2];
+                       break;
+               }
+               i += msg->options[i+1]+2;
+       }
+       
+       _SysDebug("dhcp_msg_type = %i", dhcp_msg_type);
+
+       switch( dhcp_msg_type )
+       {
+       case 1: // DHCPDISCOVER - wut?
+               break;
+       case 2: // DHCPOFFER
+               // Send out request for this address
+               if( Iface->State != STATE_DISCOVER_SENT )       return 0;
+               Send_DHCPREQUEST(Iface, data, dhcp_msg_type_ofs);
+               break;
+       case 3: // DHCPREQUEST - wut?
+               break;
+       case 4: // DHCPDECLINE - ?
+               break;
+       case 5: // DHCPACK
+               // TODO: Apply address
+               SetAddress(Iface, &msg->yiaddr, subnet_mask, router);
+               return 1;
+       }
+       return 0;
+}
+
+void SetAddress(tInterface *Iface, void *Addr, void *Mask, void *Router)
+{
+        int    mask_bits = 0;  
+
+       // Translate the mask
+       if( Mask )
+       {
+               uint8_t *mask = Mask;
+                int    i;
+               _SysDebug("Mask %i.%i.%i.%i", mask[0], mask[1], mask[2], mask[3]);
+               for( i = 0; i < 4 && mask[i] == 0xFF; i ++ ) ;
+               mask_bits = i*8;
+               if( i == 4 )
+               {
+                       // Wut? /32?
+               }
+               else
+               {
+                       switch(mask[i])
+                       {
+                       case 0x00:      mask_bits += 0; break;
+                       case 0x80:      mask_bits += 1; break;
+                       case 0xC0:      mask_bits += 2; break;
+                       case 0xE0:      mask_bits += 3; break;
+                       case 0xF0:      mask_bits += 4; break;
+                       case 0xF8:      mask_bits += 5; break;
+                       case 0xFC:      mask_bits += 6; break;
+                       case 0xFE:      mask_bits += 7; break;
+                       default:
+                               // Bad mask!
+                               break;
+                       }
+               }
+       }
+       
+       {
+               uint8_t *addr = Addr;
+               _SysDebug("Addr %i.%i.%i.%i/%i", addr[0], addr[1], addr[2], addr[3], mask_bits);
+
+               printf("Assigned %i.%i.%i.%i/%i to IF#%i (%s)\n",
+                       addr[0], addr[1], addr[2], addr[3], mask_bits,
+                       Iface->Num, Iface->Adapter
+                       );
+       }
+
+       ioctl(Iface->IfaceFD, 6, Addr);
+       ioctl(Iface->IfaceFD, 7, &mask_bits);
+
+       if( Router );
+       {
+               uint8_t *addr = Router;
+               _SysDebug("Router %i.%i.%i.%i", addr[0], addr[1], addr[2], addr[3]);
+               
+               // Set default route
+                int    fd;
+               fd = open("/Devices/ip/routes/4:00000000:0:0", OPENFLAG_CREATE);
+               if(fd == -1) {
+                       fprintf(stderr, "ERROR: Unable to open default route\n");
+               }
+               else {
+                       char ifname[snprintf(NULL,0,"%i",Iface->Num)+1];
+                       sprintf(ifname, "%i", Iface->Num);
+                       ioctl(fd, ioctl(fd, 3, "set_nexthop"), Router);
+                       ioctl(fd, ioctl(fd, 3, "set_interface"), ifname);
+                       close(fd);
+               }
+       }
+}
+
index 6091bdc..334ea13 100644 (file)
@@ -227,7 +227,7 @@ void DumpRoutes(void)
        
        dp = open(IPSTACK_ROOT"/routes", OPENFLAG_READ);
        
-       printf("ID\tType\tNetwork \tGateway \tMetric\tIFace\n");
+       printf("Type\tNetwork \tGateway \tMetric\tIFace\n");
        
        while( readdir(dp, filename) )
        {
@@ -327,15 +327,24 @@ void DumpRoute(const char *Name)
                return ;
        }
        
-       type = ioctl(fd, 4, NULL);
-       
-       // Ignore -1 values
-       if( type == -1 ) {
-               return ;
+        int    ofs = 2;
+       type = atoi(Name);
+       
+        int    i;
+        int    len = Net_GetAddressSize(type);
+       uint8_t net[len], gw[len];
+        int    subnet, metric;
+       for( i = 0; i < len; i ++ ) {
+               char tmp[5] = "0x00";
+               tmp[2] = Name[ofs++];
+               tmp[3] = Name[ofs++];
+               net[i] = atoi(tmp);
        }
-       
-       // Number
-       printf("%s\t", Name);
+       ofs ++;
+       subnet = atoi(Name+ofs);
+       ofs ++;
+       metric = atoi(Name+ofs);
+       ioctl(fd, ioctl(fd, 3, "get_nexthop"), gw);     // Get Gateway/NextHop
        
        // Get the address type
        switch(type)
@@ -344,37 +353,18 @@ void DumpRoute(const char *Name)
                printf("DISABLED\n");
                break;
        case 4: // IPv4
-               {
-               uint8_t net[4], addr[4];
-                int    subnet, metric;
                printf("IPv4\t");
-               ioctl(fd, ioctl(fd, 3, "get_network"), net);    // Get Network
-               ioctl(fd, ioctl(fd, 3, "get_nexthop"), addr);   // Get Gateway/NextHop
-               subnet = ioctl(fd, ioctl(fd, 3, "getset_subnetbits"), NULL);    // Get Subnet Bits
-               metric = ioctl(fd, ioctl(fd, 3, "getset_metric"), NULL);        // Get Subnet Bits
-               printf("%s/%i\t", Net_PrintAddress(4, net), subnet);
-               printf("%s \t", Net_PrintAddress(4, addr));
-               printf("%i\t", metric);
-               }
                break;
        case 6: // IPv6
-               {
-               uint16_t        net[8], addr[8];
-                int    subnet, metric;
                printf("IPv6\t");
-               ioctl(fd, ioctl(fd, 3, "get_network"), net);    // Get Network
-               ioctl(fd, ioctl(fd, 3, "get_nexthop"), addr);   // Get Gateway/NextHop
-               subnet = ioctl(fd, ioctl(fd, 3, "getset_subnetbits"), NULL);    // Get Subnet Bits
-               metric = ioctl(fd, ioctl(fd, 3, "getset_metric"), NULL);        // Get Subnet Bits
-               printf("%s/%i\t", Net_PrintAddress(6, net), subnet);
-               printf("%s\t", Net_PrintAddress(6, addr));
-               printf("%i\t", metric);
-               }
                break;
        default:        // Unknow
                printf("UNKNOWN (%i)\n", type);
                break;
        }
+       printf("%s/%i\t", Net_PrintAddress(type, net), subnet);
+       printf("%s \t", Net_PrintAddress(type, gw));
+       printf("%i\t", metric);
        
        // Interface
        {
@@ -417,7 +407,6 @@ void AddRoute(const char *Interface, int AddressType, void *Dest, int MaskBits,
 {
         int    fd;
         int    num;
-       char    tmp[sizeof(IPSTACK_ROOT"/routes/") + 5];        // enough for 4 digits
        char    *ifaceToFree = NULL;
        
        // Get interface name
@@ -460,19 +449,33 @@ void AddRoute(const char *Interface, int AddressType, void *Dest, int MaskBits,
        }
        
        // Create route
-       fd = open(IPSTACK_ROOT"/routes", 0);
-       num = ioctl(fd, ioctl(fd, 3, "add_route"), (char*)Interface);
-       close(fd);
-       
-       // Open route
-       sprintf(tmp, IPSTACK_ROOT"/routes/%i", num);
-       fd = open(tmp, 0);
+        int    addrsize = Net_GetAddressSize(AddressType);
+        int    len = snprintf(NULL, 0, "/Devices/ip/routes/%i::%i:%i", AddressType, MaskBits, Metric) + addrsize*2;
+       char    path[len+1];
+       {
+                int    i, ofs;
+               ofs = sprintf(path, "/Devices/ip/routes/%i:", AddressType);
+               for( i = 0; i < addrsize; i ++ )
+                       sprintf(path+ofs+i*2, "%02x", ((uint8_t*)Dest)[i]);
+               ofs += addrsize*2;
+               sprintf(path+ofs, ":%i:%i", MaskBits, Metric);
+       }
+
+       fd = open(path, 0);
+       if( fd != -1 ) {
+               close(fd);
+               fprintf(stderr, "Unable to create route '%s', already exists\n", path);
+               return ;
+       }
+       fd = open(path, OPENFLAG_CREATE, 0);
+       if( fd == -1 ) {
+               fprintf(stderr, "Unable to create '%s'\n", path);
+               return ;
+       }
        
-       ioctl(fd, ioctl(fd, 3, "set_network"), Dest);
        if( NextHop )
                ioctl(fd, ioctl(fd, 3, "set_nexthop"), NextHop);
-       ioctl(fd, ioctl(fd, 3, "getset_subnetbits"), &MaskBits);
-       ioctl(fd, ioctl(fd, 3, "getset_metric"), &Metric);
+       ioctl(fd, ioctl(fd, 3, "set_interface"), (void*)Interface);
        
        close(fd);
        
@@ -483,8 +486,8 @@ void AddRoute(const char *Interface, int AddressType, void *Dest, int MaskBits,
 
 /**
  * \note Debugging HACK!
- * \brief Autoconfigure the specified device to 10.0.2.55/8 using
- *        10.0.2.1 as the gateway.
+ * \brief Autoconfigure the specified device to 10.0.2.55/24 using
+ *        10.0.2.2 as the gateway.
  */
 int DoAutoConfig(const char *Device)
 {
index 20223bb..cf01d60 100644 (file)
@@ -8,8 +8,6 @@
 #include <net.h>\r
 #include <readline.h>\r
 \r
-#define BUFSIZ 1023\r
-\r
 // === TYPES ===\r
 typedef struct sServer {\r
        struct sServer  *Next;\r
index 4c8c84d..33113c8 100644 (file)
@@ -14,7 +14,6 @@
 // === PROTOTYPES ===
 void   PrintUsage(char *ProgName);
 void   PrintHelp(char *ProgName);
- int   GetAddress( char *Address, uint8_t *Addr );
 
 // === GLOBALS ===
  int   giNumberOfPings = 1;
@@ -81,19 +80,7 @@ int main(int argc, char *argv[])
                return 1;
        }
        
-       if( !iface )
-       {
-               iface = Net_GetInterface(type, addr);
-               if( !iface ) {
-                       fprintf(stderr, "Unable to find a route to '%s'\n",
-                               Net_PrintAddress(type, addr)
-                               );
-                       return -1;
-               }
-               
-               printf("iface = '%s'\n", iface);
-       }
-       
+       if( iface )
        {
                char    *_iface = malloc( sizeof("/Devices/ip/") + strlen(iface) + 1 );
                strcpy(_iface, "/Devices/ip/");
@@ -101,14 +88,24 @@ int main(int argc, char *argv[])
                free(iface);    // TODO: Handle when this is not heap
                iface = _iface;
                printf("iface = '%s'\n", iface);
+               fd = open(iface, OPENFLAG_EXEC);
+               if(fd == -1) {
+                       fprintf(stderr, "ERROR: Unable to open interface '%s'\n", iface);
+                       return 1;
+               }
+               
        }
-       
-       fd = open(iface, OPENFLAG_EXEC);
-       if(fd == -1) {
-               fprintf(stderr, "ERROR: Unable to open interface '%s'\n", iface);
-               return 1;
+       else
+       {
+               fd = Net_OpenSocket(type, addr, NULL);
+               if( fd == -1 ) {
+                       fprintf(stderr, "Unable to find a route to '%s'\n",
+                               Net_PrintAddress(type, addr)
+                               );
+                       return -1;
+               }
        }
-               
+       
        call = ioctl(fd, 3, "ping");
        if(call == 0) {
                fprintf(stderr, "ERROR: '%s' does not have a 'ping' call\n", iface);
@@ -137,127 +134,3 @@ void PrintHelp(char *ProgName)
        fprintf(stderr, " -h\tPrint this message\n");
 }
 
-/**
- * \brief Read an IPv4 Address
- */
-int GetAddress4(char *String, uint8_t *Addr)
-{
-        int    i = 0;
-        int    j;
-        int    val;
-       
-       for( j = 0; String[i] && j < 4; j ++ )
-       {
-               val = 0;
-               for( ; String[i] && String[i] != '.'; i++ )
-               {
-                       if('0' > String[i] || String[i] > '9') {
-                               printf("0<c<9 expected, '%c' found\n", String[i]);
-                               return 0;
-                       }
-                       val = val*10 + String[i] - '0';
-               }
-               if(val > 255) {
-                       printf("val > 255 (%i)\n", val);
-                       return 0;
-               }
-               Addr[j] = val;
-               
-               if(String[i] == '.')
-                       i ++;
-       }
-       if( j != 4 ) {
-               printf("4 parts expected, %i found\n", j);
-               return 0;
-       }
-       if(String[i] != '\0') {
-               printf("EOS != '\\0', '%c'\n", String[i]);
-               return 0;
-       }
-       return 1;
-}
-
-/**
- * \brief Read an IPv6 Address
- */
-int GetAddress6(char *String, uint8_t *Addr)
-{
-        int    i = 0;
-        int    j, k;
-        int    val, split = -1, end;
-       uint16_t        hi[8], low[8];
-       
-       for( j = 0; String[i] && j < 8; j ++ )
-       {
-               if(String[i] == ':') {
-                       if(split != -1) {
-                               printf("Two '::'s\n");
-                               return 0;
-                       }
-                       split = j;
-                       i ++;
-                       continue;
-               }
-               
-               val = 0;
-               for( k = 0; String[i] && String[i] != ':'; i++, k++ )
-               {
-                       val *= 16;
-                       if('0' <= String[i] && String[i] <= '9')
-                               val += String[i] - '0';
-                       else if('A' <= String[i] && String[i] <= 'F')
-                               val += String[i] - 'A' + 10;
-                       else if('a' <= String[i] && String[i] <= 'f')
-                               val += String[i] - 'a' + 10;
-                       else {
-                               printf("%c unexpected\n", String[i]);
-                               return 0;
-                       }
-               }
-               
-               if(val > 0xFFFF) {
-                       printf("val (0x%x) > 0xFFFF\n", val);
-                       return 0;
-               }
-               
-               if(split == -1)
-                       hi[j] = val;
-               else
-                       low[j-split] = val;
-               
-               if( String[i] == ':' ) {
-                       i ++;
-               }
-       }
-       end = j;
-       
-       for( j = 0; j < split; j ++ )
-       {
-               Addr[j*2] = hi[j]>>8;
-               Addr[j*2+1] = hi[j]&0xFF;
-       }
-       for( ; j < 8 - (end - split); j++ )
-       {
-               Addr[j*2] = 0;
-               Addr[j*2+1] = 0;
-       }
-       k = 0;
-       for( ; j < 8; j ++, k++)
-       {
-               Addr[j*2] = hi[k]>>8;
-               Addr[j*2+1] = hi[k]&0xFF;
-       }
-       
-       return 1;
-}
-
-int GetAddress(char *String, uint8_t *Addr)
-{
-       if( GetAddress4(String, Addr) )
-               return 4;
-       
-       if( GetAddress6(String, Addr) )
-               return 6;
-       
-       return 0;
-}
index 7733805..3fdbf00 100644 (file)
@@ -7,8 +7,6 @@
 #include <readline.h>\r
 #include <string.h>\r
 \r
-#define BUFSIZ 2048\r
-\r
 // === PROTOTYPES ===\r
  int   main(int argc, char *argv[], char *envp[]);\r
  int   OpenTCP(const char *AddressString, short PortNumber);\r
diff --git a/Usermode/Applications/telnetd_src/Makefile b/Usermode/Applications/telnetd_src/Makefile
new file mode 100644 (file)
index 0000000..a85a071
--- /dev/null
@@ -0,0 +1,12 @@
+# Project: telnetd
+
+-include ../Makefile.cfg
+
+LDFLAGS += -lnet
+
+OBJ = main.o
+BIN = telnetd
+DIR = SBin
+CFLAGS += -std=c99
+
+-include ../Makefile.tpl
diff --git a/Usermode/Applications/telnetd_src/main.c b/Usermode/Applications/telnetd_src/main.c
new file mode 100644 (file)
index 0000000..8a66ad7
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ */
+#include <stddef.h>
+#include <net.h>
+#include <unistd.h>
+#include <stdio.h>
+
+// === TYPES ===
+typedef struct sClient
+{
+        int    Socket;
+        int    stdout;
+        int    stdin;
+} tClient;
+
+// === PROTOTYPES ===
+void   EventLoop(void);
+void   Server_NewClient(int FD);
+void   HandleServerBoundData(tClient *Client);
+void   HandleClientBoundData(tClient *Client);
+
+// === GLOBALS ===
+// --- Configuration ---
+ int   giConfig_MaxClients = 5;
+// --- State ---
+ int   giServerFD;
+tClient        *gaClients;
+ int   giNumClients;
+
+// === CODE ===
+int main(int argc, char *argv[])
+{
+       // TODO: Configure
+
+       // Initialise
+       gaClients = calloc(giConfig_MaxClients, sizeof(tClient));
+
+       // Open server
+       {
+               uint8_t data[16];
+                int    addrtype = Net_ParseAddress("10.0.2.10", data);
+                int    port = 23;
+               giServerFD = Net_OpenSocket(addrtype, data, "tcps");
+               ioctl(giServerFD, 4, &port);    // Set port and start listening
+       }
+
+       // Event loop
+       EventLoop();
+       
+       return 0;
+}
+
+void EventLoop(void)
+{
+       fd_set  fds;
+        int    maxfd;
+
+       void FD_SET_MAX(fd_set *set, int fd, int *maxfd)
+       {
+               FD_SET(fd, set);
+               if(*maxfd < fd) *maxfd = fd;
+       }
+
+       for( ;; )
+       {
+               FD_ZERO(&fds);
+               maxfd = 0;
+               // Fill select
+               FD_SET_MAX(&fds, giServerFD, &maxfd);
+               for( int i = 0; i < giConfig_MaxClients; i ++ )
+               {
+                       if( gaClients[i].Socket == 0 )  continue ;
+                       _SysDebug("Socket = %i, stdout = %i",
+                               gaClients[i].Socket, gaClients[i].stdout);
+                       FD_SET_MAX(&fds, gaClients[i].Socket, &maxfd);
+                       FD_SET_MAX(&fds, gaClients[i].stdout,  &maxfd);
+               }
+               
+               // Select!
+               select( maxfd+1, &fds, NULL, NULL, NULL );
+               
+               // Check events
+               if( FD_ISSET(giServerFD, &fds) )
+               {
+                       Server_NewClient(giServerFD);
+               }
+               for( int i = 0; i < giConfig_MaxClients; i ++ )
+               {
+                       if( FD_ISSET(gaClients[i].Socket, &fds) )
+                       {
+                               // Handle client data
+                               HandleServerBoundData(&gaClients[i]);
+                       }
+                       if( FD_ISSET(gaClients[i].stdout, &fds) )
+                       {
+                               // Handle output from terminal
+                               HandleClientBoundData(&gaClients[i]);
+                       }
+               }
+       }
+}
+
+void Server_NewClient(int FD)
+{
+       tClient *clt;
+       
+       // TODO: Is this done in the IPStack?
+       if( giNumClients == giConfig_MaxClients )
+       {
+               // Open, reject
+               close( _SysOpenChild(FD, "", O_RDWR) );
+               return ;
+       }
+       
+       // Allocate client structure and open socket
+       for( int i = 0; i < giConfig_MaxClients; i ++ )
+       {
+               if( gaClients[i].Socket == 0 ) {
+                       clt = &gaClients[i];
+                       break;
+               }
+       }
+       // Accept the connection
+       clt->Socket = _SysOpenChild(FD, "", O_RDWR);
+       giNumClients ++;
+       
+       // Create stdin/stdout
+       clt->stdin = open("/Devices/fifo/anon", O_RDWR);
+       clt->stdout = open("/Devices/fifo/anon", O_RDWR);
+       
+       // TODO: Arguments and envp
+       {
+               int fds[3] = {clt->stdin, clt->stdout, clt->stdout};
+               const char      *argv[] = {NULL};
+               _SysSpawn("/Acess/SBin/login", argv, argv, 3, fds);
+       }
+}
+
+void HandleServerBoundData(tClient *Client)
+{
+       char    buf[BUFSIZ];
+        int    len;
+       
+       len = read(Client->Socket, buf, BUFSIZ);
+       if( len <= 0 )  return ;
+       write(Client->stdin, buf, len);
+}
+
+void HandleClientBoundData(tClient *Client)
+{
+       char    buf[BUFSIZ];
+        int    len;
+       
+       len = read(Client->stdout, buf, BUFSIZ);
+       if( len <= 0 )  return ;
+       write(Client->Socket, buf, len);
+}
+
index 57e49be..e32dd60 100644 (file)
@@ -19,7 +19,7 @@ DEPFILES := $(addsuffix .dep,$(OBJ))
 all: $(_BIN) $(_XBIN)
 
 clean:
-       $(RM) $(_BIN) $(_XBIN) $(OBJ) $(_BIN).dsm $(DEPFILES)
+       $(RM) $(_BIN) $(_XBIN) $(OBJ) $(_BIN).dsm $(DEPFILES) $(EXTRACLEAN)
 
 install: all
        @echo [xCP] $(DISTROOT)/Libs/$(BIN)
index 95ae441..24c4af3 100644 (file)
@@ -2,7 +2,7 @@
 OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm",
              "elf32-littlearm")
 OUTPUT_ARCH(arm)
-ENTRY(_start)
+ENTRY(start)
 SEARCH_DIR(__LIBDIR)
 INPUT(crt0.o)
 SECTIONS
index 178b75e..49afb1e 100644 (file)
@@ -5,9 +5,10 @@
 -include ../Makefile.cfg
 
 OBJ := main.o lib.o loadlib.o export.o elf.o pe.o
-OBJ += arch/$(ARCHDIR).ao
+OBJ += arch/$(ARCHDIR).ao_
 BIN = ld-acess.so
 EXTRABIN := libld-acess.so
+EXTRACLEAN := $(_OBJPREFIX)_stublib.o
 
 CFLAGS   = -g -Wall -fno-builtin -fno-leading-underscore -fno-stack-protector -fPIC
 CFLAGS  += $(CPPFLAGS)
@@ -23,16 +24,18 @@ $(_XBIN): $(_OBJPREFIX)_stublib.o
 
 
 # Override .ao to look in the object prefix for the source
-%.ao: %.$(ASSUFFIX)
+$(_OBJPREFIX)arch/$(ARCHDIR).ao_: $(_OBJPREFIX)arch/$(ARCHDIR).$(ASSUFFIX)
        @echo [AS] -o $@
        @mkdir -p $(dir $@)
        @$(AS) $(ASFLAGS) -o $@ $<
 
-.PRECIOUS: $(OBJ:%.ao=%.asm)
+#.PRECIOUS: $(OBJ:%.ao=%.asm)
 
 # Preprocessing objects if needed
-$(_OBJPREFIX)%: %.h
+$(_OBJPREFIX)arch/$(ARCHDIR).$(ASSUFFIX): arch/$(ARCHDIR).$(ASSUFFIX).h arch/syscalls.s.h
        @echo [CPP] -o $@
        @mkdir -p $(dir $@)
        @$(CPP) $(CPPFLAGS) -P -D__ASSEMBLER__ $< -o $@
 
+$(_OBJPREFIX)_stublib.o: arch/syscalls.s.h
+
diff --git a/Usermode/Libraries/ld-acess.so_src/arch/.gitignore b/Usermode/Libraries/ld-acess.so_src/arch/.gitignore
new file mode 100644 (file)
index 0000000..aa6f529
--- /dev/null
@@ -0,0 +1 @@
+x86.asm
index 1c7a5bb..cd20d80 100644 (file)
@@ -5,6 +5,7 @@ SYSCALL2(clone, SYS_CLONE)
 SYSCALL2(kill, SYS_KILL)
 SYSCALL0(yield, SYS_YIELD)
 SYSCALL0(sleep, SYS_SLEEP)
+SYSCALL1(_SysWaitEvent, SYS_WAITEVENT)
 SYSCALL2(waittid, SYS_WAITTID)
 
 SYSCALL0(gettid, SYS_GETTID)
@@ -23,7 +24,7 @@ SYSCALL1(SysSetPri, SYS_SETPRI)
 SYSCALL3(SysSendMessage, SYS_SENDMSG)
 SYSCALL3(SysGetMessage, SYS_GETMSG)
 
-SYSCALL3(SysSpawn, SYS_SPAWN)
+SYSCALL5(_SysSpawn, SYS_SPAWN)
 SYSCALL3(execve, SYS_EXECVE)
 SYSCALL2(SysLoadBin, SYS_LOADBIN)
 SYSCALL1(SysUnloadBin, SYS_UNLOADBIN)
@@ -47,6 +48,6 @@ SYSCALL2(_SysGetACL,SYS_GETACL)       // int, void*
 SYSCALL1(chdir, SYS_CHDIR)     // char*
 SYSCALL3(ioctl, SYS_IOCTL)     // int, int, void*
 SYSCALL4(_SysMount, SYS_MOUNT) // char*, char*, char*, char*
-SYSCALL5(select, SYS_SELECT)   // int, fd_set*, fd_set*, fd_set*, tTime*
+SYSCALL6(_SysSelect, SYS_SELECT)       // int, fd_set*, fd_set*, fd_set*, tTime*, uint32_t
 
 SYSCALL3(_SysOpenChild, SYS_OPENCHILD)
index 379efc1..6f67811 100644 (file)
@@ -57,7 +57,7 @@ extern void   SysDebugV(const char *fmt, ...);
 extern void    *SysLoadBin(const char *path, void **entry);
 extern int     SysUnloadBin(void *Base);
 extern void    SysSetFaultHandler(int (*Hanlder)(int));
-extern int     open(const char *filename, int flags);
+extern int     open(const char *filename, int flags, ...);
 extern int     close(int fd);
 
 // === ELF Loader ===
index 2da0e6b..41ba01f 100644 (file)
@@ -27,6 +27,7 @@ const struct {
        EXP(kill),
        EXP(yield),
        EXP(sleep),
+       EXP(_SysWaitEvent),
        EXP(waittid),
        EXP(gettid),
        EXP(getpid),
@@ -44,7 +45,7 @@ const struct {
        EXP(SysSendMessage),
        EXP(SysGetMessage),
 
-       //EXP(SysSpawn),
+       EXP(_SysSpawn),
        EXP(execve),
        EXP(SysLoadBin),
        EXP(SysUnloadBin),
@@ -64,7 +65,7 @@ const struct {
        EXP(chdir),
        EXP(ioctl),
        EXP(_SysMount),
-       EXP(select),
+       EXP(_SysSelect),
 
        EXP(_SysOpenChild),
        
index 8d9960c..7142820 100644 (file)
@@ -8,7 +8,7 @@ CFLAGS   +=
 ASFLAGS  +=\r
 LDFLAGS  += -soname libc.so -Map map.txt -lgcc\r
 \r
-OBJ  = stub.o heap.o stdlib.o env.o fileIO.o string.o select.o\r
+OBJ  = stub.o heap.o stdlib.o env.o fileIO.o string.o select.o rand.o\r
 OBJ += arch/$(ARCHDIR).ao\r
 # signals.o\r
 DEPFILES := $(OBJ:%.o=%.d)\r
diff --git a/Usermode/Libraries/libc.so_src/rand.c b/Usermode/Libraries/libc.so_src/rand.c
new file mode 100644 (file)
index 0000000..acdfddf
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Acess2 Lib C
+ * - By John Hodge (thePowersGang)
+ *
+ * rand.c
+ * - srand/rand/rand_p functions
+ */
+#include <stdlib.h>
+
+// === GLOBALS ===
+unsigned int   _rand_state_x = 123456789;
+unsigned int   _rand_state_y = 362436069;
+unsigned int   _rand_state_z = 521288629;
+unsigned int   _rand_state_w = 88675123;
+
+// === FUNCTIONS ===
+int rand_p(unsigned int *seedp)
+{
+       const int const_a = 0x731ADE, const_c = 12345;
+       // Linear Congruency
+       *seedp = *seedp * const_a + const_c;
+       return *seedp;
+}
+
+void srand(unsigned int seed)
+{
+       _rand_state_x = rand_p( &seed );
+       _rand_state_y = rand_p( &seed );
+       _rand_state_z = rand_p( &seed );
+       _rand_state_w = rand_p( &seed );
+}
+
+int rand(void)
+{
+       unsigned int t;
+       
+       t = _rand_state_x ^ (_rand_state_x << 11);
+       _rand_state_x = _rand_state_y; _rand_state_y = _rand_state_z; _rand_state_z = _rand_state_w;
+       return _rand_state_w = _rand_state_w ^ (_rand_state_w >> 19) ^ t ^ (t >> 8); 
+}
+
index 31b23e5..0430c84 100644 (file)
 #include <stdio.h>
 #define DEBUG  0
 
+static inline uint32_t htonl(uint32_t v)
+{
+       return    (((v >> 24) & 0xFF) <<  0)
+               | (((v >> 16) & 0xFF) <<  8)
+               | (((v >>  8) & 0xFF) << 16)
+               | (((v >>  0) & 0xFF) << 24);
+}
+static inline uint16_t htons(uint16_t v)
+{
+       return    (((v >> 8) & 0xFF) <<  0)
+               | (((v >> 0) & 0xFF) <<  8);
+}
+#define htonb(v)       v
+#define ntohl(v)       htonl(v)
+#define ntohs(v)       htons(v)
+#define ntohb(v)       v
+
 #define __thread               // Disable TLS
 
 /**
@@ -191,8 +208,8 @@ static const char *Net_PrintIPv6Address(uint16_t *Address)
        #endif
        
        sprintf(ret, "%x:%x:%x:%x:%x:%x:%x:%x",
-               Address[0], Address[1], Address[2], Address[3],
-               Address[4], Address[5], Address[6], Address[7]
+               ntohs(Address[0]), ntohs(Address[1]), ntohs(Address[2]), ntohs(Address[3]),
+               ntohs(Address[4]), ntohs(Address[5]), ntohs(Address[6]), ntohs(Address[7])
                );
        
        return ret;
index b39d754..403a339 100644 (file)
@@ -11,6 +11,7 @@
 #include <stdlib.h>
 #include <stdio.h>
 
+
 // === CODE ===
 int SoMain(void)
 {
@@ -40,16 +41,16 @@ int Net_OpenSocket(int AddrType, void *Addr, const char *Filename)
        
        if(Filename)
        {
-                int    len = snprintf(NULL, 100, "/Devices/ip/routes/%i:%s/%s", AddrType, hexAddr, Filename);
+                int    len = snprintf(NULL, 100, "/Devices/ip/routes/@%i:%s/%s", AddrType, hexAddr, Filename);
                char    path[len+1];
-               snprintf(path, 100, "/Devices/ip/routes/%i:%s/%s", AddrType, hexAddr, Filename);
+               snprintf(path, 100, "/Devices/ip/routes/@%i:%s/%s", AddrType, hexAddr, Filename);
                return open(path, OPENFLAG_READ|OPENFLAG_WRITE);
        }
        else
        {
-                int    len = snprintf(NULL, 100, "/Devices/ip/routes/%i:%s", AddrType, hexAddr);
+                int    len = snprintf(NULL, 100, "/Devices/ip/routes/@%i:%s", AddrType, hexAddr);
                char    path[len+1];
-               snprintf(path, 100, "/Devices/ip/routes/%i:%s", AddrType, hexAddr);
+               snprintf(path, 100, "/Devices/ip/routes/@%i:%s", AddrType, hexAddr);
                return open(path, OPENFLAG_READ);
        }
 }
@@ -89,15 +90,18 @@ char *Net_GetInterface(int AddressType, void *Address)
        
        // Check answer validity
        if( routeNum > 0 ) {
-                int    len = sprintf(NULL, "/Devices/ip/routes/%i", routeNum);
+                int    len = sprintf(NULL, "/Devices/ip/routes/#%i", routeNum);
                char    buf[len+1];
                char    *ret;
                
-               sprintf(buf, "/Devices/ip/routes/%i", routeNum);
+               sprintf(buf, "/Devices/ip/routes/#%i", routeNum);
                
                // Open route
                fd = open(buf, 0);
-               if( !fd )       return NULL;    // Shouldn't happen :/
+               if( fd == -1 ) {
+                       fprintf(stderr, "Net_GetInterface - ERROR: Unabel to open %s\n", buf);
+                       return NULL;    // Shouldn't happen :/
+               }
                
                // Allocate space for name
                ret = malloc( ioctl(fd, ioctl(fd, 3, "get_interface"), NULL) + 1 );
diff --git a/Usermode/include/acess/intdefs.h b/Usermode/include/acess/intdefs.h
new file mode 100644 (file)
index 0000000..c33e7d5
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ */
+#ifndef _ACESS_INTDEFS_H_
+#define _ACESS_INTDEFS_H_
+
+#define INT_MIN        -0x80000000
+#define INT_MAX        0x7FFFFFFF
+
+typedef unsigned char  __uint8_t;
+typedef unsigned short __uint16_t;
+typedef unsigned int   __uint32_t;
+typedef unsigned long long     __uint64_t;
+
+typedef signed char            __int8_t;
+typedef signed short   __int16_t;
+typedef signed int             __int32_t;
+typedef signed long long       __int64_t;
+
+#if ARCHDIR_is_x86
+typedef __int32_t      __intptr_t;
+typedef __uint32_t     __uintptr_t;
+#elif ARCHDIR_is_x86_64
+typedef __int64_t      __intptr_t;
+typedef __uint64_t     __uintptr_t;
+#elif ARCHDIR_is_armv7
+typedef __int32_t      __intptr_t;
+typedef __uint32_t     __uintptr_t;
+#else
+# error "Unknown pointer size"
+#endif
+
+//typedef uint64_t     off_t;
+
+#endif
+
index 6d7751b..cdd0187 100644 (file)
 # define NULL  ((void*)0)
 #endif
 
+#define THREAD_EVENT_VFS       0x0001
+#define THREAD_EVENT_IPCMSG    0x0002
+#define THREAD_EVENT_SIGNAL    0x0004
+
 #define OPENFLAG_EXEC  0x01
 #define OPENFLAG_READ  0x02
 #define OPENFLAG_WRITE 0x04
@@ -38,10 +42,12 @@ extern void _exit(int status)       __attribute__((noreturn));
 extern void    sleep(void);
 extern void    yield(void);
 extern int     kill(int pid, int sig);
-extern void    wait(int miliseconds);
+//extern void  wait(int miliseconds);
+extern int     _SysWaitEvent(int EventMask);
 extern int     waittid(int id, int *status);
 extern int     clone(int flags, void *stack);
 extern int     execve(char *path, char **argv, char **envp);
+extern int     _SysSpawn(const char *Path, const char **argv, const char **envp, int nFDs, int *FDs);
 extern int     gettid(void);
 extern int     getpid(void);
 extern int     _SysSetFaultHandler(int (*Handler)(int));
@@ -56,7 +62,7 @@ extern void   setgid(int id);
 
 // --- VFS ---
 extern int     chdir(const char *dir);
-extern int     open(const char *path, int flags);
+extern int     open(const char *path, int flags, ...);
 extern int     reopen(int fd, const char *path, int flags);
 extern int     close(int fd);
 extern uint    read(int fd, void *buffer, uint length);
@@ -69,7 +75,8 @@ extern int    readdir(int fd, char *dest);
 extern int     _SysOpenChild(int fd, char *name, int flags);
 extern int     _SysGetACL(int fd, t_sysACL *dest);
 extern int     _SysMount(const char *Device, const char *Directory, const char *Type, const char *Options);
-extern int     select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errfds, time_t *timeout);
+extern int     _SysSelect(int nfds, fd_set *read, fd_set *write, fd_set *err, time_t *timeout, int extraevents);
+#define select(nfs, rdfds, wrfds, erfds, timeout)      _SysSelect(nfs, rdfds, wrfds, erfds, timeout, 0)
 
 // --- IPC ---
 extern int     SysSendMessage(pid_t dest, uint length, const void *Data);
index 738541d..ea352f3 100644 (file)
@@ -3,13 +3,26 @@
 
 // TODO: Fully implement errno.h, make sure it matches the kernel one
 
+extern int     _errno;
 #define        errno   _errno
 
 #define strerror(_x)   "Unimplemented"
 
 enum
 {
-       EINVAL
+       EOK,
+       EINVAL,
+       ERANGE,
+       ENODEV,
+       EBADF,
+       EINTR,
+       EAGAIN,
+       ENOMEM,
+
+       EADDRNOTAVAIL,
+       EINPROGRESS,
+
+       E_LAST
 };
 
 #endif
index f71b2e7..cc72b00 100644 (file)
@@ -8,7 +8,13 @@
 #ifndef _SIGNAL_H_
 #define _SIGNAL_H_
 
+#define SIG_DFL        ((void*)0)
+#define SIG_ERR        ((void*)-1)
 
+#define        SIGABRT 6
+
+#define SIGPIPE        1001
+#define SIGCHLD        1002
 
 #endif
 
diff --git a/Usermode/include/stddef.h b/Usermode/include/stddef.h
new file mode 100644 (file)
index 0000000..efbabb3
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef _STDDEF_H_
+#define _STDDEF_H_
+
+#ifndef NULL
+# define NULL  ((void*)0)
+#endif
+
+typedef unsigned int   size_t;
+
+#endif
index d0f949e..5df57ea 100644 (file)
@@ -3,31 +3,22 @@
 #ifndef _STDINT_H_
 #define _STDINT_H_
 
+#include "acess/intdefs.h"
+
 #define INT_MIN        -0x80000000
 #define INT_MAX        0x7FFFFFFF
 
-typedef unsigned char  uint8_t;
-typedef unsigned short uint16_t;
-typedef unsigned int   uint32_t;
-typedef unsigned long long     uint64_t;
-
-typedef signed char            int8_t;
-typedef signed short   int16_t;
-typedef signed int             int32_t;
-typedef signed long long       int64_t;
+typedef __uint8_t      uint8_t;
+typedef __uint16_t     uint16_t;
+typedef __uint32_t     uint32_t;
+typedef __uint64_t     uint64_t;
+typedef __int8_t       int8_t;
+typedef __int16_t      int16_t;
+typedef __int32_t      int32_t;
+typedef __int64_t      int64_t;
 
-#if ARCHDIR_is_x86
-typedef int32_t        intptr_t;
-typedef uint32_t       uintptr_t;
-#elif ARCHDIR_is_x86_64
-typedef int64_t        intptr_t;
-typedef uint64_t       uintptr_t;
-#elif ARCHDIR_is_armv7
-typedef int32_t        intptr_t;
-typedef uint32_t       uintptr_t;
-#else
-# error "Unknown pointer size"
-#endif
+typedef __intptr_t     intptr_t;
+typedef __uintptr_t    uintptr_t;
 
 //typedef uint64_t     off_t;
 
index 8d95065..be4f20a 100644 (file)
@@ -13,6 +13,7 @@ typedef struct sFILE  FILE;
 
 /* === CONSTANTS === */
 #define EOF    (-1)
+#define BUFSIZ 1024
 
 /* --- Standard IO --- */
 extern int     printf(const char *format, ...);
index 160993d..0e6d9e0 100644 (file)
@@ -35,6 +35,11 @@ extern void  *calloc(size_t __nmemb, size_t __size);
 extern void    *realloc(void *__ptr, size_t __size);\r
 extern int     IsHeap(void *ptr);\r
 \r
+/* --- Random --- */\r
+extern void    srand(unsigned int seed);\r
+extern int     rand(void);\r
+extern int     rand_p(unsigned int *seedp);\r
+\r
 #ifndef SEEK_CUR\r
 # define SEEK_CUR      0\r
 # define SEEK_SET      1\r
index 10384ba..ecd0fa3 100644 (file)
@@ -5,18 +5,19 @@
 #ifndef _SYS_STAT_H_
 #define _SYS_STAT_H_
 
-#include <stdint.h>    /* Evil */
-#include <stddef.h>
+#include <acess/intdefs.h>     /* Evil */
+#include "../stddef.h"
 
+;
 typedef void   *dev_t; /* TODO: How to identify a device with Acess */
-typedef uint64_t       ino_t;
+typedef __uint64_t     ino_t;
 typedef unsigned int   blksize_t;
-typedef uint64_t       blkcnt_t;
+typedef __uint64_t     blkcnt_t;
 typedef unsigned int   nlink_t;
-typedef uint32_t       mode_t;
+typedef __uint32_t     mode_t;
 
-typedef uint32_t       uid_t;
-typedef uint32_t       gid_t;
+typedef __uint32_t     uid_t;
+typedef __uint32_t     gid_t;
 
 #define        S_IFMT          0170000 /* type of file */
 #define                S_IFDIR 0040000 /* directory */
index 0cc50d1..206211d 100644 (file)
@@ -3,6 +3,8 @@
 #ifndef _SYS_TYPES_H
 #define _SYS_TYPES_H
 
+#include <acess/intdefs.h>
+
 typedef struct stat    t_fstat;
 
 #define FD_SETSIZE     128
@@ -52,6 +54,10 @@ extern void  FD_CLR(int fd, fd_set *fdsetp);
 extern void    FD_SET(int fd, fd_set *fdsetp);
 extern int     FD_ISSET(int fd, fd_set *fdsetp);
 
+typedef __uint8_t      u_int8_t;
+typedef __uint16_t     u_int16_t;
+typedef __uint32_t     u_int32_t;
+
 #include "../sys/stat.h"
 
 #endif
index 7861255..bd7afce 100644 (file)
@@ -8,6 +8,9 @@
 #ifndef _TIME_H_
 #define _TIME_H_
 
+#include <acess/intdefs.h>
+#include <sys/types.h> // time_t
+
 struct tm
 {
         int    tm_sec;
@@ -21,5 +24,11 @@ struct tm
         int    tm_isdst;
 };
 
+#define CLOCKS_PER_SEC 1000
+
+typedef signed long long       clock_t;
+
+extern clock_t clock();
+
 #endif
 
diff --git a/Usermode/include/unistd.h b/Usermode/include/unistd.h
new file mode 100644 (file)
index 0000000..d7d194d
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef _UNISTD_H_
+#define _UNISTD_H_
+
+#define        O_RDWR  (OPENFLAG_READ|OPENFLAG_WRITE)
+
+#include "acess/sys.h"
+
+
+#endif
+

UCC git Repository :: git.ucc.asn.au