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 size_t Binary_int_CacheArgs(const char **Path, const char ***ArgV, const char ***EnvP, void *DestBuffer);
35 int Proc_int_Execve(const char *File, const char **ArgV, const char **EnvP, int DataSize, bool bClearUser);
36 tVAddr Binary_Load(const char *Path, tVAddr *EntryPoint);
37 tBinary *Binary_GetInfo(tMount MountID, tInode InodeID);
38 tVAddr Binary_MapIn(tBinary *Binary, const char *Path, tVAddr LoadMin, tVAddr LoadMax);
39 tVAddr Binary_IsMapped(tBinary *Binary);
40 tBinary *Binary_DoLoad(tMount MountID, tInode Inode, const char *Path);
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);
49 int Binary_int_CheckMemFree( tVAddr _start, size_t _len );
52 tShortSpinlock glBinListLock;
53 tBinary *glLoadedBinaries = NULL;
54 char **gsaRegInterps = NULL;
56 tShortSpinlock glKBinListLock;
57 tKernelBin *glLoadedKernelLibs;
58 tBinaryType *gRegBinTypes = &gELF_Info;
62 * \brief Registers a binary type
64 int Binary_RegisterType(tBinaryType *Type)
66 Type->Next = gRegBinTypes;
72 * \fn int Proc_Spawn(const char *Path)
74 int Proc_Spawn(const char *Path)
76 char stackPath[strlen(Path)+1];
79 strcpy(stackPath, Path);
81 LOG("stackPath = '%s'", stackPath);
83 if(Proc_Clone(CLONE_VM|CLONE_NOUSER) == 0)
86 const char *args[2] = {stackPath, NULL};
87 LOG("stackPath = '%s'", stackPath);
88 Proc_Execve(stackPath, args, &args[1], 0);
98 size_t Binary_int_CacheArgs(const char **Path, const char ***ArgV, const char ***EnvP, void *DestBuffer)
110 const char **argv = *ArgV;
111 for( argc = 0; argv[argc]; argc ++ )
112 size += strlen( argv[argc] ) + 1;
116 const char **envp = *EnvP;
117 for( envc = 0; envp[envc]; envc ++ )
118 size += strlen( envp[envc] ) + 1;
120 size = (size + sizeof(void*)-1) & ~(sizeof(void*)-1); // Word align
121 size += (argc+1+envc+1)*sizeof(void*); // Arrays
124 size += strlen( *Path ) + 1;
130 strbuf = (void*)&arrays[argc+1+envc+1];
135 const char **argv = *ArgV;
136 for( i = 0; argv[i]; i ++ )
139 strcpy(strbuf, argv[i]);
140 strbuf += strlen( argv[i] ) + 1;
149 const char **envp = *EnvP;
150 for( i = 0; envp[i]; i ++ )
153 strcpy(strbuf, envp[i]);
154 strbuf += strlen( envp[i] ) + 1;
163 strcpy(strbuf, *Path);
172 * \brief Create a new process with the specified set of file descriptors
174 int Proc_SysSpawn(const char *Binary, const char **ArgV, const char **EnvP, int nFD, int *FDs)
177 // --- Save File, ArgV and EnvP
178 size_t size = Binary_int_CacheArgs( &Binary, &ArgV, &EnvP, NULL );
179 void *cachebuf = malloc( size );
180 Binary_int_CacheArgs( &Binary, &ArgV, &EnvP, cachebuf );
182 // Cache the VFS handles
183 void *handles = VFS_SaveHandles(nFD, FDs);
185 // Create new process
186 tPID ret = Proc_Clone(CLONE_VM|CLONE_NOUSER);
189 VFS_RestoreHandles(nFD, handles);
190 VFS_FreeSavedHandles(nFD, handles);
192 Proc_int_Execve(Binary, ArgV, EnvP, size, 0);
197 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)
213 return Proc_int_Execve(File, ArgV, EnvP, DataSize, 1);
216 int Proc_int_Execve(const char *File, const char **ArgV, const char **EnvP, int DataSize, bool bClearUser)
220 Uint base; // Uint because Proc_StartUser wants it
223 ENTER("sFile pArgV pEnvP", File, ArgV, EnvP);
225 // --- Save File, ArgV and EnvP
228 DataSize = Binary_int_CacheArgs( &File, &ArgV, &EnvP, NULL );
229 cachebuf = malloc( DataSize );
230 Binary_int_CacheArgs( &File, &ArgV, &EnvP, cachebuf );
234 for( argc = 0; ArgV && ArgV[argc]; argc ++ )
237 // --- Set Process Name
238 Threads_SetName(File);
240 // --- Clear User Address space
243 // MM_ClearUser should preserve handles
245 // - NOTE: Not a reliable test, but helps for now
246 ASSERTC( VFS_IOCtl(0, 0, NULL), !=, -1 );
249 // --- Load new binary
250 base = Binary_Load(File, &entry);
253 Log_Warning("Binary", "Proc_Execve - Unable to load '%s' [errno=%i]", File, errno);
255 Threads_Exit(0, -10);
259 LOG("entry = 0x%x, base = 0x%x", entry, base);
261 // --- And... Jump to it
262 Proc_StartUser(entry, base, argc, ArgV, DataSize);
263 for(;;); // Tell GCC that we never return
267 * \brief Load a binary into the current address space
268 * \param Path Path to binary to load
269 * \param EntryPoint Pointer for exectuable entry point
270 * \return Virtual address where the binary has been loaded
272 tVAddr Binary_Load(const char *Path, tVAddr *EntryPoint)
279 ENTER("sPath pEntryPoint", Path, EntryPoint);
281 // Sanity Check Argument
287 // Check if this path has been loaded before.
289 // TODO: Implement a list of string/tBinary pairs for loaded bins
296 fd = VFS_Open(Path, VFS_OPENFLAG_READ|VFS_OPENFLAG_EXEC);
298 LOG("%s does not exist", Path);
301 VFS_FInfo(fd, &info, 0);
303 mount_id = info.mount;
305 LOG("mount_id = %i, inode = %i", mount_id, inode);
308 // TODO: Also get modifcation time?
310 // Check if the binary has already been loaded
311 if( !(pBinary = Binary_GetInfo(mount_id, inode)) )
312 pBinary = Binary_DoLoad(mount_id, inode, Path); // Else load it
315 if(pBinary == NULL) {
320 // Map into process space
321 base = Binary_MapIn(pBinary, Path, BIN_LOWEST, BIN_HIGHEST);
330 if(pBinary->Interpreter) {
332 if( Binary_Load(pBinary->Interpreter, &start) == 0 ) {
333 Log_Error("Binary", "Can't load interpeter '%s' for '%s'",
334 pBinary->Interpreter, Path);
341 *EntryPoint = pBinary->Entry - pBinary->Base + base;
344 LOG("*EntryPoint = 0x%x", *EntryPoint);
346 return base; // Pass the base as an argument to the user if there is an interpreter
350 * \brief Finds a matching binary entry
351 * \param MountID Mountpoint ID of binary file
352 * \param InodeID Inode ID of the file
353 * \return Pointer to the binary definition (if already loaded)
355 tBinary *Binary_GetInfo(tMount MountID, tInode InodeID)
358 for(pBinary = glLoadedBinaries; pBinary; pBinary = pBinary->Next)
360 if(pBinary->MountID == MountID && pBinary->Inode == InodeID)
367 * \brief Maps an already-loaded binary into an address space.
368 * \param Binary Pointer to globally stored binary definition
369 * \param Path Path to the binary's file (for debug)
370 * \param LoadMin Lowest location to map to
371 * \param LoadMax Highest location to map to
372 * \return Base load address
374 tVAddr Binary_MapIn(tBinary *Binary, const char *Path, tVAddr LoadMin, tVAddr LoadMax)
379 ENTER("pBinary sPath pLoadMin pLoadMax", Binary, Path, LoadMin, LoadMax);
381 // Reference Executable (Makes sure that it isn't unloaded)
382 Binary->ReferenceCount ++;
387 // Check if base is free
390 LOG("Checking base %p", base);
391 for( i = 0; i < Binary->NumSections; i ++ )
393 if( Binary_int_CheckMemFree( Binary->LoadSections[i].Virtual, Binary->LoadSections[i].MemSize ) )
396 LOG("Address 0x%x is taken\n", Binary->LoadSections[i].Virtual);
402 // Check if the executable has no base or it is not free
405 // If so, give it a base
407 while(base >= LoadMin)
409 for( i = 0; i < Binary->NumSections; i ++ )
411 tVAddr addr = Binary->LoadSections[i].Virtual - Binary->Base + base;
412 size_t size = Binary->LoadSections[i].MemSize;
413 if( addr + size > LoadMax )
415 if( Binary_int_CheckMemFree( addr, size ) )
418 // If space was found, break
419 if(i == Binary->NumSections) break;
420 // Else decrement pointer and try again
421 base -= BIN_GRANUALITY;
423 LOG("Allocated base %p", base);
428 Log_Warning("Binary", "Executable '%s' cannot be loaded, no space", Path);
434 if( Binary->MountID )
435 fd = VFS_OpenInode(Binary->MountID, Binary->Inode, VFS_OPENFLAG_READ);
437 fd = VFS_Open(Path, VFS_OPENFLAG_READ);
438 for( i = 0; i < Binary->NumSections; i ++ )
440 tBinarySection *sect = &Binary->LoadSections[i];
441 Uint protflags, mapflags;
442 tVAddr addr = sect->Virtual - Binary->Base + base;
443 LOG("%i - %p, 0x%x bytes from offset 0x%llx (%x)", i, addr, sect->FileSize, sect->Offset, sect->Flags);
445 protflags = MMAP_PROT_READ;
446 mapflags = MMAP_MAP_FIXED;
448 if( sect->Flags & BIN_SECTFLAG_EXEC )
449 protflags |= MMAP_PROT_EXEC;
450 // Read only pages are COW
451 if( sect->Flags & BIN_SECTFLAG_RO ) {
452 VFS_MMap( (void*)addr, sect->FileSize, protflags, MMAP_MAP_SHARED|mapflags, fd, sect->Offset );
455 protflags |= MMAP_PROT_WRITE;
456 VFS_MMap( (void*)addr, sect->FileSize, protflags, MMAP_MAP_PRIVATE|mapflags, fd, sect->Offset );
459 // Apply anonymous memory for BSS
460 if( sect->FileSize < sect->MemSize ) {
461 mapflags |= MMAP_MAP_ANONYMOUS;
463 (void*)(addr + sect->FileSize), sect->MemSize - sect->FileSize,
464 protflags, MMAP_MAP_PRIVATE|mapflags,
470 Log_Debug("Binary", "PID %i - Mapped '%s' to %p", Threads_GetPID(), Path, base);
479 * \fn Uint Binary_IsMapped(tBinary *binary)
480 * \brief Check if a binary is already mapped into the address space
481 * \param binary Binary information to check
482 * \return Current Base or 0
484 Uint Binary_IsMapped(tBinary *binary)
488 // Check prefered base
489 iBase = binary->Base;
490 if(MM_GetPage( iBase ) == (binary->Pages[0].Physical & ~0xFFF))
493 for(iBase = BIN_HIGHEST;
495 iBase -= BIN_GRANUALITY)
497 if(MM_GetPage( iBase ) == (binary->Pages[0].Physical & ~0xFFF))
506 * \fn tBinary *Binary_DoLoad(char *truePath)
507 * \brief Loads a binary file into memory
508 * \param truePath Absolute filename of binary
510 tBinary *Binary_DoLoad(tMount MountID, tInode Inode, const char *Path)
515 tBinaryType *bt = gRegBinTypes;
517 ENTER("iMountID XInode sPath", MountID, Inode, Path);
522 fp = VFS_OpenInode(MountID, Inode, VFS_OPENFLAG_READ);
526 fp = VFS_Open(Path, VFS_OPENFLAG_READ);
529 LOG("Unable to load file, access denied");
534 LOG("fp = 0x%x", fp);
537 VFS_Read(fp, 4, &ident);
538 VFS_Seek(fp, 0, SEEK_SET);
540 LOG("ident = 0x%x", ident);
542 // Determine the type
543 for(; bt; bt = bt->Next)
545 if( (ident & bt->Mask) != (Uint32)bt->Ident )
547 LOG("bt = %p (%s)", bt, bt->Name);
548 pBinary = bt->Load(fp);
557 Log_Warning("Binary", "'%s' is an unknown file type. (%02x %02x %02x %02x)",
558 Path, ident&0xFF, (ident>>8)&0xFF, (ident>>16)&0xFF, (ident>>24)&0xFF);
563 LOG("pBinary = %p", pBinary);
566 if(pBinary == NULL) {
571 // Initialise Structure
572 pBinary->ReferenceCount = 0;
573 pBinary->MountID = MountID;
574 pBinary->Inode = Inode;
577 LOG("Interpreter: '%s'", pBinary->Interpreter);
578 LOG("Base: 0x%x, Entry: 0x%x", pBinary->Base, pBinary->Entry);
579 LOG("NumSections: %i", pBinary->NumSections);
582 SHORTLOCK(&glBinListLock);
583 pBinary->Next = glLoadedBinaries;
584 glLoadedBinaries = pBinary;
585 SHORTREL(&glBinListLock);
587 // TODO: Register the path with the binary
595 * \fn void Binary_Unload(void *Base)
596 * \brief Unload / Unmap a binary
597 * \param Base Loaded Base
598 * \note Currently used only for kernel libaries
600 void Binary_Unload(void *Base)
603 tKernelBin *prev = NULL;
606 if((Uint)Base < 0xC0000000)
608 // TODO: User Binaries
609 Log_Warning("BIN", "Unloading user binaries is currently unimplemented");
614 for(pKBin = glLoadedKernelLibs;
616 prev = pKBin, pKBin = pKBin->Next)
619 if(pKBin->Base != Base) continue;
621 for(i = 0; i < pKBin->Info->NumSections; i++)
623 // TODO: VFS_MUnmap();
625 // Dereference Binary
626 Binary_Dereference( pKBin->Info );
628 if(prev) prev->Next = pKBin->Next;
629 else glLoadedKernelLibs = pKBin->Next;
637 * \fn void Binary_Dereference(tBinary *Info)
638 * \brief Dereferences and if nessasary, deletes a binary
639 * \param Info Binary information structure
641 void Binary_Dereference(tBinary *Info)
643 // Decrement reference count
644 Info->ReferenceCount --;
646 // Check if it is still in use
647 if(Info->ReferenceCount) return;
649 /// \todo Implement binary freeing
653 * \fn char *Binary_RegInterp(char *Path)
654 * \brief Registers an Interpreter
655 * \param Path Path to interpreter provided by executable
657 char *Binary_RegInterp(char *Path)
660 // NULL Check Argument
661 if(Path == NULL) return NULL;
662 // NULL Check the array
663 if(gsaRegInterps == NULL)
666 gsaRegInterps = malloc( sizeof(char*) );
667 gsaRegInterps[0] = malloc( strlen(Path) );
668 strcpy(gsaRegInterps[0], Path);
669 return gsaRegInterps[0];
673 for( i = 0; i < giRegInterps; i++ )
675 if(strcmp(gsaRegInterps[i], Path) == 0)
676 return gsaRegInterps[i];
679 // Interpreter is not in list
681 gsaRegInterps = malloc( sizeof(char*)*giRegInterps );
682 gsaRegInterps[i] = malloc( strlen(Path) );
683 strcpy(gsaRegInterps[i], Path);
684 return gsaRegInterps[i];
688 // Kernel Binary Handling
691 * \fn void *Binary_LoadKernel(const char *File)
692 * \brief Load a binary into kernel space
693 * \note This function shares much with #Binary_Load, but does it's own mapping
694 * \param File File to load into the kernel
696 void *Binary_LoadKernel(const char *File)
699 tKernelBin *pKBinary;
704 ENTER("sFile", File);
706 // Sanity Check Argument
713 int fd = VFS_Open(File, VFS_OPENFLAG_READ);
716 LOG("Opening failed");
720 VFS_FInfo(fd, &info, 0);
721 mount_id = info.mount;
724 LOG("Mount %i, Inode %lli", mount_id, inode);
727 // Check if the binary has already been loaded
728 if( (pBinary = Binary_GetInfo(mount_id, inode)) )
730 for(pKBinary = glLoadedKernelLibs;
732 pKBinary = pKBinary->Next )
734 if(pKBinary->Info == pBinary) {
735 LOG("Already loaded");
736 LEAVE('p', pKBinary->Base);
737 return pKBinary->Base;
742 pBinary = Binary_DoLoad(mount_id, inode, File); // Else load it
745 if(pBinary == NULL) {
750 LOG("Loaded as %p", pBinary);
752 // Now pBinary is valid (either freshly loaded or only user mapped)
753 // So, map it into kernel space
756 // Reference Executable (Makes sure that it isn't unloaded)
757 pBinary->ReferenceCount ++;
759 base = Binary_MapIn(pBinary, File, KLIB_LOWEST, KLIB_HIGHEST);
766 // TODO: Could this cause race conditions if a binary isn't fully loaded when used
767 pKBinary = malloc(sizeof(*pKBinary));
768 pKBinary->Base = (void*)base;
769 pKBinary->Info = pBinary;
770 SHORTLOCK( &glKBinListLock );
771 pKBinary->Next = glLoadedKernelLibs;
772 glLoadedKernelLibs = pKBinary;
773 SHORTREL( &glKBinListLock );
780 * \fn Uint Binary_Relocate(void *Base)
781 * \brief Relocates a loaded binary (used by kernel libraries)
782 * \param Base Loaded base address of binary
783 * \return Boolean Success
785 Uint Binary_Relocate(void *Base)
787 Uint32 ident = *(Uint32*) Base;
788 tBinaryType *bt = gRegBinTypes;
790 for( ; bt; bt = bt->Next)
792 if( (ident & bt->Mask) == (Uint)bt->Ident )
793 return bt->Relocate( (void*)Base);
796 Log_Warning("BIN", "%p is an unknown file type. (%02x %02x %02x %02x)",
797 Base, ident&0xFF, (ident>>8)&0xFF, (ident>>16)&0xFF, (ident>>24)&0xFF);
802 * \fn int Binary_GetSymbol(char *Name, Uint *Val)
803 * \brief Get a symbol value
804 * \return Value of symbol or -1 on error
806 * Gets the value of a symbol from either the currently loaded
807 * libraries or the kernel's exports.
809 int Binary_GetSymbol(const char *Name, Uint *Val)
811 if( Binary_GetSymbolEx(Name, Val) ) return 1;
816 * \fn Uint Binary_GetSymbolEx(char *Name, Uint *Value)
817 * \brief Get a symbol value
819 * Gets the value of a symbol from either the currently loaded
820 * libraries or the kernel's exports.
822 Uint Binary_GetSymbolEx(const char *Name, Uint *Value)
825 int numKSyms = ((Uint)&gKernelSymbolsEnd-(Uint)&gKernelSymbols)/sizeof(tKernelSymbol);
828 for( int i = 0; i < numKSyms; i++ )
830 if(strcmp(Name, gKernelSymbols[i].Name) == 0) {
831 LOG("KSym %s = %p", gKernelSymbols[i].Name, gKernelSymbols[i].Value);
832 *Value = gKernelSymbols[i].Value;
838 // Scan Loaded Libraries
839 for(pKBin = glLoadedKernelLibs;
841 pKBin = pKBin->Next )
843 if( Binary_FindSymbol(pKBin->Base, Name, Value) ) {
848 Log_Warning("BIN", "Unable to find symbol '%s'", Name);
853 * \fn Uint Binary_FindSymbol(void *Base, char *Name, Uint *Val)
854 * \brief Get a symbol from the specified library
855 * \param Base Base address
856 * \param Name Name of symbol to find
857 * \param Val Pointer to place final value
859 Uint Binary_FindSymbol(void *Base, const char *Name, Uint *Val)
861 Uint32 ident = *(Uint32*) Base;
862 tBinaryType *bt = gRegBinTypes;
864 for(; bt; bt = bt->Next)
866 if( (ident & bt->Mask) == (Uint)bt->Ident )
867 return bt->GetSymbol(Base, Name, Val);
870 Log_Warning("BIN", "Binary_FindSymbol - %p is an unknown file type. (%02x %02x %02x %02x)",
871 Base, ident&0xFF, ident>>8, ident>>16, ident>>24);
876 * \brief Check if a range of memory is fully free
877 * \return Inverse boolean free (0 if all pages are unmapped)
879 int Binary_int_CheckMemFree( tVAddr _start, size_t _len )
881 ENTER("p_start x_len", _start, _len);
883 _len += _start & (PAGE_SIZE-1);
884 _len = (_len + PAGE_SIZE - 1) & ~(PAGE_SIZE-1);
885 _start &= ~(PAGE_SIZE-1);
886 LOG("_start = %p, _len = 0x%x", _start, _len);
887 for( ; _len > PAGE_SIZE; _len -= PAGE_SIZE, _start += PAGE_SIZE ) {
888 if( MM_GetPhysAddr( (void*)_start ) != 0 ) {
893 if( _len == PAGE_SIZE && MM_GetPhysAddr( (void*)_start ) != 0 ) {
903 EXPORT(Binary_FindSymbol);
904 EXPORT(Binary_Unload);