11 #define BIN_LOWEST MM_USER_MIN // 1MiB
12 #define BIN_GRANUALITY 0x10000 // 64KiB
13 #define BIN_HIGHEST (USER_LIB_MAX-BIN_GRANUALITY) // Just below the kernel
14 #define KLIB_LOWEST MM_MODULE_MIN
15 #define KLIB_GRANUALITY 0x10000 // 32KiB
16 #define KLIB_HIGHEST (MM_MODULE_MAX-KLIB_GRANUALITY)
19 typedef struct sKernelBin {
20 struct sKernelBin *Next;
26 extern int Proc_Clone(Uint *Err, Uint Flags);
27 extern char *Threads_GetName(int ID);
28 extern void Threads_Exit(int, int);
29 extern Uint MM_ClearUser(void);
30 extern void Proc_StartUser(Uint Entrypoint, Uint *Bases, int ArgC, char **ArgV, char **EnvP, int DataSize);
31 extern tKernelSymbol gKernelSymbols[];
32 extern void gKernelSymbolsEnd;
33 extern tBinaryType gELF_Info;
36 int Proc_Execve(char *File, char **ArgV, char **EnvP);
37 Uint Binary_Load(char *file, Uint *entryPoint);
38 tBinary *Binary_GetInfo(char *truePath);
39 Uint Binary_MapIn(tBinary *binary);
40 Uint Binary_IsMapped(tBinary *binary);
41 tBinary *Binary_DoLoad(char *truePath);
42 void Binary_Dereference(tBinary *Info);
43 Uint Binary_Relocate(void *Base);
44 Uint Binary_GetSymbolEx(char *Name, Uint *Value);
45 Uint Binary_FindSymbol(void *Base, char *Name, Uint *Val);
48 int glBinListLock = 0;
49 tBinary *glLoadedBinaries = NULL;
50 char **gsaRegInterps = NULL;
52 int glKBinListLock = 0;
53 tKernelBin *glLoadedKernelLibs;
54 tBinaryType *gRegBinTypes = &gELF_Info;
58 * \brief Registers a binary type
60 int Binary_RegisterType(tBinaryType *Type)
62 Type->Next = gRegBinTypes;
68 * \fn int Proc_Spawn(char *Path)
70 int Proc_Spawn(char *Path)
72 char stackPath[strlen(Path)+1];
74 strcpy(stackPath, Path);
76 LOG("stackPath = '%s'\n", stackPath);
78 if(Proc_Clone(NULL, CLONE_VM) == 0)
81 char *args[2] = {stackPath, NULL};
82 LOG("stackPath = '%s'\n", stackPath);
83 Proc_Execve(stackPath, args, &args[1]);
90 * \fn int Proc_Execve(char *File, char **ArgV, char **EnvP)
91 * \brief Replace the current user image with another
92 * \param File File to load as the next image
93 * \param ArgV Arguments to pass to user
94 * \param EnvP User's environment
95 * \note Called Proc_ for historical reasons
97 int Proc_Execve(char *File, char **ArgV, char **EnvP)
101 char *argenvBuf, *strBuf;
102 char **argvSaved, **envpSaved;
107 ENTER("sFile pArgV pEnvP", File, ArgV, EnvP);
109 // --- Save File, ArgV and EnvP (also get argc)
111 // Count Arguments, Environment Variables and total string sizes
113 for( argc = 0; ArgV && ArgV[argc]; argc++ )
114 argenvBytes += strlen(ArgV[argc])+1;
115 for( envc = 0; EnvP && EnvP[envc]; envc++ )
116 argenvBytes += strlen(EnvP[envc])+1;
117 argenvBytes = (argenvBytes + sizeof(void*)-1) & ~(sizeof(void*)-1);
118 argenvBytes += (argc+1)*sizeof(void*) + (envc+1)*sizeof(void*);
121 argenvBuf = malloc(argenvBytes);
122 if(argenvBuf == NULL) {
123 Log_Error("BIN", "Proc_Execve - What the hell? The kernel is out of heap space");
126 strBuf = argenvBuf + (argc+1)*sizeof(void*) + (envc+1)*sizeof(void*);
129 argvSaved = (char **) argenvBuf;
130 for( i = 0; i < argc; i++ )
132 argvSaved[i] = strBuf;
133 strcpy(argvSaved[i], ArgV[i]);
134 strBuf += strlen(ArgV[i])+1;
137 envpSaved = &argvSaved[i+1];
138 for( i = 0; i < envc; i++ )
140 envpSaved[i] = strBuf;
141 strcpy(envpSaved[i], EnvP[i]);
142 strBuf += strlen(EnvP[i])+1;
146 savedFile = malloc(strlen(File)+1);
147 strcpy(savedFile, File);
149 // --- Set Process Name
150 Threads_SetName(File);
152 // --- Clear User Address space
155 // --- Load new binary
156 bases[0] = Binary_Load(savedFile, &entry);
160 Log_Warning("BIN", "Proc_Execve - Unable to load '%s'", Threads_GetName(-1));
165 LOG("entry = 0x%x, bases[0] = 0x%x", entry, bases[0]);
167 // --- And... Jump to it
168 Proc_StartUser(entry, bases, argc, argvSaved, envpSaved, argenvBytes);
169 for(;;); // Tell GCC that we never return
173 * \fn Uint Binary_Load(char *file, Uint *entryPoint)
175 Uint Binary_Load(char *file, Uint *entryPoint)
181 ENTER("sfile", file);
183 // Sanity Check Argument
189 // Get True File Path
190 sTruePath = VFS_GetTruePath(file);
192 if(sTruePath == NULL) {
193 Log_Warning("BIN", "'%s' does not exist.", file);
198 LOG("sTruePath = '%s'", sTruePath);
200 // Check if the binary has already been loaded
201 if( !(pBinary = Binary_GetInfo(sTruePath)) )
202 pBinary = Binary_DoLoad(sTruePath); // Else load it
208 if(pBinary == NULL) {
214 if( (base = Binary_IsMapped(pBinary)) ) {
220 // Map into process space
221 base = Binary_MapIn(pBinary); // If so then map it in
230 if(pBinary->Interpreter) {
232 if( Binary_Load(pBinary->Interpreter, &start) == 0 ) {
239 *entryPoint = pBinary->Entry - pBinary->Base + base;
242 LOG("*entryPoint = 0x%x", *entryPoint);
244 return base; // Pass the base as an argument to the user if there is an interpreter
248 * \brief Finds a matching binary entry
249 * \param TruePath File Identifier (True path name)
251 tBinary *Binary_GetInfo(char *TruePath)
254 pBinary = glLoadedBinaries;
257 if(strcmp(pBinary->TruePath, TruePath) == 0)
259 pBinary = pBinary->Next;
265 \fn Uint Binary_MapIn(tBinary *binary)
266 \brief Maps an already-loaded binary into an address space.
267 \param binary Pointer to globally stored data.
269 Uint Binary_MapIn(tBinary *binary)
275 // Reference Executable (Makes sure that it isn't unloaded)
276 binary->ReferenceCount ++;
281 // Check if base is free
284 for(i=0;i<binary->NumPages;i++)
286 if( MM_GetPhysAddr( binary->Pages[i].Virtual & ~0xFFF ) ) {
288 LOG("Address 0x%x is taken\n", binary->Pages[i].Virtual & ~0xFFF);
294 // Check if the executable has no base or it is not free
297 // If so, give it a base
299 while(base >= BIN_LOWEST)
301 for(i=0;i<binary->NumPages;i++)
303 addr = binary->Pages[i].Virtual & ~0xFFF;
304 addr -= binary->Base;
306 if( MM_GetPhysAddr( addr ) ) break;
308 // If space was found, break
309 if(i == binary->NumPages) break;
310 // Else decrement pointer and try again
311 base -= BIN_GRANUALITY;
316 if(base < BIN_LOWEST) {
317 Log_Warning("BIN", "Executable '%s' cannot be loaded, no space", binary->TruePath);
322 for(i=0;i<binary->NumPages;i++)
324 addr = binary->Pages[i].Virtual & ~0xFFF;
325 addr -= binary->Base;
327 LOG("%i - 0x%x to 0x%x", i, addr, binary->Pages[i].Physical);
328 MM_Map( addr, (Uint) (binary->Pages[i].Physical) );
331 if( binary->Pages[i].Flags & BIN_PAGEFLAG_RO)
332 MM_SetFlags( addr, MM_PFLAG_RO, -1 );
334 MM_SetFlags( addr, MM_PFLAG_COW, -1 );
337 if( binary->Pages[i].Flags & BIN_PAGEFLAG_EXEC )
338 MM_SetFlags( addr, MM_PFLAG_EXEC, -1 );
340 MM_SetFlags( addr, MM_PFLAG_EXEC, 0 );
344 Log_Debug("Binary", "PID %i - Mapped '%s' to 0x%x", Threads_GetPID(), binary->TruePath, base);
346 //LOG("*0x%x = 0x%x\n", binary->Pages[0].Virtual, *(Uint*)binary->Pages[0].Virtual);
353 * \fn Uint Binary_IsMapped(tBinary *binary)
354 * \brief Check if a binary is already mapped into the address space
355 * \param binary Binary information to check
356 * \return Current Base or 0
358 Uint Binary_IsMapped(tBinary *binary)
362 // Check prefered base
363 iBase = binary->Base;
364 if(MM_GetPage( iBase ) == (binary->Pages[0].Physical & ~0xFFF))
367 for(iBase = BIN_HIGHEST;
369 iBase -= BIN_GRANUALITY)
371 if(MM_GetPage( iBase ) == (binary->Pages[0].Physical & ~0xFFF))
380 * \fn tBinary *Binary_DoLoad(char *truePath)
381 * \brief Loads a binary file into memory
382 * \param truePath Absolute filename of binary
384 tBinary *Binary_DoLoad(char *truePath)
389 tBinaryType *bt = gRegBinTypes;
391 ENTER("struePath", truePath);
394 fp = VFS_Open(truePath, VFS_OPENFLAG_READ);
396 LOG("Unable to load file, access denied");
402 VFS_Read(fp, 4, &ident);
403 VFS_Seek(fp, 0, SEEK_SET);
405 for(; bt; bt = bt->Next)
407 if( (ident & bt->Mask) != (Uint)bt->Ident )
409 pBinary = bt->Load(fp);
413 Log_Warning("BIN", "'%s' is an unknown file type. (%02x %02x %02x %02x)",
414 truePath, ident&0xFF, (ident>>8)&0xFF, (ident>>16)&0xFF, (ident>>24)&0xFF);
420 if(pBinary == NULL) {
425 // Initialise Structure
426 pBinary->ReferenceCount = 0;
427 pBinary->TruePath = malloc( strlen(truePath) + 1 );
428 strcpy(pBinary->TruePath, truePath);
431 LOG("Interpreter: '%s'", pBinary->Interpreter);
432 LOG("Base: 0x%x, Entry: 0x%x", pBinary->Base, pBinary->Entry);
433 LOG("NumPages: %i", pBinary->NumPages);
436 for(i = 0; i < pBinary->NumPages; i ++)
440 paddr = (Uint)MM_AllocPhys();
442 Log_Warning("BIN", "Binary_DoLoad - Physical memory allocation failed");
444 MM_DerefPhys( pBinary->Pages[i].Physical );
448 MM_RefPhys( paddr ); // Make sure it is _NOT_ freed until we want it to be
449 dest = MM_MapTemp( paddr );
450 dest += pBinary->Pages[i].Virtual & 0xFFF;
451 LOG("dest = 0x%x, paddr = 0x%x", dest, paddr);
452 LOG("Pages[%i]={Physical:0x%llx,Virtual:%p,Size:0x%x}",
453 i, pBinary->Pages[i].Physical, pBinary->Pages[i].Virtual, pBinary->Pages[i].Size);
456 if(pBinary->Pages[i].Physical == -1) {
458 memset( (void*)dest, 0, 1024 - (pBinary->Pages[i].Virtual & 0xFFF) );
462 VFS_Seek( fp, pBinary->Pages[i].Physical, 1 );
463 // If the address is not aligned, or the page is not full
464 // sized, copy part of it
465 if( (dest & 0xFFF) > 0 || pBinary->Pages[i].Size < 0x1000)
467 // Validate the size to prevent Kernel page faults
468 // Clips to one page and prints a warning
469 if( pBinary->Pages[i].Size + (dest & 0xFFF) > 0x1000) {
470 Log_Warning("Binary", "Loader error: Page %i (%p) of '%s' is %i bytes (> 4096)",
471 i, pBinary->Pages[i].Virtual, truePath,
472 (dest&0xFFF) + pBinary->Pages[i].Size);
473 pBinary->Pages[i].Size = 0x1000 - (dest & 0xFFF);
475 LOG("%i - 0x%llx - 0x%x bytes",
476 i, pBinary->Pages[i].Physical, pBinary->Pages[i].Size);
477 // Zero from `dest` to the end of the page
478 memset( (void*)dest, 0, 0x1000 - (dest&0xFFF) );
480 VFS_Read( fp, pBinary->Pages[i].Size, (void*)dest );
485 // Check if the page is oversized
486 if(pBinary->Pages[i].Size > 0x1000)
487 Log_Warning("Binary", "Loader error - Page %i (%p) of '%s' is %i bytes (> 4096)",
488 i, pBinary->Pages[i].Virtual, truePath,
489 pBinary->Pages[i].Size);
491 LOG("%i - 0x%x", i, pBinary->Pages[i].Physical);
492 VFS_Read( fp, 0x1000, (void*)dest );
495 pBinary->Pages[i].Physical = paddr;
498 LOG("Page Count: %i", pBinary->NumPages);
504 LOCK(&glBinListLock);
505 pBinary->Next = glLoadedBinaries;
506 glLoadedBinaries = pBinary;
507 RELEASE(&glBinListLock);
515 * \fn void Binary_Unload(void *Base)
516 * \brief Unload / Unmap a binary
517 * \param Base Loaded Base
518 * \note Currently used only for kernel libaries
520 void Binary_Unload(void *Base)
523 tKernelBin *prev = NULL;
526 if((Uint)Base < 0xC0000000)
528 // TODO: User Binaries
529 Log_Warning("BIN", "Unloading user binaries is currently unimplemented");
534 for(pKBin = glLoadedKernelLibs;
536 prev = pKBin, pKBin = pKBin->Next)
539 if(pKBin->Base != Base) continue;
541 for(i = 0; i < pKBin->Info->NumPages; i++) {
542 MM_Deallocate( (Uint)Base + (i << 12) );
544 // Dereference Binary
545 Binary_Dereference( pKBin->Info );
547 if(prev) prev->Next = pKBin->Next;
548 else glLoadedKernelLibs = pKBin->Next;
556 * \fn void Binary_Dereference(tBinary *Info)
557 * \brief Dereferences and if nessasary, deletes a binary
558 * \param Info Binary information structure
560 void Binary_Dereference(tBinary *Info)
562 // Decrement reference count
563 Info->ReferenceCount --;
565 // Check if it is still in use
566 if(Info->ReferenceCount) return;
568 /// \todo Implement binary freeing
572 * \fn char *Binary_RegInterp(char *Path)
573 * \brief Registers an Interpreter
574 * \param Path Path to interpreter provided by executable
576 char *Binary_RegInterp(char *Path)
579 // NULL Check Argument
580 if(Path == NULL) return NULL;
581 // NULL Check the array
582 if(gsaRegInterps == NULL)
585 gsaRegInterps = malloc( sizeof(char*) );
586 gsaRegInterps[0] = malloc( strlen(Path) );
587 strcpy(gsaRegInterps[0], Path);
588 return gsaRegInterps[0];
592 for( i = 0; i < giRegInterps; i++ )
594 if(strcmp(gsaRegInterps[i], Path) == 0)
595 return gsaRegInterps[i];
598 // Interpreter is not in list
600 gsaRegInterps = malloc( sizeof(char*)*giRegInterps );
601 gsaRegInterps[i] = malloc( strlen(Path) );
602 strcpy(gsaRegInterps[i], Path);
603 return gsaRegInterps[i];
607 // Kernel Binary Handling
610 * \fn void *Binary_LoadKernel(char *File)
611 * \brief Load a binary into kernel space
612 * \note This function shares much with #Binary_Load, but does it's own mapping
613 * \param File File to load into the kernel
615 void *Binary_LoadKernel(char *File)
619 tKernelBin *pKBinary;
624 ENTER("sfile", File);
626 // Sanity Check Argument
632 // Get True File Path
633 sTruePath = VFS_GetTruePath(File);
634 if(sTruePath == NULL) {
639 // Check if the binary has already been loaded
640 if( (pBinary = Binary_GetInfo(sTruePath)) )
642 for(pKBinary = glLoadedKernelLibs;
644 pKBinary = pKBinary->Next )
646 if(pKBinary->Info == pBinary) {
647 LEAVE('p', pKBinary->Base);
648 return pKBinary->Base;
653 pBinary = Binary_DoLoad(sTruePath); // Else load it
656 if(pBinary == NULL) {
662 // Now pBinary is valid (either freshly loaded or only user mapped)
663 // So, map it into kernel space
666 // Reference Executable (Makes sure that it isn't unloaded)
667 pBinary->ReferenceCount ++;
669 // Check compiled base
670 base = pBinary->Base;
672 if(base < KLIB_LOWEST || base > KLIB_HIGHEST || base + (pBinary->NumPages<<12) > KLIB_HIGHEST) {
675 // - Check if it is a valid base address
678 for(i=0;i<pBinary->NumPages;i++)
680 if( MM_GetPhysAddr( pBinary->Pages[i].Virtual & ~0xFFF ) ) {
682 LOG("Address 0x%x is taken\n", pBinary->Pages[i].Virtual & ~0xFFF);
688 // Check if the executable has no base or it is not free
691 // If so, give it a base
693 while(base < KLIB_HIGHEST)
695 for(i = 0; i < pBinary->NumPages; i++)
697 addr = pBinary->Pages[i].Virtual & ~0xFFF;
698 addr -= pBinary->Base;
700 if( MM_GetPhysAddr( addr ) ) break;
702 // If space was found, break
703 if(i == pBinary->NumPages) break;
704 // Else decrement pointer and try again
705 base += KLIB_GRANUALITY;
710 if(base >= KLIB_HIGHEST) {
711 Log_Warning("BIN", "Executable '%s' cannot be loaded into kernel, no space", pBinary->TruePath);
712 Binary_Dereference( pBinary );
717 LOG("base = 0x%x", base);
720 LOG("pBinary = {NumPages:%i, Pages=%p}", pBinary->NumPages, pBinary->Pages);
721 for(i = 0; i < pBinary->NumPages; i++)
723 addr = pBinary->Pages[i].Virtual & ~0xFFF;
724 addr -= pBinary->Base;
726 LOG("%i - 0x%x to 0x%x", i, addr, pBinary->Pages[i].Physical);
727 MM_Map( addr, (Uint) (pBinary->Pages[i].Physical) );
728 MM_SetFlags( addr, MM_PFLAG_KERNEL, MM_PFLAG_KERNEL );
730 if( pBinary->Pages[i].Flags & BIN_PAGEFLAG_RO) // Read-Only?
731 MM_SetFlags( addr, MM_PFLAG_RO, MM_PFLAG_KERNEL );
735 if( !Binary_Relocate( (void*)base ) )
737 Warning("[BIN ] Relocation of '%s' failed, unloading", sTruePath);
738 Binary_Unload( (void*)base );
739 Binary_Dereference( pBinary );
744 // Add to list (relocator must look at itself manually, not via Binary_GetSymbol)
745 pKBinary = malloc(sizeof(*pKBinary));
746 pKBinary->Base = (void*)base;
747 pKBinary->Info = pBinary;
748 LOCK( &glKBinListLock );
749 pKBinary->Next = glLoadedKernelLibs;
750 glLoadedKernelLibs = pKBinary;
751 RELEASE( &glKBinListLock );
758 * \fn Uint Binary_Relocate(void *Base)
759 * \brief Relocates a loaded binary (used by kernel libraries)
760 * \param Base Loaded base address of binary
761 * \return Boolean Success
763 Uint Binary_Relocate(void *Base)
765 Uint32 ident = *(Uint32*) Base;
766 tBinaryType *bt = gRegBinTypes;
768 for(; bt; bt = bt->Next)
770 if( (ident & bt->Mask) == (Uint)bt->Ident )
771 return bt->Relocate( (void*)Base);
774 Log_Warning("BIN", "%p is an unknown file type. (%02x %02x %02x %02x)",
775 Base, ident&0xFF, (ident>>8)&0xFF, (ident>>16)&0xFF, (ident>>24)&0xFF);
780 * \fn int Binary_GetSymbol(char *Name, Uint *Val)
781 * \brief Get a symbol value
782 * \return Value of symbol or -1 on error
784 * Gets the value of a symbol from either the currently loaded
785 * libraries or the kernel's exports.
787 int Binary_GetSymbol(char *Name, Uint *Val)
789 if( Binary_GetSymbolEx(Name, Val) ) return 1;
794 * \fn Uint Binary_GetSymbolEx(char *Name, Uint *Value)
795 * \brief Get a symbol value
797 * Gets the value of a symbol from either the currently loaded
798 * libraries or the kernel's exports.
800 Uint Binary_GetSymbolEx(char *Name, Uint *Value)
804 int numKSyms = ((Uint)&gKernelSymbolsEnd-(Uint)&gKernelSymbols)/sizeof(tKernelSymbol);
807 for( i = 0; i < numKSyms; i++ )
809 if(strcmp(Name, gKernelSymbols[i].Name) == 0) {
810 *Value = gKernelSymbols[i].Value;
815 // Scan Loaded Libraries
816 for(pKBin = glLoadedKernelLibs;
818 pKBin = pKBin->Next )
820 if( Binary_FindSymbol(pKBin->Base, Name, Value) ) {
825 Log_Warning("BIN", "Unable to find symbol '%s'", Name);
830 * \fn Uint Binary_FindSymbol(void *Base, char *Name, Uint *Val)
831 * \brief Get a symbol from the specified library
832 * \param Base Base address
833 * \param Name Name of symbol to find
834 * \param Val Pointer to place final value
836 Uint Binary_FindSymbol(void *Base, char *Name, Uint *Val)
838 Uint32 ident = *(Uint32*) Base;
839 tBinaryType *bt = gRegBinTypes;
841 for(; bt; bt = bt->Next)
843 if( (ident & bt->Mask) == (Uint)bt->Ident )
844 return bt->GetSymbol(Base, Name, Val);
847 Log_Warning("BIN", "Binary_FindSymbol - %p is an unknown file type. (%02x %02x %02x %02x)",
848 Base, ident&0xFF, ident>>8, ident>>16, ident>>24);
853 EXPORT(Binary_FindSymbol);
854 EXPORT(Binary_Unload);