x86_64 support, requiring a slight refactor to the build system.
authorJohn Hodge <[email protected]>
Tue, 11 May 2010 13:47:01 +0000 (21:47 +0800)
committerJohn Hodge <[email protected]>
Tue, 11 May 2010 13:47:01 +0000 (21:47 +0800)
- The x86_64 port does not compile yet, still working on that
- The new cross compiler I'm using for the 32-bit builds is a little
  more pedantic, so it seems that the i386 doesn't build either.

25 files changed:
Kernel/Makefile.BuildNum
Kernel/arch/x86/include/proc.h
Kernel/arch/x86_64/Makefile
Kernel/arch/x86_64/include/arch.h
Kernel/arch/x86_64/include/mm_virt.h
Kernel/arch/x86_64/include/proc.h [new file with mode: 0644]
Kernel/arch/x86_64/include/vm8086.h [new file with mode: 0644]
Kernel/arch/x86_64/lib.c
Kernel/arch/x86_64/link.ld [new file with mode: 0644]
Kernel/arch/x86_64/rme.c [new symlink]
Kernel/arch/x86_64/rme.h [new symlink]
Kernel/bin/elf.c
Kernel/binary.c
Kernel/include/acess.h
Kernel/include/threads.h
Kernel/messages.c
Kernel/vfs/open.c
Makefile
Makefile.cfg
Makefile.i386.cfg [new file with mode: 0644]
Makefile.x86_64.cfg [new file with mode: 0644]
Modules/IPStack/Makefile
Modules/Makefile.tpl
Modules/Storage/ATA/main.c
Modules/Storage/FDD/fdd.c

index 334be63..c6eedfb 100644 (file)
@@ -1 +1 @@
-BUILD_NUM = 2145
+BUILD_NUM = 2150
index 0a1d754..baf9402 100644 (file)
@@ -7,9 +7,6 @@
 
 #include <threads.h>
 
-// === CONSTANTS ===
-#define GETMSG_IGNORE  ((void*)-1)
-
 // === TYPES ===
 #if USE_MP
 typedef struct sCPU
index 3820a69..68b9b61 100644 (file)
@@ -10,7 +10,7 @@
 #OBJDUMP = objdump
 
 CPPFLAGS       =
-CFLAGS         =
+CFLAGS         = $(KERNEL_CFLAGS)
 ASFLAGS                = -f elf
 
 ifeq ($(ARCH),amd64)
index d812a51..e076b08 100644 (file)
@@ -5,17 +5,24 @@
 #ifndef _ARCH_H_
 #define _ARCH_H_
 
+#include <stdint.h>
 #define KERNEL_BASE    0xFFFF8000##00000000
+#define BITS   64
 
 // === Core Types ===
 typedef signed char    Sint8;
 typedef unsigned char  Uint8;
 typedef signed short   Sint16;
 typedef unsigned short Uint16;
-typedef signed long    Sint32;
-typedef unsigned long  Uint32;
-typedef signed long long       Sint64;
-typedef unsigned long long     Uint64;
+typedef signed int     Sint32;
+typedef unsigned int   Uint32;
+#if __WORDSIZE == 64
+typedef signed long int        Sint64;
+typedef unsigned long int      Uint64;
+#else
+typedef signed long long int   Sint64;
+typedef unsigned long long int Uint64;
+#endif
 
 typedef Uint64 Uint;
 typedef Uint64 tPAddr;
@@ -24,10 +31,38 @@ typedef Uint64      tVAddr;
 //typedef unsigned int size_t;
 typedef Uint64 size_t;
 
-typedef int    tSpinlock;
+typedef volatile int    tSpinlock;
+#define IS_LOCKED(lockptr)      (!!(*(tSpinlock*)lockptr))
+#define LOCK(lockptr)   do {int v=1;\
+       while(v)\
+       __asm__ __volatile__("lock xchgl %%eax, (%%edi)":"=a"(v):"a"(1),"D"(lockptr));\
+       }while(0)
+#define RELEASE(lockptr)       __asm__ __volatile__("lock andl $0, (%%edi)"::"D"(lockptr));
+#define HALT()  __asm__ __volatile__ ("hlt")
 
-#define LOCK(_ptr)
-#define RELEASE(_ptr)
+// Systemcall Registers
+typedef struct sSyscallRegs
+{
+       Uint    Arg4, Arg5;     // RDI, RSI
+       Uint    Arg6;   // RBP
+       Uint    Resvd2[1];      // Kernel RSP
+       union {
+               Uint    Arg1;
+               Uint    Error;
+       };      // RBX
+       union {
+               Uint    Arg3;
+               Uint    RetHi;  // High 64 bits of ret
+       };      // RDX
+       Uint    Arg2;   // RCX
+       union {
+               Uint    Num;
+               Uint    Return;
+       };      // RAX
+       Uint    Resvd3[5];      // Int, Err, rip, CS, ...
+       Uint    StackPointer;   // RSP
+       Uint    Resvd4[1];      // SS   
+}      tSyscallRegs;
 
 #endif
 
index 2dd28dd..8032cc7 100644 (file)
@@ -9,6 +9,8 @@
 #ifndef _VMEM_H_
 #define _VMEM_H_
 
+#include <arch.h>
+
 // === Memory Location Definitions ===
 /*
  * Userland - Lower Half
  * 0xFFFF8000 00000000 - 0xFFFFFFFF FFFFFFFF   2**47   Kernel Range
  *       8000 00000000 -       8000 7FFFFFFF   2 GiB   Identity Map
  *       8000 80000000 -       8001 00000000   2 GiB   Kernel Heap
- *       9000 00000000 0       9800 00000000   cbf     Module Space
+ *       9000 00000000 -       9800 00000000   cbf     Module Space
+ *       9800 00000000 -       9900 00000000   cbf     Per-Process Data
+ *       9900 00000000 -       9A00 00000000   cbf     Kernel VFS
  */
 
-#define        KERNEL_BASE     0xFFF8000##00000000
-#define MM_KHEAP_BASE  (KERNEL_BASE|0x80000000)
-#define MM_KHEAP_MAX   (KERNEL_BASE|0x1##00000000)
+#define        MM_USER_MIN     0x00008FFF##FFFFF000
+//#define      KERNEL_BASE     0xFFF8000##00000000
+#define MM_KHEAP_BASE  (KERNEL_BASE|(0x0000##80000000))
+#define MM_KHEAP_MAX   (KERNEL_BASE|(0x0001##00000000))
+#define MM_MODULE_MIN  (KERNEL_BASE|(0x1000##00000000))
+#define MM_MODULE_MAX  (KERNEL_BASE|(0x1800##00000000))
+#define MM_PPD_BASE    (KERNEL_BASE|(0x1800##00000000))
+#define MM_PPD_VFS     (KERNEL_BASE|(0x1880##00000000))
+#define MM_KERNEL_VFS  (KERNEL_BASE|(0x1900##00000000))
 
 #endif
diff --git a/Kernel/arch/x86_64/include/proc.h b/Kernel/arch/x86_64/include/proc.h
new file mode 100644 (file)
index 0000000..016375f
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Acess2 x86_64 Port
+ * 
+ * proc.h - Process/Thread management code
+ */
+#ifndef _PROC_H_
+#define _PROC_H_
+
+#include <arch.h>
+
+typedef struct sMemoryState
+{
+       tPAddr  CR3;
+}      tMemoryState;
+
+typedef struct sTaskState
+{
+       Uint    RIP, RSP, RBP;
+}      tTaskState;
+
+#endif
+
diff --git a/Kernel/arch/x86_64/include/vm8086.h b/Kernel/arch/x86_64/include/vm8086.h
new file mode 100644 (file)
index 0000000..353ad7a
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Acess2 VM8086 BIOS Interface
+ * - By John Hodge (thePowersGang)
+ *
+ * vm8086.h
+ * - Core Header
+ */
+#ifndef _VM80806_H_
+#define _VM80806_H_
+
+// === TYPES ===
+/**
+ * \note Semi-opaque - Past \a .IP, the implementation may add any data
+ *       it needs to the state.
+ */
+typedef struct sVM8086
+{
+       Uint16  AX, CX, DX, BX;
+       Uint16  BP, SP, SI, DI;
+       
+       Uint16  SS, DS, ES;
+       
+       Uint16  CS, IP;
+       
+       struct sVM8086_InternalData     *Internal;
+}      tVM8086;
+
+// === FUNCTIONS ===
+/**
+ * \brief Create an instance of the VM8086 Emulator
+ * \note Do not free this pointer with ::free, instead use ::VM8086_Free
+ * \return Pointer to a tVM8086 structure, this structure may be larger than
+ *         tVM8086 due to internal data.
+ */
+extern tVM8086 *VM8086_Init(void);
+/**
+ * \brief Free an allocated tVM8086 structure
+ * \param State        Emulator state to free
+ */
+extern void    VM8086_Free(tVM8086 *State);
+/**
+ * \brief Allocate a piece of memory in the emulated address space and
+ *        return a host and emulated pointer to it.
+ * \param State        Emulator state
+ * \param Size Size of memory block
+ * \param Segment      Pointer to location to store the allocated memory's segment
+ * \param Offset       Pointet to location to store the allocated memory's offset
+ * \return Host pointer to the allocated memory
+ */
+extern void    *VM8086_Allocate(tVM8086 *State, int Size, Uint16 *Segment, Uint16 *Offset);
+/**
+ * \brief Gets a pointer to a piece of emulated memory
+ * \todo Only 1 machine page is garenteed to be contiguous
+ * \param State        Emulator State
+ * \param Segment      Source Segment
+ * \param Offset       Source Offset
+ * \return Host pointer to the emulated memory
+ */
+extern void *VM8086_GetPointer(tVM8086 *State, Uint16 Segment, Uint16 Ofs);
+/**
+ * \brief Calls a real-mode interrupt described by the current state of the IVT.
+ * \param State        Emulator State
+ * \param Interrupt    BIOS Interrupt to call
+ */
+extern void    VM8086_Int(tVM8086 *State, Uint8 Interrupt);
+
+#endif
index e69de29..e3669c0 100644 (file)
@@ -0,0 +1,93 @@
+/*
+ */
+#include <acess.h>
+#include <arch.h>
+
+// === CODE ===
+
+void outb(Uint16 Port, Uint8 Data)
+{
+       __asm__ __volatile__ ("outb %%al, %%dx"::"d"(Port),"a"(Data));
+}
+void outw(Uint16 Port, Uint16 Data)
+{
+       __asm__ __volatile__ ("outw %%ax, %%dx"::"d"(Port),"a"(Data));
+}
+void outd(Uint16 Port, Uint32 Data)
+{
+       __asm__ __volatile__ ("outl %%eax, %%dx"::"d"(Port),"a"(Data));
+}
+Uint8 inb(Uint16 Port)
+{
+       Uint8   ret;
+       __asm__ __volatile__ ("inb %%dx, %%al":"=a"(ret):"d"(Port));
+       return ret;
+}
+Uint16 inw(Uint16 Port)
+{
+       Uint16  ret;
+       __asm__ __volatile__ ("inw %%dx, %%ax":"=a"(ret):"d"(Port));
+       return ret;
+}
+Uint32 ind(Uint16 Port)
+{
+       Uint32  ret;
+       __asm__ __volatile__ ("inl %%dx, %%eax":"=a"(ret):"d"(Port));
+       return ret;
+}
+
+// === Endianness ===
+Uint32 BigEndian32(Uint32 Value)
+{
+       Uint32  ret;
+       ret = (Value >> 24);
+       ret |= ((Value >> 16) & 0xFF) << 8;
+       ret |= ((Value >>  8) & 0xFF) << 16;
+       ret |= ((Value >>  0) & 0xFF) << 24;
+       return ret;
+}
+
+Uint16 BigEndian16(Uint16 Value)
+{
+       return  (Value>>8)|(Value<<8);
+}
+
+// === Memory Manipulation ===
+void *memcpy(void *__dest, const void *__src, size_t __count)
+{
+       if( ((tVAddr)__dest & 7) != ((tVAddr)__src & 7) )
+               __asm__ __volatile__ ("rep movsb" : : "D"(__dest),"S"(__src),"c"(__count));
+       else {
+               const Uint8     *src = __src;
+               Uint8   *dst = __dest;
+               while( (tVAddr)src & 7 && __count ) {
+                       *dst++ = *src++;
+                       __count --;
+               }
+
+               __asm__ __volatile__ ("rep movsq" : : "D"(dst),"S"(src),"c"(__count/8));
+               src += __count & ~7;
+               dst += __count & ~7;
+               __count = __count & 7;
+               while( __count-- )
+                       *dst++ = *src++;
+       }
+       return __dest;
+}
+
+void *memset(void *__dest, int __val, size_t __count)
+{
+       if( __val != 0 || ((tVAddr)__dest & 7) != 0 )
+               __asm__ __volatile__ ("rep stosb" : : "D"(__dest),"a"(__val),"c"(__count));
+       else {
+               Uint8   *dst = __dest;
+
+               __asm__ __volatile__ ("rep stosq" : : "D"(dst),"a"(0),"c"(__count/8));
+               dst += __count & ~7;
+               __count = __count & 7;
+               while( __count-- )
+                       *dst++ = 0;
+       }
+       return __dest;
+}
+
diff --git a/Kernel/arch/x86_64/link.ld b/Kernel/arch/x86_64/link.ld
new file mode 100644 (file)
index 0000000..cab3c5c
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * AcessMicro Kernel
+ * Linker Script
+ */
+
+_kernel_base = 0xFFFF800000000000;
+
+//lowStart = start - _kernel_base;
+ENTRY(start)
+OUTPUT_FORMAT(elf64-x86-64)
+
+SECTIONS {
+       . = 0x100000;
+       __load_addr = .;
+       .multiboot : AT(ADDR(.multiboot)) {
+               *(.multiboot)
+       }
+       
+       . += _kernel_base;
+       
+       .text ALIGN(0x1000): AT(ADDR(.text) - _kernel_base) {
+               *(.text)
+       }
+       
+       .usertext ALIGN(0x1000): AT(ADDR(.usertext) - _kernel_base) {
+               _UsertextBase = .;
+               *(.usertext)
+       }
+       _UsertextEnd = .;
+       
+       .rodata ALIGN(0x1000): AT(ADDR(.rodata) - _kernel_base) {
+               *(.initpd)
+               *(.rodata)
+               *(.rdata)
+               gKernelModules = .;
+               *(KMODULES)
+               gKernelModulesEnd = .;
+               . = ALIGN(4);
+               gKernelSymbols = .;
+               *(KEXPORT)
+               gKernelSymbolsEnd = .;
+
+
+       }
+       /*
+       .debug_abbrev : { *(.debug_abbrev) }
+       .debug_info : { *(.debug_info) }
+       .debug_line : { *(.debug_line) }
+       .debug_loc : { *(.debug_loc) }
+       .debug_pubnames : { *(.debug_pubnames) }
+       .debug_aranges : { *(.debug_aranges) }
+       .debug_ranges : { *(.debug_ranges) }
+       .debug_str : { *(.debug_str) }
+       .debug_frame : { *(.debug_frame) }
+       */
+       
+       .padata ALIGN (0x1000) : AT(ADDR(.padata) - _kernel_base) {
+               *(.padata)
+       }
+       
+       .data ALIGN (0x1000) : AT(ADDR(.data) - _kernel_base) {
+               *(.data)
+       }
+
+       __bss_start = .;
+       .bss : AT(ADDR(.bss) - _kernel_base) {
+               _sbss = .;
+               *(COMMON)
+               *(.bss)
+               _ebss = .;
+       }
+       gKernelEnd = (. + 0xFFF)&0xFFFFFFFFFFFFF000;
+}
diff --git a/Kernel/arch/x86_64/rme.c b/Kernel/arch/x86_64/rme.c
new file mode 120000 (symlink)
index 0000000..330f4f5
--- /dev/null
@@ -0,0 +1 @@
+/home/tpg/Projects/RealmodeEmulator/src/rme.c
\ No newline at end of file
diff --git a/Kernel/arch/x86_64/rme.h b/Kernel/arch/x86_64/rme.h
new file mode 120000 (symlink)
index 0000000..98b2739
--- /dev/null
@@ -0,0 +1 @@
+/home/tpg/Projects/RealmodeEmulator/src/rme.h
\ No newline at end of file
index ad8edb0..3209c04 100644 (file)
@@ -297,7 +297,7 @@ int Elf_Relocate(void *Base)
                                Warning("ELF", "Elf_Relocate - Multiple PT_DYNAMIC segments\n");\r
                                continue;\r
                        }\r
-                       dynamicTab = (void *) phtab[i].VAddr;\r
+                       dynamicTab = (void *) (tVAddr) phtab[i].VAddr;\r
                        j = i;  // Save Dynamic Table ID\r
                        break;\r
                }\r
@@ -326,20 +326,20 @@ int Elf_Relocate(void *Base)
                // --- Symbol Table ---\r
                case DT_SYMTAB:\r
                        dynamicTab[j].d_val += iBaseDiff;\r
-                       dynsymtab = (void*)(dynamicTab[j].d_val);\r
+                       dynsymtab = (void*) (tVAddr) dynamicTab[j].d_val;\r
                        hdr->misc.SymTable = dynamicTab[j].d_val;       // Saved in unused bytes of ident\r
                        break;\r
                \r
                // --- String Table ---\r
                case DT_STRTAB:\r
                        dynamicTab[j].d_val += iBaseDiff;\r
-                       dynstrtab = (void*)(dynamicTab[j].d_val);\r
+                       dynstrtab = (void*) (tVAddr) dynamicTab[j].d_val;\r
                        break;\r
                \r
                // --- Hash Table --\r
                case DT_HASH:\r
                        dynamicTab[j].d_val += iBaseDiff;\r
-                       iSymCount = ((Uint*)(dynamicTab[j].d_val))[1];\r
+                       iSymCount = ((Uint*)((tVAddr)dynamicTab[j].d_val))[1];\r
                        hdr->misc.HashTable = dynamicTab[j].d_val;      // Saved in unused bytes of ident\r
                        break;\r
                }\r
