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 Uint MM_ClearUser(void);
29 extern void Proc_StartUser(Uint Entrypoint, Uint *Bases, int ArgC, char **ArgV, char **EnvP, int DataSize);
30 extern tKernelSymbol gKernelSymbols[];
31 extern tKernelSymbol gKernelSymbolsEnd[];
32 extern tBinaryType gELF_Info;
35 int Proc_Execve(const char *File, const char **ArgV, const char **EnvP);
36 Uint Binary_Load(const char *file, Uint *entryPoint);
37 tBinary *Binary_GetInfo(const char *truePath);
38 Uint Binary_MapIn(tBinary *binary);
39 Uint Binary_IsMapped(tBinary *binary);
40 tBinary *Binary_DoLoad(const char *truePath);
41 void Binary_Dereference(tBinary *Info);
43 Uint Binary_Relocate(void *Base);
45 Uint Binary_GetSymbolEx(const char *Name, Uint *Value);
47 Uint Binary_FindSymbol(void *Base, const char *Name, Uint *Val);
51 tShortSpinlock glBinListLock;
52 tBinary *glLoadedBinaries = NULL;
53 char **gsaRegInterps = NULL;
55 tShortSpinlock glKBinListLock;
56 tKernelBin *glLoadedKernelLibs;
57 tBinaryType *gRegBinTypes = &gELF_Info;
61 * \brief Registers a binary type
63 int Binary_RegisterType(tBinaryType *Type)
65 Type->Next = gRegBinTypes;
71 * \fn int Proc_Spawn(const char *Path)
73 int Proc_Spawn(const char *Path)
75 char stackPath[strlen(Path)+1];
78 strcpy(stackPath, Path);
80 LOG("stackPath = '%s'\n", stackPath);
82 if(Proc_Clone(NULL, CLONE_VM) == 0)
85 const char *args[2] = {stackPath, NULL};
86 LOG("stackPath = '%s'\n", stackPath);
87 Proc_Execve(stackPath, args, &args[1]);
95 * \fn int Proc_Execve(char *File, char **ArgV, char **EnvP)
96 * \brief Replace the current user image with another
97 * \param File File to load as the next image
98 * \param ArgV Arguments to pass to user
99 * \param EnvP User's environment
100 * \note Called Proc_ for historical reasons
102 int Proc_Execve(const char *File, const char **ArgV, const char **EnvP)
106 char **argenvBuf, *strBuf;
107 char **argvSaved, **envpSaved;
112 ENTER("sFile pArgV pEnvP", File, ArgV, EnvP);
114 // --- Save File, ArgV and EnvP (also get argc)
116 // Count Arguments, Environment Variables and total string sizes
118 for( argc = 0; ArgV && ArgV[argc]; argc++ )
119 argenvBytes += strlen(ArgV[argc])+1;
120 for( envc = 0; EnvP && EnvP[envc]; envc++ )
121 argenvBytes += strlen(EnvP[envc])+1;
122 argenvBytes = (argenvBytes + sizeof(void*)-1) & ~(sizeof(void*)-1);
123 argenvBytes += (argc+1)*sizeof(void*) + (envc+1)*sizeof(void*);
126 argenvBuf = malloc(argenvBytes);
127 if(argenvBuf == NULL) {
128 Log_Error("Binary", "Proc_Execve - What the hell? The kernel is out of heap space");
132 strBuf = (char*)argenvBuf + (argc+1)*sizeof(void*) + (envc+1)*sizeof(void*);
135 argvSaved = argenvBuf;
136 for( i = 0; i < argc; i++ )
138 argvSaved[i] = strBuf;
139 strcpy(argvSaved[i], ArgV[i]);
140 strBuf += strlen(ArgV[i])+1;
143 envpSaved = &argvSaved[i+1];
144 for( i = 0; i < envc; i++ )
146 envpSaved[i] = strBuf;
147 strcpy(envpSaved[i], EnvP[i]);
148 strBuf += strlen(EnvP[i])+1;
152 savedFile = malloc(strlen(File)+1);
153 strcpy(savedFile, File);
155 // --- Set Process Name
156 Threads_SetName(File);
158 // --- Clear User Address space
161 // --- Load new binary
162 bases[0] = Binary_Load(savedFile, &entry);
166 Log_Warning("Binary", "Proc_Execve - Unable to load '%s'", Threads_GetName(-1));
168 Threads_Exit(0, -10);
172 LOG("entry = 0x%x, bases[0] = 0x%x", entry, bases[0]);
174 // --- And... Jump to it
175 Proc_StartUser(entry, bases, argc, argvSaved, envpSaved, argenvBytes);
176 for(;;); // Tell GCC that we never return
180 * \fn Uint Binary_Load(char *file, Uint *entryPoint)
181 * \brief Load a binary into the current address space
182 * \param file Path to binary to load
183 * \param entryPoint Pointer for exectuable entry point
185 Uint Binary_Load(const char *file, Uint *entryPoint)
191 ENTER("sfile pentryPoint", file, entryPoint);
193 // Sanity Check Argument
199 // Get True File Path
200 sTruePath = VFS_GetTruePath(file);
201 LOG("sTruePath = %p", sTruePath);
203 if(sTruePath == NULL) {
204 Log_Warning("Binary", "%p '%s' does not exist.", file, file);
209 LOG("sTruePath = '%s'", sTruePath);
211 // TODO: Also get modifcation time
213 // Check if the binary has already been loaded
214 if( !(pBinary = Binary_GetInfo(sTruePath)) )
215 pBinary = Binary_DoLoad(sTruePath); // Else load it
221 if(pBinary == NULL) {
227 if( (base = Binary_IsMapped(pBinary)) ) {
233 // Map into process space
234 base = Binary_MapIn(pBinary); // If so then map it in
243 if(pBinary->Interpreter) {
245 if( Binary_Load(pBinary->Interpreter, &start) == 0 ) {
252 *entryPoint = pBinary->Entry - pBinary->Base + base;
255 LOG("*entryPoint = 0x%x", *entryPoint);
257 return base; // Pass the base as an argument to the user if there is an interpreter
261 * \brief Finds a matching binary entry
262 * \param TruePath File Identifier (True path name)
264 tBinary *Binary_GetInfo(const char *TruePath)
267 pBinary = glLoadedBinaries;
270 if(strcmp(pBinary->TruePath, TruePath) == 0)
272 pBinary = pBinary->Next;
278 \fn Uint Binary_MapIn(tBinary *binary)
279 \brief Maps an already-loaded binary into an address space.
280 \param binary Pointer to globally stored data.
282 Uint Binary_MapIn(tBinary *binary)
288 // Reference Executable (Makes sure that it isn't unloaded)
289 binary->ReferenceCount ++;
294 // Check if base is free
297 for(i=0;i<binary->NumPages;i++)
299 if( MM_GetPhysAddr( binary->Pages[i].Virtual & ~0xFFF ) ) {
301 LOG("Address 0x%x is taken\n", binary->Pages[i].Virtual & ~0xFFF);
307 // Check if the executable has no base or it is not free
310 // If so, give it a base
312 while(base >= BIN_LOWEST)
314 for(i=0;i<binary->NumPages;i++)
316 addr = binary->Pages[i].Virtual & ~0xFFF;
317 addr -= binary->Base;
319 if( MM_GetPhysAddr( addr ) ) break;
321 // If space was found, break
322 if(i == binary->NumPages) break;
323 // Else decrement pointer and try again
324 base -= BIN_GRANUALITY;
329 if(base < BIN_LOWEST) {
330 Log_Warning("BIN", "Executable '%s' cannot be loaded, no space", binary->TruePath);
335 for(i=0;i<binary->NumPages;i++)
337 addr = binary->Pages[i].Virtual & ~0xFFF;
338 addr -= binary->Base;
340 LOG("%i - 0x%x to 0x%x", i, addr, binary->Pages[i].Physical);
341 MM_Map( addr, (Uint) (binary->Pages[i].Physical) );
344 if( binary->Pages[i].Flags & BIN_PAGEFLAG_RO)
345 MM_SetFlags( addr, MM_PFLAG_RO, -1 );
347 MM_SetFlags( addr, MM_PFLAG_COW, -1 );
350 if( binary->Pages[i].Flags & BIN_PAGEFLAG_EXEC )
351 MM_SetFlags( addr, MM_PFLAG_EXEC, -1 );
353 MM_SetFlags( addr, MM_PFLAG_EXEC, 0 );
357 Log_Debug("Binary", "PID %i - Mapped '%s' to 0x%x", Threads_GetPID(), binary->TruePath, base);
359 //LOG("*0x%x = 0x%x\n", binary->Pages[0].Virtual, *(Uint*)binary->Pages[0].Virtual);
366 * \fn Uint Binary_IsMapped(tBinary *binary)
367 * \brief Check if a binary is already mapped into the address space
368 * \param binary Binary information to check
369 * \return Current Base or 0
371 Uint Binary_IsMapped(tBinary *binary)
375 // Check prefered base
376 iBase = binary->Base;
377 if(MM_GetPage( iBase ) == (binary->Pages[0].Physical & ~0xFFF))
380 for(iBase = BIN_HIGHEST;
382 iBase -= BIN_GRANUALITY)
384 if(MM_GetPage( iBase ) == (binary->Pages[0].Physical & ~0xFFF))
393 * \fn tBinary *Binary_DoLoad(char *truePath)
394 * \brief Loads a binary file into memory
395 * \param truePath Absolute filename of binary
397 tBinary *Binary_DoLoad(const char *truePath)
402 tBinaryType *bt = gRegBinTypes;
404 ENTER("struePath", truePath);
407 fp = VFS_Open(truePath, VFS_OPENFLAG_READ);
409 LOG("Unable to load file, access denied");
415 VFS_Read(fp, 4, &ident);
416 VFS_Seek(fp, 0, SEEK_SET);
418 for(; bt; bt = bt->Next)
420 if( (ident & bt->Mask) != (Uint)bt->Ident )
422 pBinary = bt->Load(fp);
426 Log_Warning("BIN", "'%s' is an unknown file type. (%02x %02x %02x %02x)",
427 truePath, ident&0xFF, (ident>>8)&0xFF, (ident>>16)&0xFF, (ident>>24)&0xFF);
433 if(pBinary == NULL) {
438 // Initialise Structure
439 pBinary->ReferenceCount = 0;
440 pBinary->TruePath = strdup(truePath);
443 LOG("Interpreter: '%s'", pBinary->Interpreter);
444 LOG("Base: 0x%x, Entry: 0x%x", pBinary->Base, pBinary->Entry);
445 LOG("NumPages: %i", pBinary->NumPages);
448 for(i = 0; i < pBinary->NumPages; i ++)
452 paddr = (Uint)MM_AllocPhys();
454 Log_Warning("BIN", "Binary_DoLoad - Physical memory allocation failed");
456 MM_DerefPhys( pBinary->Pages[i].Physical );
460 MM_RefPhys( paddr ); // Make sure it is _NOT_ freed until we want it to be
461 dest = MM_MapTemp( paddr );
462 dest += pBinary->Pages[i].Virtual & 0xFFF;
463 LOG("dest = 0x%x, paddr = 0x%x", dest, paddr);
464 LOG("Pages[%i]={Physical:0x%llx,Virtual:%p,Size:0x%x}",
465 i, pBinary->Pages[i].Physical, pBinary->Pages[i].Virtual, pBinary->Pages[i].Size);
468 if(pBinary->Pages[i].Physical == -1) {
470 memset( (void*)dest, 0, 1024 - (pBinary->Pages[i].Virtual & 0xFFF) );
474 VFS_Seek( fp, pBinary->Pages[i].Physical, 1 );
475 // If the address is not aligned, or the page is not full
476 // sized, copy part of it
477 if( (dest & 0xFFF) > 0 || pBinary->Pages[i].Size < 0x1000)
479 // Validate the size to prevent Kernel page faults
480 // Clips to one page and prints a warning
481 if( pBinary->Pages[i].Size + (dest & 0xFFF) > 0x1000) {
482 Log_Warning("Binary", "Loader error: Page %i (%p) of '%s' is %i bytes (> 4096)",
483 i, pBinary->Pages[i].Virtual, truePath,
484 (dest&0xFFF) + pBinary->Pages[i].Size);
485 pBinary->Pages[i].Size = 0x1000 - (dest & 0xFFF);
487 LOG("%i - 0x%llx - 0x%x bytes",
488 i, pBinary->Pages[i].Physical, pBinary->Pages[i].Size);
489 // Zero from `dest` to the end of the page
490 memset( (void*)dest, 0, 0x1000 - (dest&0xFFF) );
492 VFS_Read( fp, pBinary->Pages[i].Size, (void*)dest );
497 // Check if the page is oversized
498 if(pBinary->Pages[i].Size > 0x1000)
499 Log_Warning("Binary", "Loader error - Page %i (%p) of '%s' is %i bytes (> 4096)",
500 i, pBinary->Pages[i].Virtual, truePath,
501 pBinary->Pages[i].Size);
503 LOG("%i - 0x%x", i, pBinary->Pages[i].Physical);
504 VFS_Read( fp, 0x1000, (void*)dest );
507 pBinary->Pages[i].Physical = paddr;
510 LOG("Page Count: %i", pBinary->NumPages);
516 SHORTLOCK(&glBinListLock);
517 pBinary->Next = glLoadedBinaries;
518 glLoadedBinaries = pBinary;
519 SHORTREL(&glBinListLock);
527 * \fn void Binary_Unload(void *Base)
528 * \brief Unload / Unmap a binary
529 * \param Base Loaded Base
530 * \note Currently used only for kernel libaries
532 void Binary_Unload(void *Base)
535 tKernelBin *prev = NULL;
538 if((Uint)Base < 0xC0000000)
540 // TODO: User Binaries
541 Log_Warning("BIN", "Unloading user binaries is currently unimplemented");
546 for(pKBin = glLoadedKernelLibs;
548 prev = pKBin, pKBin = pKBin->Next)
551 if(pKBin->Base != Base) continue;
553 for(i = 0; i < pKBin->Info->NumPages; i++) {
554 MM_Deallocate( (Uint)Base + (i << 12) );
556 // Dereference Binary
557 Binary_Dereference( pKBin->Info );
559 if(prev) prev->Next = pKBin->Next;
560 else glLoadedKernelLibs = pKBin->Next;
568 * \fn void Binary_Dereference(tBinary *Info)
569 * \brief Dereferences and if nessasary, deletes a binary
570 * \param Info Binary information structure
572 void Binary_Dereference(tBinary *Info)
574 // Decrement reference count
575 Info->ReferenceCount --;
577 // Check if it is still in use
578 if(Info->ReferenceCount) return;
580 /// \todo Implement binary freeing
584 * \fn char *Binary_RegInterp(char *Path)
585 * \brief Registers an Interpreter
586 * \param Path Path to interpreter provided by executable
588 char *Binary_RegInterp(char *Path)
591 // NULL Check Argument
592 if(Path == NULL) return NULL;
593 // NULL Check the array
594 if(gsaRegInterps == NULL)
597 gsaRegInterps = malloc( sizeof(char*) );
598 gsaRegInterps[0] = malloc( strlen(Path) );
599 strcpy(gsaRegInterps[0], Path);
600 return gsaRegInterps[0];
604 for( i = 0; i < giRegInterps; i++ )
606 if(strcmp(gsaRegInterps[i], Path) == 0)
607 return gsaRegInterps[i];
610 // Interpreter is not in list
612 gsaRegInterps = malloc( sizeof(char*)*giRegInterps );
613 gsaRegInterps[i] = malloc( strlen(Path) );
614 strcpy(gsaRegInterps[i], Path);
615 return gsaRegInterps[i];
619 // Kernel Binary Handling
622 * \fn void *Binary_LoadKernel(const char *File)
623 * \brief Load a binary into kernel space
624 * \note This function shares much with #Binary_Load, but does it's own mapping
625 * \param File File to load into the kernel
627 void *Binary_LoadKernel(const char *File)
631 tKernelBin *pKBinary;
636 ENTER("sFile", File);
638 // Sanity Check Argument
644 // Get True File Path
645 sTruePath = VFS_GetTruePath(File);
646 if(sTruePath == NULL) {
651 // Check if the binary has already been loaded
652 if( (pBinary = Binary_GetInfo(sTruePath)) )
654 for(pKBinary = glLoadedKernelLibs;
656 pKBinary = pKBinary->Next )
658 if(pKBinary->Info == pBinary) {
659 LEAVE('p', pKBinary->Base);
660 return pKBinary->Base;
665 pBinary = Binary_DoLoad(sTruePath); // Else load it
668 if(pBinary == NULL) {
674 // Now pBinary is valid (either freshly loaded or only user mapped)
675 // So, map it into kernel space
678 // Reference Executable (Makes sure that it isn't unloaded)
679 pBinary->ReferenceCount ++;
681 // Check compiled base
682 base = pBinary->Base;
684 if(base < KLIB_LOWEST || base > KLIB_HIGHEST || base + (pBinary->NumPages<<12) > KLIB_HIGHEST) {
687 // - Check if it is a valid base address
690 for(i=0;i<pBinary->NumPages;i++)
692 if( MM_GetPhysAddr( pBinary->Pages[i].Virtual & ~0xFFF ) ) {
694 LOG("Address 0x%x is taken\n", pBinary->Pages[i].Virtual & ~0xFFF);
700 // Check if the executable has no base or it is not free
703 // If so, give it a base
705 while(base < KLIB_HIGHEST)
707 for(i = 0; i < pBinary->NumPages; i++)
709 addr = pBinary->Pages[i].Virtual & ~0xFFF;
710 addr -= pBinary->Base;
712 if( MM_GetPhysAddr( addr ) ) break;
714 // If space was found, break
715 if(i == pBinary->NumPages) break;
716 // Else decrement pointer and try again
717 base += KLIB_GRANUALITY;
722 if(base >= KLIB_HIGHEST) {
723 Log_Warning("BIN", "Executable '%s' cannot be loaded into kernel, no space", pBinary->TruePath);
724 Binary_Dereference( pBinary );
729 LOG("base = 0x%x", base);
732 LOG("pBinary = {NumPages:%i, Pages=%p}", pBinary->NumPages, pBinary->Pages);
733 for(i = 0; i < pBinary->NumPages; i++)
735 addr = pBinary->Pages[i].Virtual & ~0xFFF;
736 addr -= pBinary->Base;
738 LOG("%i - 0x%x to 0x%x", i, addr, pBinary->Pages[i].Physical);
739 MM_Map( addr, (Uint) (pBinary->Pages[i].Physical) );
740 MM_SetFlags( addr, MM_PFLAG_KERNEL, MM_PFLAG_KERNEL );
742 if( pBinary->Pages[i].Flags & BIN_PAGEFLAG_RO) // Read-Only?
743 MM_SetFlags( addr, MM_PFLAG_RO, MM_PFLAG_KERNEL );
747 if( !Binary_Relocate( (void*)base ) )
749 Log_Warning("BIN", "Relocation of '%s' failed, unloading", sTruePath);
750 Binary_Unload( (void*)base );
751 Binary_Dereference( pBinary );
756 // Add to list (relocator must look at itself manually, not via Binary_GetSymbol)
757 pKBinary = malloc(sizeof(*pKBinary));
758 pKBinary->Base = (void*)base;
759 pKBinary->Info = pBinary;
760 SHORTLOCK( &glKBinListLock );
761 pKBinary->Next = glLoadedKernelLibs;
762 glLoadedKernelLibs = pKBinary;
763 SHORTREL( &glKBinListLock );
770 * \fn Uint Binary_Relocate(void *Base)
771 * \brief Relocates a loaded binary (used by kernel libraries)
772 * \param Base Loaded base address of binary
773 * \return Boolean Success
775 Uint Binary_Relocate(void *Base)
777 Uint32 ident = *(Uint32*) Base;
778 tBinaryType *bt = gRegBinTypes;
780 for(; bt; bt = bt->Next)
782 if( (ident & bt->Mask) == (Uint)bt->Ident )
783 return bt->Relocate( (void*)Base);
786 Log_Warning("BIN", "%p is an unknown file type. (%02x %02x %02x %02x)",
787 Base, ident&0xFF, (ident>>8)&0xFF, (ident>>16)&0xFF, (ident>>24)&0xFF);
792 * \fn int Binary_GetSymbol(char *Name, Uint *Val)
793 * \brief Get a symbol value
794 * \return Value of symbol or -1 on error
796 * Gets the value of a symbol from either the currently loaded
797 * libraries or the kernel's exports.
799 int Binary_GetSymbol(const char *Name, Uint *Val)
801 if( Binary_GetSymbolEx(Name, Val) ) return 1;
806 * \fn Uint Binary_GetSymbolEx(char *Name, Uint *Value)
807 * \brief Get a symbol value
809 * Gets the value of a symbol from either the currently loaded
810 * libraries or the kernel's exports.
812 Uint Binary_GetSymbolEx(const char *Name, Uint *Value)
816 int numKSyms = ((Uint)&gKernelSymbolsEnd-(Uint)&gKernelSymbols)/sizeof(tKernelSymbol);
819 for( i = 0; i < numKSyms; i++ )
821 if(strcmp(Name, gKernelSymbols[i].Name) == 0) {
822 *Value = gKernelSymbols[i].Value;
827 // Scan Loaded Libraries
828 for(pKBin = glLoadedKernelLibs;
830 pKBin = pKBin->Next )
832 if( Binary_FindSymbol(pKBin->Base, Name, Value) ) {
837 Log_Warning("BIN", "Unable to find symbol '%s'", Name);
842 * \fn Uint Binary_FindSymbol(void *Base, char *Name, Uint *Val)
843 * \brief Get a symbol from the specified library
844 * \param Base Base address
845 * \param Name Name of symbol to find
846 * \param Val Pointer to place final value
848 Uint Binary_FindSymbol(void *Base, const char *Name, Uint *Val)
850 Uint32 ident = *(Uint32*) Base;
851 tBinaryType *bt = gRegBinTypes;
853 for(; bt; bt = bt->Next)
855 if( (ident & bt->Mask) == (Uint)bt->Ident )
856 return bt->GetSymbol(Base, Name, Val);
859 Log_Warning("BIN", "Binary_FindSymbol - %p is an unknown file type. (%02x %02x %02x %02x)",
860 Base, ident&0xFF, ident>>8, ident>>16, ident>>24);
865 EXPORT(Binary_FindSymbol);
866 EXPORT(Binary_Unload);