11 #define BIN_LOWEST MM_USER_MIN // 1MiB
12 #define BIN_GRANUALITY 0x10000 // 64KiB
13 //! \todo Move 0xBC000000 to mm_virt.h
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 int Proc_Clone(Uint *Err, Uint Flags);
28 extern char *Threads_GetName(int ID);
29 extern void Threads_Exit(int, int);
30 extern Uint MM_ClearUser(void);
31 extern void Proc_StartUser(Uint Entrypoint, Uint *Bases, int ArgC, char **ArgV, char **EnvP, int DataSize);
32 extern tKernelSymbol gKernelSymbols[];
33 extern void gKernelSymbolsEnd;
34 extern tBinaryType gELF_Info;
37 int Proc_Execve(char *File, char **ArgV, char **EnvP);
38 Uint Binary_Load(char *file, Uint *entryPoint);
39 tBinary *Binary_GetInfo(char *truePath);
40 Uint Binary_MapIn(tBinary *binary);
41 Uint Binary_IsMapped(tBinary *binary);
42 tBinary *Binary_DoLoad(char *truePath);
43 void Binary_Dereference(tBinary *Info);
44 Uint Binary_Relocate(void *Base);
45 Uint Binary_GetSymbolEx(char *Name, Uint *Value);
46 Uint Binary_FindSymbol(void *Base, char *Name, Uint *Val);
49 int glBinListLock = 0;
50 tBinary *glLoadedBinaries = NULL;
51 char **gsaRegInterps = NULL;
53 int glKBinListLock = 0;
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(char *Path)
71 int Proc_Spawn(char *Path)
73 char stackPath[strlen(Path)+1];
75 strcpy(stackPath, Path);
77 LOG("stackPath = '%s'\n", stackPath);
79 if(Proc_Clone(NULL, CLONE_VM) == 0)
82 char *args[2] = {stackPath, NULL};
83 LOG("stackPath = '%s'\n", stackPath);
84 Proc_Execve(stackPath, args, &args[1]);
91 * \fn int Proc_Execve(char *File, char **ArgV, char **EnvP)
92 * \brief Replace the current user image with another
93 * \param File File to load as the next image
94 * \param ArgV Arguments to pass to user
95 * \param EnvP User's environment
96 * \note Called Proc_ for historical reasons
98 int Proc_Execve(char *File, char **ArgV, char **EnvP)
102 char *argenvBuf, *strBuf;
103 char **argvSaved, **envpSaved;
108 ENTER("sFile pArgV pEnvP", File, ArgV, EnvP);
110 // --- Save File, ArgV and EnvP (also get argc)
112 // Count Arguments, Environment Variables and total string sizes
114 for( argc = 0; ArgV && ArgV[argc]; argc++ )
115 argenvBytes += strlen(ArgV[argc])+1;
116 for( envc = 0; EnvP && EnvP[envc]; envc++ )
117 argenvBytes += strlen(EnvP[envc])+1;
118 argenvBytes = (argenvBytes + sizeof(void*)-1) & ~(sizeof(void*)-1);
119 argenvBytes += (argc+1)*sizeof(void*) + (envc+1)*sizeof(void*);
122 argenvBuf = malloc(argenvBytes);
123 if(argenvBuf == NULL) {
124 Warning("Proc_Execve - What the hell? The kernel is out of heap space");
127 strBuf = argenvBuf + (argc+1)*sizeof(void*) + (envc+1)*sizeof(void*);
130 argvSaved = (char **) argenvBuf;
131 for( i = 0; i < argc; i++ )
133 argvSaved[i] = strBuf;
134 strcpy(argvSaved[i], ArgV[i]);
135 strBuf += strlen(ArgV[i])+1;
138 envpSaved = &argvSaved[i+1];
139 for( i = 0; i < envc; i++ )
141 envpSaved[i] = strBuf;
142 strcpy(envpSaved[i], EnvP[i]);
143 strBuf += strlen(EnvP[i])+1;
147 savedFile = malloc(strlen(File)+1);
148 strcpy(savedFile, File);
150 // --- Set Process Name
151 Threads_SetName(File);
153 // --- Clear User Address space
156 // --- Load new binary
157 bases[0] = Binary_Load(savedFile, &entry);
161 Warning("Proc_Execve - Unable to load '%s'", Threads_GetName(-1));
166 LOG("entry = 0x%x, bases[0] = 0x%x", entry, bases[0]);
168 // --- And... Jump to it
169 Proc_StartUser(entry, bases, argc, argvSaved, envpSaved, argenvBytes);
170 for(;;); // Tell GCC that we never return
174 * \fn Uint Binary_Load(char *file, Uint *entryPoint)
176 Uint Binary_Load(char *file, Uint *entryPoint)
182 ENTER("sfile", file);
184 // Sanity Check Argument
190 // Get True File Path
191 sTruePath = VFS_GetTruePath(file);
193 if(sTruePath == NULL) {
194 Warning("[BIN ] '%s' does not exist.", file);
199 LOG("sTruePath = '%s'", sTruePath);
201 // Check if the binary has already been loaded
202 if( !(pBinary = Binary_GetInfo(sTruePath)) )
203 pBinary = Binary_DoLoad(sTruePath); // Else load it
209 if(pBinary == NULL) {
215 if( (base = Binary_IsMapped(pBinary)) ) {
221 // Map into process space
222 base = Binary_MapIn(pBinary); // If so then map it in
231 if(pBinary->Interpreter) {
233 if( Binary_Load(pBinary->Interpreter, &start) == 0 ) {
240 *entryPoint = pBinary->Entry - pBinary->Base + base;
243 LOG("*entryPoint = 0x%x", *entryPoint);
245 return base; // Pass the base as an argument to the user if there is an interpreter
249 * \brief Finds a matching binary entry
250 * \param TruePath File Identifier (True path name)
252 tBinary *Binary_GetInfo(char *TruePath)
255 pBinary = glLoadedBinaries;
258 if(strcmp(pBinary->TruePath, TruePath) == 0)
260 pBinary = pBinary->Next;
266 \fn Uint Binary_MapIn(tBinary *binary)
267 \brief Maps an already-loaded binary into an address space.
268 \param binary Pointer to globally stored data.
270 Uint Binary_MapIn(tBinary *binary)
276 // Reference Executable (Makes sure that it isn't unloaded)
277 binary->ReferenceCount ++;
282 // Check if base is free
285 for(i=0;i<binary->NumPages;i++)
287 if( MM_GetPhysAddr( binary->Pages[i].Virtual & ~0xFFF ) ) {
289 LOG("Address 0x%x is taken\n", binary->Pages[i].Virtual & ~0xFFF);
295 // Check if the executable has no base or it is not free
298 // If so, give it a base
300 while(base >= BIN_LOWEST)
302 for(i=0;i<binary->NumPages;i++)
304 addr = binary->Pages[i].Virtual & ~0xFFF;
305 addr -= binary->Base;
307 if( MM_GetPhysAddr( addr ) ) break;
309 // If space was found, break
310 if(i == binary->NumPages) break;
311 // Else decrement pointer and try again
312 base -= BIN_GRANUALITY;
317 if(base < BIN_LOWEST) {
318 Warning("[BIN ] Executable '%s' cannot be loaded, no space", binary->TruePath);
323 for(i=0;i<binary->NumPages;i++)
325 addr = binary->Pages[i].Virtual & ~0xFFF;
326 addr -= binary->Base;
328 LOG("%i - 0x%x to 0x%x", i, addr, binary->Pages[i].Physical);
329 MM_Map( addr, (Uint) (binary->Pages[i].Physical) );
332 if( binary->Pages[i].Flags & BIN_PAGEFLAG_RO)
333 MM_SetFlags( addr, MM_PFLAG_RO, -1 );
335 MM_SetFlags( addr, MM_PFLAG_COW, -1 );
338 if( binary->Pages[i].Flags & BIN_PAGEFLAG_EXEC )
339 MM_SetFlags( addr, MM_PFLAG_EXEC, -1 );
341 MM_SetFlags( addr, MM_PFLAG_EXEC, 0 );
345 //Log("Mapped '%s' to 0x%x", binary->TruePath, base);
347 //LOG("*0x%x = 0x%x\n", binary->Pages[0].Virtual, *(Uint*)binary->Pages[0].Virtual);
354 * \fn Uint Binary_IsMapped(tBinary *binary)
355 * \brief Check if a binary is already mapped into the address space
356 * \param binary Binary information to check
357 * \return Current Base or 0
359 Uint Binary_IsMapped(tBinary *binary)
363 // Check prefered base
364 iBase = binary->Base;
365 if(MM_GetPage( iBase ) == (binary->Pages[0].Physical & ~0xFFF))
368 for(iBase = BIN_HIGHEST;
370 iBase -= BIN_GRANUALITY)
372 if(MM_GetPage( iBase ) == (binary->Pages[0].Physical & ~0xFFF))
381 * \fn tBinary *Binary_DoLoad(char *truePath)
382 * \brief Loads a binary file into memory
383 * \param truePath Absolute filename of binary
385 tBinary *Binary_DoLoad(char *truePath)
390 tBinaryType *bt = gRegBinTypes;
392 ENTER("struePath", truePath);
395 fp = VFS_Open(truePath, VFS_OPENFLAG_READ);
397 LOG("Unable to load file, access denied");
403 VFS_Read(fp, 4, &ident);
404 VFS_Seek(fp, 0, SEEK_SET);
406 for(; bt; bt = bt->Next)
408 if( (ident & bt->Mask) != (Uint)bt->Ident )
410 pBinary = bt->Load(fp);
414 Warning("[BIN ] '%s' is an unknown file type. (0x%x 0x%x 0x%x 0x%x)",
415 truePath, ident&0xFF, (ident>>8)&0xFF, (ident>>16)&0xFF, (ident>>24)&0xFF);
421 if(pBinary == NULL) {
426 // Initialise Structure
427 pBinary->ReferenceCount = 0;
428 pBinary->TruePath = malloc( strlen(truePath) + 1 );
429 strcpy(pBinary->TruePath, truePath);
432 LOG("Interpreter: '%s'", pBinary->Interpreter);
433 LOG("Base: 0x%x, Entry: 0x%x", pBinary->Base, pBinary->Entry);
434 LOG("NumPages: %i", pBinary->NumPages);
437 for(i=0;i<pBinary->NumPages;i++)
441 paddr = (Uint)MM_AllocPhys();
443 Warning("Binary_DoLoad - Physical memory allocation failed");
445 MM_DerefPhys( pBinary->Pages[i].Physical );
449 MM_RefPhys( paddr ); // Make sure it is _NOT_ freed until we want it to be
450 dest = MM_MapTemp( paddr );
451 dest += pBinary->Pages[i].Virtual & 0xFFF;
452 LOG("dest = 0x%x, paddr = 0x%x", dest, paddr);
453 LOG("Pages[%i]={Physical:0x%llx,Virtual:%p,Size:0x%x}",
454 i, pBinary->Pages[i].Physical, pBinary->Pages[i].Virtual, pBinary->Pages[i].Size);
457 if(pBinary->Pages[i].Physical == -1) {
459 memset( (void*)dest, 0, 1024 - (pBinary->Pages[i].Virtual & 0xFFF) );
463 VFS_Seek( fp, pBinary->Pages[i].Physical, 1 );
464 if(pBinary->Pages[i].Size != 0x1000) {
465 LOG("%i - 0x%llx - 0x%x bytes",
466 i, pBinary->Pages[i].Physical, pBinary->Pages[i].Size);
467 memset( (void*)dest, 0, 0x1000 -(dest&0xFFF) );
468 VFS_Read( fp, pBinary->Pages[i].Size, (void*)dest );
470 LOG("%i - 0x%x", i, pBinary->Pages[i].Physical);
471 VFS_Read( fp, 0x1000, (void*)dest );
474 pBinary->Pages[i].Physical = paddr;
477 LOG("Page Count: %i", pBinary->NumPages);
483 LOCK(&glBinListLock);
484 pBinary->Next = glLoadedBinaries;
485 glLoadedBinaries = pBinary;
486 RELEASE(&glBinListLock);
494 * \fn void Binary_Unload(void *Base)
495 * \brief Unload / Unmap a binary
496 * \param Base Loaded Base
497 * \note Currently used only for kernel libaries
499 void Binary_Unload(void *Base)
502 tKernelBin *prev = NULL;
505 if((Uint)Base < 0xC0000000)
507 // TODO: User Binaries
508 Warning("[BIN ] Unloading user binaries is currently unimplemented");
513 for(pKBin = glLoadedKernelLibs;
515 prev = pKBin, pKBin = pKBin->Next)
518 if(pKBin->Base != Base) continue;
520 for(i = 0; i < pKBin->Info->NumPages; i++) {
521 MM_Deallocate( (Uint)Base + (i << 12) );
523 // Dereference Binary
524 Binary_Dereference( pKBin->Info );
526 if(prev) prev->Next = pKBin->Next;
527 else glLoadedKernelLibs = pKBin->Next;
535 * \fn void Binary_Dereference(tBinary *Info)
536 * \brief Dereferences and if nessasary, deletes a binary
537 * \param Info Binary information structure
539 void Binary_Dereference(tBinary *Info)
541 // Decrement reference count
542 Info->ReferenceCount --;
544 // Check if it is still in use
545 if(Info->ReferenceCount) return;
547 /// \todo Implement binary freeing
551 * \fn char *Binary_RegInterp(char *Path)
552 * \brief Registers an Interpreter
553 * \param Path Path to interpreter provided by executable
555 char *Binary_RegInterp(char *Path)
558 // NULL Check Argument
559 if(Path == NULL) return NULL;
560 // NULL Check the array
561 if(gsaRegInterps == NULL)
564 gsaRegInterps = malloc( sizeof(char*) );
565 gsaRegInterps[0] = malloc( strlen(Path) );
566 strcpy(gsaRegInterps[0], Path);
567 return gsaRegInterps[0];
571 for( i = 0; i < giRegInterps; i++ )
573 if(strcmp(gsaRegInterps[i], Path) == 0)
574 return gsaRegInterps[i];
577 // Interpreter is not in list
579 gsaRegInterps = malloc( sizeof(char*)*giRegInterps );
580 gsaRegInterps[i] = malloc( strlen(Path) );
581 strcpy(gsaRegInterps[i], Path);
582 return gsaRegInterps[i];
586 // Kernel Binary Handling
589 * \fn void *Binary_LoadKernel(char *File)
590 * \brief Load a binary into kernel space
591 * \note This function shares much with #Binary_Load, but does it's own mapping
592 * \param File File to load into the kernel
594 void *Binary_LoadKernel(char *File)
598 tKernelBin *pKBinary;
603 ENTER("sfile", File);
605 // Sanity Check Argument
611 // Get True File Path
612 sTruePath = VFS_GetTruePath(File);
613 if(sTruePath == NULL) {
618 // Check if the binary has already been loaded
619 if( (pBinary = Binary_GetInfo(sTruePath)) )
621 for(pKBinary = glLoadedKernelLibs;
623 pKBinary = pKBinary->Next )
625 if(pKBinary->Info == pBinary) {
626 LEAVE('p', pKBinary->Base);
627 return pKBinary->Base;
632 pBinary = Binary_DoLoad(sTruePath); // Else load it
635 if(pBinary == NULL) {
641 // Now pBinary is valid (either freshly loaded or only user mapped)
642 // So, map it into kernel space
645 // Reference Executable (Makes sure that it isn't unloaded)
646 pBinary->ReferenceCount ++;
648 // Check compiled base
649 base = pBinary->Base;
651 if(base < KLIB_LOWEST || base > KLIB_HIGHEST || base + (pBinary->NumPages<<12) > KLIB_HIGHEST) {
654 // - Check if it is a valid base address
657 for(i=0;i<pBinary->NumPages;i++)
659 if( MM_GetPhysAddr( pBinary->Pages[i].Virtual & ~0xFFF ) ) {
661 LOG("Address 0x%x is taken\n", pBinary->Pages[i].Virtual & ~0xFFF);
667 // Check if the executable has no base or it is not free
670 // If so, give it a base
672 while(base < KLIB_HIGHEST)
674 for(i = 0; i < pBinary->NumPages; i++)
676 addr = pBinary->Pages[i].Virtual & ~0xFFF;
677 addr -= pBinary->Base;
679 if( MM_GetPhysAddr( addr ) ) break;
681 // If space was found, break
682 if(i == pBinary->NumPages) break;
683 // Else decrement pointer and try again
684 base += KLIB_GRANUALITY;
689 if(base >= KLIB_HIGHEST) {
690 Warning("[BIN ] Executable '%s' cannot be loaded into kernel, no space", pBinary->TruePath);
691 Binary_Dereference( pBinary );
696 LOG("base = 0x%x", base);
699 LOG("pBinary = {NumPages:%i, Pages=%p}", pBinary->NumPages, pBinary->Pages);
700 for(i = 0; i < pBinary->NumPages; i++)
702 addr = pBinary->Pages[i].Virtual & ~0xFFF;
703 addr -= pBinary->Base;
705 LOG("%i - 0x%x to 0x%x", i, addr, pBinary->Pages[i].Physical);
706 MM_Map( addr, (Uint) (pBinary->Pages[i].Physical) );
707 MM_SetFlags( addr, MM_PFLAG_KERNEL, MM_PFLAG_KERNEL );
709 if( pBinary->Pages[i].Flags & BIN_PAGEFLAG_RO) // Read-Only?
710 MM_SetFlags( addr, MM_PFLAG_RO, MM_PFLAG_KERNEL );
714 if( !Binary_Relocate( (void*)base ) )
716 Warning("[BIN ] Relocation of '%s' failed, unloading", sTruePath);
717 Binary_Unload( (void*)base );
718 Binary_Dereference( pBinary );
723 // Add to list (relocator must look at itself manually, not via Binary_GetSymbol)
724 pKBinary = malloc(sizeof(*pKBinary));
725 pKBinary->Base = (void*)base;
726 pKBinary->Info = pBinary;
727 LOCK( &glKBinListLock );
728 pKBinary->Next = glLoadedKernelLibs;
729 glLoadedKernelLibs = pKBinary;
730 RELEASE( &glKBinListLock );
737 * \fn Uint Binary_Relocate(void *Base)
738 * \brief Relocates a loaded binary (used by kernel libraries)
739 * \param Base Loaded base address of binary
740 * \return Boolean Success
742 Uint Binary_Relocate(void *Base)
744 Uint32 ident = *(Uint32*) Base;
745 tBinaryType *bt = gRegBinTypes;
747 for(; bt; bt = bt->Next)
749 if( (ident & bt->Mask) == (Uint)bt->Ident )
750 return bt->Relocate( (void*)Base);
753 Warning("[BIN ] 0x%x is an unknown file type. (0x%x 0x%x 0x%x 0x%x)",
754 Base, ident&0xFF, (ident>>8)&0xFF, (ident>>16)&0xFF, (ident>>24)&0xFF);
759 * \fn int Binary_GetSymbol(char *Name, Uint *Val)
760 * \brief Get a symbol value
761 * \return Value of symbol or -1 on error
763 * Gets the value of a symbol from either the currently loaded
764 * libraries or the kernel's exports.
766 int Binary_GetSymbol(char *Name, Uint *Val)
768 if( Binary_GetSymbolEx(Name, Val) ) return 1;
773 * \fn Uint Binary_GetSymbolEx(char *Name, Uint *Value)
774 * \brief Get a symbol value
776 * Gets the value of a symbol from either the currently loaded
777 * libraries or the kernel's exports.
779 Uint Binary_GetSymbolEx(char *Name, Uint *Value)
783 int numKSyms = ((Uint)&gKernelSymbolsEnd-(Uint)&gKernelSymbols)/sizeof(tKernelSymbol);
786 for( i = 0; i < numKSyms; i++ )
788 if(strcmp(Name, gKernelSymbols[i].Name) == 0) {
789 *Value = gKernelSymbols[i].Value;
794 // Scan Loaded Libraries
795 for(pKBin = glLoadedKernelLibs;
797 pKBin = pKBin->Next )
799 if( Binary_FindSymbol(pKBin->Base, Name, Value) ) {
804 Warning("[BIN ] Unable to find symbol '%s'", Name);
809 * \fn Uint Binary_FindSymbol(void *Base, char *Name, Uint *Val)
810 * \brief Get a symbol from the specified library
811 * \param Base Base address
812 * \param Name Name of symbol to find
813 * \param Val Pointer to place final value
815 Uint Binary_FindSymbol(void *Base, char *Name, Uint *Val)
817 Uint32 ident = *(Uint32*) Base;
818 tBinaryType *bt = gRegBinTypes;
820 for(; bt; bt = bt->Next)
822 if( (ident & bt->Mask) == (Uint)bt->Ident )
823 return bt->GetSymbol(Base, Name, Val);
826 Warning("[BIN ] 0x%x is an unknown file type. (0x%x 0x%x 0x%x 0x%x)",
827 Base, ident&0xFF, ident>>8, ident>>16, ident>>24);
832 EXPORT(Binary_FindSymbol);
833 EXPORT(Binary_Unload);