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 tVAddr Binary_Load(const char *Path, tVAddr *EntryPoint);
35 tBinary *Binary_GetInfo(tMount MountID, tInode InodeID);
36 tVAddr Binary_MapIn(tBinary *Binary, const char *Path, tVAddr LoadMin, tVAddr LoadMax);
37 tVAddr Binary_IsMapped(tBinary *Binary);
38 tBinary *Binary_DoLoad(tMount MountID, tInode Inode, const char *Path);
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);
47 int Binary_int_CheckMemFree( tVAddr _start, size_t _len );
50 tShortSpinlock glBinListLock;
51 tBinary *glLoadedBinaries = NULL;
52 char **gsaRegInterps = NULL;
54 tShortSpinlock glKBinListLock;
55 tKernelBin *glLoadedKernelLibs;
56 tBinaryType *gRegBinTypes = &gELF_Info;
60 * \brief Registers a binary type
62 int Binary_RegisterType(tBinaryType *Type)
64 Type->Next = gRegBinTypes;
70 * \fn int Proc_Spawn(const char *Path)
72 int Proc_Spawn(const char *Path)
74 char stackPath[strlen(Path)+1];
77 strcpy(stackPath, Path);
79 LOG("stackPath = '%s'", stackPath);
81 if(Proc_Clone(CLONE_VM) == 0)
84 const char *args[2] = {stackPath, NULL};
85 LOG("stackPath = '%s'", stackPath);
86 Proc_Execve(stackPath, args, &args[1]);
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;
108 Uint base; // Uint because Proc_StartUser wants it
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 LOG("argc = %i, envc = %i", envc);
121 argenvBytes = (argenvBytes + sizeof(void*)-1) & ~(sizeof(void*)-1);
122 argenvBytes += (argc+1)*sizeof(void*) + (envc+1)*sizeof(void*);
125 argenvBuf = malloc(argenvBytes);
126 if(argenvBuf == NULL) {
127 Log_Error("Binary", "Proc_Execve - What the hell? The kernel is out of heap space");
131 strBuf = (char*)argenvBuf + (argc+1)*sizeof(void*) + (envc+1)*sizeof(void*);
134 argvSaved = argenvBuf;
135 for( i = 0; i < argc; i++ )
137 argvSaved[i] = strBuf;
138 strcpy(argvSaved[i], ArgV[i]);
139 LOG("argv[%i] = '%s'", i, strBuf);
140 strBuf += strlen(ArgV[i])+1;
143 envpSaved = &argvSaved[i+1];
144 for( i = 0; i < envc; i++ )
146 envpSaved[i] = strBuf;
147 LOG("envp[%i] = '%s'", i, strBuf);
148 strcpy(envpSaved[i], EnvP[i]);
149 strBuf += strlen(EnvP[i])+1;
153 savedFile = malloc(strlen(File)+1);
154 strcpy(savedFile, File);
156 // --- Set Process Name
157 Threads_SetName(File);
159 // --- Clear User Address space
162 // --- Load new binary
163 base = Binary_Load(savedFile, &entry);
168 Log_Warning("Binary", "Proc_Execve - Unable to load '%s'", Threads_GetName(-1));
170 Threads_Exit(0, -10);
174 LOG("entry = 0x%x, base = 0x%x", entry, base);
176 // MM_DumpTables(0, KERNEL_BASE);
179 // --- And... Jump to it
180 Proc_StartUser(entry, base, argc, argvSaved, argenvBytes);
181 for(;;); // Tell GCC that we never return
185 * \brief Load a binary into the current address space
186 * \param Path Path to binary to load
187 * \param EntryPoint Pointer for exectuable entry point
188 * \return Virtual address where the binary has been loaded
190 tVAddr Binary_Load(const char *Path, tVAddr *EntryPoint)
197 ENTER("sPath pEntryPoint", Path, EntryPoint);
199 // Sanity Check Argument
205 // Check if this path has been loaded before.
207 // TODO: Implement a list of string/tBinary pairs for loaded bins
214 fd = VFS_Open(Path, VFS_OPENFLAG_READ|VFS_OPENFLAG_EXEC);
216 LOG("%s does not exist", Path);
219 VFS_FInfo(fd, &info, 0);
221 mount_id = info.mount;
223 LOG("mount_id = %i, inode = %i", mount_id, inode);
226 // TODO: Also get modifcation time?
228 // Check if the binary has already been loaded
229 if( !(pBinary = Binary_GetInfo(mount_id, inode)) )
230 pBinary = Binary_DoLoad(mount_id, inode, Path); // Else load it
233 if(pBinary == NULL) {
238 // Map into process space
239 base = Binary_MapIn(pBinary, Path, BIN_LOWEST, BIN_HIGHEST);
248 if(pBinary->Interpreter) {
250 if( Binary_Load(pBinary->Interpreter, &start) == 0 ) {
257 *EntryPoint = pBinary->Entry - pBinary->Base + base;
260 LOG("*EntryPoint = 0x%x", *EntryPoint);
262 return base; // Pass the base as an argument to the user if there is an interpreter
266 * \brief Finds a matching binary entry
267 * \param MountID Mountpoint ID of binary file
268 * \param InodeID Inode ID of the file
269 * \return Pointer to the binary definition (if already loaded)
271 tBinary *Binary_GetInfo(tMount MountID, tInode InodeID)
274 for(pBinary = glLoadedBinaries; pBinary; pBinary = pBinary->Next)
276 if(pBinary->MountID == MountID && pBinary->Inode == InodeID)
283 * \brief Maps an already-loaded binary into an address space.
284 * \param Binary Pointer to globally stored binary definition
285 * \param Path Path to the binary's file (for debug)
286 * \param LoadMin Lowest location to map to
287 * \param LoadMax Highest location to map to
288 * \return Base load address
290 tVAddr Binary_MapIn(tBinary *Binary, const char *Path, tVAddr LoadMin, tVAddr LoadMax)
295 ENTER("pBinary sPath pLoadMin pLoadMax", Binary, Path, LoadMin, LoadMax);
297 // Reference Executable (Makes sure that it isn't unloaded)
298 Binary->ReferenceCount ++;
303 // Check if base is free
306 LOG("Checking base %p", base);
307 for( i = 0; i < Binary->NumSections; i ++ )
309 if( Binary_int_CheckMemFree( Binary->LoadSections[i].Virtual, Binary->LoadSections[i].MemSize ) )
312 LOG("Address 0x%x is taken\n", Binary->LoadSections[i].Virtual);
318 // Check if the executable has no base or it is not free
321 // If so, give it a base
323 while(base >= LoadMin)
325 for( i = 0; i < Binary->NumSections; i ++ )
327 tVAddr addr = Binary->LoadSections[i].Virtual - Binary->Base + base;
328 if( Binary_int_CheckMemFree( addr, Binary->LoadSections[i].MemSize ) )
331 // If space was found, break
332 if(i == Binary->NumSections) break;
333 // Else decrement pointer and try again
334 base -= BIN_GRANUALITY;
336 LOG("Allocated base %p", base);
341 Log_Warning("Binary", "Executable '%s' cannot be loaded, no space", Path);
347 fd = VFS_OpenInode(Binary->MountID, Binary->Inode, VFS_OPENFLAG_READ);
348 for( i = 0; i < Binary->NumSections; i ++ )
350 tBinarySection *sect = &Binary->LoadSections[i];
351 Uint protflags, mapflags;
352 tVAddr addr = sect->Virtual - Binary->Base + base;
353 LOG("%i - %p to offset 0x%llx (%x)", i, addr, sect->Offset, sect->Flags);
355 protflags = MMAP_PROT_READ;
356 mapflags = MMAP_MAP_FIXED;
358 if( sect->Flags & BIN_SECTFLAG_EXEC )
359 protflags |= MMAP_PROT_EXEC;
360 // Read only pages are COW
361 if( sect->Flags & BIN_SECTFLAG_RO ) {
362 VFS_MMap( (void*)addr, sect->FileSize, protflags, MMAP_MAP_SHARED|mapflags, fd, sect->Offset );
365 protflags |= MMAP_PROT_WRITE;
366 VFS_MMap( (void*)addr, sect->FileSize, protflags, MMAP_MAP_PRIVATE|mapflags, fd, sect->Offset );
369 // Apply anonymous memory for BSS
370 if( sect->FileSize < sect->MemSize ) {
371 mapflags |= MMAP_MAP_ANONYMOUS;
373 (void*)(addr + sect->FileSize), sect->MemSize - sect->FileSize,
374 protflags, MMAP_MAP_PRIVATE|mapflags,
380 Log_Debug("Binary", "PID %i - Mapped '%s' to %p", Threads_GetPID(), Path, base);
389 * \fn Uint Binary_IsMapped(tBinary *binary)
390 * \brief Check if a binary is already mapped into the address space
391 * \param binary Binary information to check
392 * \return Current Base or 0
394 Uint Binary_IsMapped(tBinary *binary)
398 // Check prefered base
399 iBase = binary->Base;
400 if(MM_GetPage( iBase ) == (binary->Pages[0].Physical & ~0xFFF))
403 for(iBase = BIN_HIGHEST;
405 iBase -= BIN_GRANUALITY)
407 if(MM_GetPage( iBase ) == (binary->Pages[0].Physical & ~0xFFF))
416 * \fn tBinary *Binary_DoLoad(char *truePath)
417 * \brief Loads a binary file into memory
418 * \param truePath Absolute filename of binary
420 tBinary *Binary_DoLoad(tMount MountID, tInode Inode, const char *Path)
425 tBinaryType *bt = gRegBinTypes;
427 ENTER("iMountID XInode sPath", MountID, Inode, Path);
430 fp = VFS_OpenInode(MountID, Inode, VFS_OPENFLAG_READ);
432 LOG("Unable to load file, access denied");
437 LOG("fp = 0x%x", fp);
440 VFS_Read(fp, 4, &ident);
441 VFS_Seek(fp, 0, SEEK_SET);
443 LOG("ident = 0x%x", ident);
445 // Determine the type
446 for(; bt; bt = bt->Next)
448 if( (ident & bt->Mask) != (Uint32)bt->Ident )
450 LOG("bt = %p (%s)", bt, bt->Name);
451 pBinary = bt->Load(fp);
460 Log_Warning("Binary", "'%s' is an unknown file type. (%02x %02x %02x %02x)",
461 Path, ident&0xFF, (ident>>8)&0xFF, (ident>>16)&0xFF, (ident>>24)&0xFF);
466 LOG("pBinary = %p", pBinary);
469 if(pBinary == NULL) {
474 // Initialise Structure
475 pBinary->ReferenceCount = 0;
476 pBinary->MountID = MountID;
477 pBinary->Inode = Inode;
480 LOG("Interpreter: '%s'", pBinary->Interpreter);
481 LOG("Base: 0x%x, Entry: 0x%x", pBinary->Base, pBinary->Entry);
482 LOG("NumSections: %i", pBinary->NumSections);
485 SHORTLOCK(&glBinListLock);
486 pBinary->Next = glLoadedBinaries;
487 glLoadedBinaries = pBinary;
488 SHORTREL(&glBinListLock);
490 // TODO: Register the path with the binary
498 * \fn void Binary_Unload(void *Base)
499 * \brief Unload / Unmap a binary
500 * \param Base Loaded Base
501 * \note Currently used only for kernel libaries
503 void Binary_Unload(void *Base)
506 tKernelBin *prev = NULL;
509 if((Uint)Base < 0xC0000000)
511 // TODO: User Binaries
512 Log_Warning("BIN", "Unloading user binaries is currently unimplemented");
517 for(pKBin = glLoadedKernelLibs;
519 prev = pKBin, pKBin = pKBin->Next)
522 if(pKBin->Base != Base) continue;
524 for(i = 0; i < pKBin->Info->NumSections; i++)
526 // TODO: VFS_MUnmap();
528 // Dereference Binary
529 Binary_Dereference( pKBin->Info );
531 if(prev) prev->Next = pKBin->Next;
532 else glLoadedKernelLibs = pKBin->Next;
540 * \fn void Binary_Dereference(tBinary *Info)
541 * \brief Dereferences and if nessasary, deletes a binary
542 * \param Info Binary information structure
544 void Binary_Dereference(tBinary *Info)
546 // Decrement reference count
547 Info->ReferenceCount --;
549 // Check if it is still in use
550 if(Info->ReferenceCount) return;
552 /// \todo Implement binary freeing
556 * \fn char *Binary_RegInterp(char *Path)
557 * \brief Registers an Interpreter
558 * \param Path Path to interpreter provided by executable
560 char *Binary_RegInterp(char *Path)
563 // NULL Check Argument
564 if(Path == NULL) return NULL;
565 // NULL Check the array
566 if(gsaRegInterps == NULL)
569 gsaRegInterps = malloc( sizeof(char*) );
570 gsaRegInterps[0] = malloc( strlen(Path) );
571 strcpy(gsaRegInterps[0], Path);
572 return gsaRegInterps[0];
576 for( i = 0; i < giRegInterps; i++ )
578 if(strcmp(gsaRegInterps[i], Path) == 0)
579 return gsaRegInterps[i];
582 // Interpreter is not in list
584 gsaRegInterps = malloc( sizeof(char*)*giRegInterps );
585 gsaRegInterps[i] = malloc( strlen(Path) );
586 strcpy(gsaRegInterps[i], Path);
587 return gsaRegInterps[i];
591 // Kernel Binary Handling
594 * \fn void *Binary_LoadKernel(const char *File)
595 * \brief Load a binary into kernel space
596 * \note This function shares much with #Binary_Load, but does it's own mapping
597 * \param File File to load into the kernel
599 void *Binary_LoadKernel(const char *File)
602 tKernelBin *pKBinary;
607 ENTER("sFile", File);
609 // Sanity Check Argument
616 int fd = VFS_Open(File, VFS_OPENFLAG_READ);
622 VFS_FInfo(fd, &info, 0);
623 mount_id = info.mount;
628 // Check if the binary has already been loaded
629 if( (pBinary = Binary_GetInfo(mount_id, inode)) )
631 for(pKBinary = glLoadedKernelLibs;
633 pKBinary = pKBinary->Next )
635 if(pKBinary->Info == pBinary) {
636 LEAVE('p', pKBinary->Base);
637 return pKBinary->Base;
642 pBinary = Binary_DoLoad(mount_id, inode, File); // Else load it
645 if(pBinary == NULL) {
651 // Now pBinary is valid (either freshly loaded or only user mapped)
652 // So, map it into kernel space
655 // Reference Executable (Makes sure that it isn't unloaded)
656 pBinary->ReferenceCount ++;
658 Binary_MapIn(pBinary, File, KLIB_LOWEST, KLIB_HIGHEST);
661 if( !Binary_Relocate( (void*)base ) )
663 Log_Warning("Binary", "Relocation of '%s' failed, unloading", File);
664 Binary_Unload( (void*)base );
665 Binary_Dereference( pBinary );
670 // Add to list (relocator must look at itself manually, not via Binary_GetSymbol)
671 pKBinary = malloc(sizeof(*pKBinary));
672 pKBinary->Base = (void*)base;
673 pKBinary->Info = pBinary;
674 SHORTLOCK( &glKBinListLock );
675 pKBinary->Next = glLoadedKernelLibs;
676 glLoadedKernelLibs = pKBinary;
677 SHORTREL( &glKBinListLock );
684 * \fn Uint Binary_Relocate(void *Base)
685 * \brief Relocates a loaded binary (used by kernel libraries)
686 * \param Base Loaded base address of binary
687 * \return Boolean Success
689 Uint Binary_Relocate(void *Base)
691 Uint32 ident = *(Uint32*) Base;
692 tBinaryType *bt = gRegBinTypes;
694 for(; bt; bt = bt->Next)
696 if( (ident & bt->Mask) == (Uint)bt->Ident )
697 return bt->Relocate( (void*)Base);
700 Log_Warning("BIN", "%p is an unknown file type. (%02x %02x %02x %02x)",
701 Base, ident&0xFF, (ident>>8)&0xFF, (ident>>16)&0xFF, (ident>>24)&0xFF);
706 * \fn int Binary_GetSymbol(char *Name, Uint *Val)
707 * \brief Get a symbol value
708 * \return Value of symbol or -1 on error
710 * Gets the value of a symbol from either the currently loaded
711 * libraries or the kernel's exports.
713 int Binary_GetSymbol(const char *Name, Uint *Val)
715 if( Binary_GetSymbolEx(Name, Val) ) return 1;
720 * \fn Uint Binary_GetSymbolEx(char *Name, Uint *Value)
721 * \brief Get a symbol value
723 * Gets the value of a symbol from either the currently loaded
724 * libraries or the kernel's exports.
726 Uint Binary_GetSymbolEx(const char *Name, Uint *Value)
730 int numKSyms = ((Uint)&gKernelSymbolsEnd-(Uint)&gKernelSymbols)/sizeof(tKernelSymbol);
733 for( i = 0; i < numKSyms; i++ )
735 if(strcmp(Name, gKernelSymbols[i].Name) == 0) {
736 *Value = gKernelSymbols[i].Value;
741 // Scan Loaded Libraries
742 for(pKBin = glLoadedKernelLibs;
744 pKBin = pKBin->Next )
746 if( Binary_FindSymbol(pKBin->Base, Name, Value) ) {
751 Log_Warning("BIN", "Unable to find symbol '%s'", Name);
756 * \fn Uint Binary_FindSymbol(void *Base, char *Name, Uint *Val)
757 * \brief Get a symbol from the specified library
758 * \param Base Base address
759 * \param Name Name of symbol to find
760 * \param Val Pointer to place final value
762 Uint Binary_FindSymbol(void *Base, const char *Name, Uint *Val)
764 Uint32 ident = *(Uint32*) Base;
765 tBinaryType *bt = gRegBinTypes;
767 for(; bt; bt = bt->Next)
769 if( (ident & bt->Mask) == (Uint)bt->Ident )
770 return bt->GetSymbol(Base, Name, Val);
773 Log_Warning("BIN", "Binary_FindSymbol - %p is an unknown file type. (%02x %02x %02x %02x)",
774 Base, ident&0xFF, ident>>8, ident>>16, ident>>24);
779 * \brief Check if a range of memory is fully free
780 * \return Inverse boolean free (0 if all pages are unmapped)
782 int Binary_int_CheckMemFree( tVAddr _start, size_t _len )
784 _len += _start & (PAGE_SIZE-1);
785 _len = (_len + PAGE_SIZE - 1) & ~(PAGE_SIZE-1);
786 _start &= ~(PAGE_SIZE-1);
787 for( ; _len > PAGE_SIZE; _len -= PAGE_SIZE, _start += PAGE_SIZE ) {
788 if( MM_GetPhysAddr(_start) != 0 )
791 if( _len == PAGE_SIZE && MM_GetPhysAddr(_start) != 0 )
798 EXPORT(Binary_FindSymbol);
799 EXPORT(Binary_Unload);