10 #include <vfs_threads.h>
13 #define BIN_LOWEST MM_USER_MIN // 1MiB
14 #define BIN_GRANUALITY 0x10000 // 64KiB
15 #define BIN_HIGHEST (USER_LIB_MAX-BIN_GRANUALITY) // Just below the kernel
16 #define KLIB_LOWEST MM_MODULE_MIN
17 #define KLIB_GRANUALITY 0x10000 // 32KiB
18 #define KLIB_HIGHEST (MM_MODULE_MAX-KLIB_GRANUALITY)
21 typedef struct sKernelBin {
22 struct sKernelBin *Next;
28 extern char *Threads_GetName(int ID);
29 extern tKernelSymbol gKernelSymbols[];
30 extern tKernelSymbol gKernelSymbolsEnd[];
31 extern tBinaryType gELF_Info;
34 int Binary_int_CacheArgs(const char **Path, const char ***ArgV, const char ***EnvP, void *DestBuffer);
35 tVAddr Binary_Load(const char *Path, tVAddr *EntryPoint);
36 tBinary *Binary_GetInfo(tMount MountID, tInode InodeID);
37 tVAddr Binary_MapIn(tBinary *Binary, const char *Path, tVAddr LoadMin, tVAddr LoadMax);
38 tVAddr Binary_IsMapped(tBinary *Binary);
39 tBinary *Binary_DoLoad(tMount MountID, tInode Inode, const char *Path);
40 void Binary_Dereference(tBinary *Info);
42 Uint Binary_Relocate(void *Base);
44 Uint Binary_GetSymbolEx(const char *Name, Uint *Value);
46 Uint Binary_FindSymbol(void *Base, const char *Name, Uint *Val);
48 int Binary_int_CheckMemFree( tVAddr _start, size_t _len );
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'", stackPath);
82 if(Proc_Clone(CLONE_VM|CLONE_NOUSER) == 0)
85 const char *args[2] = {stackPath, NULL};
86 LOG("stackPath = '%s'", stackPath);
87 Proc_Execve(stackPath, args, &args[1], 0);
97 int Binary_int_CacheArgs(const char **Path, const char ***ArgV, const char ***EnvP, void *DestBuffer)
99 int size, argc=0, envc=0;
108 const char **argv = *ArgV;
109 for( argc = 0; argv[argc]; argc ++ )
110 size += strlen( argv[argc] ) + 1;
114 const char **envp = *EnvP;
115 for( envc = 0; envp[envc]; envc ++ )
116 size += strlen( envp[envc] ) + 1;
118 size = (size + sizeof(void*)-1) & ~(sizeof(void*)-1); // Word align
119 size += (argc+1+envc+1)*sizeof(void*); // Arrays
122 size += strlen( *Path ) + 1;
128 strbuf = (void*)&arrays[argc+1+envc+1];
133 const char **argv = *ArgV;
134 for( i = 0; argv[i]; i ++ )
137 strcpy(strbuf, argv[i]);
138 strbuf += strlen( argv[i] ) + 1;
147 const char **envp = *EnvP;
148 for( i = 0; envp[i]; i ++ )
151 strcpy(strbuf, envp[i]);
152 strbuf += strlen( envp[i] ) + 1;
161 strcpy(strbuf, *Path);
170 * \brief Create a new process with the specified set of file descriptors
172 int Proc_SysSpawn(const char *Binary, const char **ArgV, const char **EnvP, int nFD, int *FDs)
179 // --- Save File, ArgV and EnvP
180 size = Binary_int_CacheArgs( &Binary, &ArgV, &EnvP, NULL );
181 cachebuf = alloca( size );
182 Binary_int_CacheArgs( &Binary, &ArgV, &EnvP, cachebuf );
184 // Cache the VFS handles
185 handles = VFS_SaveHandles(nFD, FDs);
187 // Create new process
188 ret = Proc_Clone(CLONE_VM|CLONE_NOUSER);
191 VFS_RestoreHandles(nFD, handles);
192 VFS_FreeSavedHandles(nFD, handles);
193 Proc_Execve(Binary, ArgV, EnvP, size);
198 VFS_FreeSavedHandles(nFD, handles);
205 * \brief Replace the current user image with another
206 * \param File File to load as the next image
207 * \param ArgV Arguments to pass to user
208 * \param EnvP User's environment
209 * \note Called Proc_ for historical reasons
211 int Proc_Execve(const char *File, const char **ArgV, const char **EnvP, int DataSize)
215 Uint base; // Uint because Proc_StartUser wants it
218 ENTER("sFile pArgV pEnvP", File, ArgV, EnvP);
220 // --- Save File, ArgV and EnvP
223 DataSize = Binary_int_CacheArgs( &File, &ArgV, &EnvP, NULL );
224 cachebuf = malloc( DataSize );
225 Binary_int_CacheArgs( &File, &ArgV, &EnvP, cachebuf );
229 for( argc = 0; ArgV && ArgV[argc]; argc ++ );
231 // --- Set Process Name
232 Threads_SetName(File);
234 // --- Clear User Address space
237 // --- Load new binary
238 base = Binary_Load(File, &entry);
241 Log_Warning("Binary", "Proc_Execve - Unable to load '%s'", File);
243 Threads_Exit(0, -10);
247 LOG("entry = 0x%x, base = 0x%x", entry, base);
249 // --- And... Jump to it
250 Proc_StartUser(entry, base, argc, ArgV, DataSize);
251 for(;;); // Tell GCC that we never return
255 * \brief Load a binary into the current address space
256 * \param Path Path to binary to load
257 * \param EntryPoint Pointer for exectuable entry point
258 * \return Virtual address where the binary has been loaded
260 tVAddr Binary_Load(const char *Path, tVAddr *EntryPoint)
267 ENTER("sPath pEntryPoint", Path, EntryPoint);
269 // Sanity Check Argument
275 // Check if this path has been loaded before.
277 // TODO: Implement a list of string/tBinary pairs for loaded bins
284 fd = VFS_Open(Path, VFS_OPENFLAG_READ|VFS_OPENFLAG_EXEC);
286 LOG("%s does not exist", Path);
289 VFS_FInfo(fd, &info, 0);
291 mount_id = info.mount;
293 LOG("mount_id = %i, inode = %i", mount_id, inode);
296 // TODO: Also get modifcation time?
298 // Check if the binary has already been loaded
299 if( !(pBinary = Binary_GetInfo(mount_id, inode)) )
300 pBinary = Binary_DoLoad(mount_id, inode, Path); // Else load it
303 if(pBinary == NULL) {
308 // Map into process space
309 base = Binary_MapIn(pBinary, Path, BIN_LOWEST, BIN_HIGHEST);
318 if(pBinary->Interpreter) {
320 if( Binary_Load(pBinary->Interpreter, &start) == 0 ) {
327 *EntryPoint = pBinary->Entry - pBinary->Base + base;
330 LOG("*EntryPoint = 0x%x", *EntryPoint);
332 return base; // Pass the base as an argument to the user if there is an interpreter
336 * \brief Finds a matching binary entry
337 * \param MountID Mountpoint ID of binary file
338 * \param InodeID Inode ID of the file
339 * \return Pointer to the binary definition (if already loaded)
341 tBinary *Binary_GetInfo(tMount MountID, tInode InodeID)
344 for(pBinary = glLoadedBinaries; pBinary; pBinary = pBinary->Next)
346 if(pBinary->MountID == MountID && pBinary->Inode == InodeID)
353 * \brief Maps an already-loaded binary into an address space.
354 * \param Binary Pointer to globally stored binary definition
355 * \param Path Path to the binary's file (for debug)
356 * \param LoadMin Lowest location to map to
357 * \param LoadMax Highest location to map to
358 * \return Base load address
360 tVAddr Binary_MapIn(tBinary *Binary, const char *Path, tVAddr LoadMin, tVAddr LoadMax)
365 ENTER("pBinary sPath pLoadMin pLoadMax", Binary, Path, LoadMin, LoadMax);
367 // Reference Executable (Makes sure that it isn't unloaded)
368 Binary->ReferenceCount ++;
373 // Check if base is free
376 LOG("Checking base %p", base);
377 for( i = 0; i < Binary->NumSections; i ++ )
379 if( Binary_int_CheckMemFree( Binary->LoadSections[i].Virtual, Binary->LoadSections[i].MemSize ) )
382 LOG("Address 0x%x is taken\n", Binary->LoadSections[i].Virtual);
388 // Check if the executable has no base or it is not free
391 // If so, give it a base
393 while(base >= LoadMin)
395 for( i = 0; i < Binary->NumSections; i ++ )
397 tVAddr addr = Binary->LoadSections[i].Virtual - Binary->Base + base;
398 if( Binary_int_CheckMemFree( addr, Binary->LoadSections[i].MemSize ) )
401 // If space was found, break
402 if(i == Binary->NumSections) break;
403 // Else decrement pointer and try again
404 base -= BIN_GRANUALITY;
406 LOG("Allocated base %p", base);
411 Log_Warning("Binary", "Executable '%s' cannot be loaded, no space", Path);
417 fd = VFS_OpenInode(Binary->MountID, Binary->Inode, VFS_OPENFLAG_READ);
418 for( i = 0; i < Binary->NumSections; i ++ )
420 tBinarySection *sect = &Binary->LoadSections[i];
421 Uint protflags, mapflags;
422 tVAddr addr = sect->Virtual - Binary->Base + base;
423 LOG("%i - %p to offset 0x%llx (%x)", i, addr, sect->Offset, sect->Flags);
425 protflags = MMAP_PROT_READ;
426 mapflags = MMAP_MAP_FIXED;
428 if( sect->Flags & BIN_SECTFLAG_EXEC )
429 protflags |= MMAP_PROT_EXEC;
430 // Read only pages are COW
431 if( sect->Flags & BIN_SECTFLAG_RO ) {
432 VFS_MMap( (void*)addr, sect->FileSize, protflags, MMAP_MAP_SHARED|mapflags, fd, sect->Offset );
435 protflags |= MMAP_PROT_WRITE;
436 VFS_MMap( (void*)addr, sect->FileSize, protflags, MMAP_MAP_PRIVATE|mapflags, fd, sect->Offset );
439 // Apply anonymous memory for BSS
440 if( sect->FileSize < sect->MemSize ) {
441 mapflags |= MMAP_MAP_ANONYMOUS;
443 (void*)(addr + sect->FileSize), sect->MemSize - sect->FileSize,
444 protflags, MMAP_MAP_PRIVATE|mapflags,
450 Log_Debug("Binary", "PID %i - Mapped '%s' to %p", Threads_GetPID(), Path, base);
459 * \fn Uint Binary_IsMapped(tBinary *binary)
460 * \brief Check if a binary is already mapped into the address space
461 * \param binary Binary information to check
462 * \return Current Base or 0
464 Uint Binary_IsMapped(tBinary *binary)
468 // Check prefered base
469 iBase = binary->Base;
470 if(MM_GetPage( iBase ) == (binary->Pages[0].Physical & ~0xFFF))
473 for(iBase = BIN_HIGHEST;
475 iBase -= BIN_GRANUALITY)
477 if(MM_GetPage( iBase ) == (binary->Pages[0].Physical & ~0xFFF))
486 * \fn tBinary *Binary_DoLoad(char *truePath)
487 * \brief Loads a binary file into memory
488 * \param truePath Absolute filename of binary
490 tBinary *Binary_DoLoad(tMount MountID, tInode Inode, const char *Path)
495 tBinaryType *bt = gRegBinTypes;
497 ENTER("iMountID XInode sPath", MountID, Inode, Path);
500 fp = VFS_OpenInode(MountID, Inode, VFS_OPENFLAG_READ);
502 LOG("Unable to load file, access denied");
507 LOG("fp = 0x%x", fp);
510 VFS_Read(fp, 4, &ident);
511 VFS_Seek(fp, 0, SEEK_SET);
513 LOG("ident = 0x%x", ident);
515 // Determine the type
516 for(; bt; bt = bt->Next)
518 if( (ident & bt->Mask) != (Uint32)bt->Ident )
520 LOG("bt = %p (%s)", bt, bt->Name);
521 pBinary = bt->Load(fp);
530 Log_Warning("Binary", "'%s' is an unknown file type. (%02x %02x %02x %02x)",
531 Path, ident&0xFF, (ident>>8)&0xFF, (ident>>16)&0xFF, (ident>>24)&0xFF);
536 LOG("pBinary = %p", pBinary);
539 if(pBinary == NULL) {
544 // Initialise Structure
545 pBinary->ReferenceCount = 0;
546 pBinary->MountID = MountID;
547 pBinary->Inode = Inode;
550 LOG("Interpreter: '%s'", pBinary->Interpreter);
551 LOG("Base: 0x%x, Entry: 0x%x", pBinary->Base, pBinary->Entry);
552 LOG("NumSections: %i", pBinary->NumSections);
555 SHORTLOCK(&glBinListLock);
556 pBinary->Next = glLoadedBinaries;
557 glLoadedBinaries = pBinary;
558 SHORTREL(&glBinListLock);
560 // TODO: Register the path with the binary
568 * \fn void Binary_Unload(void *Base)
569 * \brief Unload / Unmap a binary
570 * \param Base Loaded Base
571 * \note Currently used only for kernel libaries
573 void Binary_Unload(void *Base)
576 tKernelBin *prev = NULL;
579 if((Uint)Base < 0xC0000000)
581 // TODO: User Binaries
582 Log_Warning("BIN", "Unloading user binaries is currently unimplemented");
587 for(pKBin = glLoadedKernelLibs;
589 prev = pKBin, pKBin = pKBin->Next)
592 if(pKBin->Base != Base) continue;
594 for(i = 0; i < pKBin->Info->NumSections; i++)
596 // TODO: VFS_MUnmap();
598 // Dereference Binary
599 Binary_Dereference( pKBin->Info );
601 if(prev) prev->Next = pKBin->Next;
602 else glLoadedKernelLibs = pKBin->Next;
610 * \fn void Binary_Dereference(tBinary *Info)
611 * \brief Dereferences and if nessasary, deletes a binary
612 * \param Info Binary information structure
614 void Binary_Dereference(tBinary *Info)
616 // Decrement reference count
617 Info->ReferenceCount --;
619 // Check if it is still in use
620 if(Info->ReferenceCount) return;
622 /// \todo Implement binary freeing
626 * \fn char *Binary_RegInterp(char *Path)
627 * \brief Registers an Interpreter
628 * \param Path Path to interpreter provided by executable
630 char *Binary_RegInterp(char *Path)
633 // NULL Check Argument
634 if(Path == NULL) return NULL;
635 // NULL Check the array
636 if(gsaRegInterps == NULL)
639 gsaRegInterps = malloc( sizeof(char*) );
640 gsaRegInterps[0] = malloc( strlen(Path) );
641 strcpy(gsaRegInterps[0], Path);
642 return gsaRegInterps[0];
646 for( i = 0; i < giRegInterps; i++ )
648 if(strcmp(gsaRegInterps[i], Path) == 0)
649 return gsaRegInterps[i];
652 // Interpreter is not in list
654 gsaRegInterps = malloc( sizeof(char*)*giRegInterps );
655 gsaRegInterps[i] = malloc( strlen(Path) );
656 strcpy(gsaRegInterps[i], Path);
657 return gsaRegInterps[i];
661 // Kernel Binary Handling
664 * \fn void *Binary_LoadKernel(const char *File)
665 * \brief Load a binary into kernel space
666 * \note This function shares much with #Binary_Load, but does it's own mapping
667 * \param File File to load into the kernel
669 void *Binary_LoadKernel(const char *File)
672 tKernelBin *pKBinary;
677 ENTER("sFile", File);
679 // Sanity Check Argument
686 int fd = VFS_Open(File, VFS_OPENFLAG_READ);
692 VFS_FInfo(fd, &info, 0);
693 mount_id = info.mount;
698 // Check if the binary has already been loaded
699 if( (pBinary = Binary_GetInfo(mount_id, inode)) )
701 for(pKBinary = glLoadedKernelLibs;
703 pKBinary = pKBinary->Next )
705 if(pKBinary->Info == pBinary) {
706 LEAVE('p', pKBinary->Base);
707 return pKBinary->Base;
712 pBinary = Binary_DoLoad(mount_id, inode, File); // Else load it
715 if(pBinary == NULL) {
721 // Now pBinary is valid (either freshly loaded or only user mapped)
722 // So, map it into kernel space
725 // Reference Executable (Makes sure that it isn't unloaded)
726 pBinary->ReferenceCount ++;
728 Binary_MapIn(pBinary, File, KLIB_LOWEST, KLIB_HIGHEST);
731 if( !Binary_Relocate( (void*)base ) )
733 Log_Warning("Binary", "Relocation of '%s' failed, unloading", File);
734 Binary_Unload( (void*)base );
735 Binary_Dereference( pBinary );
740 // Add to list (relocator must look at itself manually, not via Binary_GetSymbol)
741 pKBinary = malloc(sizeof(*pKBinary));
742 pKBinary->Base = (void*)base;
743 pKBinary->Info = pBinary;
744 SHORTLOCK( &glKBinListLock );
745 pKBinary->Next = glLoadedKernelLibs;
746 glLoadedKernelLibs = pKBinary;
747 SHORTREL( &glKBinListLock );
754 * \fn Uint Binary_Relocate(void *Base)
755 * \brief Relocates a loaded binary (used by kernel libraries)
756 * \param Base Loaded base address of binary
757 * \return Boolean Success
759 Uint Binary_Relocate(void *Base)
761 Uint32 ident = *(Uint32*) Base;
762 tBinaryType *bt = gRegBinTypes;
764 for(; bt; bt = bt->Next)
766 if( (ident & bt->Mask) == (Uint)bt->Ident )
767 return bt->Relocate( (void*)Base);
770 Log_Warning("BIN", "%p is an unknown file type. (%02x %02x %02x %02x)",
771 Base, ident&0xFF, (ident>>8)&0xFF, (ident>>16)&0xFF, (ident>>24)&0xFF);
776 * \fn int Binary_GetSymbol(char *Name, Uint *Val)
777 * \brief Get a symbol value
778 * \return Value of symbol or -1 on error
780 * Gets the value of a symbol from either the currently loaded
781 * libraries or the kernel's exports.
783 int Binary_GetSymbol(const char *Name, Uint *Val)
785 if( Binary_GetSymbolEx(Name, Val) ) return 1;
790 * \fn Uint Binary_GetSymbolEx(char *Name, Uint *Value)
791 * \brief Get a symbol value
793 * Gets the value of a symbol from either the currently loaded
794 * libraries or the kernel's exports.
796 Uint Binary_GetSymbolEx(const char *Name, Uint *Value)
800 int numKSyms = ((Uint)&gKernelSymbolsEnd-(Uint)&gKernelSymbols)/sizeof(tKernelSymbol);
803 for( i = 0; i < numKSyms; i++ )
805 if(strcmp(Name, gKernelSymbols[i].Name) == 0) {
806 *Value = gKernelSymbols[i].Value;
811 // Scan Loaded Libraries
812 for(pKBin = glLoadedKernelLibs;
814 pKBin = pKBin->Next )
816 if( Binary_FindSymbol(pKBin->Base, Name, Value) ) {
821 Log_Warning("BIN", "Unable to find symbol '%s'", Name);
826 * \fn Uint Binary_FindSymbol(void *Base, char *Name, Uint *Val)
827 * \brief Get a symbol from the specified library
828 * \param Base Base address
829 * \param Name Name of symbol to find
830 * \param Val Pointer to place final value
832 Uint Binary_FindSymbol(void *Base, const char *Name, Uint *Val)
834 Uint32 ident = *(Uint32*) Base;
835 tBinaryType *bt = gRegBinTypes;
837 for(; bt; bt = bt->Next)
839 if( (ident & bt->Mask) == (Uint)bt->Ident )
840 return bt->GetSymbol(Base, Name, Val);
843 Log_Warning("BIN", "Binary_FindSymbol - %p is an unknown file type. (%02x %02x %02x %02x)",
844 Base, ident&0xFF, ident>>8, ident>>16, ident>>24);
849 * \brief Check if a range of memory is fully free
850 * \return Inverse boolean free (0 if all pages are unmapped)
852 int Binary_int_CheckMemFree( tVAddr _start, size_t _len )
854 _len += _start & (PAGE_SIZE-1);
855 _len = (_len + PAGE_SIZE - 1) & ~(PAGE_SIZE-1);
856 _start &= ~(PAGE_SIZE-1);
857 for( ; _len > PAGE_SIZE; _len -= PAGE_SIZE, _start += PAGE_SIZE ) {
858 if( MM_GetPhysAddr(_start) != 0 )
861 if( _len == PAGE_SIZE && MM_GetPhysAddr(_start) != 0 )
868 EXPORT(Binary_FindSymbol);
869 EXPORT(Binary_Unload);