Kernel/armv7 - Implemetned Hivecs, fixing bugs
[tpg/acess2.git] / Kernel / binary.c
index 2237d1b..7e271ed 100644 (file)
-/*\r
- * Acess2\r
- * Common Binary Loader\r
- */\r
-#define DEBUG  0\r
-#include <common.h>\r
-#include <binary.h>\r
-\r
-// === CONSTANTS ===\r
-#define BIN_LOWEST     MM_USER_MIN             // 1MiB\r
-#define BIN_GRANUALITY 0x10000         // 64KiB\r
-#define BIN_HIGHEST    (0xBC000000-BIN_GRANUALITY)             // Just below the kernel\r
-#define        KLIB_LOWEST     MM_MODULE_MIN\r
-#define KLIB_GRANUALITY        0x8000          // 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 void    Threads_SetName(char *Name);\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
- * \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
- \fn tBinary *Binary_GetInfo(char *truePath)\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
-               if( binary->Pages[i].Physical & 1)      // Read-Only\r
-                       MM_SetFlags( addr, MM_PFLAG_RO, -1 );\r
-               else\r
-                       MM_SetFlags( addr, MM_PFLAG_COW, -1 );\r
-       }\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
-               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%x,Virtual:0x%x,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 );\r
-               }\r
-               else\r
-               {\r
-                       VFS_Seek( fp, pBinary->Pages[i].Physical, 1 );\r
-                       if(pBinary->Pages[i].Size != 0x1000) {\r
-                               LOG("%i - 0x%x - 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 *path)\r
- * \brief Load a binary into kernel space\r
- * \note This function shares much with #Binary_Load, but does it's own mapping\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
-               #if 0   // Why was this here? It's the kernel\r
-               if( pBinary->Pages[i].Physical & 1)     // Read-Only\r
-                       MM_SetFlags( addr, MM_PFLAG_RO, MM_PFLAG_KERNEL );\r
-               else\r
-                       MM_SetFlags( addr, MM_PFLAG_COW, MM_PFLAG_KERNEL );\r
-                       //MM_SetCOW( addr );\r
-               #endif\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_GetSymbolBin(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
+/*
+ * Acess2
+ * Common Binary Loader
+ */
+#define DEBUG  0
+#include <acess.h>
+#include <binary.h>
+#include <mm_virt.h>
+#include <hal_proc.h>
+
+// === CONSTANTS ===
+#define BIN_LOWEST     MM_USER_MIN             // 1MiB
+#define BIN_GRANUALITY 0x10000         // 64KiB
+#define BIN_HIGHEST    (USER_LIB_MAX-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 char    *Threads_GetName(int ID);
+extern tKernelSymbol   gKernelSymbols[];
+extern tKernelSymbol   gKernelSymbolsEnd[];
+extern tBinaryType     gELF_Info;
+
+// === PROTOTYPES ===
+ int   Proc_Execve(const char *File, const char **ArgV, const char **EnvP);
+tVAddr Binary_Load(const char *Path, tVAddr *EntryPoint);
+tBinary        *Binary_GetInfo(tMount MountID, tInode InodeID);
+tVAddr Binary_MapIn(tBinary *Binary, const char *Path, tVAddr LoadMin, tVAddr LoadMax);
+tVAddr Binary_IsMapped(tBinary *Binary);
+tBinary *Binary_DoLoad(tMount MountID, tInode Inode, const char *Path);
+void   Binary_Dereference(tBinary *Info);
+#if 0
+Uint   Binary_Relocate(void *Base);
+#endif
+Uint   Binary_GetSymbolEx(const char *Name, Uint *Value);
+#if 0
+Uint   Binary_FindSymbol(void *Base, const char *Name, Uint *Val);
+#endif
+ int   Binary_int_CheckMemFree( tVAddr _start, size_t _len );
+
+// === GLOBALS ===
+tShortSpinlock glBinListLock;
+tBinary        *glLoadedBinaries = NULL;
+char   **gsaRegInterps = NULL;
+ int   giRegInterps = 0;
+tShortSpinlock glKBinListLock;
+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(const char *Path)
+ */
+int Proc_Spawn(const char *Path)
+{
+       char    stackPath[strlen(Path)+1];
+       ENTER("sPath", Path);
+       
+       strcpy(stackPath, Path);
+       
+       LOG("stackPath = '%s'", stackPath);
+       
+       if(Proc_Clone(CLONE_VM) == 0)
+       {
+               // CHILD
+               const char      *args[2] = {stackPath, NULL};
+               LOG("stackPath = '%s'", stackPath);
+               Proc_Execve(stackPath, args, &args[1]);
+               for(;;);
+       }
+       LEAVE('i', 0);
+       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(const char *File, const char **ArgV, const char **EnvP)
+{
+        int    argc, envc, i;
+        int    argenvBytes;
+       char    **argenvBuf, *strBuf;
+       char    **argvSaved, **envpSaved;
+       char    *savedFile;
+       tVAddr  entry;
+       Uint    bases[2] = {0}; // Uint because Proc_StartUser wants it
+       
+       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) {
+               Log_Error("Binary", "Proc_Execve - What the hell? The kernel is out of heap space");
+               LEAVE('i', 0);
+               return 0;
+       }
+       strBuf = (char*)argenvBuf + (argc+1)*sizeof(void*) + (envc+1)*sizeof(void*);
+       
+       // Populate
+       argvSaved = argenvBuf;
+       for( i = 0; i < argc; i++ )
+       {
+               argvSaved[i] = strBuf;
+               strcpy(argvSaved[i], ArgV[i]);
+               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;
+       }
+       envpSaved[i] = NULL;
+       
+       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)
+       {
+               Log_Warning("Binary", "Proc_Execve - Unable to load '%s'", Threads_GetName(-1));
+               LEAVE('-');
+               Threads_Exit(0, -10);
+               for(;;);
+       }
+       
+       LOG("entry = 0x%x, bases[0] = 0x%x", entry, bases[0]);
+
+//     MM_DumpTables(0, KERNEL_BASE);
+
+       LEAVE('-');
+       // --- And... Jump to it
+       Proc_StartUser(entry, bases, argc, argvSaved, envpSaved, argenvBytes);
+       for(;;);        // Tell GCC that we never return
+}
+
+/**
+ * \brief Load a binary into the current address space
+ * \param Path Path to binary to load
+ * \param EntryPoint   Pointer for exectuable entry point
+ * \return Virtual address where the binary has been loaded
+ */
+tVAddr Binary_Load(const char *Path, tVAddr *EntryPoint)
+{
+       tMount  mount_id;
+       tInode  inode;
+       tBinary *pBinary;
+       tVAddr  base = -1;
+
+       ENTER("sPath pEntryPoint", Path, EntryPoint);
+       
+       // Sanity Check Argument
+       if(Path == NULL) {
+               LEAVE('x', 0);
+               return 0;
+       }
+
+       // Check if this path has been loaded before.
+       #if 0
+       // TODO: Implement a list of string/tBinary pairs for loaded bins
+       #endif
+
+       // Get Inode
+       {
+               int fd;
+               tFInfo  info;
+               fd = VFS_Open(Path, VFS_OPENFLAG_READ|VFS_OPENFLAG_EXEC);
+               if( fd == -1 ) {
+                       LOG("%s does not exist", Path);
+                       LEAVE_RET('x', 0);
+               }
+               VFS_FInfo(fd, &info, 0);
+               VFS_Close(fd);
+               mount_id = info.mount;
+               inode = info.inode;
+               LOG("mount_id = %i, inode = %i", mount_id, inode);
+       }
+
+       // TODO: Also get modifcation time?
+
+       // Check if the binary has already been loaded
+       if( !(pBinary = Binary_GetInfo(mount_id, inode)) )
+               pBinary = Binary_DoLoad(mount_id, inode, Path); // Else load it
+       
+       // Error Check
+       if(pBinary == NULL) {
+               LEAVE('x', 0);
+               return 0;
+       }
+       
+       // Map into process space
+       base = Binary_MapIn(pBinary, Path, BIN_LOWEST, BIN_HIGHEST);
+       
+       // Check for errors
+       if(base == 0) {
+               LEAVE('x', 0);
+               return 0;
+       }
+       
+       // Interpret
+       if(pBinary->Interpreter) {
+               tVAddr  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(tMount MountID, tInode InodeID)
+{
+       tBinary *pBinary;
+       pBinary = glLoadedBinaries;
+       while(pBinary)
+       {
+               if(pBinary->MountID == MountID && pBinary->Inode == InodeID)
+                       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.
+*/
+tVAddr Binary_MapIn(tBinary *Binary, const char *Path, tVAddr LoadMin, tVAddr LoadMax)
+{
+       tVAddr  base;
+        int    i, fd;
+
+       ENTER("pBinary sPath pLoadMin pLoadMax", Binary, Path, LoadMin, LoadMax);
+
+       // 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)
+       {
+               LOG("Checking base %p", base);
+               for(i=0;i<Binary->NumSections;i++)
+               {
+                       if( Binary_int_CheckMemFree( Binary->LoadSections[i].Virtual, Binary->LoadSections[i].MemSize ) )
+                       {
+                               base = 0;
+                               LOG("Address 0x%x is taken\n", Binary->LoadSections[i].Virtual);
+                               break;
+                       }
+               }
+       }
+       
+       // Check if the executable has no base or it is not free
+       if(base == 0)
+       {
+               // If so, give it a base
+               base = LoadMax;
+               while(base >= LoadMin)
+               {
+                       for( i = 0; i < Binary->NumSections; i ++ )
+                       {
+                               tVAddr  addr = Binary->LoadSections[i].Virtual - Binary->Base + base;
+                               if( Binary_int_CheckMemFree( addr, Binary->LoadSections[i].MemSize ) )
+                                       break;
+                       }
+                       // If space was found, break
+                       if(i == Binary->NumSections)            break;
+                       // Else decrement pointer and try again
+                       base -= BIN_GRANUALITY;
+               }
+               LOG("Allocated base %p", base);
+       }
+       
+       // Error Check
+       if(base < LoadMin) {
+               Log_Warning("Binary", "Executable '%s' cannot be loaded, no space", Path);
+               LEAVE('i', 0);
+               return 0;
+       }
+       
+       // Map Executable In
+       fd = VFS_OpenInode(Binary->MountID, Binary->Inode, VFS_OPENFLAG_READ);
+       for( i = 0; i < Binary->NumSections; i ++ )
+       {
+               tBinarySection  *sect = &Binary->LoadSections[i];
+               Uint    protflags, mapflags;
+               tVAddr  addr = sect->Virtual - Binary->Base + base;
+               LOG("%i - %p to 0x%llx (%x)", i, addr, sect->Offset, sect->Flags);
+
+               protflags = MMAP_PROT_READ;
+               mapflags = MMAP_MAP_FIXED;
+
+               if( sect->Flags & BIN_SECTFLAG_EXEC )
+                       protflags |= MMAP_PROT_EXEC;
+               if( sect->Flags & BIN_SECTFLAG_RO  ) {
+                       VFS_MMap( (void*)addr, sect->FileSize, protflags, MMAP_MAP_SHARED|mapflags, fd, sect->Offset );
+               }
+               else {
+                       protflags |= MMAP_PROT_WRITE;
+                       VFS_MMap( (void*)addr, sect->FileSize, protflags, MMAP_MAP_PRIVATE|mapflags, fd, sect->Offset );
+               }
+               if( sect->FileSize < sect->MemSize ) {
+                       mapflags |= MMAP_MAP_ANONYMOUS;
+                       VFS_MMap(
+                               (void*)(addr + sect->FileSize), sect->MemSize - sect->FileSize,
+                               protflags, MMAP_MAP_PRIVATE|mapflags,
+                               0, 0
+                               );
+//                     memset((void*)(addr + sect->FileSize), 0, sect->MemSize - sect->FileSize);
+               }
+       }
+       
+       Log_Debug("Binary", "PID %i - Mapped '%s' to 0x%x", Threads_GetPID(), Path, base);
+       VFS_Close(fd);
+       
+       //LOG("*0x%x = 0x%x\n", binary->Pages[0].Virtual, *(Uint*)binary->Pages[0].Virtual);
+       
+       LEAVE('p', base);
+       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(tMount MountID, tInode Inode, const char *Path)
+{
+       tBinary *pBinary;
+        int    fp;
+       Uint32  ident;
+       tBinaryType     *bt = gRegBinTypes;
+       
+       ENTER("iMountID XInode sPath", MountID, Inode, Path);
+       
+       // Open File
+       fp = VFS_OpenInode(MountID, Inode, VFS_OPENFLAG_READ);
+       if(fp == -1) {
+               LOG("Unable to load file, access denied");
+               LEAVE('n');
+               return NULL;
+       }
+
+       LOG("fp = 0x%x", fp);
+       
+       // Read File Type
+       VFS_Read(fp, 4, &ident);
+       VFS_Seek(fp, 0, SEEK_SET);
+
+       LOG("ident = 0x%x", ident);
+
+       // Determine the type   
+       for(; bt; bt = bt->Next)
+       {
+               if( (ident & bt->Mask) != (Uint32)bt->Ident )
+                       continue;
+               LOG("bt = %p (%s)", bt, bt->Name);
+               pBinary = bt->Load(fp);
+               break;
+       }
+
+       LOG("pBinary = %p", pBinary);
+       
+       // Close File
+       VFS_Close(fp);
+       
+       // Catch errors
+       if(!bt) {
+               Log_Warning("Binary", "'%s' is an unknown file type. (%02x %02x %02x %02x)",
+                       Path, 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->MountID = MountID;
+       pBinary->Inode = Inode;
+       
+       // Debug Information
+       LOG("Interpreter: '%s'", pBinary->Interpreter);
+       LOG("Base: 0x%x, Entry: 0x%x", pBinary->Base, pBinary->Entry);
+       LOG("NumSections: %i", pBinary->NumSections);
+       
+       // Add to the list
+       SHORTLOCK(&glBinListLock);
+       pBinary->Next = glLoadedBinaries;
+       glLoadedBinaries = pBinary;
+       SHORTREL(&glBinListLock);
+
+       // TODO: Register the path with the binary      
+
+       // 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
+               Log_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->NumSections; i++)
+               {
+                       // TODO: VFS_MUnmap();
+               }
+               // 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(const 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(const char *File)
+{
+       tBinary *pBinary;
+       tKernelBin      *pKBinary;
+       tVAddr  base = -1;
+       tMount  mount_id;
+       tInode  inode;
+
+       ENTER("sFile", File);
+       
+       // Sanity Check Argument
+       if(File == NULL) {
+               LEAVE('n');
+               return 0;
+       }
+
+       {
+               int fd = VFS_Open(File, VFS_OPENFLAG_READ);
+               tFInfo  info;
+               if(fd == -1) {
+                       LEAVE('n');
+                       return NULL;
+               }
+               VFS_FInfo(fd, &info, 0);
+               mount_id = info.mount;
+               inode = info.inode;
+               VFS_Close(fd);
+       }
+       
+       // Check if the binary has already been loaded
+       if( (pBinary = Binary_GetInfo(mount_id, inode)) )
+       {
+               for(pKBinary = glLoadedKernelLibs;
+                       pKBinary;
+                       pKBinary = pKBinary->Next )
+               {
+                       if(pKBinary->Info == pBinary) {
+                               LEAVE('p', pKBinary->Base);
+                               return pKBinary->Base;
+                       }
+               }
+       }
+       else
+               pBinary = Binary_DoLoad(mount_id, inode, File); // 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 ++;
+
+       Binary_MapIn(pBinary, File, KLIB_LOWEST, KLIB_HIGHEST);
+
+       // Relocate Library
+       if( !Binary_Relocate( (void*)base ) )
+       {
+               Log_Warning("Binary", "Relocation of '%s' failed, unloading", File);
+               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;
+       SHORTLOCK( &glKBinListLock );
+       pKBinary->Next = glLoadedKernelLibs;
+       glLoadedKernelLibs = pKBinary;
+       SHORTREL( &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);
+       }
+       
+       Log_Warning("BIN", "%p is an unknown file type. (%02x %02x %02x %02x)",
+               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(const 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(const 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;
+               }
+       }
+       
+       Log_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, const 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);
+       }
+       
+       Log_Warning("BIN", "Binary_FindSymbol - %p is an unknown file type. (%02x %02x %02x %02x)",
+               Base, ident&0xFF, ident>>8, ident>>16, ident>>24);
+       return 0;
+}
+
+/**
+ * \brief Check if a range of memory is fully free
+ * \return Inverse boolean free (0 if all pages are unmapped)
+ */
+int Binary_int_CheckMemFree( tVAddr _start, size_t _len )
+{
+       _len += _start & (PAGE_SIZE-1);
+       _len = (_len + PAGE_SIZE - 1) & ~(PAGE_SIZE-1);
+       _start &= ~(PAGE_SIZE-1);
+       for( ; _len > PAGE_SIZE; _len -= PAGE_SIZE, _start += PAGE_SIZE ) {
+               if( MM_GetPhysAddr(_start) != 0 )
+                       return 1;
+       }
+       if( _len == PAGE_SIZE && MM_GetPhysAddr(_start) != 0 )
+               return 1;
+       return 0;
+}
+
+
+// === EXPORTS ===
+EXPORT(Binary_FindSymbol);
+EXPORT(Binary_Unload);

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