12 #define BIN_LOWEST MM_USER_MIN // 1MiB
13 #define BIN_GRANUALITY 0x10000 // 64KiB
14 #define BIN_HIGHEST (USER_LIB_MAX-BIN_GRANUALITY) // Just below the kernel
15 #define KLIB_LOWEST MM_MODULE_MIN
16 #define KLIB_GRANUALITY 0x10000 // 32KiB
17 #define KLIB_HIGHEST (MM_MODULE_MAX-KLIB_GRANUALITY)
20 typedef struct sKernelBin {
21 struct sKernelBin *Next;
27 extern char *Threads_GetName(int ID);
28 extern tKernelSymbol gKernelSymbols[];
29 extern tKernelSymbol gKernelSymbolsEnd[];
30 extern tBinaryType gELF_Info;
33 int Proc_Execve(const char *File, const char **ArgV, const char **EnvP);
34 Uint Binary_Load(const char *file, Uint *entryPoint);
35 tBinary *Binary_GetInfo(const char *truePath);
36 Uint Binary_MapIn(tBinary *binary);
37 Uint Binary_IsMapped(tBinary *binary);
38 tBinary *Binary_DoLoad(const char *truePath);
39 void Binary_Dereference(tBinary *Info);
41 Uint Binary_Relocate(void *Base);
43 Uint Binary_GetSymbolEx(const char *Name, Uint *Value);
45 Uint Binary_FindSymbol(void *Base, const char *Name, Uint *Val);
49 tShortSpinlock glBinListLock;
50 tBinary *glLoadedBinaries = NULL;
51 char **gsaRegInterps = NULL;
53 tShortSpinlock glKBinListLock;
54 tKernelBin *glLoadedKernelLibs;
55 tBinaryType *gRegBinTypes = &gELF_Info;
59 * \brief Registers a binary type
61 int Binary_RegisterType(tBinaryType *Type)
63 Type->Next = gRegBinTypes;
69 * \fn int Proc_Spawn(const char *Path)
71 int Proc_Spawn(const char *Path)
73 char stackPath[strlen(Path)+1];
76 strcpy(stackPath, Path);
78 LOG("stackPath = '%s'\n", stackPath);
80 if(Proc_Clone(CLONE_VM) == 0)
83 const char *args[2] = {stackPath, NULL};
84 LOG("stackPath = '%s'\n", stackPath);
85 Proc_Execve(stackPath, args, &args[1]);
93 * \fn int Proc_Execve(char *File, char **ArgV, char **EnvP)
94 * \brief Replace the current user image with another
95 * \param File File to load as the next image
96 * \param ArgV Arguments to pass to user
97 * \param EnvP User's environment
98 * \note Called Proc_ for historical reasons
100 int Proc_Execve(const char *File, const char **ArgV, const char **EnvP)
104 char **argenvBuf, *strBuf;
105 char **argvSaved, **envpSaved;
110 ENTER("sFile pArgV pEnvP", File, ArgV, EnvP);
112 // --- Save File, ArgV and EnvP (also get argc)
114 // Count Arguments, Environment Variables and total string sizes
116 for( argc = 0; ArgV && ArgV[argc]; argc++ )
117 argenvBytes += strlen(ArgV[argc])+1;
118 for( envc = 0; EnvP && EnvP[envc]; envc++ )
119 argenvBytes += strlen(EnvP[envc])+1;
120 argenvBytes = (argenvBytes + sizeof(void*)-1) & ~(sizeof(void*)-1);
121 argenvBytes += (argc+1)*sizeof(void*) + (envc+1)*sizeof(void*);
124 argenvBuf = malloc(argenvBytes);
125 if(argenvBuf == NULL) {
126 Log_Error("Binary", "Proc_Execve - What the hell? The kernel is out of heap space");
130 strBuf = (char*)argenvBuf + (argc+1)*sizeof(void*) + (envc+1)*sizeof(void*);
133 argvSaved = argenvBuf;
134 for( i = 0; i < argc; i++ )
136 argvSaved[i] = strBuf;
137 strcpy(argvSaved[i], ArgV[i]);
138 strBuf += strlen(ArgV[i])+1;
141 envpSaved = &argvSaved[i+1];
142 for( i = 0; i < envc; i++ )
144 envpSaved[i] = strBuf;
145 strcpy(envpSaved[i], EnvP[i]);
146 strBuf += strlen(EnvP[i])+1;
150 savedFile = malloc(strlen(File)+1);
151 strcpy(savedFile, File);
153 // --- Set Process Name
154 Threads_SetName(File);
156 // --- Clear User Address space
159 // --- Load new binary
160 bases[0] = Binary_Load(savedFile, &entry);
164 Log_Warning("Binary", "Proc_Execve - Unable to load '%s'", Threads_GetName(-1));
166 Threads_Exit(0, -10);
170 LOG("entry = 0x%x, bases[0] = 0x%x", entry, bases[0]);
172 // --- And... Jump to it
173 Proc_StartUser(entry, bases, argc, argvSaved, envpSaved, argenvBytes);
174 for(;;); // Tell GCC that we never return
178 * \fn Uint Binary_Load(char *file, Uint *entryPoint)
179 * \brief Load a binary into the current address space
180 * \param file Path to binary to load
181 * \param entryPoint Pointer for exectuable entry point
183 Uint Binary_Load(const char *file, Uint *entryPoint)
189 ENTER("sfile pentryPoint", file, entryPoint);
191 // Sanity Check Argument
197 // Get True File Path
198 sTruePath = VFS_GetTruePath(file);
199 LOG("sTruePath = %p", sTruePath);
201 if(sTruePath == NULL) {
202 Log_Warning("Binary", "%p '%s' does not exist.", file, file);
207 LOG("sTruePath = '%s'", sTruePath);
209 // TODO: Also get modifcation time
211 // Check if the binary has already been loaded
212 if( !(pBinary = Binary_GetInfo(sTruePath)) )
213 pBinary = Binary_DoLoad(sTruePath); // Else load it
219 if(pBinary == NULL) {
225 if( (base = Binary_IsMapped(pBinary)) ) {
231 // Map into process space
232 base = Binary_MapIn(pBinary); // If so then map it in
241 if(pBinary->Interpreter) {
243 if( Binary_Load(pBinary->Interpreter, &start) == 0 ) {
250 *entryPoint = pBinary->Entry - pBinary->Base + base;
253 LOG("*entryPoint = 0x%x", *entryPoint);
255 return base; // Pass the base as an argument to the user if there is an interpreter
259 * \brief Finds a matching binary entry
260 * \param TruePath File Identifier (True path name)
262 tBinary *Binary_GetInfo(const char *TruePath)
265 pBinary = glLoadedBinaries;
268 if(strcmp(pBinary->TruePath, TruePath) == 0)
270 pBinary = pBinary->Next;
276 \fn Uint Binary_MapIn(tBinary *binary)
277 \brief Maps an already-loaded binary into an address space.
278 \param binary Pointer to globally stored data.
280 Uint Binary_MapIn(tBinary *binary)
286 // Reference Executable (Makes sure that it isn't unloaded)
287 binary->ReferenceCount ++;
292 // Check if base is free
295 for(i=0;i<binary->NumPages;i++)
297 if( MM_GetPhysAddr( binary->Pages[i].Virtual & ~0xFFF ) ) {
299 LOG("Address 0x%x is taken\n", binary->Pages[i].Virtual & ~0xFFF);
305 // Check if the executable has no base or it is not free
308 // If so, give it a base
310 while(base >= BIN_LOWEST)
312 for(i=0;i<binary->NumPages;i++)
314 addr = binary->Pages[i].Virtual & ~0xFFF;
315 addr -= binary->Base;
317 if( MM_GetPhysAddr( addr ) ) break;
319 // If space was found, break
320 if(i == binary->NumPages) break;
321 // Else decrement pointer and try again
322 base -= BIN_GRANUALITY;
327 if(base < BIN_LOWEST) {
328 Log_Warning("BIN", "Executable '%s' cannot be loaded, no space", binary->TruePath);
333 for(i=0;i<binary->NumPages;i++)
335 addr = binary->Pages[i].Virtual & ~0xFFF;
336 addr -= binary->Base;
338 LOG("%i - 0x%x to 0x%x", i, addr, binary->Pages[i].Physical);
339 MM_Map( addr, (Uint) (binary->Pages[i].Physical) );
342 if( binary->Pages[i].Flags & BIN_PAGEFLAG_RO)
343 MM_SetFlags( addr, MM_PFLAG_RO, -1 );
345 MM_SetFlags( addr, MM_PFLAG_COW, -1 );
348 if( binary->Pages[i].Flags & BIN_PAGEFLAG_EXEC )
349 MM_SetFlags( addr, MM_PFLAG_EXEC, -1 );
351 MM_SetFlags( addr, MM_PFLAG_EXEC, 0 );
355 Log_Debug("Binary", "PID %i - Mapped '%s' to 0x%x", Threads_GetPID(), binary->TruePath, base);
357 //LOG("*0x%x = 0x%x\n", binary->Pages[0].Virtual, *(Uint*)binary->Pages[0].Virtual);
364 * \fn Uint Binary_IsMapped(tBinary *binary)
365 * \brief Check if a binary is already mapped into the address space
366 * \param binary Binary information to check
367 * \return Current Base or 0
369 Uint Binary_IsMapped(tBinary *binary)
373 // Check prefered base
374 iBase = binary->Base;
375 if(MM_GetPage( iBase ) == (binary->Pages[0].Physical & ~0xFFF))
378 for(iBase = BIN_HIGHEST;
380 iBase -= BIN_GRANUALITY)
382 if(MM_GetPage( iBase ) == (binary->Pages[0].Physical & ~0xFFF))
391 * \fn tBinary *Binary_DoLoad(char *truePath)
392 * \brief Loads a binary file into memory
393 * \param truePath Absolute filename of binary
395 tBinary *Binary_DoLoad(const char *truePath)
400 tBinaryType *bt = gRegBinTypes;
402 ENTER("struePath", truePath);
405 fp = VFS_Open(truePath, VFS_OPENFLAG_READ);
407 LOG("Unable to load file, access denied");
413 VFS_Read(fp, 4, &ident);
414 VFS_Seek(fp, 0, SEEK_SET);
416 for(; bt; bt = bt->Next)
418 if( (ident & bt->Mask) != (Uint)bt->Ident )
420 pBinary = bt->Load(fp);
424 Log_Warning("BIN", "'%s' is an unknown file type. (%02x %02x %02x %02x)",
425 truePath, ident&0xFF, (ident>>8)&0xFF, (ident>>16)&0xFF, (ident>>24)&0xFF);
431 if(pBinary == NULL) {
436 // Initialise Structure
437 pBinary->ReferenceCount = 0;
438 pBinary->TruePath = strdup(truePath);
441 LOG("Interpreter: '%s'", pBinary->Interpreter);
442 LOG("Base: 0x%x, Entry: 0x%x", pBinary->Base, pBinary->Entry);
443 LOG("NumPages: %i", pBinary->NumPages);
446 for(i = 0; i < pBinary->NumPages; i ++)
450 paddr = (Uint)MM_AllocPhys();
452 Log_Warning("BIN", "Binary_DoLoad - Physical memory allocation failed");
454 MM_DerefPhys( pBinary->Pages[i].Physical );
458 MM_RefPhys( paddr ); // Make sure it is _NOT_ freed until we want it to be
459 dest = MM_MapTemp( paddr );
460 dest += pBinary->Pages[i].Virtual & 0xFFF;
461 LOG("dest = 0x%x, paddr = 0x%x", dest, paddr);
462 LOG("Pages[%i]={Physical:0x%llx,Virtual:%p,Size:0x%x}",
463 i, pBinary->Pages[i].Physical, pBinary->Pages[i].Virtual, pBinary->Pages[i].Size);
466 if(pBinary->Pages[i].Physical == -1) {
468 memset( (void*)dest, 0, 1024 - (pBinary->Pages[i].Virtual & 0xFFF) );
472 VFS_Seek( fp, pBinary->Pages[i].Physical, 1 );
473 // If the address is not aligned, or the page is not full
474 // sized, copy part of it
475 if( (dest & 0xFFF) > 0 || pBinary->Pages[i].Size < 0x1000)
477 // Validate the size to prevent Kernel page faults
478 // Clips to one page and prints a warning
479 if( pBinary->Pages[i].Size + (dest & 0xFFF) > 0x1000) {
480 Log_Warning("Binary", "Loader error: Page %i (%p) of '%s' is %i bytes (> 4096)",
481 i, pBinary->Pages[i].Virtual, truePath,
482 (dest&0xFFF) + pBinary->Pages[i].Size);
483 pBinary->Pages[i].Size = 0x1000 - (dest & 0xFFF);
485 LOG("%i - 0x%llx - 0x%x bytes",
486 i, pBinary->Pages[i].Physical, pBinary->Pages[i].Size);
487 // Zero from `dest` to the end of the page
488 memset( (void*)dest, 0, 0x1000 - (dest&0xFFF) );
490 VFS_Read( fp, pBinary->Pages[i].Size, (void*)dest );
495 // Check if the page is oversized
496 if(pBinary->Pages[i].Size > 0x1000)
497 Log_Warning("Binary", "Loader error - Page %i (%p) of '%s' is %i bytes (> 4096)",
498 i, pBinary->Pages[i].Virtual, truePath,
499 pBinary->Pages[i].Size);
501 LOG("%i - 0x%x", i, pBinary->Pages[i].Physical);
502 VFS_Read( fp, 0x1000, (void*)dest );
505 pBinary->Pages[i].Physical = paddr;
508 LOG("Page Count: %i", pBinary->NumPages);
514 SHORTLOCK(&glBinListLock);
515 pBinary->Next = glLoadedBinaries;
516 glLoadedBinaries = pBinary;
517 SHORTREL(&glBinListLock);
525 * \fn void Binary_Unload(void *Base)
526 * \brief Unload / Unmap a binary
527 * \param Base Loaded Base
528 * \note Currently used only for kernel libaries
530 void Binary_Unload(void *Base)
533 tKernelBin *prev = NULL;
536 if((Uint)Base < 0xC0000000)
538 // TODO: User Binaries
539 Log_Warning("BIN", "Unloading user binaries is currently unimplemented");
544 for(pKBin = glLoadedKernelLibs;
546 prev = pKBin, pKBin = pKBin->Next)
549 if(pKBin->Base != Base) continue;
551 for(i = 0; i < pKBin->Info->NumPages; i++) {
552 MM_Deallocate( (Uint)Base + (i << 12) );
554 // Dereference Binary
555 Binary_Dereference( pKBin->Info );
557 if(prev) prev->Next = pKBin->Next;
558 else glLoadedKernelLibs = pKBin->Next;
566 * \fn void Binary_Dereference(tBinary *Info)
567 * \brief Dereferences and if nessasary, deletes a binary
568 * \param Info Binary information structure
570 void Binary_Dereference(tBinary *Info)
572 // Decrement reference count
573 Info->ReferenceCount --;
575 // Check if it is still in use
576 if(Info->ReferenceCount) return;
578 /// \todo Implement binary freeing
582 * \fn char *Binary_RegInterp(char *Path)
583 * \brief Registers an Interpreter
584 * \param Path Path to interpreter provided by executable
586 char *Binary_RegInterp(char *Path)
589 // NULL Check Argument
590 if(Path == NULL) return NULL;
591 // NULL Check the array
592 if(gsaRegInterps == NULL)
595 gsaRegInterps = malloc( sizeof(char*) );
596 gsaRegInterps[0] = malloc( strlen(Path) );
597 strcpy(gsaRegInterps[0], Path);
598 return gsaRegInterps[0];
602 for( i = 0; i < giRegInterps; i++ )
604 if(strcmp(gsaRegInterps[i], Path) == 0)
605 return gsaRegInterps[i];
608 // Interpreter is not in list
610 gsaRegInterps = malloc( sizeof(char*)*giRegInterps );
611 gsaRegInterps[i] = malloc( strlen(Path) );
612 strcpy(gsaRegInterps[i], Path);
613 return gsaRegInterps[i];
617 // Kernel Binary Handling
620 * \fn void *Binary_LoadKernel(const char *File)
621 * \brief Load a binary into kernel space
622 * \note This function shares much with #Binary_Load, but does it's own mapping
623 * \param File File to load into the kernel
625 void *Binary_LoadKernel(const char *File)
629 tKernelBin *pKBinary;
634 ENTER("sFile", File);
636 // Sanity Check Argument
642 // Get True File Path
643 sTruePath = VFS_GetTruePath(File);
644 if(sTruePath == NULL) {
649 // Check if the binary has already been loaded
650 if( (pBinary = Binary_GetInfo(sTruePath)) )
652 for(pKBinary = glLoadedKernelLibs;
654 pKBinary = pKBinary->Next )
656 if(pKBinary->Info == pBinary) {
657 LEAVE('p', pKBinary->Base);
658 return pKBinary->Base;
663 pBinary = Binary_DoLoad(sTruePath); // Else load it
666 if(pBinary == NULL) {
672 // Now pBinary is valid (either freshly loaded or only user mapped)
673 // So, map it into kernel space
676 // Reference Executable (Makes sure that it isn't unloaded)
677 pBinary->ReferenceCount ++;
679 // Check compiled base
680 base = pBinary->Base;
682 if(base < KLIB_LOWEST || base > KLIB_HIGHEST || base + (pBinary->NumPages<<12) > KLIB_HIGHEST) {
685 // - Check if it is a valid base address
688 for(i=0;i<pBinary->NumPages;i++)
690 if( MM_GetPhysAddr( pBinary->Pages[i].Virtual & ~0xFFF ) ) {
692 LOG("Address 0x%x is taken\n", pBinary->Pages[i].Virtual & ~0xFFF);
698 // Check if the executable has no base or it is not free
701 // If so, give it a base
703 while(base < KLIB_HIGHEST)
705 for(i = 0; i < pBinary->NumPages; i++)
707 addr = pBinary->Pages[i].Virtual & ~0xFFF;
708 addr -= pBinary->Base;
710 if( MM_GetPhysAddr( addr ) ) break;
712 // If space was found, break
713 if(i == pBinary->NumPages) break;
714 // Else decrement pointer and try again
715 base += KLIB_GRANUALITY;
720 if(base >= KLIB_HIGHEST) {
721 Log_Warning("BIN", "Executable '%s' cannot be loaded into kernel, no space", pBinary->TruePath);
722 Binary_Dereference( pBinary );
727 LOG("base = 0x%x", base);
730 LOG("pBinary = {NumPages:%i, Pages=%p}", pBinary->NumPages, pBinary->Pages);
731 for(i = 0; i < pBinary->NumPages; i++)
733 addr = pBinary->Pages[i].Virtual & ~0xFFF;
734 addr -= pBinary->Base;
736 LOG("%i - 0x%x to 0x%x", i, addr, pBinary->Pages[i].Physical);
737 MM_Map( addr, (Uint) (pBinary->Pages[i].Physical) );
738 MM_SetFlags( addr, MM_PFLAG_KERNEL, MM_PFLAG_KERNEL );
740 if( pBinary->Pages[i].Flags & BIN_PAGEFLAG_RO) // Read-Only?
741 MM_SetFlags( addr, MM_PFLAG_RO, MM_PFLAG_KERNEL );
745 if( !Binary_Relocate( (void*)base ) )
747 Log_Warning("BIN", "Relocation of '%s' failed, unloading", sTruePath);
748 Binary_Unload( (void*)base );
749 Binary_Dereference( pBinary );
754 // Add to list (relocator must look at itself manually, not via Binary_GetSymbol)
755 pKBinary = malloc(sizeof(*pKBinary));
756 pKBinary->Base = (void*)base;
757 pKBinary->Info = pBinary;
758 SHORTLOCK( &glKBinListLock );
759 pKBinary->Next = glLoadedKernelLibs;
760 glLoadedKernelLibs = pKBinary;
761 SHORTREL( &glKBinListLock );
768 * \fn Uint Binary_Relocate(void *Base)
769 * \brief Relocates a loaded binary (used by kernel libraries)
770 * \param Base Loaded base address of binary
771 * \return Boolean Success
773 Uint Binary_Relocate(void *Base)
775 Uint32 ident = *(Uint32*) Base;
776 tBinaryType *bt = gRegBinTypes;
778 for(; bt; bt = bt->Next)
780 if( (ident & bt->Mask) == (Uint)bt->Ident )
781 return bt->Relocate( (void*)Base);
784 Log_Warning("BIN", "%p is an unknown file type. (%02x %02x %02x %02x)",
785 Base, ident&0xFF, (ident>>8)&0xFF, (ident>>16)&0xFF, (ident>>24)&0xFF);
790 * \fn int Binary_GetSymbol(char *Name, Uint *Val)
791 * \brief Get a symbol value
792 * \return Value of symbol or -1 on error
794 * Gets the value of a symbol from either the currently loaded
795 * libraries or the kernel's exports.
797 int Binary_GetSymbol(const char *Name, Uint *Val)
799 if( Binary_GetSymbolEx(Name, Val) ) return 1;
804 * \fn Uint Binary_GetSymbolEx(char *Name, Uint *Value)
805 * \brief Get a symbol value
807 * Gets the value of a symbol from either the currently loaded
808 * libraries or the kernel's exports.
810 Uint Binary_GetSymbolEx(const char *Name, Uint *Value)
814 int numKSyms = ((Uint)&gKernelSymbolsEnd-(Uint)&gKernelSymbols)/sizeof(tKernelSymbol);
817 for( i = 0; i < numKSyms; i++ )
819 if(strcmp(Name, gKernelSymbols[i].Name) == 0) {
820 *Value = gKernelSymbols[i].Value;
825 // Scan Loaded Libraries
826 for(pKBin = glLoadedKernelLibs;
828 pKBin = pKBin->Next )
830 if( Binary_FindSymbol(pKBin->Base, Name, Value) ) {
835 Log_Warning("BIN", "Unable to find symbol '%s'", Name);
840 * \fn Uint Binary_FindSymbol(void *Base, char *Name, Uint *Val)
841 * \brief Get a symbol from the specified library
842 * \param Base Base address
843 * \param Name Name of symbol to find
844 * \param Val Pointer to place final value
846 Uint Binary_FindSymbol(void *Base, const char *Name, Uint *Val)
848 Uint32 ident = *(Uint32*) Base;
849 tBinaryType *bt = gRegBinTypes;
851 for(; bt; bt = bt->Next)
853 if( (ident & bt->Mask) == (Uint)bt->Ident )
854 return bt->GetSymbol(Base, Name, Val);
857 Log_Warning("BIN", "Binary_FindSymbol - %p is an unknown file type. (%02x %02x %02x %02x)",
858 Base, ident&0xFF, ident>>8, ident>>16, ident>>24);
863 EXPORT(Binary_FindSymbol);
864 EXPORT(Binary_Unload);