index 77309f3..ffa0730 100644 (file)
-/*\r
- * Acess2\r
- * Common Binary Loader\r
- */\r
-#define DEBUG  0\r
-#include <acess.h>\r
-#include <binary.h>\r
-\r
-// === CONSTANTS ===\r
-#define BIN_LOWEST     MM_USER_MIN             // 1MiB\r
-#define BIN_GRANUALITY 0x10000         // 64KiB\r
-//! \todo Move 0xBC000000 to mm_virt.h\r
-#define BIN_HIGHEST    (0xBC000000-BIN_GRANUALITY)             // Just below the kernel\r
-#define        KLIB_LOWEST     MM_MODULE_MIN\r
-#define KLIB_GRANUALITY        0x10000         // 32KiB\r
-#define        KLIB_HIGHEST    (MM_MODULE_MAX-KLIB_GRANUALITY)\r
-\r
-// === TYPES ===\r
-typedef struct sKernelBin {\r
-       struct sKernelBin       *Next;\r
-       void    *Base;\r
-       tBinary *Info;\r
-} tKernelBin;\r
-\r
-// === IMPORTS ===\r
-extern int     Proc_Clone(Uint *Err, Uint Flags);\r
-extern char    *Threads_GetName(int ID);\r
-extern void    Threads_Exit(int, int);\r
-extern Uint    MM_ClearUser();\r
-extern void    Proc_StartUser(Uint Entrypoint, Uint *Bases, int ArgC, char **ArgV, char **EnvP, int DataSize);\r
-extern tKernelSymbol   gKernelSymbols[];\r
-extern void            gKernelSymbolsEnd;\r
-extern tBinaryType     gELF_Info;\r
-\r
-// === PROTOTYPES ===\r
- int   Proc_Execve(char *File, char **ArgV, char **EnvP);\r
-Uint   Binary_Load(char *file, Uint *entryPoint);\r
-tBinary *Binary_GetInfo(char *truePath);\r
-Uint   Binary_MapIn(tBinary *binary);\r
-Uint   Binary_IsMapped(tBinary *binary);\r
-tBinary *Binary_DoLoad(char *truePath);\r
-void   Binary_Dereference(tBinary *Info);\r
-Uint   Binary_Relocate(void *Base);\r
-Uint   Binary_GetSymbolEx(char *Name, Uint *Value);\r
-Uint   Binary_FindSymbol(void *Base, char *Name, Uint *Val);\r
-\r
-// === GLOBALS ===\r
- int   glBinListLock = 0;\r
-tBinary        *glLoadedBinaries = NULL;\r
-char   **gsaRegInterps = NULL;\r
- int   giRegInterps = 0;\r
- int   glKBinListLock = 0;\r
-tKernelBin     *glLoadedKernelLibs;\r
-tBinaryType    *gRegBinTypes = &gELF_Info;\r
\r
-// === FUNCTIONS ===\r
-/**\r
- * \brief Registers a binary type\r
- */\r
-int Binary_RegisterType(tBinaryType *Type)\r
-{\r
-       Type->Next = gRegBinTypes;\r
-       gRegBinTypes = Type;\r
-       return 1;\r
-}\r
-\r
-/**\r
- * \fn int Proc_Spawn(char *Path)\r
- */\r
-int Proc_Spawn(char *Path)\r
-{\r
-       char    stackPath[strlen(Path)+1];\r
-       \r
-       strcpy(stackPath, Path);\r
-       \r
-       LOG("stackPath = '%s'\n", stackPath);\r
-       \r
-       if(Proc_Clone(NULL, CLONE_VM) == 0)\r
-       {\r
-               // CHILD\r
-               char    *args[2] = {stackPath, NULL};\r
-               LOG("stackPath = '%s'\n", stackPath);\r
-               Proc_Execve(stackPath, args, &args[1]);\r
-               for(;;);\r
-       }\r
-       return 0;\r
-}\r
-\r
-/**\r
- * \fn int Proc_Execve(char *File, char **ArgV, char **EnvP)\r
- * \brief Replace the current user image with another\r
- * \param File File to load as the next image\r
- * \param ArgV Arguments to pass to user\r
- * \param EnvP User's environment\r
- * \note Called Proc_ for historical reasons\r
- */\r
-int Proc_Execve(char *File, char **ArgV, char **EnvP)\r
-{\r
-        int    argc, envc, i;\r
-        int    argenvBytes;\r
-       char    *argenvBuf, *strBuf;\r
-       char    **argvSaved, **envpSaved;\r
-       char    *savedFile;\r
-       Uint    entry;\r
-       Uint    bases[2] = {0};\r
-       \r
-       ENTER("sFile pArgV pEnvP", File, ArgV, EnvP);\r
-       \r
-       // --- Save File, ArgV and EnvP (also get argc)\r
-       \r
-       // Count Arguments, Environment Variables and total string sizes\r
-       argenvBytes = 0;\r
-       for( argc = 0; ArgV && ArgV[argc]; argc++ )\r
-               argenvBytes += strlen(ArgV[argc])+1;\r
-       for( envc = 0; EnvP && EnvP[envc]; envc++ )\r
-               argenvBytes += strlen(EnvP[envc])+1;\r
-       argenvBytes = (argenvBytes + sizeof(void*)-1) & ~(sizeof(void*)-1);\r
-       argenvBytes += (argc+1)*sizeof(void*) + (envc+1)*sizeof(void*);\r
-       \r
-       // Allocate\r
-       argenvBuf = malloc(argenvBytes);\r
-       if(argenvBuf == NULL) {\r
-               Warning("Proc_Execve - What the hell? The kernel is out of heap space");\r
-               return 0;\r
-       }\r
-       strBuf = argenvBuf + (argc+1)*sizeof(void*) + (envc+1)*sizeof(void*);\r
-       \r
-       // Populate\r
-       argvSaved = (char **) argenvBuf;\r
-       for( i = 0; i < argc; i++ )\r
-       {\r
-               argvSaved[i] = strBuf;\r
-               strcpy(argvSaved[i], ArgV[i]);\r
-               strBuf += strlen(ArgV[i])+1;\r
-       }\r
-       argvSaved[i] = NULL;\r
-       envpSaved = &argvSaved[i+1];\r
-       for( i = 0; i < envc; i++ )\r
-       {\r
-               envpSaved[i] = strBuf;\r
-               strcpy(envpSaved[i], EnvP[i]);\r
-               strBuf += strlen(EnvP[i])+1;\r
-       }\r
-       \r
-       savedFile = malloc(strlen(File)+1);\r
-       strcpy(savedFile, File);\r
-       \r
-       // --- Set Process Name\r
-       Threads_SetName(File);\r
-       \r
-       // --- Clear User Address space\r
-       MM_ClearUser();\r
-       \r
-       // --- Load new binary\r
-       bases[0] = Binary_Load(savedFile, &entry);\r
-       free(savedFile);\r
-       if(bases[0] == 0)\r
-       {\r
-               Warning("Proc_Execve - Unable to load '%s'", Threads_GetName(-1));\r
-               Threads_Exit(0, 0);\r
-               for(;;);\r
-       }\r
-       \r
-       LOG("entry = 0x%x, bases[0] = 0x%x", entry, bases[0]);\r
-       LEAVE('-');\r
-       // --- And... Jump to it\r
-       Proc_StartUser(entry, bases, argc, argvSaved, envpSaved, argenvBytes);\r
-       for(;;);        // Tell GCC that we never return\r
-}\r
-\r
-/**\r
- * \fn Uint Binary_Load(char *file, Uint *entryPoint)\r
- */\r
-Uint Binary_Load(char *file, Uint *entryPoint)\r
-{\r
-       char    *sTruePath;\r
-       tBinary *pBinary;\r
-       Uint    base = -1;\r
-\r
-       ENTER("sfile", file);\r
-       \r
-       // Sanity Check Argument\r
-       if(file == NULL) {\r
-               LEAVE('x', 0);\r
-               return 0;\r
-       }\r
-\r
-       // Get True File Path\r
-       sTruePath = VFS_GetTruePath(file);\r
-       \r
-       if(sTruePath == NULL) {\r
-               Warning("[BIN  ] '%s' does not exist.", file);\r
-               LEAVE('x', 0);\r
-               return 0;\r
-       }\r
-       \r
-       LOG("sTruePath = '%s'", sTruePath);\r
-\r
-       // Check if the binary has already been loaded\r
-       if( !(pBinary = Binary_GetInfo(sTruePath)) )\r
-               pBinary = Binary_DoLoad(sTruePath);     // Else load it\r
-       \r
-       // Clean Up\r
-       free(sTruePath);\r
-       \r
-       // Error Check\r
-       if(pBinary == NULL) {\r
-               LEAVE('x', 0);\r
-               return 0;\r
-       }\r
-       \r
-       #if 0\r
-       if( (base = Binary_IsMapped(pBinary)) ) {\r
-               LEAVE('x', base);\r
-               return base;\r
-       }\r
-       #endif\r
-       \r
-       // Map into process space\r
-       base = Binary_MapIn(pBinary);   // If so then map it in\r
-       \r
-       // Check for errors\r
-       if(base == 0) {\r
-               LEAVE('x', 0);\r
-               return 0;\r
-       }\r
-       \r
-       // Interpret\r
-       if(pBinary->Interpreter) {\r
-               Uint start;\r
-               if( Binary_Load(pBinary->Interpreter, &start) == 0 ) {\r
-                       LEAVE('x', 0);\r
-                       return 0;\r
-               }\r
-               *entryPoint = start;\r
-       }\r
-       else\r
-               *entryPoint = pBinary->Entry - pBinary->Base + base;\r
-       \r
-       // Return\r
-       LOG("*entryPoint = 0x%x", *entryPoint);\r
-       LEAVE('x', base);\r
-       return base;    // Pass the base as an argument to the user if there is an interpreter\r
-}\r
-\r
-/**\r
- * \brief Finds a matching binary entry\r
- * \param TruePath     File Identifier (True path name)\r
- */\r
-tBinary *Binary_GetInfo(char *TruePath)\r
-{\r
-       tBinary *pBinary;\r
-       pBinary = glLoadedBinaries;\r
-       while(pBinary)\r
-       {\r
-               if(strcmp(pBinary->TruePath, TruePath) == 0)\r
-                       return pBinary;\r
-               pBinary = pBinary->Next;\r
-       }\r
-       return NULL;\r
-}\r
-\r
-/**\r
- \fn Uint Binary_MapIn(tBinary *binary)\r
- \brief Maps an already-loaded binary into an address space.\r
- \param binary Pointer to globally stored data.\r
-*/\r
-Uint Binary_MapIn(tBinary *binary)\r
-{\r
-       Uint    base;\r
-       Uint    addr;\r
-        int    i;\r
-       \r
-       // Reference Executable (Makes sure that it isn't unloaded)\r
-       binary->ReferenceCount ++;\r
-       \r
-       // Get Binary Base\r
-       base = binary->Base;\r
-       \r
-       // Check if base is free\r
-       if(base != 0)\r
-       {\r
-               for(i=0;i<binary->NumPages;i++)\r
-               {\r
-                       if( MM_GetPhysAddr( binary->Pages[i].Virtual & ~0xFFF ) ) {\r
-                               base = 0;\r
-                               LOG("Address 0x%x is taken\n", binary->Pages[i].Virtual & ~0xFFF);\r
-                               break;\r
-                       }\r
-               }\r
-       }\r
-       \r
-       // Check if the executable has no base or it is not free\r
-       if(base == 0)\r
-       {\r
-               // If so, give it a base\r
-               base = BIN_HIGHEST;\r
-               while(base >= BIN_LOWEST)\r
-               {\r
-                       for(i=0;i<binary->NumPages;i++)\r
-                       {\r
-                               addr = binary->Pages[i].Virtual & ~0xFFF;\r
-                               addr -= binary->Base;\r
-                               addr += base;\r
-                               if( MM_GetPhysAddr( addr ) )    break;\r
-                       }\r
-                       // If space was found, break\r
-                       if(i == binary->NumPages)               break;\r
-                       // Else decrement pointer and try again\r
-                       base -= BIN_GRANUALITY;\r
-               }\r
-       }\r
-       \r
-       // Error Check\r
-       if(base < BIN_LOWEST) {\r
-               Warning("[BIN ] Executable '%s' cannot be loaded, no space", binary->TruePath);\r
-               return 0;\r
-       }\r
-       \r
-       // Map Executable In\r
-       for(i=0;i<binary->NumPages;i++)\r
-       {\r
-               addr = binary->Pages[i].Virtual & ~0xFFF;\r
-               addr -= binary->Base;\r
-               addr += base;\r
-               LOG("%i - 0x%x to 0x%x", i, addr, binary->Pages[i].Physical);\r
-               MM_Map( addr, (Uint) (binary->Pages[i].Physical) );\r
-               \r
-               // Read-Only?\r
-               if( binary->Pages[i].Flags & BIN_PAGEFLAG_RO)\r
-                       MM_SetFlags( addr, MM_PFLAG_RO, -1 );\r
-               else\r
-                       MM_SetFlags( addr, MM_PFLAG_COW, -1 );\r
-               \r
-               // Execute?\r
-               if( binary->Pages[i].Flags & BIN_PAGEFLAG_EXEC )\r
-                       MM_SetFlags( addr, MM_PFLAG_EXEC, -1 );\r
-               else\r
-                       MM_SetFlags( addr, MM_PFLAG_EXEC, 0 );\r
-               \r
-       }\r
-       \r
-       //Log("Mapped '%s' to 0x%x", binary->TruePath, base);\r
-       \r
-       //LOG("*0x%x = 0x%x\n", binary->Pages[0].Virtual, *(Uint*)binary->Pages[0].Virtual);\r
-       \r
-       return base;\r
-}\r
-\r
-#if 0\r
-/**\r
- * \fn Uint Binary_IsMapped(tBinary *binary)\r
- * \brief Check if a binary is already mapped into the address space\r
- * \param binary       Binary information to check\r
- * \return Current Base or 0\r
- */\r
-Uint Binary_IsMapped(tBinary *binary)\r
-{\r
-       Uint    iBase;\r
-       \r
-       // Check prefered base\r
-       iBase = binary->Base;\r
-       if(MM_GetPage( iBase ) == (binary->Pages[0].Physical & ~0xFFF))\r
-               return iBase;\r
-       \r
-       for(iBase = BIN_HIGHEST;\r
-               iBase >= BIN_LOWEST;\r
-               iBase -= BIN_GRANUALITY)\r
-       {\r
-               if(MM_GetPage( iBase ) == (binary->Pages[0].Physical & ~0xFFF))\r
-                       return iBase;\r
-       }\r
-       \r
-       return 0;\r
-}\r
-#endif\r
-\r
-/**\r
- * \fn tBinary *Binary_DoLoad(char *truePath)\r
- * \brief Loads a binary file into memory\r
- * \param truePath     Absolute filename of binary\r
- */\r
-tBinary *Binary_DoLoad(char *truePath)\r
-{\r
-       tBinary *pBinary;\r
-        int    fp, i;\r
-       Uint    ident;\r
-       tBinaryType     *bt = gRegBinTypes;\r
-       \r
-       ENTER("struePath", truePath);\r
-       \r
-       // Open File\r
-       fp = VFS_Open(truePath, VFS_OPENFLAG_READ);\r
-       if(fp == -1) {\r
-               LOG("Unable to load file, access denied");\r
-               LEAVE('n');\r
-               return NULL;\r
-       }\r
-       \r
-       // Read File Type\r
-       VFS_Read(fp, 4, &ident);\r
-       VFS_Seek(fp, 0, SEEK_SET);\r
-       \r
-       for(; bt; bt = bt->Next)\r
-       {\r
-               if( (ident & bt->Mask) != (Uint)bt->Ident )\r
-                       continue;\r
-               pBinary = bt->Load(fp);\r
-               break;\r
-       }\r
-       if(!bt) {\r
-               Warning("[BIN ] '%s' is an unknown file type. (0x%x 0x%x 0x%x 0x%x)",\r
-                       truePath, ident&0xFF, (ident>>8)&0xFF, (ident>>16)&0xFF, (ident>>24)&0xFF);\r
-               LEAVE('n');\r
-               return NULL;\r
-       }\r
-       \r
-       // Error Check\r
-       if(pBinary == NULL) {\r
-               LEAVE('n');\r
-               return NULL;\r
-       }\r
-       \r
-       // Initialise Structure\r
-       pBinary->ReferenceCount = 0;\r
-       pBinary->TruePath = malloc( strlen(truePath) + 1 );\r
-       strcpy(pBinary->TruePath, truePath);\r
-       \r
-       // Debug Information\r
-       LOG("Interpreter: '%s'", pBinary->Interpreter);\r
-       LOG("Base: 0x%x, Entry: 0x%x", pBinary->Base, pBinary->Entry);\r
-       LOG("NumPages: %i", pBinary->NumPages);\r
-       \r
-       // Read Data\r
-       for(i=0;i<pBinary->NumPages;i++)\r
-       {\r
-               Uint    dest;\r
-               tPAddr  paddr;\r
-               paddr = (Uint)MM_AllocPhys();\r
-               if(paddr == 0) {\r
-                       Warning("Binary_DoLoad - Physical memory allocation failed");\r
-                       for( ; i--; ) {\r
-                               MM_DerefPhys( pBinary->Pages[i].Physical );\r
-                       }\r
-                       return NULL;\r
-               }\r
-               MM_RefPhys( paddr );    // Make sure it is _NOT_ freed until we want it to be\r
-               dest = MM_MapTemp( paddr );\r
-               dest += pBinary->Pages[i].Virtual & 0xFFF;\r
-               LOG("dest = 0x%x, paddr = 0x%x", dest, paddr);\r
-               LOG("Pages[%i]={Physical:0x%llx,Virtual:%p,Size:0x%x}",\r
-                       i, pBinary->Pages[i].Physical, pBinary->Pages[i].Virtual, pBinary->Pages[i].Size);\r
-               \r
-               // Pure Empty Page\r
-               if(pBinary->Pages[i].Physical == -1) {\r
-                       LOG("%i - ZERO", i);\r
-                       memsetd( (void*)dest, 0, 1024 - (pBinary->Pages[i].Virtual & 0xFFF)/4 );\r
-               }\r
-               else\r
-               {\r
-                       VFS_Seek( fp, pBinary->Pages[i].Physical, 1 );\r
-                       if(pBinary->Pages[i].Size != 0x1000) {\r
-                               LOG("%i - 0x%llx - 0x%x bytes",\r
-                                       i, pBinary->Pages[i].Physical, pBinary->Pages[i].Size);\r
-                               memset( (void*)dest, 0, 0x1000 -(dest&0xFFF) );\r
-                               VFS_Read( fp, pBinary->Pages[i].Size, (void*)dest );\r
-                       } else {\r
-                               LOG("%i - 0x%x", i, pBinary->Pages[i].Physical);\r
-                               VFS_Read( fp, 0x1000, (void*)dest );\r
-                       }\r
-               }\r
-               pBinary->Pages[i].Physical = paddr;\r
-               MM_FreeTemp( dest );\r
-       }\r
-       LOG("Page Count: %i", pBinary->NumPages);\r
-       \r
-       // Close File\r
-       VFS_Close(fp);\r
-       \r
-       // Add to the list\r
-       LOCK(&glBinListLock);\r
-       pBinary->Next = glLoadedBinaries;\r
-       glLoadedBinaries = pBinary;\r
-       RELEASE(&glBinListLock);\r
-       \r
-       // Return\r
-       LEAVE('p', pBinary);\r
-       return pBinary;\r
-}\r
-\r
-/**\r
- * \fn void Binary_Unload(void *Base)\r
- * \brief Unload / Unmap a binary\r
- * \param Base Loaded Base\r
- * \note Currently used only for kernel libaries\r
- */\r
-void Binary_Unload(void *Base)\r
-{\r
-       tKernelBin      *pKBin;\r
-       tKernelBin      *prev = NULL;\r
-        int    i;\r
-       \r
-       if((Uint)Base < 0xC0000000)\r
-       {\r
-               // TODO: User Binaries\r
-               Warning("[BIN ] Unloading user binaries is currently unimplemented");\r
-               return;\r
-       }\r
-       \r
-       // Kernel Libraries\r
-       for(pKBin = glLoadedKernelLibs;\r
-               pKBin;\r
-               prev = pKBin, pKBin = pKBin->Next)\r
-       {\r
-               // Check the base\r
-               if(pKBin->Base != Base) continue;\r
-               // Deallocate Memory\r
-               for(i = 0; i < pKBin->Info->NumPages; i++) {\r
-                       MM_Deallocate( (Uint)Base + (i << 12) );\r
-               }\r
-               // Dereference Binary\r
-               Binary_Dereference( pKBin->Info );\r
-               // Remove from list\r
-               if(prev)        prev->Next = pKBin->Next;\r
-               else            glLoadedKernelLibs = pKBin->Next;\r
-               // Free Kernel Lib\r
-               free(pKBin);\r
-               return;\r
-       }\r
-}\r
-\r
-/**\r
- * \fn void Binary_Dereference(tBinary *Info)\r
- * \brief Dereferences and if nessasary, deletes a binary\r
- * \param Info Binary information structure\r
- */\r
-void Binary_Dereference(tBinary *Info)\r
-{\r
-       // Decrement reference count\r
-       Info->ReferenceCount --;\r
-       \r
-       // Check if it is still in use\r
-       if(Info->ReferenceCount)        return;\r
-       \r
-       /// \todo Implement binary freeing\r
-}\r
-\r
-/**\r
- * \fn char *Binary_RegInterp(char *Path)\r
- * \brief Registers an Interpreter\r
- * \param Path Path to interpreter provided by executable\r
- */\r
-char *Binary_RegInterp(char *Path)\r
-{\r
-        int    i;\r
-       // NULL Check Argument\r
-       if(Path == NULL)        return NULL;\r
-       // NULL Check the array\r
-       if(gsaRegInterps == NULL)\r
-       {\r
-               giRegInterps = 1;\r
-               gsaRegInterps = malloc( sizeof(char*) );\r
-               gsaRegInterps[0] = malloc( strlen(Path) );\r
-               strcpy(gsaRegInterps[0], Path);\r
-               return gsaRegInterps[0];\r
-       }\r
-       \r
-       // Scan Array\r
-       for( i = 0; i < giRegInterps; i++ )\r
-       {\r
-               if(strcmp(gsaRegInterps[i], Path) == 0)\r
-                       return gsaRegInterps[i];\r
-       }\r
-       \r
-       // Interpreter is not in list\r
-       giRegInterps ++;\r
-       gsaRegInterps = malloc( sizeof(char*)*giRegInterps );\r
-       gsaRegInterps[i] = malloc( strlen(Path) );\r
-       strcpy(gsaRegInterps[i], Path);\r
-       return gsaRegInterps[i];\r
-}\r
-\r
-// ============\r
-// Kernel Binary Handling\r
-// ============\r
-/**\r
- * \fn void *Binary_LoadKernel(char *File)\r
- * \brief Load a binary into kernel space\r
- * \note This function shares much with #Binary_Load, but does it's own mapping\r
- * \param File File to load into the kernel\r
- */\r
-void *Binary_LoadKernel(char *File)\r
-{\r
-       char    *sTruePath;\r
-       tBinary *pBinary;\r
-       tKernelBin      *pKBinary;\r
-       Uint    base = -1;\r
-       Uint    addr;\r
-        int    i;\r
-\r
-       ENTER("sfile", File);\r
-       \r
-       // Sanity Check Argument\r
-       if(File == NULL) {\r
-               LEAVE('n');\r
-               return 0;\r
-       }\r
-\r
-       // Get True File Path\r
-       sTruePath = VFS_GetTruePath(File);\r
-       if(sTruePath == NULL) {\r
-               LEAVE('n');\r
-               return 0;\r
-       }\r
-       \r
-       // Check if the binary has already been loaded\r
-       if( (pBinary = Binary_GetInfo(sTruePath)) )\r
-       {\r
-               for(pKBinary = glLoadedKernelLibs;\r
-                       pKBinary;\r
-                       pKBinary = pKBinary->Next )\r
-               {\r
-                       if(pKBinary->Info == pBinary) {\r
-                               LEAVE('p', pKBinary->Base);\r
-                               return pKBinary->Base;\r
-                       }\r
-               }\r
-       }\r
-       else\r
-               pBinary = Binary_DoLoad(sTruePath);     // Else load it\r
-       \r
-       // Error Check\r
-       if(pBinary == NULL) {\r
-               LEAVE('n');\r
-               return NULL;\r
-       }\r
-       \r
-       // --------------\r
-       // Now pBinary is valid (either freshly loaded or only user mapped)\r
-       // So, map it into kernel space\r
-       // --------------\r
-       \r
-       // Reference Executable (Makes sure that it isn't unloaded)\r
-       pBinary->ReferenceCount ++;\r
-       \r
-       // Check compiled base\r
-       base = pBinary->Base;\r
-       // - Sanity Check\r
-       if(base < KLIB_LOWEST || base > KLIB_HIGHEST || base + (pBinary->NumPages<<12) > KLIB_HIGHEST) {\r
-               base = 0;\r
-       }\r
-       // - Check if it is a valid base address\r
-       if(base != 0)\r
-       {\r
-               for(i=0;i<pBinary->NumPages;i++)\r
-               {\r
-                       if( MM_GetPhysAddr( pBinary->Pages[i].Virtual & ~0xFFF ) ) {\r
-                               base = 0;\r
-                               LOG("Address 0x%x is taken\n", pBinary->Pages[i].Virtual & ~0xFFF);\r
-                               break;\r
-                       }\r
-               }\r
-       }\r
-       \r
-       // Check if the executable has no base or it is not free\r
-       if(base == 0)\r
-       {\r
-               // If so, give it a base\r
-               base = KLIB_LOWEST;\r
-               while(base < KLIB_HIGHEST)\r
-               {\r
-                       for(i = 0; i < pBinary->NumPages; i++)\r
-                       {\r
-                               addr = pBinary->Pages[i].Virtual & ~0xFFF;\r
-                               addr -= pBinary->Base;\r
-                               addr += base;\r
-                               if( MM_GetPhysAddr( addr ) )    break;\r
-                       }\r
-                       // If space was found, break\r
-                       if(i == pBinary->NumPages)              break;\r
-                       // Else decrement pointer and try again\r
-                       base += KLIB_GRANUALITY;\r
-               }\r
-       }\r
-       \r
-       // - Error Check\r
-       if(base >= KLIB_HIGHEST) {\r
-               Warning("[BIN ] Executable '%s' cannot be loaded into kernel, no space", pBinary->TruePath);\r
-               Binary_Dereference( pBinary );\r
-               LEAVE('n');\r
-               return 0;\r
-       }\r
-       \r
-       LOG("base = 0x%x", base);\r
-       \r
-       // - Map binary in\r
-       LOG("pBinary = {NumPages:%i, Pages=%p}", pBinary->NumPages, pBinary->Pages);\r
-       for(i = 0; i < pBinary->NumPages; i++)\r
-       {\r
-               addr = pBinary->Pages[i].Virtual & ~0xFFF;\r
-               addr -= pBinary->Base;\r
-               addr += base;\r
-               LOG("%i - 0x%x to 0x%x", i, addr, pBinary->Pages[i].Physical);\r
-               MM_Map( addr, (Uint) (pBinary->Pages[i].Physical) );\r
-               MM_SetFlags( addr, MM_PFLAG_KERNEL, MM_PFLAG_KERNEL );\r
-               \r
-               if( pBinary->Pages[i].Flags & BIN_PAGEFLAG_RO)  // Read-Only?\r
-                       MM_SetFlags( addr, MM_PFLAG_RO, MM_PFLAG_KERNEL );\r
-       }
-\r
-       // Relocate Library\r
-       if( !Binary_Relocate( (void*)base ) )\r
-       {\r
-               Warning("[BIN ] Relocation of '%s' failed, unloading", sTruePath);\r
-               Binary_Unload( (void*)base );\r
-               Binary_Dereference( pBinary );\r
-               LEAVE('n');\r
-               return 0;\r
-       }\r
-       \r
-       // Add to list (relocator must look at itself manually, not via Binary_GetSymbol)\r
-       pKBinary = malloc(sizeof(*pKBinary));\r
-       pKBinary->Base = (void*)base;\r
-       pKBinary->Info = pBinary;\r
-       LOCK( &glKBinListLock );\r
-       pKBinary->Next = glLoadedKernelLibs;\r
-       glLoadedKernelLibs = pKBinary;\r
-       RELEASE( &glKBinListLock );\r
-       \r
-       LEAVE('p', base);\r
-       return (void*)base;\r
-}\r
-\r
-/**\r
- * \fn Uint Binary_Relocate(void *Base)\r
- * \brief Relocates a loaded binary (used by kernel libraries)\r
- * \param Base Loaded base address of binary\r
- * \return Boolean Success\r
- */\r
-Uint Binary_Relocate(void *Base)\r
-{\r
-       Uint32  ident = *(Uint32*) Base;\r
-       tBinaryType     *bt = gRegBinTypes;\r
-       \r
-       for(; bt; bt = bt->Next)\r
-       {\r
-               if( (ident & bt->Mask) == (Uint)bt->Ident )\r
-                       return bt->Relocate( (void*)Base);\r
-       }\r
-       \r
-       Warning("[BIN ] 0x%x is an unknown file type. (0x%x 0x%x 0x%x 0x%x)",\r
-               Base, ident&0xFF, (ident>>8)&0xFF, (ident>>16)&0xFF, (ident>>24)&0xFF);\r
-       return 0;\r
-}\r
-\r
-/**\r
- * \fn int Binary_GetSymbol(char *Name, Uint *Val)\r
- * \brief Get a symbol value\r
- * \return Value of symbol or -1 on error\r
- * \r
- * Gets the value of a symbol from either the currently loaded\r
- * libraries or the kernel's exports.\r
- */\r
-int Binary_GetSymbol(char *Name, Uint *Val)\r
-{\r
-       if( Binary_GetSymbolEx(Name, Val) )     return 1;\r
-       return 0;\r
-}\r
-\r
-/**\r
- * \fn Uint Binary_GetSymbolEx(char *Name, Uint *Value)\r
- * \brief Get a symbol value\r
- * \r
- * Gets the value of a symbol from either the currently loaded\r
- * libraries or the kernel's exports.\r
- */\r
-Uint Binary_GetSymbolEx(char *Name, Uint *Value)\r
-{\r
-        int    i;\r
-       tKernelBin      *pKBin;\r
-        int    numKSyms = ((Uint)&gKernelSymbolsEnd-(Uint)&gKernelSymbols)/sizeof(tKernelSymbol);\r
-       \r
-       // Scan Kernel\r
-       for( i = 0; i < numKSyms; i++ )\r
-       {\r
-               if(strcmp(Name, gKernelSymbols[i].Name) == 0) {\r
-                       *Value = gKernelSymbols[i].Value;\r
-                       return 1;\r
-               }\r
-       }\r
-       \r
-       // Scan Loaded Libraries\r
-       for(pKBin = glLoadedKernelLibs;\r
-               pKBin;\r
-               pKBin = pKBin->Next )\r
-       {\r
-               if( Binary_FindSymbol(pKBin->Base, Name, Value) ) {\r
-                       return 1;\r
-               }\r
-       }\r
-       
-       Warning("[BIN ] Unable to find symbol '%s'", Name);\r
-       return 0;\r
-}\r
-\r
-/**\r
- * \fn Uint Binary_FindSymbol(void *Base, char *Name, Uint *Val)\r
- * \brief Get a symbol from the specified library\r
- * \param Base Base address\r
- * \param Name Name of symbol to find\r
- * \param Val  Pointer to place final value\r
- */\r
-Uint Binary_FindSymbol(void *Base, char *Name, Uint *Val)\r
-{\r
-       Uint32  ident = *(Uint32*) Base;\r
-       tBinaryType     *bt = gRegBinTypes;\r
-       \r
-       for(; bt; bt = bt->Next)\r
-       {\r
-               if( (ident & bt->Mask) == (Uint)bt->Ident )\r
-                       return bt->GetSymbol(Base, Name, Val);\r
-       }\r
-       \r
-       Warning("[BIN ] 0x%x is an unknown file type. (0x%x 0x%x 0x%x 0x%x)",\r
-               Base, ident&0xFF, ident>>8, ident>>16, ident>>24);\r
-       return 0;\r
-}\r
-\r
-// === EXPORTS ===\r
-EXPORT(Binary_FindSymbol);\r
-EXPORT(Binary_Unload);\r
+/*
+ * Acess2
+ * Common Binary Loader
+ */
+#define DEBUG  0
+#include <acess.h>
+#include <binary.h>
+#include <mm_virt.h>
+
+// === CONSTANTS ===
+#define BIN_LOWEST     MM_USER_MIN             // 1MiB
+#define BIN_GRANUALITY 0x10000         // 64KiB
+//! \todo Move 0xBC000000 to mm_virt.h
+#define BIN_HIGHEST    (0xBC000000-BIN_GRANUALITY)             // Just below the kernel
+#define        KLIB_LOWEST     MM_MODULE_MIN
+#define KLIB_GRANUALITY        0x10000         // 32KiB
+#define        KLIB_HIGHEST    (MM_MODULE_MAX-KLIB_GRANUALITY)
+
+// === TYPES ===
+typedef struct sKernelBin {
+       struct sKernelBin       *Next;
+       void    *Base;
+       tBinary *Info;
+} tKernelBin;
+
+// === IMPORTS ===
+extern int     Proc_Clone(Uint *Err, Uint Flags);
+extern char    *Threads_GetName(int ID);
+extern void    Threads_Exit(int, int);
+extern Uint    MM_ClearUser();
+extern void    Proc_StartUser(Uint Entrypoint, Uint *Bases, int ArgC, char **ArgV, char **EnvP, int DataSize);
+extern tKernelSymbol   gKernelSymbols[];
+extern void            gKernelSymbolsEnd;
+extern tBinaryType     gELF_Info;
+
+// === PROTOTYPES ===
+ int   Proc_Execve(char *File, char **ArgV, char **EnvP);
+Uint   Binary_Load(char *file, Uint *entryPoint);
+tBinary *Binary_GetInfo(char *truePath);
+Uint   Binary_MapIn(tBinary *binary);
+Uint   Binary_IsMapped(tBinary *binary);
+tBinary *Binary_DoLoad(char *truePath);
+void   Binary_Dereference(tBinary *Info);
+Uint   Binary_Relocate(void *Base);
+Uint   Binary_GetSymbolEx(char *Name, Uint *Value);
+Uint   Binary_FindSymbol(void *Base, char *Name, Uint *Val);
+
+// === GLOBALS ===
+ int   glBinListLock = 0;
+tBinary        *glLoadedBinaries = NULL;
+char   **gsaRegInterps = NULL;
+ int   giRegInterps = 0;
+ int   glKBinListLock = 0;
+tKernelBin     *glLoadedKernelLibs;
+tBinaryType    *gRegBinTypes = &gELF_Info;
+// === FUNCTIONS ===
+/**
+ * \brief Registers a binary type
+ */
+int Binary_RegisterType(tBinaryType *Type)
+{
+       Type->Next = gRegBinTypes;
+       gRegBinTypes = Type;
+       return 1;
+}
+
+/**
+ * \fn int Proc_Spawn(char *Path)
+ */
+int Proc_Spawn(char *Path)
+{
+       char    stackPath[strlen(Path)+1];
+       
+       strcpy(stackPath, Path);
+       
+       LOG("stackPath = '%s'\n", stackPath);
+       
+       if(Proc_Clone(NULL, CLONE_VM) == 0)
+       {
+               // CHILD
+               char    *args[2] = {stackPath, NULL};
+               LOG("stackPath = '%s'\n", stackPath);
+               Proc_Execve(stackPath, args, &args[1]);
+               for(;;);
+       }
+       return 0;
+}
+
+/**
+ * \fn int Proc_Execve(char *File, char **ArgV, char **EnvP)
+ * \brief Replace the current user image with another
+ * \param File File to load as the next image
+ * \param ArgV Arguments to pass to user
+ * \param EnvP User's environment
+ * \note Called Proc_ for historical reasons
+ */
+int Proc_Execve(char *File, char **ArgV, char **EnvP)
+{
+        int    argc, envc, i;
+        int    argenvBytes;
+       char    *argenvBuf, *strBuf;
+       char    **argvSaved, **envpSaved;
+       char    *savedFile;
+       Uint    entry;
+       Uint    bases[2] = {0};
+       
+       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;
+       argenvBytes = (argenvBytes + sizeof(void*)-1) & ~(sizeof(void*)-1);
+       argenvBytes += (argc+1)*sizeof(void*) + (envc+1)*sizeof(void*);
+       
+       // Allocate
+       argenvBuf = malloc(argenvBytes);
+       if(argenvBuf == NULL) {
+               Warning("Proc_Execve - What the hell? The kernel is out of heap space");
+               return 0;
+       }
+       strBuf = argenvBuf + (argc+1)*sizeof(void*) + (envc+1)*sizeof(void*);
+       
+       // Populate
+       argvSaved = (char **) argenvBuf;
+       for( i = 0; i < argc; i++ )
+       {
+               argvSaved[i] = strBuf;
+               strcpy(argvSaved[i], ArgV[i]);
+               strBuf += strlen(ArgV[i])+1;
+       }
+       argvSaved[i] = NULL;
+       envpSaved = &argvSaved[i+1];
+       for( i = 0; i < envc; i++ )
+       {
+               envpSaved[i] = strBuf;
+               strcpy(envpSaved[i], EnvP[i]);
+               strBuf += strlen(EnvP[i])+1;
+       }
+       
+       savedFile = malloc(strlen(File)+1);
+       strcpy(savedFile, File);
+       
+       // --- Set Process Name
+       Threads_SetName(File);
+       
+       // --- Clear User Address space
+       MM_ClearUser();
+       
+       // --- Load new binary
+       bases[0] = Binary_Load(savedFile, &entry);
+       free(savedFile);
+       if(bases[0] == 0)
+       {
+               Warning("Proc_Execve - Unable to load '%s'", Threads_GetName(-1));
+               Threads_Exit(0, 0);
+               for(;;);
+       }
+       
+       LOG("entry = 0x%x, bases[0] = 0x%x", entry, bases[0]);
+       LEAVE('-');
+       // --- And... Jump to it
+       Proc_StartUser(entry, bases, argc, argvSaved, envpSaved, argenvBytes);
+       for(;;);        // Tell GCC that we never return
+}
+
+/**
+ * \fn Uint Binary_Load(char *file, Uint *entryPoint)
+ */
+Uint Binary_Load(char *file, Uint *entryPoint)
+{
+       char    *sTruePath;
+       tBinary *pBinary;
+       Uint    base = -1;
+
+       ENTER("sfile", file);
+       
+       // Sanity Check Argument
+       if(file == NULL) {
+               LEAVE('x', 0);
+               return 0;
+       }
+
+       // Get True File Path
+       sTruePath = VFS_GetTruePath(file);
+       
+       if(sTruePath == NULL) {
+               Warning("[BIN  ] '%s' does not exist.", file);
+               LEAVE('x', 0);
+               return 0;
+       }
+       
+       LOG("sTruePath = '%s'", sTruePath);
+
+       // Check if the binary has already been loaded
+       if( !(pBinary = Binary_GetInfo(sTruePath)) )
+               pBinary = Binary_DoLoad(sTruePath);     // Else load it
+       
+       // Clean Up
+       free(sTruePath);
+       
+       // Error Check
+       if(pBinary == NULL) {
+               LEAVE('x', 0);
+               return 0;
+       }
+       
+       #if 0
+       if( (base = Binary_IsMapped(pBinary)) ) {
+               LEAVE('x', base);
+               return base;
+       }
+       #endif
+       
+       // Map into process space
+       base = Binary_MapIn(pBinary);   // If so then map it in
+       
+       // Check for errors
+       if(base == 0) {
+               LEAVE('x', 0);
+               return 0;
+       }
+       
+       // Interpret
+       if(pBinary->Interpreter) {
+               Uint start;
+               if( Binary_Load(pBinary->Interpreter, &start) == 0 ) {
+                       LEAVE('x', 0);
+                       return 0;
+               }
+               *entryPoint = start;
+       }
+       else
+               *entryPoint = pBinary->Entry - pBinary->Base + base;
+       
+       // Return
+       LOG("*entryPoint = 0x%x", *entryPoint);
+       LEAVE('x', base);
+       return base;    // Pass the base as an argument to the user if there is an interpreter
+}
+
+/**
+ * \brief Finds a matching binary entry
+ * \param TruePath     File Identifier (True path name)
+ */
+tBinary *Binary_GetInfo(char *TruePath)
+{
+       tBinary *pBinary;
+       pBinary = glLoadedBinaries;
+       while(pBinary)
+       {
+               if(strcmp(pBinary->TruePath, TruePath) == 0)
+                       return pBinary;
+               pBinary = pBinary->Next;
+       }
+       return NULL;
+}
+
+/**
+ \fn Uint Binary_MapIn(tBinary *binary)
+ \brief Maps an already-loaded binary into an address space.
+ \param binary Pointer to globally stored data.
+*/
+Uint Binary_MapIn(tBinary *binary)
+{
+       Uint    base;
+       Uint    addr;
+        int    i;
+       
+       // Reference Executable (Makes sure that it isn't unloaded)
+       binary->ReferenceCount ++;
+       
+       // Get Binary Base
+       base = binary->Base;
+       
+       // Check if base is free
+       if(base != 0)
+       {
+               for(i=0;i<binary->NumPages;i++)
+               {
+                       if( MM_GetPhysAddr( binary->Pages[i].Virtual & ~0xFFF ) ) {
+                               base = 0;
+                               LOG("Address 0x%x is taken\n", binary->Pages[i].Virtual & ~0xFFF);
+                               break;
+                       }
+               }
+       }
+       
+       // Check if the executable has no base or it is not free
+       if(base == 0)
+       {
+               // If so, give it a base
+               base = BIN_HIGHEST;
+               while(base >= BIN_LOWEST)
+               {
+                       for(i=0;i<binary->NumPages;i++)
+                       {
+                               addr = binary->Pages[i].Virtual & ~0xFFF;
+                               addr -= binary->Base;
+                               addr += base;
+                               if( MM_GetPhysAddr( addr ) )    break;
+                       }
+                       // If space was found, break
+                       if(i == binary->NumPages)               break;
+                       // Else decrement pointer and try again
+                       base -= BIN_GRANUALITY;
+               }
+       }
+       
+       // Error Check
+       if(base < BIN_LOWEST) {
+               Warning("[BIN ] Executable '%s' cannot be loaded, no space", binary->TruePath);
+               return 0;
+       }
+       
+       // Map Executable In
+       for(i=0;i<binary->NumPages;i++)
+       {
+               addr = binary->Pages[i].Virtual & ~0xFFF;
+               addr -= binary->Base;
+               addr += base;
+               LOG("%i - 0x%x to 0x%x", i, addr, binary->Pages[i].Physical);
+               MM_Map( addr, (Uint) (binary->Pages[i].Physical) );
+               
+               // Read-Only?
+               if( binary->Pages[i].Flags & BIN_PAGEFLAG_RO)
+                       MM_SetFlags( addr, MM_PFLAG_RO, -1 );
+               else
+                       MM_SetFlags( addr, MM_PFLAG_COW, -1 );
+               
+               // Execute?
+               if( binary->Pages[i].Flags & BIN_PAGEFLAG_EXEC )
+                       MM_SetFlags( addr, MM_PFLAG_EXEC, -1 );
+               else
+                       MM_SetFlags( addr, MM_PFLAG_EXEC, 0 );
+               
+       }
+       
+       //Log("Mapped '%s' to 0x%x", binary->TruePath, base);
+       
+       //LOG("*0x%x = 0x%x\n", binary->Pages[0].Virtual, *(Uint*)binary->Pages[0].Virtual);
+       
+       return base;
+}
+
+#if 0
+/**
+ * \fn Uint Binary_IsMapped(tBinary *binary)
+ * \brief Check if a binary is already mapped into the address space
+ * \param binary       Binary information to check
+ * \return Current Base or 0
+ */
+Uint Binary_IsMapped(tBinary *binary)
+{
+       Uint    iBase;
+       
+       // Check prefered base
+       iBase = binary->Base;
+       if(MM_GetPage( iBase ) == (binary->Pages[0].Physical & ~0xFFF))
+               return iBase;
+       
+       for(iBase = BIN_HIGHEST;
+               iBase >= BIN_LOWEST;
+               iBase -= BIN_GRANUALITY)
+       {
+               if(MM_GetPage( iBase ) == (binary->Pages[0].Physical & ~0xFFF))
+                       return iBase;
+       }
+       
+       return 0;
+}
+#endif
+
+/**
+ * \fn tBinary *Binary_DoLoad(char *truePath)
+ * \brief Loads a binary file into memory
+ * \param truePath     Absolute filename of binary
+ */
+tBinary *Binary_DoLoad(char *truePath)
+{
+       tBinary *pBinary;
+        int    fp, i;
+       Uint    ident;
+       tBinaryType     *bt = gRegBinTypes;
+       
+       ENTER("struePath", truePath);
+       
+       // Open File
+       fp = VFS_Open(truePath, VFS_OPENFLAG_READ);
+       if(fp == -1) {
+               LOG("Unable to load file, access denied");
+               LEAVE('n');
+               return NULL;
+       }
+       
+       // Read File Type
+       VFS_Read(fp, 4, &ident);
+       VFS_Seek(fp, 0, SEEK_SET);
+       
+       for(; bt; bt = bt->Next)
+       {
+               if( (ident & bt->Mask) != (Uint)bt->Ident )
+                       continue;
+               pBinary = bt->Load(fp);
+               break;
+       }
+       if(!bt) {
+               Warning("[BIN ] '%s' is an unknown file type. (0x%x 0x%x 0x%x 0x%x)",
+                       truePath, ident&0xFF, (ident>>8)&0xFF, (ident>>16)&0xFF, (ident>>24)&0xFF);
+               LEAVE('n');
+               return NULL;
+       }
+       
+       // Error Check
+       if(pBinary == NULL) {
+               LEAVE('n');
+               return NULL;
+       }
+       
+       // Initialise Structure
+       pBinary->ReferenceCount = 0;
+       pBinary->TruePath = malloc( strlen(truePath) + 1 );
+       strcpy(pBinary->TruePath, truePath);
+       
+       // Debug Information
+       LOG("Interpreter: '%s'", pBinary->Interpreter);
+       LOG("Base: 0x%x, Entry: 0x%x", pBinary->Base, pBinary->Entry);
+       LOG("NumPages: %i", pBinary->NumPages);
+       
+       // Read Data
+       for(i=0;i<pBinary->NumPages;i++)
+       {
+               Uint    dest;
+               tPAddr  paddr;
+               paddr = (Uint)MM_AllocPhys();
+               if(paddr == 0) {
+                       Warning("Binary_DoLoad - Physical memory allocation failed");
+                       for( ; i--; ) {
+                               MM_DerefPhys( pBinary->Pages[i].Physical );
+                       }
+                       return NULL;
+               }
+               MM_RefPhys( paddr );    // Make sure it is _NOT_ freed until we want it to be
+               dest = MM_MapTemp( paddr );
+               dest += pBinary->Pages[i].Virtual & 0xFFF;
+               LOG("dest = 0x%x, paddr = 0x%x", dest, paddr);
+               LOG("Pages[%i]={Physical:0x%llx,Virtual:%p,Size:0x%x}",
+                       i, pBinary->Pages[i].Physical, pBinary->Pages[i].Virtual, pBinary->Pages[i].Size);
+               
+               // Pure Empty Page
+               if(pBinary->Pages[i].Physical == -1) {
+                       LOG("%i - ZERO", i);
+                       memset( (void*)dest, 0, 1024 - (pBinary->Pages[i].Virtual & 0xFFF) );
+               }
+               else
+               {
+                       VFS_Seek( fp, pBinary->Pages[i].Physical, 1 );
+                       if(pBinary->Pages[i].Size != 0x1000) {
+                               LOG("%i - 0x%llx - 0x%x bytes",
+                                       i, pBinary->Pages[i].Physical, pBinary->Pages[i].Size);
+                               memset( (void*)dest, 0, 0x1000 -(dest&0xFFF) );
+                               VFS_Read( fp, pBinary->Pages[i].Size, (void*)dest );
+                       } else {
+                               LOG("%i - 0x%x", i, pBinary->Pages[i].Physical);
+                               VFS_Read( fp, 0x1000, (void*)dest );
+                       }
+               }
+               pBinary->Pages[i].Physical = paddr;
+               MM_FreeTemp( dest );
+       }
+       LOG("Page Count: %i", pBinary->NumPages);
+       
+       // Close File
+       VFS_Close(fp);
+       
+       // Add to the list
+       LOCK(&glBinListLock);
+       pBinary->Next = glLoadedBinaries;
+       glLoadedBinaries = pBinary;
+       RELEASE(&glBinListLock);
+       
+       // Return
+       LEAVE('p', pBinary);
+       return pBinary;
+}
+
+/**
+ * \fn void Binary_Unload(void *Base)
+ * \brief Unload / Unmap a binary
+ * \param Base Loaded Base
+ * \note Currently used only for kernel libaries
+ */
+void Binary_Unload(void *Base)
+{
+       tKernelBin      *pKBin;
+       tKernelBin      *prev = NULL;
+        int    i;
+       
+       if((Uint)Base < 0xC0000000)
+       {
+               // TODO: User Binaries
+               Warning("[BIN ] Unloading user binaries is currently unimplemented");
+               return;
+       }
+       
+       // Kernel Libraries
+       for(pKBin = glLoadedKernelLibs;
+               pKBin;
+               prev = pKBin, pKBin = pKBin->Next)
+       {
+               // Check the base
+               if(pKBin->Base != Base) continue;
+               // Deallocate Memory
+               for(i = 0; i < pKBin->Info->NumPages; i++) {
+                       MM_Deallocate( (Uint)Base + (i << 12) );
+               }
+               // Dereference Binary
+               Binary_Dereference( pKBin->Info );
+               // Remove from list
+               if(prev)        prev->Next = pKBin->Next;
+               else            glLoadedKernelLibs = pKBin->Next;
+               // Free Kernel Lib
+               free(pKBin);
+               return;
+       }
+}
+
+/**
+ * \fn void Binary_Dereference(tBinary *Info)
+ * \brief Dereferences and if nessasary, deletes a binary
+ * \param Info Binary information structure
+ */
+void Binary_Dereference(tBinary *Info)
+{
+       // Decrement reference count
+       Info->ReferenceCount --;
+       
+       // Check if it is still in use
+       if(Info->ReferenceCount)        return;
+       
+       /// \todo Implement binary freeing
+}
+
+/**
+ * \fn char *Binary_RegInterp(char *Path)
+ * \brief Registers an Interpreter
+ * \param Path Path to interpreter provided by executable
+ */
+char *Binary_RegInterp(char *Path)
+{
+        int    i;
+       // NULL Check Argument
+       if(Path == NULL)        return NULL;
+       // NULL Check the array
+       if(gsaRegInterps == NULL)
+       {
+               giRegInterps = 1;
+               gsaRegInterps = malloc( sizeof(char*) );
+               gsaRegInterps[0] = malloc( strlen(Path) );
+               strcpy(gsaRegInterps[0], Path);
+               return gsaRegInterps[0];
+       }
+       
+       // Scan Array
+       for( i = 0; i < giRegInterps; i++ )
+       {
+               if(strcmp(gsaRegInterps[i], Path) == 0)
+                       return gsaRegInterps[i];
+       }
+       
+       // Interpreter is not in list
+       giRegInterps ++;
+       gsaRegInterps = malloc( sizeof(char*)*giRegInterps );
+       gsaRegInterps[i] = malloc( strlen(Path) );
+       strcpy(gsaRegInterps[i], Path);
+       return gsaRegInterps[i];
+}
+
+// ============
+// Kernel Binary Handling
+// ============
+/**
+ * \fn void *Binary_LoadKernel(char *File)
+ * \brief Load a binary into kernel space
+ * \note This function shares much with #Binary_Load, but does it's own mapping
+ * \param File File to load into the kernel
+ */
+void *Binary_LoadKernel(char *File)
+{
+       char    *sTruePath;
+       tBinary *pBinary;
+       tKernelBin      *pKBinary;
+       Uint    base = -1;
+       Uint    addr;
+        int    i;
+
+       ENTER("sfile", File);
+       
+       // Sanity Check Argument
+       if(File == NULL) {
+               LEAVE('n');
+               return 0;
+       }
+
+       // Get True File Path
+       sTruePath = VFS_GetTruePath(File);
+       if(sTruePath == NULL) {
+               LEAVE('n');
+               return 0;
+       }
+       
+       // Check if the binary has already been loaded
+       if( (pBinary = Binary_GetInfo(sTruePath)) )
+       {
+               for(pKBinary = glLoadedKernelLibs;
+                       pKBinary;
+                       pKBinary = pKBinary->Next )
+               {
+                       if(pKBinary->Info == pBinary) {
+                               LEAVE('p', pKBinary->Base);
+                               return pKBinary->Base;
+                       }
+               }
+       }
+       else
+               pBinary = Binary_DoLoad(sTruePath);     // Else load it
+       
+       // Error Check
+       if(pBinary == NULL) {
+               LEAVE('n');
+               return NULL;
+       }
+       
+       // --------------
+       // Now pBinary is valid (either freshly loaded or only user mapped)
+       // So, map it into kernel space
+       // --------------
+       
+       // Reference Executable (Makes sure that it isn't unloaded)
+       pBinary->ReferenceCount ++;
+       
+       // Check compiled base
+       base = pBinary->Base;
+       // - Sanity Check
+       if(base < KLIB_LOWEST || base > KLIB_HIGHEST || base + (pBinary->NumPages<<12) > KLIB_HIGHEST) {
+               base = 0;
+       }
+       // - Check if it is a valid base address
+       if(base != 0)
+       {
+               for(i=0;i<pBinary->NumPages;i++)
+               {
+                       if( MM_GetPhysAddr( pBinary->Pages[i].Virtual & ~0xFFF ) ) {
+                               base = 0;
+                               LOG("Address 0x%x is taken\n", pBinary->Pages[i].Virtual & ~0xFFF);
+                               break;
+                       }
+               }
+       }
+       
+       // Check if the executable has no base or it is not free
+       if(base == 0)
+       {
+               // If so, give it a base
+               base = KLIB_LOWEST;
+               while(base < KLIB_HIGHEST)
+               {
+                       for(i = 0; i < pBinary->NumPages; i++)
+                       {
+                               addr = pBinary->Pages[i].Virtual & ~0xFFF;
+                               addr -= pBinary->Base;
+                               addr += base;
+                               if( MM_GetPhysAddr( addr ) )    break;
+                       }
+                       // If space was found, break
+                       if(i == pBinary->NumPages)              break;
+                       // Else decrement pointer and try again
+                       base += KLIB_GRANUALITY;
+               }
+       }
+       
+       // - Error Check
+       if(base >= KLIB_HIGHEST) {
+               Warning("[BIN ] Executable '%s' cannot be loaded into kernel, no space", pBinary->TruePath);
+               Binary_Dereference( pBinary );
+               LEAVE('n');
+               return 0;
+       }
+       
+       LOG("base = 0x%x", base);
+       
+       // - Map binary in
+       LOG("pBinary = {NumPages:%i, Pages=%p}", pBinary->NumPages, pBinary->Pages);
+       for(i = 0; i < pBinary->NumPages; i++)
+       {
+               addr = pBinary->Pages[i].Virtual & ~0xFFF;
+               addr -= pBinary->Base;
+               addr += base;
+               LOG("%i - 0x%x to 0x%x", i, addr, pBinary->Pages[i].Physical);
+               MM_Map( addr, (Uint) (pBinary->Pages[i].Physical) );
+               MM_SetFlags( addr, MM_PFLAG_KERNEL, MM_PFLAG_KERNEL );
+               
+               if( pBinary->Pages[i].Flags & BIN_PAGEFLAG_RO)  // Read-Only?
+                       MM_SetFlags( addr, MM_PFLAG_RO, MM_PFLAG_KERNEL );
+       }
+
+       // Relocate Library
+       if( !Binary_Relocate( (void*)base ) )
+       {
+               Warning("[BIN ] Relocation of '%s' failed, unloading", sTruePath);
+               Binary_Unload( (void*)base );
+               Binary_Dereference( pBinary );
+               LEAVE('n');
+               return 0;
+       }
+       
+       // Add to list (relocator must look at itself manually, not via Binary_GetSymbol)
+       pKBinary = malloc(sizeof(*pKBinary));
+       pKBinary->Base = (void*)base;
+       pKBinary->Info = pBinary;
+       LOCK( &glKBinListLock );
+       pKBinary->Next = glLoadedKernelLibs;
+       glLoadedKernelLibs = pKBinary;
+       RELEASE( &glKBinListLock );
+       
+       LEAVE('p', base);
+       return (void*)base;
+}
+
+/**
+ * \fn Uint Binary_Relocate(void *Base)
+ * \brief Relocates a loaded binary (used by kernel libraries)
+ * \param Base Loaded base address of binary
+ * \return Boolean Success
+ */
+Uint Binary_Relocate(void *Base)
+{
+       Uint32  ident = *(Uint32*) Base;
+       tBinaryType     *bt = gRegBinTypes;
+       
+       for(; bt; bt = bt->Next)
+       {
+               if( (ident & bt->Mask) == (Uint)bt->Ident )
+                       return bt->Relocate( (void*)Base);
+       }
+       
+       Warning("[BIN ] 0x%x is an unknown file type. (0x%x 0x%x 0x%x 0x%x)",
+               Base, ident&0xFF, (ident>>8)&0xFF, (ident>>16)&0xFF, (ident>>24)&0xFF);
+       return 0;
+}
+
+/**
+ * \fn int Binary_GetSymbol(char *Name, Uint *Val)
+ * \brief Get a symbol value
+ * \return Value of symbol or -1 on error
+ * 
+ * Gets the value of a symbol from either the currently loaded
+ * libraries or the kernel's exports.
+ */
+int Binary_GetSymbol(char *Name, Uint *Val)
+{
+       if( Binary_GetSymbolEx(Name, Val) )     return 1;
+       return 0;
+}
+
+/**
+ * \fn Uint Binary_GetSymbolEx(char *Name, Uint *Value)
+ * \brief Get a symbol value
+ * 
+ * Gets the value of a symbol from either the currently loaded
+ * libraries or the kernel's exports.
+ */
+Uint Binary_GetSymbolEx(char *Name, Uint *Value)
+{
+        int    i;
+       tKernelBin      *pKBin;
+        int    numKSyms = ((Uint)&gKernelSymbolsEnd-(Uint)&gKernelSymbols)/sizeof(tKernelSymbol);
+       
+       // Scan Kernel
+       for( i = 0; i < numKSyms; i++ )
+       {
+               if(strcmp(Name, gKernelSymbols[i].Name) == 0) {
+                       *Value = gKernelSymbols[i].Value;
+                       return 1;
+               }
+       }
+       
+       // Scan Loaded Libraries
+       for(pKBin = glLoadedKernelLibs;
+               pKBin;
+               pKBin = pKBin->Next )
+       {
+               if( Binary_FindSymbol(pKBin->Base, Name, Value) ) {
+                       return 1;
+               }
+       }
+       
+       Warning("[BIN ] Unable to find symbol '%s'", Name);
+       return 0;
+}
+
+/**
+ * \fn Uint Binary_FindSymbol(void *Base, char *Name, Uint *Val)
+ * \brief Get a symbol from the specified library
+ * \param Base Base address
+ * \param Name Name of symbol to find
+ * \param Val  Pointer to place final value
+ */
+Uint Binary_FindSymbol(void *Base, char *Name, Uint *Val)
+{
+       Uint32  ident = *(Uint32*) Base;
+       tBinaryType     *bt = gRegBinTypes;
+       
+       for(; bt; bt = bt->Next)
+       {
+               if( (ident & bt->Mask) == (Uint)bt->Ident )
+                       return bt->GetSymbol(Base, Name, Val);
+       }
+       
+       Warning("[BIN ] 0x%x is an unknown file type. (0x%x 0x%x 0x%x 0x%x)",
+               Base, ident&0xFF, ident>>8, ident>>16, ident>>24);
+       return 0;
+}
+
+// === EXPORTS ===
+EXPORT(Binary_FindSymbol);
+EXPORT(Binary_Unload);
index 8e62578..2bb60ca 100644 (file)
@@ -8,7 +8,7 @@
 #define NULL   ((void*)0)
 #define PACKED __attribute__ ((packed))
 
