-/*\r
- * Acess2\r
- * Common Binary Loader\r
- */\r
-#include <common.h>\r
-#include <binary.h>\r
-\r
-#define DEBUG 0\r
-\r
-#if DEBUG\r
-#else\r
-# undef ENTER\r
-# undef LOG\r
-# undef LEAVE\r
-# define ENTER(...)\r
-# define LOG(...)\r
-# define LEAVE(...)\r
-#endif\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 Proc_SetThreadName(char *Name);\r
-extern Uint MM_ClearUser();\r
-extern void Proc_Exit();\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
- Proc_SetThreadName(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'", File);\r
- Proc_Exit();\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, ident>>16, ident>>24);\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>
+#include <vfs_threads.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 Binary_int_CacheArgs(const char **Path, const char ***ArgV, const char ***EnvP, void *DestBuffer);
+tVAddr Binary_Load(const char *Path, tVAddr *EntryPoint);
+tBinary *Binary_GetInfo(tMount MountID, tInode InodeID);
+tVAddr Binary_MapIn(tBinary *Binary, const char *Path, tVAddr LoadMin, tVAddr LoadMax);
+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|CLONE_NOUSER) == 0)
+ {
+ // CHILD
+ const char *args[2] = {stackPath, NULL};
+ LOG("stackPath = '%s'", stackPath);
+ Proc_Execve(stackPath, args, &args[1], 0);
+ for(;;);
+ }
+ LEAVE('i', 0);
+ return 0;
+}
+
+/**
+ * \todo Document
+ */
+int Binary_int_CacheArgs(const char **Path, const char ***ArgV, const char ***EnvP, void *DestBuffer)
+{
+ int size, argc=0, envc=0;
+ int i;
+ char *strbuf;
+ const char **arrays;
+
+ // Calculate size
+ size = 0;
+ if( ArgV && *ArgV )
+ {
+ const char **argv = *ArgV;
+ for( argc = 0; argv[argc]; argc ++ )
+ size += strlen( argv[argc] ) + 1;
+ }
+ if( EnvP && *EnvP )
+ {
+ const char **envp = *EnvP;
+ for( envc = 0; envp[envc]; envc ++ )
+ size += strlen( envp[envc] ) + 1;
+ }
+ size = (size + sizeof(void*)-1) & ~(sizeof(void*)-1); // Word align
+ size += (argc+1+envc+1)*sizeof(void*); // Arrays
+ if( Path )
+ {
+ size += strlen( *Path ) + 1;
+ }
+
+ if( DestBuffer )
+ {
+ arrays = DestBuffer;
+ strbuf = (void*)&arrays[argc+1+envc+1];
+
+ // Fill ArgV
+ if( ArgV && *ArgV )
+ {
+ const char **argv = *ArgV;
+ for( i = 0; argv[i]; i ++ )
+ {
+ arrays[i] = strbuf;
+ strcpy(strbuf, argv[i]);
+ strbuf += strlen( argv[i] ) + 1;
+ }
+ *ArgV = arrays;
+ arrays += i;
+ }
+ *arrays++ = NULL;
+ // Fill EnvP
+ if( EnvP && *EnvP )
+ {
+ const char **envp = *EnvP;
+ for( i = 0; envp[i]; i ++ )
+ {
+ arrays[i] = strbuf;
+ strcpy(strbuf, envp[i]);
+ strbuf += strlen( envp[i] ) + 1;
+ }
+ *EnvP = arrays;
+ arrays += i;
+ }
+ *arrays++ = NULL;
+ // Fill path
+ if( Path )
+ {
+ strcpy(strbuf, *Path);
+ *Path = strbuf;
+ }
+ }
+
+ return size;
+}
+
+/**
+ * \brief Create a new process with the specified set of file descriptors
+ */
+int Proc_SysSpawn(const char *Binary, const char **ArgV, const char **EnvP, int nFD, int *FDs)
+{
+ void *handles;
+ void *cachebuf;
+ int size;
+ tPID ret;
+
+ // --- Save File, ArgV and EnvP
+ size = Binary_int_CacheArgs( &Binary, &ArgV, &EnvP, NULL );
+ cachebuf = malloc( size );
+ Binary_int_CacheArgs( &Binary, &ArgV, &EnvP, cachebuf );
+
+ // Cache the VFS handles
+ handles = VFS_SaveHandles(nFD, FDs);
+
+ // Create new process
+ ret = Proc_Clone(CLONE_VM|CLONE_NOUSER);
+ if( ret == 0 )
+ {
+ VFS_RestoreHandles(nFD, handles);
+ VFS_FreeSavedHandles(nFD, handles);
+ // Frees cachebuf
+ Proc_Execve(Binary, ArgV, EnvP, size);
+ for(;;);
+ }
+ if( ret < 0 )
+ {
+ VFS_FreeSavedHandles(nFD, handles);
+ }
+
+ return ret;
+}
+
+/**
+ * \brief Replace the current user image with another
+ * \param File File to load as the next image
+ * \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 DataSize)
+{
+ void *cachebuf;
+ tVAddr entry;
+ Uint base; // Uint because Proc_StartUser wants it
+ int argc;
+
+ ENTER("sFile pArgV pEnvP", File, ArgV, EnvP);
+
+ // --- Save File, ArgV and EnvP
+ if( DataSize == 0 )
+ {
+ DataSize = Binary_int_CacheArgs( &File, &ArgV, &EnvP, NULL );
+ cachebuf = malloc( DataSize );
+ Binary_int_CacheArgs( &File, &ArgV, &EnvP, cachebuf );
+ }
+
+ // --- Get argc
+ for( argc = 0; ArgV && ArgV[argc]; argc ++ );
+
+ // --- Set Process Name
+ Threads_SetName(File);
+
+ // --- Clear User Address space
+ // NOTE: This is a little roundabout, maybe telling ClearUser to not touch the
+ // PPD area would be a better idea.
+ {
+ int nfd = *Threads_GetMaxFD();
+ void *handles;
+ handles = VFS_SaveHandles(nfd, NULL);
+ VFS_CloseAllUserHandles();
+ MM_ClearUser();
+ VFS_RestoreHandles(nfd, handles);
+ VFS_FreeSavedHandles(nfd, handles);
+ }
+
+ // --- Load new binary
+ base = Binary_Load(File, &entry);
+ if(base == 0)
+ {
+ Log_Warning("Binary", "Proc_Execve - Unable to load '%s'", File);
+ LEAVE('-');
+ Threads_Exit(0, -10);
+ for(;;);
+ }
+
+ LOG("entry = 0x%x, base = 0x%x", entry, base);
+ LEAVE('-');
+ // --- And... Jump to it
+ Proc_StartUser(entry, base, argc, ArgV, DataSize);
+ 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 MountID Mountpoint ID of binary file
+ * \param InodeID Inode ID of the file
+ * \return Pointer to the binary definition (if already loaded)
+ */
+tBinary *Binary_GetInfo(tMount MountID, tInode InodeID)
+{
+ tBinary *pBinary;
+ for(pBinary = glLoadedBinaries; pBinary; pBinary = pBinary->Next)
+ {
+ if(pBinary->MountID == MountID && pBinary->Inode == InodeID)
+ return pBinary;
+ }
+ return NULL;
+}
+
+/**
+ * \brief Maps an already-loaded binary into an address space.
+ * \param Binary Pointer to globally stored binary definition
+ * \param Path Path to the binary's file (for debug)
+ * \param LoadMin Lowest location to map to
+ * \param LoadMax Highest location to map to
+ * \return Base load address
+ */
+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 offset 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;
+ // Read only pages are COW
+ 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 );
+ }
+
+ // Apply anonymous memory for BSS
+ 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
+ );
+ }
+ }
+
+ Log_Debug("Binary", "PID %i - Mapped '%s' to %p", Threads_GetPID(), Path, base);
+ VFS_Close(fd);
+
+ 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;
+ }
+
+ // 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;
+ }
+
+ LOG("pBinary = %p", pBinary);
+
+ // 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);