-#include <stdint.h>
+//#include <stdint.h>
 #include <arch.h>
 #include <stdarg.h>
 #include "errno.h"
index 2b066d9..f23c5b5 100644 (file)
@@ -5,6 +5,7 @@
 
 #include <arch.h>
 #include <signal.h>
+#include <proc.h>
 
 typedef struct sMessage
 {
@@ -77,6 +78,8 @@ enum eFaultNumbers
        FAULT_FLOAT
 };
 
+#define GETMSG_IGNORE  ((void*)-1)
+
 // === FUNCTIONS ===
 extern tThread *Proc_GetCurThread();
 extern tThread *Threads_GetThread(Uint TID);
index aaedf5c..32e579b 100644 (file)
@@ -3,7 +3,7 @@
  * messages.c
  */
 #include <acess.h>
-#include <proc.h>
+#include <threads.h>
 #include <errno.h>
 
 // === CODE ===
index d5e940e..04facc7 100644 (file)
@@ -4,6 +4,7 @@
  */
 #define DEBUG  0
 #include <acess.h>
+#include <mm_virt.h>
 #include "vfs.h"
 #include "vfs_int.h"
 #include "vfs_ext.h"
index ba53f12..905f5ca 100644 (file)
--- a/Makefile
+++ b/Makefile
 
 SUBMAKE = $(MAKE) --no-print-directory
 
-MODULES += $(DYNMODS)
+#MODULES += $(DYNMODS)
 USRLIBS := crt0.o acess.ld ld-acess.so libacess.so libgcc.so libc.so
 USRAPPS := init login CLIShell cat ls mount ifconfig
 
-#ALL_DYNMODS = $(addprefix all-,$(DYNMODS))
+ALL_DYNMODS = $(addprefix all-,$(DYNMODS))
 ALL_MODULES := $(addprefix all-,$(MODULES))
 ALL_USRLIBS := $(addprefix all-,$(USRLIBS))
 ALL_USRAPPS := $(addprefix all-,$(USRAPPS))
@@ -43,6 +43,8 @@ clean:        $(CLEAN_DYNMODS) $(CLEAN_MODULES) clean-Kernel $(CLEAN_USRLIBS) $(CLEAN_U
 install:       $(INSTALL_DYNMODS) $(INSTALL_MODULES) install-Kernel $(INSTALL_USRLIBS) $(INSTALL_USRAPPS)
 
 # Compile Only
+$(ALL_DYNMODS): all-%:
+       @echo === Dynamic Module: $* && BUILDTYPE=dynamic $(SUBMAKE) all -C Modules/$*
 $(ALL_MODULES): all-%:
        @echo === Module: $* && $(SUBMAKE) all -C Modules/$*
 all-Kernel:
@@ -53,8 +55,8 @@ $(ALL_USRAPPS): all-%:
        @echo === User Application: $* && $(SUBMAKE) all -C Usermode/Applications/$*_src
 
 # Compile & Install
-#$(AI_DYNMODS): allinstall-%:
-#      @echo === Dynamic Module: $* && STATIC_MODULE=yes $(SUBMAKE) all install -C Modules/$*
+$(AI_DYNMODS): allinstall-%:
+       @echo === Dynamic Module: $* && BUILDTYPE=dynamic $(SUBMAKE) all install -C Modules/$*
 $(AI_MODULES): allinstall-%:
        @echo === Module: $* && $(SUBMAKE) all install -C Modules/$*
 allinstall-Kernel:
index ad972f7..cb134be 100644 (file)
@@ -2,40 +2,42 @@
 # Acess2 Build Configuration
 #
 
-CC = i586-elf-gcc
-LD = i586-elf-ld
-AS = nasm
-OBJDUMP = i586-elf-objdump
-RM = @rm -f
-STRIP = strip
-MKDIR = mkdir
-RMDIR = rm -rf
-lCP = cp
-xCP = mcopy -D o
-xMKDIR = mmd
-xRMDIR = mdeltree
-xRM = mdel
+# Source and destination configuration
+DISTROOT := a:/Acess2
+ACESSDIR := /home/tpg/Projects/Acess2
 
+# Default build programs
+CC := gcc
+LD := ld
+AS := nasm
+OBJDUMP := objdump
+RM := @rm -f
+STRIP := strip
+MKDIR := mkdir
+RMDIR := rm -rf
+lCP := cp
+xCP := mcopy -D o
+xMKDIR := mmd
+xRMDIR := mdeltree
+xRM := mdel
+
+# Load Architecture settings
 ifeq ($(ARCH),)
-       ARCH = i386
+       ARCH := i386
 endif
--include Makefile.$(ARCH).cfg
+-include $(ACESSDIR)/Makefile.$(ARCH).cfg
 ifeq ($(ARCHDIR),)
-       ARCHDIR = x86
+       ARCHDIR := x86
 endif
+-include $(ACESSDIR)/Makefile.$(ARCHDIR).cfg
 
-FILESYSTEMS = 
-DRIVERS = 
-MODULES  = Storage/ATA Storage/FDD
+FILESYSTEMS :
+DRIVERS :
+MODULES := Storage/ATA Storage/FDD
 MODULES += Network/NE2000
 MODULES += Display/VESA
 MODULES += Display/BochsGA
 MODULES += Filesystems/Ext2
 MODULES += Filesystems/FAT
 MODULES += IPStack
-DYNMODS = USB/Core Interfaces/UDI
-
-#DISTROOT = /mnt/AcessHDD/Acess2
-#DISTROOT = ~/Projects/Acess2/Filesystem
-DISTROOT = a:/Acess2
-ACESSDIR = /home/tpg/Projects/Acess2
+DYNMODS := USB/Core Interfaces/UDI
diff --git a/Makefile.i386.cfg b/Makefile.i386.cfg
new file mode 100644 (file)
index 0000000..8f8b9ca
--- /dev/null
@@ -0,0 +1,14 @@
+#
+# Acess2 Build Configuration
+#
+
+CC = i586-elf-gcc
+LD = i586-elf-ld
+AS = nasm
+OBJDUMP = i586-elf-objdump
+RM = @rm -f
+STRIP = strip
+MKDIR = mkdir
+
+ARCHDIR = x86
+
diff --git a/Makefile.x86_64.cfg b/Makefile.x86_64.cfg
new file mode 100644 (file)
index 0000000..ac012f6
--- /dev/null
@@ -0,0 +1,8 @@
+
+CC = x86_64-linux-gnu-gcc
+LD = ld
+
+KERNEL_CFLAGS = -mcmodel=large
+
+ARCHDIR = x86_64
+
index a79f09a..08cbe60 100644 (file)
@@ -1,7 +1,7 @@
 #
 #
 
-OBJ  = main.o link.o arp.o
+OBJ := main.o link.o arp.o
 OBJ += ipv4.o icmp.o
 OBJ += ipv6.o
 OBJ += udp.o tcp.o
index 9a1b6e8..a1775dd 100644 (file)
@@ -4,26 +4,33 @@
 
 _CPPFLAGS := $(CPPFLAGS)
 
-CFGFILES = 
+CFGFILES :
 CFGFILES += $(shell test -f ../../../Makefile.cfg && echo ../../../Makefile.cfg)
 CFGFILES += $(shell test -f ../../Makefile.cfg && echo ../../Makefile.cfg)
 CFGFILES += $(shell test -f ../Makefile.cfg && echo ../Makefile.cfg)
 CFGFILES += $(shell test -f Makefile.cfg && echo Makefile.cfg)
 -include $(CFGFILES)
 
-CPPFLAGS = -I$(ACESSDIR)/Kernel/include -I$(ACESSDIR)/Kernel/arch/$(ARCHDIR)/include -DARCH=$(ARCH) $(_CPPFLAGS)
-CFLAGS = -Wall -Werror -fno-stack-protector $(CPPFLAGS) -O3
-
-OBJ := $(addsuffix .$(ARCH),$(OBJ))
-ifneq ($(CATEGORY),)
-       BIN := ../$(CATEGORY)_$(NAME).kmd.$(ARCH)
+CPPFLAGS := -I$(ACESSDIR)/Kernel/include -I$(ACESSDIR)/Kernel/arch/$(ARCHDIR)/include -DARCH=$(ARCH) $(_CPPFLAGS)
+CFLAGS := $(KERNEL_CFLAGS) -Wall -Werror -fno-stack-protector $(CPPFLAGS) -O3 -fno-builtin
+
+ifeq ($(BUILDTYPE),dynamic)
+       _SUFFIX := dyn_$(ARCH)
+       ifneq ($(CATEGORY),)
+               BIN := ../$(CATEGORY)_$(NAME).kmd.$(ARCH)
+       else
+               BIN := ../$(NAME).kmd.$(ARCH)
+       endif
+       CFLAGS += -fPIC
 else
-       BIN := ../$(NAME).kmd.$(ARCH)
+       _SUFFIX := st_$(ARCH)
+       BIN := ../$(NAME).xo.$(ARCH)
 endif
-KOBJ = ../$(NAME).xo.$(ARCH)
 
-DEPFILES  = $(filter %.o.$(ARCH),$(OBJ))
-DEPFILES := $(DEPFILES:%.o.$(ARCH)=%.d.$(ARCH))
+OBJ := $(addsuffix .$(_SUFFIX),$(OBJ))
+
+DEPFILES := $(filter %.o.$(_SUFFIX),$(OBJ))
+DEPFILES := $(DEPFILES:%.o.$(_SUFFIX)=%.d.$(ARCH))
 
 .PHONY: all clean
 
@@ -35,14 +42,19 @@ clean:
 install: $(BIN)
        $(xCP) $(BIN) $(DISTROOT)/Modules/$(NAME).kmd
 
-$(BIN): $(OBJ)
+ifeq ($(BUILDTYPE),dynamic)
+$(BIN): %.kmd.$(ARCH): $(OBJ)
        @echo --- $(LD) -o $@
-       @$(LD) -T $(ACESSDIR)/Modules/link.ld -shared -nostdlib -o $@ $(OBJ)
+#      $(LD) -T $(ACESSDIR)/Modules/link.ld --allow-shlib-undefined -shared -nostdlib -o $@ $(OBJ)
+       $(LD) --allow-shlib-undefined -shared -nostdlib -o $@ $(OBJ)
        @$(OBJDUMP) -d $(BIN) > $(BIN).dsm
-       @echo --- $(LD) -o $(KOBJ)
-       @$(CC) -Wl,-r -nostdlib -o $(KOBJ) $(OBJ)
+else
+$(BIN): %.xo.$(ARCH): $(OBJ)
+       @echo --- $(LD) -o $@
+       @$(LD) -r -o $@ $(OBJ)
+endif
 
-%.o.$(ARCH): %.c Makefile ../Makefile.tpl $(CFGFILES)
+%.o.$(_SUFFIX): %.c Makefile ../Makefile.tpl $(CFGFILES)
        @echo --- $(CC) -o $@
        @$(CC) $(CFLAGS) -o $@ -c $<
        @$(CC) -M $(CPPFLAGS) -MT $@ -o $*.d.$(ARCH) $<
index dac5a2a..376563b 100644 (file)
@@ -150,7 +150,7 @@ int ATA_SetupIO()
        if( !(gATA_BusMasterBase & 1) )
        {
                if( gATA_BusMasterBase < 0x100000 )
-                       gATA_BusMasterBasePtr = (void*)(KERNEL_BASE|gATA_BusMasterBase);
+                       gATA_BusMasterBasePtr = (void*)(KERNEL_BASE | (tVAddr)gATA_BusMasterBase);
                else
                        gATA_BusMasterBasePtr = (void*)( MM_MapHWPages( gATA_BusMasterBase, 1 ) + (gATA_BusMasterBase&0xFFF) );
                LOG("gATA_BusMasterBasePtr = %p", gATA_BusMasterBasePtr);
@@ -164,15 +164,15 @@ int ATA_SetupIO()
        IRQ_AddHandler( gATA_IRQPri, ATA_IRQHandlerPri );
        IRQ_AddHandler( gATA_IRQSec, ATA_IRQHandlerSec );
 
-       gATA_PRDTs[0].PBufAddr = MM_GetPhysAddr( (Uint)&gATA_Buffers[0] );
-       gATA_PRDTs[1].PBufAddr = MM_GetPhysAddr( (Uint)&gATA_Buffers[1] );
+       gATA_PRDTs[0].PBufAddr = MM_GetPhysAddr( (tVAddr)&gATA_Buffers[0] );
+       gATA_PRDTs[1].PBufAddr = MM_GetPhysAddr( (tVAddr)&gATA_Buffers[1] );
 
        LOG("gATA_PRDTs = {PBufAddr: 0x%x, PBufAddr: 0x%x}", gATA_PRDTs[0].PBufAddr, gATA_PRDTs[1].PBufAddr);
 
-       addr = MM_GetPhysAddr( (Uint)&gATA_PRDTs[0] );
+       addr = MM_GetPhysAddr( (tVAddr)&gATA_PRDTs[0] );
        LOG("addr = 0x%x", addr);
        ATA_int_BusMasterWriteDWord(4, addr);
-       addr = MM_GetPhysAddr( (Uint)&gATA_PRDTs[1] );
+       addr = MM_GetPhysAddr( (tVAddr)&gATA_PRDTs[1] );
        LOG("addr = 0x%x", addr);
        ATA_int_BusMasterWriteDWord(12, addr);
 
@@ -238,9 +238,11 @@ void ATA_SetupVFS()
  */
 int ATA_ScanDisk(int Disk)
 {
-       Uint16  buf[256];
-       tIdentify       *identify = (void*)buf;
-       tMBR    *mbr = (void*)buf;
+       union {
+               Uint16  buf[256];
+               tIdentify       identify;
+               tMBR    mbr;
+       }       data;
        Uint16  base;
        Uint8   val;
         int    i;
@@ -275,13 +277,13 @@ int ATA_ScanDisk(int Disk)
        }
 
        // Read Data
-       for(i=0;i<256;i++)      buf[i] = inw(base);
+       for(i=0;i<256;i++)      data.buf[i] = inw(base);
 
        // Populate Disk Structure
-       if(identify->Sectors48 != 0)
-               gATA_Disks[ Disk ].Sectors = identify->Sectors48;
+       if(data.identify.Sectors48 != 0)
+               gATA_Disks[ Disk ].Sectors = data.identify.Sectors48;
        else
-               gATA_Disks[ Disk ].Sectors = identify->Sectors28;
+               gATA_Disks[ Disk ].Sectors = data.identify.Sectors28;
 
 
        LOG("gATA_Disks[ Disk ].Sectors = 0x%x", gATA_Disks[ Disk ].Sectors);
@@ -318,10 +320,10 @@ int ATA_ScanDisk(int Disk)
        // --- Scan Partitions ---
        LOG("Reading MBR");
        // Read Boot Sector
-       ATA_ReadDMA( Disk, 0, 1, mbr );
+       ATA_ReadDMA( Disk, 0, 1, &data.mbr );
 
        // Check for a GPT table
-       if(mbr->Parts[0].SystemID == 0xEE)
+       if(data.mbr.Parts[0].SystemID == 0xEE)
                ATA_ParseGPT(Disk);
        else    // No? Just parse the MBR
                ATA_ParseMBR(Disk);
index f72e548..6ad2b1a 100644 (file)
-/*\r
- * AcessOS 0.1\r
- * Floppy Disk Access Code\r
- */\r
-#define DEBUG  0\r
-#include <acess.h>\r
-#include <modules.h>\r
-#include <fs_devfs.h>\r
-#include <tpl_drv_disk.h>\r
-#include <dma.h>\r
-#include <iocache.h>\r
-\r
-#define WARN   0\r
-\r
-// === CONSTANTS ===\r
-// --- Current Version\r
-#define FDD_VERSION     ((0<<8)|(75))\r
-\r
-// --- Options\r
-#define FDD_SEEK_TIMEOUT       10      // Timeout for a seek operation\r
-#define MOTOR_ON_DELAY 500             // Miliseconds\r
-#define MOTOR_OFF_DELAY        2000    // Miliseconds\r
-#define        FDD_MAX_READWRITE_ATTEMPTS      16\r
-\r
-// === TYPEDEFS ===\r
-/**\r
- * \brief Representation of a floppy drive\r
- */\r
-typedef struct sFloppyDrive\r
-{\r
-        int    type;\r
-       volatile int    motorState;     //2 - On, 1 - Spinup, 0 - Off\r
-        int    track[2];\r
-        int    timer;\r
-       tVFS_Node       Node;\r
-       #if !USE_CACHE\r
-       tIOCache        *CacheHandle;\r
-       #endif\r
-} t_floppyDevice;\r
-\r
-/**\r
- * \brief Cached Sector\r
- */\r
-typedef struct {\r
-       Uint64  timestamp;\r
-       Uint16  disk;\r
-       Uint16  sector; // Allows 32Mb of addressable space (Plenty for FDD)\r
-       Uint8   data[512];\r
-} t_floppySector;\r
-\r
-// === CONSTANTS ===\r
-static const char      *cFDD_TYPES[] = {"None", "360kB 5.25\"", "1.2MB 5.25\"", "720kB 3.5\"", "1.44MB 3.5\"", "2.88MB 3.5\"" };\r
-static const int       cFDD_SIZES[] = { 0, 360*1024, 1200*1024, 720*1024, 1440*1024, 2880*1024 };\r
-static const short     cPORTBASE[] = { 0x3F0, 0x370 };\r
-#if DEBUG\r
-static const char      *cFDD_STATUSES[] = {NULL, "Error", "Invalid command", "Drive not ready"};\r
-#endif\r
-\r
-enum FloppyPorts {\r
-       PORT_STATUSA    = 0x0,\r
-       PORT_STATUSB    = 0x1,\r
-       PORT_DIGOUTPUT  = 0x2,\r
-       PORT_MAINSTATUS = 0x4,\r
-       PORT_DATARATE   = 0x4,\r
-       PORT_DATA               = 0x5,\r
-       PORT_DIGINPUT   = 0x7,\r
-       PORT_CONFIGCTRL = 0x7\r
-};\r
-\r
-enum FloppyCommands {\r
-       FIX_DRIVE_DATA  = 0x03,\r
-       HECK_DRIVE_STATUS       = 0x04,\r
-       CALIBRATE_DRIVE = 0x07,\r
-       CHECK_INTERRUPT_STATUS = 0x08,\r
-       SEEK_TRACK              = 0x0F,\r
-       READ_SECTOR_ID  = 0x4A,\r
-       FORMAT_TRACK    = 0x4D,\r
-       READ_TRACK              = 0x42,\r
-       READ_SECTOR             = 0x66,\r
-       WRITE_SECTOR    = 0xC5,\r
-       WRITE_DELETE_SECTOR     = 0xC9,\r
-       READ_DELETE_SECTOR      = 0xCC,\r
-};\r
-\r
-// === PROTOTYPES ===\r
-// --- Filesystem\r
- int   FDD_Install(char **Arguments);\r
-void   FDD_UnloadModule();\r
-// --- VFS Methods\r
-char   *FDD_ReadDir(tVFS_Node *Node, int pos);\r
-tVFS_Node      *FDD_FindDir(tVFS_Node *dirNode, char *Name);\r
- int   FDD_IOCtl(tVFS_Node *Node, int ID, void *Data);\r
-Uint64 FDD_ReadFS(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer);\r
-// --- Functions for IOCache/DrvUtil\r
-Uint   FDD_ReadSectors(Uint64 SectorAddr, Uint Count, void *Buffer, Uint Disk);\r
-// --- Raw Disk Access\r
- int   FDD_ReadSector(Uint32 disk, Uint64 lba, void *Buffer);\r
- int   FDD_WriteSector(Uint32 Disk, Uint64 LBA, void *Buffer);\r
-// --- Helpers\r
-void   FDD_IRQHandler(int Num);\r
-inline void    FDD_WaitIRQ();\r
-void   FDD_SensInt(int base, Uint8 *sr0, Uint8 *cyl);\r
-void   FDD_int_SendByte(int base, char byte);\r
- int   FDD_int_GetByte(int base);\r
-void   FDD_Reset(int id);\r
-void   FDD_Recalibrate(int disk);\r
- int   FDD_int_SeekTrack(int disk, int head, int track);\r
-void   FDD_int_TimerCallback(int arg);\r
-void   FDD_int_StopMotor(int disk);\r
-void   FDD_int_StartMotor(int disk);\r
- int   FDD_int_GetDims(int type, int lba, int *c, int *h, int *s, int *spt);\r
-\r
-// === GLOBALS ===\r
-MODULE_DEFINE(0, FDD_VERSION, FDD, FDD_Install, NULL, "ISADMA", NULL);\r
-t_floppyDevice gFDD_Devices[2];\r
-tSpinlock      glFDD;\r
-volatile int   gbFDD_IrqFired = 0;\r
-tDevFS_Driver  gFDD_DriverInfo = {\r
-       NULL, "fdd",\r
-       {\r
-       .Size = -1,\r
-       .NumACLs = 1,\r
-       .ACLs = &gVFS_ACL_EveryoneRX,\r
-       .Flags = VFS_FFLAG_DIRECTORY,\r
-       .ReadDir = FDD_ReadDir,\r
-       .FindDir = FDD_FindDir,\r
-       .IOCtl = FDD_IOCtl\r
-       }\r
-};\r
-\r
-// === CODE ===\r
-/**\r
- * \fn int FDD_Install(char **Arguments)\r
- * \brief Installs floppy driver\r
- */\r
-int FDD_Install(char **Arguments)\r
-{\r
-       Uint8 data;\r
-       \r
-       // Determine Floppy Types (From CMOS)\r
-       outb(0x70, 0x10);\r
-       data = inb(0x71);\r
-       gFDD_Devices[0].type = data >> 4;\r
-       gFDD_Devices[1].type = data & 0xF;\r
-       gFDD_Devices[0].track[0] = -1;\r
-       gFDD_Devices[1].track[1] = -1;\r
-       \r
-       Log_Log("FDD", "Detected Disk 0: %s and Disk 1: %s", cFDD_TYPES[data>>4], cFDD_TYPES[data&0xF]);\r
-       \r
-       if( data == 0 ) {\r
-               return MODULE_ERR_NOTNEEDED;\r
-       }\r
-       \r
-       // Clear FDD IRQ Flag\r
-       FDD_SensInt(0x3F0, NULL, NULL);\r
-       // Install IRQ6 Handler\r
-       IRQ_AddHandler(6, FDD_IRQHandler);\r
-       // Reset Primary FDD Controller\r
-       FDD_Reset(0);\r
-       \r
-       // Initialise Root Node\r
-       gFDD_DriverInfo.RootNode.CTime = gFDD_DriverInfo.RootNode.MTime\r
-               = gFDD_DriverInfo.RootNode.ATime = now();\r
-       \r
-       // Initialise Child Nodes\r
-       gFDD_Devices[0].Node.Inode = 0;\r
-       gFDD_Devices[0].Node.Flags = 0;\r
-       gFDD_Devices[0].Node.NumACLs = 0;\r
-       gFDD_Devices[0].Node.Read = FDD_ReadFS;\r
-       gFDD_Devices[0].Node.Write = NULL;//FDD_WriteFS;\r
-       memcpy(&gFDD_Devices[1].Node, &gFDD_Devices[0].Node, sizeof(tVFS_Node));\r
-       \r
-       gFDD_Devices[1].Node.Inode = 1;\r
-       \r
-       // Set Lengths\r
-       gFDD_Devices[0].Node.Size = cFDD_SIZES[data >> 4];\r
-       gFDD_Devices[1].Node.Size = cFDD_SIZES[data & 0xF];\r
-       \r
-       // Create Sector Cache\r
-       if( cFDD_SIZES[data >> 4] )\r
-       {\r
-               gFDD_Devices[0].CacheHandle = IOCache_Create(\r
-                       FDD_WriteSector, 0, 512,\r
-                       gFDD_Devices[0].Node.Size / (512*4)\r
-                       );      // Cache is 1/4 the size of the disk\r
-       }\r
-       if( cFDD_SIZES[data & 15] )\r
-       {\r
-               gFDD_Devices[1].CacheHandle = IOCache_Create(\r
-                       FDD_WriteSector, 0, 512,\r
-                       gFDD_Devices[1].Node.Size / (512*4)\r
-                       );      // Cache is 1/4 the size of the disk\r
-       }\r
-       \r
-       // Register with devfs\r
-       DevFS_AddDevice(&gFDD_DriverInfo);\r
-       \r
-       return MODULE_ERR_OK;\r
-}\r
-\r
-/**\r
- * \brief Prepare the module for removal\r
- */\r
-void FDD_UnloadModule()\r
-{\r
-        int    i;\r
-       //DevFS_DelDevice( &gFDD_DriverInfo );\r
-       LOCK(&glFDD);\r
-       for(i=0;i<4;i++) {\r
-               Time_RemoveTimer(gFDD_Devices[i].timer);\r
-               FDD_int_StopMotor(i);\r
-       }\r
-       RELEASE(&glFDD);\r
-       //IRQ_Clear(6);\r
-}\r
-\r
-/**\r
- * \fn char *FDD_ReadDir(tVFS_Node *Node, int pos)\r
- * \brief Read Directory\r
- */\r
-char *FDD_ReadDir(tVFS_Node *Node, int Pos)\r
-{\r
-       char    name[2] = "0\0";\r
-\r
-       if(Pos >= 2 || Pos < 0) return NULL;\r
-       \r
-       if(gFDD_Devices[Pos].type == 0) return VFS_SKIP;\r
-       \r
-       name[0] += Pos;\r
-       \r
-       return strdup(name);\r
-}\r
-\r
-/**\r
- * \fn tVFS_Node *FDD_FindDir(tVFS_Node *Node, char *filename);\r
- * \brief Find File Routine (for vfs_node)\r
- */\r
-tVFS_Node *FDD_FindDir(tVFS_Node *Node, char *Filename)\r
-{\r
-        int    i;\r
-       \r
-       ENTER("sFilename", Filename);\r
-       \r
-       // Sanity check string\r
-       if(Filename == NULL) {\r
-               LEAVE('n');\r
-               return NULL;\r
-       }\r
-       \r
-       // Check string length (should be 1)\r
-       if(Filename[0] == '\0' || Filename[1] != '\0') {\r
-               LEAVE('n');\r
-               return NULL;\r
-       }\r
-       \r
-       // Get First character\r
-       i = Filename[0] - '0';\r
-       \r
-       // Check for 1st disk and if it is present return\r
-       if(i == 0 && gFDD_Devices[0].type != 0) {\r
-               LEAVE('p', &gFDD_Devices[0].Node);\r
-               return &gFDD_Devices[0].Node;\r
-       }\r
-       \r
-       // Check for 2nd disk and if it is present return\r
-       if(i == 1 && gFDD_Devices[1].type != 0) {\r
-               LEAVE('p', &gFDD_Devices[1].Node);\r
-               return &gFDD_Devices[1].Node;\r
-       }\r
-       \r
-       // Else return null\r
-       LEAVE('n');\r
-       return NULL;\r
-}\r
-\r
-static const char      *casIOCTLS[] = {DRV_IOCTLNAMES,DRV_DISK_IOCTLNAMES,NULL};\r
-/**\r
- * \fn int FDD_IOCtl(tVFS_Node *Node, int id, void *data)\r
- * \brief Stub ioctl function\r
- */\r
-int FDD_IOCtl(tVFS_Node *Node, int ID, void *Data)\r
-{\r
-       switch(ID)\r
-       {\r
-       case DRV_IOCTL_TYPE:    return DRV_TYPE_DISK;\r
-       case DRV_IOCTL_IDENT:   return ModUtil_SetIdent(Data, "FDD");\r
-       case DRV_IOCTL_VERSION: return FDD_VERSION;\r
-       case DRV_IOCTL_LOOKUP:  return ModUtil_LookupString((char**)casIOCTLS, Data);\r
-       \r
-       case DISK_IOCTL_GETBLOCKSIZE:   return 512;     \r
-       \r
-       default:\r
-               return 0;\r
-       }\r
-}\r
-\r
-/**\r
- * \fn Uint64 FDD_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)\r
- * \brief Read Data from a disk\r
-*/\r
-Uint64 FDD_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)\r
-{\r
-        int    ret;\r
-       \r
-       ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);\r
-       \r
-       if(Node == NULL) {\r
-               LEAVE('i', -1);\r
-               return -1;\r
-       }\r
-       \r
-       if(Node->Inode != 0 && Node->Inode != 1) {\r
-               LEAVE('i', -1);\r
-               return -1;\r
-       }\r
-       \r
-       ret = DrvUtil_ReadBlock(Offset, Length, Buffer, FDD_ReadSectors, 512, Node->Inode);\r
-       LEAVE('i', ret);\r
-       return ret;\r
-}\r
-\r
-/**\r
- * \brief Reads \a Count contiguous sectors from a disk\r
- * \param SectorAddr   Address of the first sector\r
- * \param Count        Number of sectors to read\r
- * \param Buffer       Destination Buffer\r
- * \param Disk Disk Number\r
- * \return Number of sectors read\r
- * \note Used as a ::DrvUtil_ReadBlock helper\r
- */\r
-Uint FDD_ReadSectors(Uint64 SectorAddr, Uint Count, void *Buffer, Uint Disk)\r
-{\r
-       Uint    ret = 0;\r
-       while(Count --)\r
-       {\r
-               if( FDD_ReadSector(Disk, SectorAddr, Buffer) != 1 )\r
-                       return ret;\r
-               \r
-               Buffer = (void*)( (tVAddr)Buffer + 512 );\r
-               SectorAddr ++;\r
-               ret ++;\r
-       }\r
-       return ret;\r
-}\r
-\r
-int FDD_int_ReadWriteSector(Uint32 Disk, Uint64 SectorAddr, int Write, void *Buffer)\r
-{\r
-        int    cyl, head, sec;\r
-        int    spt, base;\r
-        int    i;\r
-        int    lba = SectorAddr;\r
-       Uint8   st0, st1, st2, rcy, rhe, rse, bps;      //      Status Values\r
-       \r
-       ENTER("iDisk XSectorAddr pBuffer", Disk, SectorAddr, Buffer);\r
-       \r
-       base = cPORTBASE[Disk >> 1];\r
-       \r
-       LOG("Calculating Disk Dimensions");\r
-       // Get CHS position\r
-       if(FDD_int_GetDims(gFDD_Devices[Disk].type, lba, &cyl, &head, &sec, &spt) != 1)\r
-       {\r
-               LEAVE('i', -1);\r
-               return -1;\r
-       }\r
-       LOG("Cyl=%i, Head=%i, Sector=%i", cyl, head, sec);\r
-       \r
-       LOCK(&glFDD);   // Lock to stop the motor stopping on us\r
-       Time_RemoveTimer(gFDD_Devices[Disk].timer);     // Remove Old Timer\r
-       // Start motor if needed\r
-       if(gFDD_Devices[Disk].motorState != 2)  FDD_int_StartMotor(Disk);\r
-       RELEASE(&glFDD);\r
-       \r
-       LOG("Wait for the motor to spin up");\r
-       \r
-       // Wait for spinup\r
-       while(gFDD_Devices[Disk].motorState == 1)       Threads_Yield();\r
-       \r
-       LOG("Acquire Spinlock");\r
-       LOCK(&glFDD);\r
-       \r
-       // Seek to track\r
-       outb(base + CALIBRATE_DRIVE, 0);\r
-       i = 0;\r
-       while(FDD_int_SeekTrack(Disk, head, (Uint8)cyl) == 0 && i++ < FDD_SEEK_TIMEOUT )\r
-               Threads_Yield();\r
-       if( i > FDD_SEEK_TIMEOUT ) {\r
-               RELEASE(&glFDD);\r
-               LEAVE('i', 0);\r
-               return 0;\r
-       }\r
-       //FDD_SensInt(base, NULL, NULL);        // Wait for IRQ\r
-               \r
-       // Read Data from DMA\r
-       LOG("Setting DMA for read");\r
-       DMA_SetChannel(2, 512, !Write); // Read 512 Bytes from channel 2\r
-       \r
-       LOG("Sending command");\r
-       \r
-       //Threads_Wait(100);    // Wait for Head to settle\r
-       Time_Delay(100);\r
-       \r
-       for( i = 0; i < FDD_MAX_READWRITE_ATTEMPTS; i ++ )\r
-       {\r
-               if( Write )\r
-                       FDD_int_SendByte(base, READ_SECTOR);    // Was 0xE6\r
-               else\r
-                       FDD_int_SendByte(base, READ_SECTOR);    // Was 0xE6\r
-               FDD_int_SendByte(base, (head << 2) | (Disk&1));\r
-               FDD_int_SendByte(base, (Uint8)cyl);\r
-               FDD_int_SendByte(base, (Uint8)head);\r
-               FDD_int_SendByte(base, (Uint8)sec);\r
-               FDD_int_SendByte(base, 0x02);   // Bytes Per Sector (Real BPS=128*2^{val})\r
-               FDD_int_SendByte(base, spt);    // SPT\r
-               FDD_int_SendByte(base, 0x1B);   // Gap Length (27 is default)\r
-               FDD_int_SendByte(base, 0xFF);   // Data Length\r
-               \r
-               // Wait for IRQ\r
-               if( Write ) {\r
-                       LOG("Writing Data");\r
-                       DMA_WriteData(2, 512, Buffer);\r
-                       LOG("Waiting for Data to be written");\r
-                       FDD_WaitIRQ();\r
-               }\r
-               else {\r
-                       LOG("Waiting for data to be read");\r
-                       FDD_WaitIRQ();\r
-                       LOG("Reading Data");\r
-                       DMA_ReadData(2, 512, Buffer);\r
-               }\r
-               \r
-               // Clear Input Buffer\r
-               LOG("Clearing Input Buffer");\r
-               // Status Values\r
-               st0 = FDD_int_GetByte(base);\r
-               st1 = FDD_int_GetByte(base);\r
-               st2 = FDD_int_GetByte(base);\r
-               \r
-               // Cylinder, Head and Sector (mutilated in some way\r
-               rcy = FDD_int_GetByte(base);\r
-               rhe = FDD_int_GetByte(base);\r
-               rse = FDD_int_GetByte(base);\r
-               // Should be the BPS set above (0x02)\r
-               bps = FDD_int_GetByte(base);\r
-               \r
-               // Check Status\r
-               // - Error Code\r
-               if(st0 & 0xC0) {\r
-                       LOG("Error (st0 & 0xC0) \"%s\"", cFDD_STATUSES[st0 >> 6]);\r
-                       continue;\r
-        }\r
-        // - Status Flags\r
-        if(st0 & 0x08) {       LOG("Drive not ready"); continue;       }\r
-        if(st1 & 0x80) {       LOG("End of Cylinder"); continue;       }\r
-               if(st1 & 0x20) {        LOG("CRC Error");       continue;       }\r
-               if(st1 & 0x10) {        LOG("Controller Timeout");      continue;       }\r
-               if(st1 & 0x04) {        LOG("No Data Found");   continue;       }\r
-               if(st1 & 0x01 || st2 & 0x01) {\r
-                       LOG("No Address mark found");\r
-                       continue;\r
-               }\r
-        if(st2 & 0x40) {       LOG("Deleted address mark");    continue;       }\r
-               if(st2 & 0x20) {        LOG("CRC error in data");       continue;       }\r
-               if(st2 & 0x10) {        LOG("Wrong Cylinder");  continue;       }\r
-               if(st2 & 0x04) {        LOG("uPD765 sector not found"); continue;       }\r
-               if(st2 & 0x02) {        LOG("Bad Cylinder");    continue;       }\r
-               \r
-               if(bps != 0x2) {\r
-                       LOG("Returned BPS = 0x%02x, not 0x02", bps);\r
-                       continue;\r
-               }\r
-               \r
-               if(st1 & 0x02) {\r
-                       LOG("Floppy not writable");\r
-                       i = FDD_MAX_READWRITE_ATTEMPTS+1;\r
-                       break;\r
-               }\r
-               \r
-               // Success!\r
-               break;\r
-       }\r
-       \r
-       // Release Spinlock\r
-       LOG("Realeasing Spinlock and setting motor to stop");\r
-       RELEASE(&glFDD);\r
-       \r
-       if(i == FDD_MAX_READWRITE_ATTEMPTS) {\r
-               Log_Warning("FDD", "Exceeded %i attempts in %s the disk",\r
-                       FDD_MAX_READWRITE_ATTEMPTS,\r
-                       (Write ? "writing to" : "reading from")\r
-                       );\r
-       }\r
-       \r
-       // Don't turn the motor off now, wait for a while\r
-       gFDD_Devices[Disk].timer = Time_CreateTimer(MOTOR_OFF_DELAY, FDD_int_StopMotor, (void*)Disk);\r
-\r
-       if( i < FDD_MAX_READWRITE_ATTEMPTS ) {\r
-               LEAVE('i', 0);\r
-               return 0;\r
-       }\r
-       else {\r
-               LEAVE('i', 1);\r
-               return 1;\r
-       }\r
-}\r
-\r
-/**\r
- * \fn int FDD_ReadSector(Uint32 Disk, Uint64 SectorAddr, void *Buffer)\r
- * \brief Read a sector from disk\r
- * \todo Make real-hardware safe (account for read errors)\r
-*/\r
-int FDD_ReadSector(Uint32 Disk, Uint64 SectorAddr, void *Buffer)\r
-{\r
-        int    ret;\r
-       \r
-       ENTER("iDisk XSectorAddr pBuffer", Disk, SectorAddr, Buffer);\r
-       \r
-       if( IOCache_Read( gFDD_Devices[Disk].CacheHandle, SectorAddr, Buffer ) == 1 ) {\r
-               LEAVE('i', 1);\r
-               return 1;\r
-       }\r
-       \r
-       // Pass to general function\r
+/*
+ * AcessOS 0.1
+ * Floppy Disk Access Code
+ */
+#define DEBUG  0
+#include <acess.h>
+#include <modules.h>
+#include <fs_devfs.h>
+#include <tpl_drv_disk.h>
+#include <dma.h>
+#include <iocache.h>
+
+#define WARN   0
+
+// === CONSTANTS ===
+// --- Current Version
+#define FDD_VERSION     ((0<<8)|(75))
+
+// --- Options
+#define FDD_SEEK_TIMEOUT       10      // Timeout for a seek operation
+#define MOTOR_ON_DELAY 500             // Miliseconds
+#define MOTOR_OFF_DELAY        2000    // Miliseconds
+#define        FDD_MAX_READWRITE_ATTEMPTS      16
+
+// === TYPEDEFS ===
+/**
+ * \brief Representation of a floppy drive
+ */
+typedef struct sFloppyDrive
+{
+        int    type;
+       volatile int    motorState;     //2 - On, 1 - Spinup, 0 - Off
+        int    track[2];
+        int    timer;
+       tVFS_Node       Node;
+       #if !USE_CACHE
+       tIOCache        *CacheHandle;
+       #endif
+} t_floppyDevice;
+
+/**
+ * \brief Cached Sector
+ */
+typedef struct {
+       Uint64  timestamp;
+       Uint16  disk;
+       Uint16  sector; // Allows 32Mb of addressable space (Plenty for FDD)
+       Uint8   data[512];
+} t_floppySector;
+
+// === CONSTANTS ===
+static const char      *cFDD_TYPES[] = {"None", "360kB 5.25\"", "1.2MB 5.25\"", "720kB 3.5\"", "1.44MB 3.5\"", "2.88MB 3.5\"" };
+static const int       cFDD_SIZES[] = { 0, 360*1024, 1200*1024, 720*1024, 1440*1024, 2880*1024 };
+static const short     cPORTBASE[] = { 0x3F0, 0x370 };
+#if DEBUG
+static const char      *cFDD_STATUSES[] = {NULL, "Error", "Invalid command", "Drive not ready"};
+#endif
+
+enum FloppyPorts {
+       PORT_STATUSA    = 0x0,
+       PORT_STATUSB    = 0x1,
+       PORT_DIGOUTPUT  = 0x2,
+       PORT_MAINSTATUS = 0x4,
+       PORT_DATARATE   = 0x4,
+       PORT_DATA               = 0x5,
+       PORT_DIGINPUT   = 0x7,
+       PORT_CONFIGCTRL = 0x7
+};
+
+enum FloppyCommands {
+       FIX_DRIVE_DATA  = 0x03,
+       HECK_DRIVE_STATUS       = 0x04,
+       CALIBRATE_DRIVE = 0x07,
+       CHECK_INTERRUPT_STATUS = 0x08,
+       SEEK_TRACK              = 0x0F,
+       READ_SECTOR_ID  = 0x4A,
+       FORMAT_TRACK    = 0x4D,
+       READ_TRACK              = 0x42,
+       READ_SECTOR             = 0x66,
+       WRITE_SECTOR    = 0xC5,
+       WRITE_DELETE_SECTOR     = 0xC9,
+       READ_DELETE_SECTOR      = 0xCC,
+};
+
+// === PROTOTYPES ===
+// --- Filesystem
+ int   FDD_Install(char **Arguments);
+void   FDD_UnloadModule();
+// --- VFS Methods
+char   *FDD_ReadDir(tVFS_Node *Node, int pos);
+tVFS_Node      *FDD_FindDir(tVFS_Node *dirNode, char *Name);
+ int   FDD_IOCtl(tVFS_Node *Node, int ID, void *Data);
+Uint64 FDD_ReadFS(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer);
+// --- Functions for IOCache/DrvUtil
+Uint   FDD_ReadSectors(Uint64 SectorAddr, Uint Count, void *Buffer, Uint Disk);
+// --- Raw Disk Access
+ int   FDD_ReadSector(Uint32 disk, Uint64 lba, void *Buffer);
+ int   FDD_WriteSector(Uint32 Disk, Uint64 LBA, void *Buffer);
+// --- Helpers
+void   FDD_IRQHandler(int Num);
+inline void    FDD_WaitIRQ();
+void   FDD_SensInt(int base, Uint8 *sr0, Uint8 *cyl);
+void   FDD_int_SendByte(int base, char byte);
+ int   FDD_int_GetByte(int base);
+void   FDD_Reset(int id);
+void   FDD_Recalibrate(int disk);
+ int   FDD_int_SeekTrack(int disk, int head, int track);
+void   FDD_int_TimerCallback(int arg);
+void   FDD_int_StopMotor(int disk);
+void   FDD_int_StartMotor(int disk);
+ int   FDD_int_GetDims(int type, int lba, int *c, int *h, int *s, int *spt);
+
+// === GLOBALS ===
+MODULE_DEFINE(0, FDD_VERSION, FDD, FDD_Install, NULL, "ISADMA", NULL);
+t_floppyDevice gFDD_Devices[2];
+tSpinlock      glFDD;
+volatile int   gbFDD_IrqFired = 0;
+tDevFS_Driver  gFDD_DriverInfo = {
+       NULL, "fdd",
+       {
+       .Size = -1,
+       .NumACLs = 1,
+       .ACLs = &gVFS_ACL_EveryoneRX,
+       .Flags = VFS_FFLAG_DIRECTORY,
+       .ReadDir = FDD_ReadDir,
+       .FindDir = FDD_FindDir,
+       .IOCtl = FDD_IOCtl
+       }
+};
+
+// === CODE ===
+/**
+ * \fn int FDD_Install(char **Arguments)
+ * \brief Installs floppy driver
+ */
+int FDD_Install(char **Arguments)
+{
+       Uint8 data;
+       
+       // Determine Floppy Types (From CMOS)
+       outb(0x70, 0x10);
+       data = inb(0x71);
+       gFDD_Devices[0].type = data >> 4;
+       gFDD_Devices[1].type = data & 0xF;
+       gFDD_Devices[0].track[0] = -1;
+       gFDD_Devices[1].track[1] = -1;
+       
+       Log_Log("FDD", "Detected Disk 0: %s and Disk 1: %s", cFDD_TYPES[data>>4], cFDD_TYPES[data&0xF]);
+       
+       if( data == 0 ) {
+               return MODULE_ERR_NOTNEEDED;
+       }
+       
+       // Clear FDD IRQ Flag
+       FDD_SensInt(0x3F0, NULL, NULL);
+       // Install IRQ6 Handler
+       IRQ_AddHandler(6, FDD_IRQHandler);
+       // Reset Primary FDD Controller
+       FDD_Reset(0);
+       
+       // Initialise Root Node
+       gFDD_DriverInfo.RootNode.CTime = gFDD_DriverInfo.RootNode.MTime
+               = gFDD_DriverInfo.RootNode.ATime = now();
+       
+       // Initialise Child Nodes
+       gFDD_Devices[0].Node.Inode = 0;
+       gFDD_Devices[0].Node.Flags = 0;
+       gFDD_Devices[0].Node.NumACLs = 0;
+       gFDD_Devices[0].Node.Read = FDD_ReadFS;
+       gFDD_Devices[0].Node.Write = NULL;//FDD_WriteFS;
+       memcpy(&gFDD_Devices[1].Node, &gFDD_Devices[0].Node, sizeof(tVFS_Node));
+       
+       gFDD_Devices[1].Node.Inode = 1;
+       
+       // Set Lengths
+       gFDD_Devices[0].Node.Size = cFDD_SIZES[data >> 4];
+       gFDD_Devices[1].Node.Size = cFDD_SIZES[data & 0xF];
+       
+       // Create Sector Cache
+       if( cFDD_SIZES[data >> 4] )
+       {
+               gFDD_Devices[0].CacheHandle = IOCache_Create(
+                       FDD_WriteSector, 0, 512,
+                       gFDD_Devices[0].Node.Size / (512*4)
+                       );      // Cache is 1/4 the size of the disk
+       }
+       if( cFDD_SIZES[data & 15] )
+       {
+               gFDD_Devices[1].CacheHandle = IOCache_Create(
+                       FDD_WriteSector, 0, 512,
+                       gFDD_Devices[1].Node.Size / (512*4)
+                       );      // Cache is 1/4 the size of the disk
+       }
+       
+       // Register with devfs
+       DevFS_AddDevice(&gFDD_DriverInfo);
+       
+       return MODULE_ERR_OK;
+}
+
+/**
+ * \brief Prepare the module for removal
+ */
+void FDD_UnloadModule()
+{
+        int    i;
+       //DevFS_DelDevice( &gFDD_DriverInfo );
+       LOCK(&glFDD);
+       for(i=0;i<4;i++) {
+               Time_RemoveTimer(gFDD_Devices[i].timer);
+               FDD_int_StopMotor(i);
+       }
+       RELEASE(&glFDD);
+       //IRQ_Clear(6);
+}
+
+/**
+ * \fn char *FDD_ReadDir(tVFS_Node *Node, int pos)
+ * \brief Read Directory
+ */
+char *FDD_ReadDir(tVFS_Node *Node, int Pos)
+{
+       char    name[2] = "0\0";
+
+       if(Pos >= 2 || Pos < 0) return NULL;
+       
+       if(gFDD_Devices[Pos].type == 0) return VFS_SKIP;
+       
+       name[0] += Pos;
+       
+       return strdup(name);
+}
+
+/**
+ * \fn tVFS_Node *FDD_FindDir(tVFS_Node *Node, char *filename);
+ * \brief Find File Routine (for vfs_node)
+ */
+tVFS_Node *FDD_FindDir(tVFS_Node *Node, char *Filename)
+{
+        int    i;
+       
+       ENTER("sFilename", Filename);
+       
+       // Sanity check string
+       if(Filename == NULL) {
+               LEAVE('n');
+               return NULL;
+       }
+       
+       // Check string length (should be 1)
+       if(Filename[0] == '\0' || Filename[1] != '\0') {
+               LEAVE('n');
+               return NULL;
+       }
+       
+       // Get First character
+       i = Filename[0] - '0';
+       
+       // Check for 1st disk and if it is present return
+       if(i == 0 && gFDD_Devices[0].type != 0) {
+               LEAVE('p', &gFDD_Devices[0].Node);
+               return &gFDD_Devices[0].Node;
+       }
+       
+       // Check for 2nd disk and if it is present return
+       if(i == 1 && gFDD_Devices[1].type != 0) {
+               LEAVE('p', &gFDD_Devices[1].Node);
+               return &gFDD_Devices[1].Node;
+       }
+       
+       // Else return null
+       LEAVE('n');
+       return NULL;
+}
+
+static const char      *casIOCTLS[] = {DRV_IOCTLNAMES,DRV_DISK_IOCTLNAMES,NULL};
+/**
+ * \fn int FDD_IOCtl(tVFS_Node *Node, int id, void *data)
+ * \brief Stub ioctl function
+ */
+int FDD_IOCtl(tVFS_Node *Node, int ID, void *Data)
+{
+       switch(ID)
+       {
+       case DRV_IOCTL_TYPE:    return DRV_TYPE_DISK;
+       case DRV_IOCTL_IDENT:   return ModUtil_SetIdent(Data, "FDD");
+       case DRV_IOCTL_VERSION: return FDD_VERSION;
+       case DRV_IOCTL_LOOKUP:  return ModUtil_LookupString((char**)casIOCTLS, Data);
+       
+       case DISK_IOCTL_GETBLOCKSIZE:   return 512;     
+       
+       default:
+               return 0;
+       }
+}
+
+/**
+ * \fn Uint64 FDD_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+ * \brief Read Data from a disk
+*/
+Uint64 FDD_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+{
+        int    ret;
+       
+       ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
+       
+       if(Node == NULL) {
+               LEAVE('i', -1);
+               return -1;
+       }
+       
+       if(Node->Inode != 0 && Node->Inode != 1) {
+               LEAVE('i', -1);
+               return -1;
+       }
+       
+       ret = DrvUtil_ReadBlock(Offset, Length, Buffer, FDD_ReadSectors, 512, Node->Inode);
+       LEAVE('i', ret);
+       return ret;
+}
+
+/**
+ * \brief Reads \a Count contiguous sectors from a disk
+ * \param SectorAddr   Address of the first sector
+ * \param Count        Number of sectors to read
+ * \param Buffer       Destination Buffer
+ * \param Disk Disk Number
+ * \return Number of sectors read
+ * \note Used as a ::DrvUtil_ReadBlock helper
+ */
+Uint FDD_ReadSectors(Uint64 SectorAddr, Uint Count, void *Buffer, Uint Disk)
+{
+       Uint    ret = 0;
+       while(Count --)
+       {
+               if( FDD_ReadSector(Disk, SectorAddr, Buffer) != 1 )
+                       return ret;
+               
+               Buffer = (void*)( (tVAddr)Buffer + 512 );
+               SectorAddr ++;
+               ret ++;
+       }
+       return ret;
+}
+
+int FDD_int_ReadWriteSector(Uint32 Disk, Uint64 SectorAddr, int Write, void *Buffer)
+{
+        int    cyl, head, sec;
+        int    spt, base;
+        int    i;
+        int    lba = SectorAddr;
+       Uint8   st0, st1, st2, rcy, rhe, rse, bps;      //      Status Values
+       
+       ENTER("iDisk XSectorAddr pBuffer", Disk, SectorAddr, Buffer);
+       
+       base = cPORTBASE[Disk >> 1];
+       
+       LOG("Calculating Disk Dimensions");
+       // Get CHS position
+       if(FDD_int_GetDims(gFDD_Devices[Disk].type, lba, &cyl, &head, &sec, &spt) != 1)
+       {
+               LEAVE('i', -1);
+               return -1;
+       }
+       LOG("Cyl=%i, Head=%i, Sector=%i", cyl, head, sec);
+       
+       LOCK(&glFDD);   // Lock to stop the motor stopping on us
+       Time_RemoveTimer(gFDD_Devices[Disk].timer);     // Remove Old Timer
+       // Start motor if needed
+       if(gFDD_Devices[Disk].motorState != 2)  FDD_int_StartMotor(Disk);
+       RELEASE(&glFDD);
+       
+       LOG("Wait for the motor to spin up");
+       
+       // Wait for spinup
+       while(gFDD_Devices[Disk].motorState == 1)       Threads_Yield();
+       
+       LOG("Acquire Spinlock");
+       LOCK(&glFDD);
+       
+       // Seek to track
+       outb(base + CALIBRATE_DRIVE, 0);
+       i = 0;
+       while(FDD_int_SeekTrack(Disk, head, (Uint8)cyl) == 0 && i++ < FDD_SEEK_TIMEOUT )
+               Threads_Yield();
+       if( i > FDD_SEEK_TIMEOUT ) {
+               RELEASE(&glFDD);
+               LEAVE('i', 0);
+               return 0;
+       }
+       //FDD_SensInt(base, NULL, NULL);        // Wait for IRQ
+               
+       // Read Data from DMA
+       LOG("Setting DMA for read");
+       DMA_SetChannel(2, 512, !Write); // Read 512 Bytes from channel 2
+       
+       LOG("Sending command");
+       
+       //Threads_Wait(100);    // Wait for Head to settle
+       Time_Delay(100);
+       
+       for( i = 0; i < FDD_MAX_READWRITE_ATTEMPTS; i ++ )
+       {
+               if( Write )
+                       FDD_int_SendByte(base, READ_SECTOR);    // Was 0xE6
+               else
+                       FDD_int_SendByte(base, READ_SECTOR);    // Was 0xE6
+               FDD_int_SendByte(base, (head << 2) | (Disk&1));
+               FDD_int_SendByte(base, (Uint8)cyl);
+               FDD_int_SendByte(base, (Uint8)head);
+               FDD_int_SendByte(base, (Uint8)sec);
+               FDD_int_SendByte(base, 0x02);   // Bytes Per Sector (Real BPS=128*2^{val})
+               FDD_int_SendByte(base, spt);    // SPT
+               FDD_int_SendByte(base, 0x1B);   // Gap Length (27 is default)
+               FDD_int_SendByte(base, 0xFF);   // Data Length
+               
+               // Wait for IRQ
+               if( Write ) {
+                       LOG("Writing Data");
+                       DMA_WriteData(2, 512, Buffer);
+                       LOG("Waiting for Data to be written");
+                       FDD_WaitIRQ();
+               }
+               else {
+                       LOG("Waiting for data to be read");
+                       FDD_WaitIRQ();
+                       LOG("Reading Data");
+                       DMA_ReadData(2, 512, Buffer);
+               }
+               
+               // Clear Input Buffer
+               LOG("Clearing Input Buffer");
+               // Status Values
+               st0 = FDD_int_GetByte(base);
+               st1 = FDD_int_GetByte(base);
+               st2 = FDD_int_GetByte(base);
+               
+               // Cylinder, Head and Sector (mutilated in some way
+               rcy = FDD_int_GetByte(base);
+               rhe = FDD_int_GetByte(base);
+               rse = FDD_int_GetByte(base);
+               // Should be the BPS set above (0x02)
+               bps = FDD_int_GetByte(base);
+               
+               // Check Status
+               // - Error Code
+               if(st0 & 0xC0) {
+                       LOG("Error (st0 & 0xC0) \"%s\"", cFDD_STATUSES[st0 >> 6]);
+                       continue;
+           }
+           // - Status Flags
+           if(st0 & 0x08) {    LOG("Drive not ready"); continue;       }
+           if(st1 & 0x80) {    LOG("End of Cylinder"); continue;       }
+               if(st1 & 0x20) {        LOG("CRC Error");       continue;       }
+               if(st1 & 0x10) {        LOG("Controller Timeout");      continue;       }
+               if(st1 & 0x04) {        LOG("No Data Found");   continue;       }
+               if(st1 & 0x01 || st2 & 0x01) {
+                       LOG("No Address mark found");
+                       continue;
+               }
+           if(st2 & 0x40) {    LOG("Deleted address mark");    continue;       }
+               if(st2 & 0x20) {        LOG("CRC error in data");       continue;       }
+               if(st2 & 0x10) {        LOG("Wrong Cylinder");  continue;       }
+               if(st2 & 0x04) {        LOG("uPD765 sector not found"); continue;       }
+               if(st2 & 0x02) {        LOG("Bad Cylinder");    continue;       }
+               
+               if(bps != 0x2) {
+                       LOG("Returned BPS = 0x%02x, not 0x02", bps);
+                       continue;
+               }
+               
+               if(st1 & 0x02) {
+                       LOG("Floppy not writable");
+                       i = FDD_MAX_READWRITE_ATTEMPTS+1;
+                       break;
+               }
+               
+               // Success!
+               break;
+       }
+       
+       // Release Spinlock
+       LOG("Realeasing Spinlock and setting motor to stop");
+       RELEASE(&glFDD);
+       
+       if(i == FDD_MAX_READWRITE_ATTEMPTS) {
+               Log_Warning("FDD", "Exceeded %i attempts in %s the disk",
+                       FDD_MAX_READWRITE_ATTEMPTS,
+                       (Write ? "writing to" : "reading from")
+                       );
+       }
+       
+       // Don't turn the motor off now, wait for a while
+       gFDD_Devices[Disk].timer = Time_CreateTimer(MOTOR_OFF_DELAY, FDD_int_StopMotor, (void*)(tVAddr)Disk);
+
+       if( i < FDD_MAX_READWRITE_ATTEMPTS ) {
+               LEAVE('i', 0);
+               return 0;
+       }
+       else {
+               LEAVE('i', 1);
+               return 1;
+       }
+}
+
+/**
+ * \fn int FDD_ReadSector(Uint32 Disk, Uint64 SectorAddr, void *Buffer)
+ * \brief Read a sector from disk
+ * \todo Make real-hardware safe (account for read errors)
+*/
+int FDD_ReadSector(Uint32 Disk, Uint64 SectorAddr, void *Buffer)
+{
+        int    ret;
+       
+       ENTER("iDisk XSectorAddr pBuffer", Disk, SectorAddr, Buffer);
+       
+       if( IOCache_Read( gFDD_Devices[Disk].CacheHandle, SectorAddr, Buffer ) == 1 ) {
+               LEAVE('i', 1);
+               return 1;
+       }
+       
+       // Pass to general function
        ret = FDD_int_ReadWriteSector(Disk, SectorAddr, 0, Buffer);
-\r
-       if( ret == 0 ) {\r
+
+       if( ret == 0 ) {
                IOCache_Add( gFDD_Devices[Disk].CacheHandle, SectorAddr, Buffer );
-               LEAVE('i', 1);\r
-               return 1;\r
-       }\r
-       else {\r
-               LOG("Reading failed");\r
-               LEAVE('i', 0);\r
-               return 0;\r
-       }\r
-}\r
-\r
-/**\r
- * \fn int FDD_WriteSector(Uint32 Disk, Uint64 LBA, void *Buffer)\r
- * \brief Write a sector to the floppy disk\r
- * \note Not Implemented\r
- */\r
-int FDD_WriteSector(Uint32 Disk, Uint64 LBA, void *Buffer)\r
-{\r
-       Warning("[FDD  ] Read Only at the moment");\r
-       return -1;\r
-}\r
-\r
-/**\r
- * \fn int FDD_int_SeekTrack(int disk, int track)\r
- * \brief Seek disk to selected track\r
- */\r
-int FDD_int_SeekTrack(int disk, int head, int track)\r
-{\r
-       Uint8   sr0, cyl;\r
-        int    base;\r
-       \r
-       base = cPORTBASE[disk>>1];\r
-       \r
-       // Check if seeking is needed\r
-       if(gFDD_Devices[disk].track[head] == track)\r
-               return 1;\r
-       \r
-       // - Seek Head 0\r
-       FDD_int_SendByte(base, SEEK_TRACK);\r
-       FDD_int_SendByte(base, (head<<2)|(disk&1));\r
-       FDD_int_SendByte(base, track);  // Send Seek command\r
-       FDD_WaitIRQ();\r
-       FDD_SensInt(base, &sr0, &cyl);  // Wait for IRQ\r
+               LEAVE('i', 1);
+               return 1;
+       }
+       else {
+               LOG("Reading failed");
+               LEAVE('i', 0);
+               return 0;
+       }
+}
+
+/**
+ * \fn int FDD_WriteSector(Uint32 Disk, Uint64 LBA, void *Buffer)
+ * \brief Write a sector to the floppy disk
+ * \note Not Implemented
+ */
+int FDD_WriteSector(Uint32 Disk, Uint64 LBA, void *Buffer)
+{
+       Warning("[FDD  ] Read Only at the moment");
+       return -1;
+}
+
+/**
+ * \fn int FDD_int_SeekTrack(int disk, int track)
+ * \brief Seek disk to selected track
+ */
+int FDD_int_SeekTrack(int disk, int head, int track)
+{
+       Uint8   sr0, cyl;
+        int    base;
+       
+       base = cPORTBASE[disk>>1];
+       
+       // Check if seeking is needed
+       if(gFDD_Devices[disk].track[head] == track)
+               return 1;
+       
+       // - Seek Head 0
+       FDD_int_SendByte(base, SEEK_TRACK);
+       FDD_int_SendByte(base, (head<<2)|(disk&1));
+       FDD_int_SendByte(base, track);  // Send Seek command
+       FDD_WaitIRQ();
+       FDD_SensInt(base, &sr0, &cyl);  // Wait for IRQ
        if((sr0 & 0xF0) != 0x20) {
                LOG("sr0 = 0x%x", sr0);
                return 0;       //Check Status
-       }\r
-       if(cyl != track)        return 0;\r
-       \r
-       // Set Track in structure\r
-       gFDD_Devices[disk].track[head] = track;\r
-       return 1;\r
-}\r
-\r
-/**\r
- * \fn int FDD_int_GetDims(int type, int lba, int *c, int *h, int *s, int *spt)\r
- * \brief Get Dimensions of a disk\r
- */\r
-int FDD_int_GetDims(int type, int lba, int *c, int *h, int *s, int *spt)\r
-{\r
-       switch(type) {\r
-       case 0:\r
-               return 0;\r
-       \r
-       // 360Kb 5.25"\r
-       case 1:\r
-               *spt = 9;\r
-               *s = (lba % 9) + 1;\r
-               *c = lba / 18;\r
-               *h = (lba / 9) & 1;\r
-               break;\r
-       \r
-       // 1220Kb 5.25"\r
-       case 2:\r
-               *spt = 15;\r
-               *s = (lba % 15) + 1;\r
-               *c = lba / 30;\r
-               *h = (lba / 15) & 1;\r
-               break;\r
-       \r
-       // 720Kb 3.5"\r
-       case 3:\r
-               *spt = 9;\r
-               *s = (lba % 9) + 1;\r
-               *c = lba / 18;\r
-               *h = (lba / 9) & 1;\r
-               break;\r
-       \r
-       // 1440Kb 3.5"\r
-       case 4:\r
-               *spt = 18;\r
-               *s = (lba % 18) + 1;\r
-               *c = lba / 36;\r
-               *h = (lba / 18) & 1;\r
-               //Log("1440k - lba=%i(0x%x), *s=%i,*c=%i,*h=%i", lba, lba, *s, *c, *h);\r
-               break;\r
-               \r
-       // 2880Kb 3.5"\r
-       case 5:\r
-               *spt = 36;\r
-               *s = (lba % 36) + 1;\r
-               *c = lba / 72;\r
-               *h = (lba / 32) & 1;\r
-               break;\r
-               \r
-       default:\r
-               return -2;\r
-       }\r
-       return 1;\r
-}\r
-\r
-/**\r
- * \fn void FDD_IRQHandler(int Num)\r
- * \brief Handles IRQ6\r
- */\r
-void FDD_IRQHandler(int Num)\r
-{\r
-    gbFDD_IrqFired = 1;\r
-}\r
-\r
-/**\r
- * \fn FDD_WaitIRQ()\r
- * \brief Wait for an IRQ6\r
- */\r
-inline void FDD_WaitIRQ()\r
-{\r
-       // Wait for IRQ\r
-       while(!gbFDD_IrqFired)  Threads_Yield();\r
-       gbFDD_IrqFired = 0;\r
-}\r
-\r
-void FDD_SensInt(int base, Uint8 *sr0, Uint8 *cyl)\r
-{\r
-       FDD_int_SendByte(base, CHECK_INTERRUPT_STATUS);\r
-       if(sr0) *sr0 = FDD_int_GetByte(base);\r
-       else    FDD_int_GetByte(base);\r
-       if(cyl) *cyl = FDD_int_GetByte(base);\r
-       else    FDD_int_GetByte(base);\r
-}\r
-\r
-/**\r
- * void FDD_int_SendByte(int base, char byte)\r
- * \brief Sends a command to the controller\r
- */\r
-void FDD_int_SendByte(int base, char byte)\r
-{\r
-    volatile int state;\r
-    int timeout = 128;\r
-    for( ; timeout--; )\r
-    {\r
-        state = inb(base + PORT_MAINSTATUS);\r
-        if ((state & 0xC0) == 0x80)\r
-        {\r
-            outb(base + PORT_DATA, byte);\r
-            return;\r
-        }\r
-        inb(0x80);     //Delay\r
-    }\r
-       \r
-       #if WARN\r
-       Warning("FDD_int_SendByte - Timeout sending byte 0x%x to base 0x%x\n", byte, base);\r
-       #endif\r
-}\r
-\r
-/**\r
- * int FDD_int_GetByte(int base, char byte)\r
- * \brief Receive data from fdd controller\r
- */\r
-int FDD_int_GetByte(int base)\r
-{\r
-    volatile int state;\r
-    int timeout;\r
-    for( timeout = 128; timeout--; )\r
-    {\r
-        state = inb((base + PORT_MAINSTATUS));\r
-        if ((state & 0xd0) == 0xd0)\r
-               return inb(base + PORT_DATA);\r
-        inb(0x80);\r
-    }\r
-    return -1;\r
-}\r
-\r
-/**\r
- * \brief Recalibrate the specified disk\r
- */\r
-void FDD_Recalibrate(int disk)\r
-{\r
-       ENTER("idisk", disk);\r
-       \r
-       LOG("Starting Motor");\r
-       FDD_int_StartMotor(disk);\r
-       // Wait for Spinup\r
-       while(gFDD_Devices[disk].motorState == 1)       Threads_Yield();\r
-       \r
-       LOG("Sending Calibrate Command");\r
-       FDD_int_SendByte(cPORTBASE[disk>>1], CALIBRATE_DRIVE);\r
-       FDD_int_SendByte(cPORTBASE[disk>>1], disk&1);\r
-       \r
-       LOG("Waiting for IRQ");\r
-       FDD_WaitIRQ();\r
-       FDD_SensInt(cPORTBASE[disk>>1], NULL, NULL);\r
-       \r
-       LOG("Stopping Motor");\r
-       FDD_int_StopMotor(disk);\r
-       LEAVE('-');\r
-}\r
-\r
-/**\r
- * \brief Reset the specified FDD controller\r
- */\r
-void FDD_Reset(int id)\r
-{\r
-       int base = cPORTBASE[id];\r
-       \r
-       ENTER("iID", id);\r
-       \r
-       outb(base + PORT_DIGOUTPUT, 0); // Stop Motors & Disable FDC\r
-       outb(base + PORT_DIGOUTPUT, 0x0C);      // Re-enable FDC (DMA and Enable)\r
-       \r
-       LOG("Awaiting IRQ");\r
-       \r
-       FDD_WaitIRQ();\r
-       FDD_SensInt(base, NULL, NULL);\r
-       \r
-       LOG("Setting Driver Info");\r
-       outb(base + PORT_DATARATE, 0);  // Set data rate to 500K/s\r
-       FDD_int_SendByte(base, FIX_DRIVE_DATA); // Step and Head Load Times\r
-       FDD_int_SendByte(base, 0xDF);   // Step Rate Time, Head Unload Time (Nibble each)\r
-       FDD_int_SendByte(base, 0x02);   // Head Load Time >> 1\r
-       while(FDD_int_SeekTrack(0, 0, 1) == 0); // set track\r
-       while(FDD_int_SeekTrack(0, 1, 1) == 0); // set track\r
-       \r
-       LOG("Recalibrating Disk");\r
-       FDD_Recalibrate((id<<1)|0);\r
+       }
+       if(cyl != track)        return 0;
+       
+       // Set Track in structure
+       gFDD_Devices[disk].track[head] = track;
+       return 1;
+}
+
+/**
+ * \fn int FDD_int_GetDims(int type, int lba, int *c, int *h, int *s, int *spt)
+ * \brief Get Dimensions of a disk
+ */
+int FDD_int_GetDims(int type, int lba, int *c, int *h, int *s, int *spt)
+{
+       switch(type) {
+       case 0:
+               return 0;
+       
+       // 360Kb 5.25"
+       case 1:
+               *spt = 9;
+               *s = (lba % 9) + 1;
+               *c = lba / 18;
+               *h = (lba / 9) & 1;
+               break;
+       
+       // 1220Kb 5.25"
+       case 2:
+               *spt = 15;
+               *s = (lba % 15) + 1;
+               *c = lba / 30;
+               *h = (lba / 15) & 1;
+               break;
+       
+       // 720Kb 3.5"
+       case 3:
+               *spt = 9;
+               *s = (lba % 9) + 1;
+               *c = lba / 18;
+               *h = (lba / 9) & 1;
+               break;
+       
+       // 1440Kb 3.5"
+       case 4:
+               *spt = 18;
+               *s = (lba % 18) + 1;
+               *c = lba / 36;
+               *h = (lba / 18) & 1;
+               //Log("1440k - lba=%i(0x%x), *s=%i,*c=%i,*h=%i", lba, lba, *s, *c, *h);
+               break;
+               
+       // 2880Kb 3.5"
+       case 5:
+               *spt = 36;
+               *s = (lba % 36) + 1;
+               *c = lba / 72;
+               *h = (lba / 32) & 1;
+               break;
+               
+       default:
+               return -2;
+       }
+       return 1;
+}
+
+/**
+ * \fn void FDD_IRQHandler(int Num)
+ * \brief Handles IRQ6
+ */
+void FDD_IRQHandler(int Num)
+{
+       gbFDD_IrqFired = 1;
+}
+
+/**
+ * \fn FDD_WaitIRQ()
+ * \brief Wait for an IRQ6
+ */
+inline void FDD_WaitIRQ()
+{
+       // Wait for IRQ
+       while(!gbFDD_IrqFired)  Threads_Yield();
+       gbFDD_IrqFired = 0;
+}
+
+void FDD_SensInt(int base, Uint8 *sr0, Uint8 *cyl)
+{
+       FDD_int_SendByte(base, CHECK_INTERRUPT_STATUS);
+       if(sr0) *sr0 = FDD_int_GetByte(base);
+       else    FDD_int_GetByte(base);
+       if(cyl) *cyl = FDD_int_GetByte(base);
+       else    FDD_int_GetByte(base);
+}
+
+/**
+ * void FDD_int_SendByte(int base, char byte)
+ * \brief Sends a command to the controller
+ */
+void FDD_int_SendByte(int base, char byte)
+{
+       volatile int state;
+       int timeout = 128;
+       for( ; timeout--; )
+       {
+           state = inb(base + PORT_MAINSTATUS);
+           if ((state & 0xC0) == 0x80)
+           {
+               outb(base + PORT_DATA, byte);
+               return;
+           }
+           inb(0x80);  //Delay
+       }
+       
+       #if WARN
+       Warning("FDD_int_SendByte - Timeout sending byte 0x%x to base 0x%x\n", byte, base);
+       #endif
+}
+
+/**
+ * int FDD_int_GetByte(int base, char byte)
+ * \brief Receive data from fdd controller
+ */
+int FDD_int_GetByte(int base)
+{
+       volatile int state;
+       int timeout;
+       for( timeout = 128; timeout--; )
+       {
+           state = inb((base + PORT_MAINSTATUS));
+           if ((state & 0xd0) == 0xd0)
+                   return inb(base + PORT_DATA);
+           inb(0x80);
+       }
+       return -1;
+}
+
+/**
+ * \brief Recalibrate the specified disk
+ */
+void FDD_Recalibrate(int disk)
+{
+       ENTER("idisk", disk);
+       
+       LOG("Starting Motor");
+       FDD_int_StartMotor(disk);
+       // Wait for Spinup
+       while(gFDD_Devices[disk].motorState == 1)       Threads_Yield();
+       
+       LOG("Sending Calibrate Command");
+       FDD_int_SendByte(cPORTBASE[disk>>1], CALIBRATE_DRIVE);
+       FDD_int_SendByte(cPORTBASE[disk>>1], disk&1);
+       
+       LOG("Waiting for IRQ");
+       FDD_WaitIRQ();
+       FDD_SensInt(cPORTBASE[disk>>1], NULL, NULL);
+       
+       LOG("Stopping Motor");
+       FDD_int_StopMotor(disk);
+       LEAVE('-');
+}
+
+/**
+ * \brief Reset the specified FDD controller
+ */
+void FDD_Reset(int id)
+{
+       int base = cPORTBASE[id];
+       
+       ENTER("iID", id);
+       
+       outb(base + PORT_DIGOUTPUT, 0); // Stop Motors & Disable FDC
+       outb(base + PORT_DIGOUTPUT, 0x0C);      // Re-enable FDC (DMA and Enable)
+       
+       LOG("Awaiting IRQ");
+       
+       FDD_WaitIRQ();
+       FDD_SensInt(base, NULL, NULL);
+       
+       LOG("Setting Driver Info");
+       outb(base + PORT_DATARATE, 0);  // Set data rate to 500K/s
+       FDD_int_SendByte(base, FIX_DRIVE_DATA); // Step and Head Load Times
+       FDD_int_SendByte(base, 0xDF);   // Step Rate Time, Head Unload Time (Nibble each)
+       FDD_int_SendByte(base, 0x02);   // Head Load Time >> 1
+       while(FDD_int_SeekTrack(0, 0, 1) == 0); // set track
+       while(FDD_int_SeekTrack(0, 1, 1) == 0); // set track
+       
+       LOG("Recalibrating Disk");
+       FDD_Recalibrate((id<<1)|0);
        FDD_Recalibrate((id<<1)|1);
-\r
-       LEAVE('-');\r
-}\r
-\r
-/**\r
- * \fn void FDD_int_TimerCallback()\r
- * \brief Called by timer\r
- */\r
-void FDD_int_TimerCallback(int arg)\r
-{\r
-       ENTER("iarg", arg);\r
-       if(gFDD_Devices[arg].motorState == 1)\r
-               gFDD_Devices[arg].motorState = 2;\r
-       Time_RemoveTimer(gFDD_Devices[arg].timer);\r
-       gFDD_Devices[arg].timer = -1;\r
-       LEAVE('-');\r
-}\r
-\r
-/**\r
- * \fn void FDD_int_StartMotor(char disk)\r
- * \brief Starts FDD Motor\r
- */\r
-void FDD_int_StartMotor(int disk)\r
-{\r
-       Uint8   state;\r
-       state = inb( cPORTBASE[ disk>>1 ] + PORT_DIGOUTPUT );\r
-       state |= 1 << (4+disk);\r
-       outb( cPORTBASE[ disk>>1 ] + PORT_DIGOUTPUT, state );\r
-       gFDD_Devices[disk].motorState = 1;\r
-       gFDD_Devices[disk].timer = Time_CreateTimer(MOTOR_ON_DELAY, FDD_int_TimerCallback, (void*)disk);\r
-}\r
-\r
-/**\r
- * \fn void FDD_int_StopMotor(int disk)\r
- * \brief Stops FDD Motor\r
- */\r
-void FDD_int_StopMotor(int disk)\r
-{\r
-       Uint8   state;\r
-       if( IS_LOCKED(&glFDD) ) return ;\r
-       ENTER("iDisk", disk);\r
-       \r
-       state = inb( cPORTBASE[ disk>>1 ] + PORT_DIGOUTPUT );\r
-       state &= ~( 1 << (4+disk) );\r
-       outb( cPORTBASE[ disk>>1 ] + PORT_DIGOUTPUT, state );\r
-    gFDD_Devices[disk].motorState = 0;\r
-    LEAVE('-');\r
-}\r
+
+       LEAVE('-');
+}
+
+/**
+ * \fn void FDD_int_TimerCallback()
+ * \brief Called by timer
+ */
+void FDD_int_TimerCallback(int arg)
+{
+       ENTER("iarg", arg);
+       if(gFDD_Devices[arg].motorState == 1)
+               gFDD_Devices[arg].motorState = 2;
+       Time_RemoveTimer(gFDD_Devices[arg].timer);
+       gFDD_Devices[arg].timer = -1;
+       LEAVE('-');
+}
+
+/**
+ * \fn void FDD_int_StartMotor(char disk)
+ * \brief Starts FDD Motor
+ */
+void FDD_int_StartMotor(int disk)
+{
+       Uint8   state;
+       state = inb( cPORTBASE[ disk>>1 ] + PORT_DIGOUTPUT );
+       state |= 1 << (4+disk);
+       outb( cPORTBASE[ disk>>1 ] + PORT_DIGOUTPUT, state );
+       gFDD_Devices[disk].motorState = 1;
+       gFDD_Devices[disk].timer = Time_CreateTimer(MOTOR_ON_DELAY, FDD_int_TimerCallback, (void*)(tVAddr)disk);
+}
+
+/**
+ * \fn void FDD_int_StopMotor(int disk)
+ * \brief Stops FDD Motor
+ */
+void FDD_int_StopMotor(int disk)
+{
+       Uint8   state;
+       if( IS_LOCKED(&glFDD) ) return ;
+       ENTER("iDisk", disk);
+       
+       state = inb( cPORTBASE[ disk>>1 ] + PORT_DIGOUTPUT );
+       state &= ~( 1 << (4+disk) );
+       outb( cPORTBASE[ disk>>1 ] + PORT_DIGOUTPUT, state );
+       gFDD_Devices[disk].motorState = 0;
+       LEAVE('-');
+}

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