Kernel - Cleanup and fix all memfiles treated as same by binary loader
[tpg/acess2.git] / KernelLand / Kernel / binary.c
1 /*
2  * Acess2
3  * Common Binary Loader
4  */
5 #define DEBUG   0
6 #include <acess.h>
7 #include <binary.h>
8 #include <mm_virt.h>
9 #include <hal_proc.h>
10 #include <vfs_threads.h>
11
12 // === CONSTANTS ===
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)
19
20 // === TYPES ===
21 typedef struct sKernelBin {
22         struct sKernelBin       *Next;
23         void    *Base;
24         tBinary *Info;
25 } tKernelBin;
26
27 // === IMPORTS ===
28 extern char     *Threads_GetName(int ID);
29 extern tKernelSymbol    gKernelSymbols[];
30 extern tKernelSymbol    gKernelSymbolsEnd[];
31 extern tBinaryType      gELF_Info;
32
33 // === PROTOTYPES ===
34  int    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);
42 #if 0
43 Uint    Binary_Relocate(void *Base);
44 #endif
45 Uint    Binary_GetSymbolEx(const char *Name, Uint *Value);
46 #if 0
47 Uint    Binary_FindSymbol(void *Base, const char *Name, Uint *Val);
48 #endif
49  int    Binary_int_CheckMemFree( tVAddr _start, size_t _len );
50
51 // === GLOBALS ===
52 tShortSpinlock  glBinListLock;
53 tBinary *glLoadedBinaries = NULL;
54 char    **gsaRegInterps = NULL;
55  int    giRegInterps = 0;
56 tShortSpinlock  glKBinListLock;
57 tKernelBin      *glLoadedKernelLibs;
58 tBinaryType     *gRegBinTypes = &gELF_Info;
59  
60 // === FUNCTIONS ===
61 /**
62  * \brief Registers a binary type
63  */
64 int Binary_RegisterType(tBinaryType *Type)
65 {
66         Type->Next = gRegBinTypes;
67         gRegBinTypes = Type;
68         return 1;
69 }
70
71 /**
72  * \fn int Proc_Spawn(const char *Path)
73  */
74 int Proc_Spawn(const char *Path)
75 {
76         char    stackPath[strlen(Path)+1];
77         ENTER("sPath", Path);
78         
79         strcpy(stackPath, Path);
80         
81         LOG("stackPath = '%s'", stackPath);
82         
83         if(Proc_Clone(CLONE_VM|CLONE_NOUSER) == 0)
84         {
85                 // CHILD
86                 const char      *args[2] = {stackPath, NULL};
87                 LOG("stackPath = '%s'", stackPath);
88                 Proc_Execve(stackPath, args, &args[1], 0);
89                 for(;;);
90         }
91         LEAVE('i', 0);
92         return 0;
93 }
94
95 /**
96  * \todo Document
97  */
98 int Binary_int_CacheArgs(const char **Path, const char ***ArgV, const char ***EnvP, void *DestBuffer)
99 {
100          int    size, argc=0, envc=0;
101          int    i;
102         char    *strbuf;
103         const char      **arrays;
104         
105         // Calculate size
106         size = 0;
107         if( ArgV && *ArgV )
108         {
109                 const char      **argv = *ArgV;
110                 for( argc = 0; argv[argc]; argc ++ )
111                         size += strlen( argv[argc] ) + 1;
112         }
113         if( EnvP && *EnvP )
114         {
115                 const char      **envp = *EnvP;
116                 for( envc = 0; envp[envc]; envc ++ )
117                         size += strlen( envp[envc] ) + 1;
118         }
119         size = (size + sizeof(void*)-1) & ~(sizeof(void*)-1);   // Word align
120         size += (argc+1+envc+1)*sizeof(void*);  // Arrays
121         if( Path )
122         {
123                 size += strlen( *Path ) + 1;
124         }
125
126         if( DestBuffer )        
127         {
128                 arrays = DestBuffer;
129                 strbuf = (void*)&arrays[argc+1+envc+1];
130         
131                 // Fill ArgV
132                 if( ArgV && *ArgV )
133                 {
134                         const char      **argv = *ArgV;
135                         for( i = 0; argv[i]; i ++ )
136                         {
137                                 arrays[i] = strbuf;
138                                 strcpy(strbuf, argv[i]);
139                                 strbuf += strlen( argv[i] ) + 1;
140                         }
141                         *ArgV = arrays;
142                         arrays += i;
143                 }
144                 *arrays++ = NULL;
145                 // Fill EnvP
146                 if( EnvP && *EnvP )
147                 {
148                         const char      **envp = *EnvP;
149                         for( i = 0; envp[i]; i ++ )
150                         {
151                                 arrays[i] = strbuf;
152                                 strcpy(strbuf, envp[i]);
153                                 strbuf += strlen( envp[i] ) + 1;
154                         }
155                         *EnvP = arrays;
156                         arrays += i;
157                 }
158                 *arrays++ = NULL;
159                 // Fill path
160                 if( Path )
161                 {
162                         strcpy(strbuf, *Path);
163                         *Path = strbuf;
164                 }
165         }
166         
167         return size;
168 }
169
170 /**
171  * \brief Create a new process with the specified set of file descriptors
172  */
173 int Proc_SysSpawn(const char *Binary, const char **ArgV, const char **EnvP, int nFD, int *FDs)
174 {
175         void    *handles;
176         void    *cachebuf;
177          int    size;
178         tPID    ret;
179         
180         // --- Save File, ArgV and EnvP
181         size = Binary_int_CacheArgs( &Binary, &ArgV, &EnvP, NULL );
182         cachebuf = malloc( size );
183         Binary_int_CacheArgs( &Binary, &ArgV, &EnvP, cachebuf );
184
185         // Cache the VFS handles        
186         handles = VFS_SaveHandles(nFD, FDs);
187
188         // Create new process   
189         ret = Proc_Clone(CLONE_VM|CLONE_NOUSER);
190         if( ret == 0 )
191         {
192                 VFS_RestoreHandles(nFD, handles);
193                 VFS_FreeSavedHandles(nFD, handles);
194                 // Frees cachebuf
195                 Proc_int_Execve(Binary, ArgV, EnvP, size, 0);
196                 for(;;);
197         }
198         if( ret == -1 )
199         {
200                 VFS_FreeSavedHandles(nFD, handles);
201                 free(cachebuf);
202         }
203         
204         return ret;
205 }
206
207 /**
208  * \brief Replace the current user image with another
209  * \param File  File to load as the next image
210  * \param ArgV  Arguments to pass to user
211  * \param EnvP  User's environment
212  * \note Called Proc_ for historical reasons
213  */
214 int Proc_Execve(const char *File, const char **ArgV, const char **EnvP, int DataSize)
215 {
216         return Proc_int_Execve(File, ArgV, EnvP, DataSize, 1);
217 }
218
219 int Proc_int_Execve(const char *File, const char **ArgV, const char **EnvP, int DataSize, bool bClearUser)
220 {
221         void    *cachebuf;
222         tVAddr  entry;
223         Uint    base;   // Uint because Proc_StartUser wants it
224          int    argc;
225         
226         ENTER("sFile pArgV pEnvP", File, ArgV, EnvP);
227         
228         // --- Save File, ArgV and EnvP
229         if( DataSize == 0 )
230         {
231                 DataSize = Binary_int_CacheArgs( &File, &ArgV, &EnvP, NULL );
232                 cachebuf = malloc( DataSize );
233                 Binary_int_CacheArgs( &File, &ArgV, &EnvP, cachebuf );
234         }
235
236         // --- Get argc 
237         for( argc = 0; ArgV && ArgV[argc]; argc ++ );
238         
239         // --- Set Process Name
240         Threads_SetName(File);
241         
242         // --- Clear User Address space
243         // NOTE: This is a little roundabout, maybe telling ClearUser to not touch the
244         //       PPD area would be a better idea.
245         if( bClearUser )
246         {
247                  int    nfd = *Threads_GetMaxFD();
248                 void    *handles;
249                 handles = VFS_SaveHandles(nfd, NULL);
250                 VFS_CloseAllUserHandles();
251                 MM_ClearUser();
252                 VFS_RestoreHandles(nfd, handles);
253                 VFS_FreeSavedHandles(nfd, handles);
254         }
255         
256         // --- Load new binary
257         base = Binary_Load(File, &entry);
258         if(base == 0)
259         {
260                 Log_Warning("Binary", "Proc_Execve - Unable to load '%s' [errno=%i]", File, errno);
261                 LEAVE('-');
262                 Threads_Exit(0, -10);
263                 for(;;);
264         }
265         
266         LOG("entry = 0x%x, base = 0x%x", entry, base);
267         LEAVE('-');
268         // --- And... Jump to it
269         Proc_StartUser(entry, base, argc, ArgV, DataSize);
270         for(;;);        // Tell GCC that we never return
271 }
272
273 /**
274  * \brief Load a binary into the current address space
275  * \param Path  Path to binary to load
276  * \param EntryPoint    Pointer for exectuable entry point
277  * \return Virtual address where the binary has been loaded
278  */
279 tVAddr Binary_Load(const char *Path, tVAddr *EntryPoint)
280 {
281         tMount  mount_id;
282         tInode  inode;
283         tBinary *pBinary;
284         tVAddr  base = -1;
285
286         ENTER("sPath pEntryPoint", Path, EntryPoint);
287         
288         // Sanity Check Argument
289         if(Path == NULL) {
290                 LEAVE('x', 0);
291                 return 0;
292         }
293
294         // Check if this path has been loaded before.
295         #if 0
296         // TODO: Implement a list of string/tBinary pairs for loaded bins
297         #endif
298
299         // Get Inode
300         {
301                 int fd;
302                 tFInfo  info;
303                 fd = VFS_Open(Path, VFS_OPENFLAG_READ|VFS_OPENFLAG_EXEC);
304                 if( fd == -1 ) {
305                         LOG("%s does not exist", Path);
306                         LEAVE_RET('x', 0);
307                 }
308                 VFS_FInfo(fd, &info, 0);
309                 VFS_Close(fd);
310                 mount_id = info.mount;
311                 inode = info.inode;
312                 LOG("mount_id = %i, inode = %i", mount_id, inode);
313         }
314
315         // TODO: Also get modifcation time?
316
317         // Check if the binary has already been loaded
318         if( !(pBinary = Binary_GetInfo(mount_id, inode)) )
319                 pBinary = Binary_DoLoad(mount_id, inode, Path); // Else load it
320         
321         // Error Check
322         if(pBinary == NULL) {
323                 LEAVE('x', 0);
324                 return 0;
325         }
326         
327         // Map into process space
328         base = Binary_MapIn(pBinary, Path, BIN_LOWEST, BIN_HIGHEST);
329         
330         // Check for errors
331         if(base == 0) {
332                 LEAVE('x', 0);
333                 return 0;
334         }
335         
336         // Interpret
337         if(pBinary->Interpreter) {
338                 tVAddr  start;
339                 if( Binary_Load(pBinary->Interpreter, &start) == 0 ) {
340                         LEAVE('x', 0);
341                         return 0;
342                 }
343                 *EntryPoint = start;
344         }
345         else
346                 *EntryPoint = pBinary->Entry - pBinary->Base + base;
347         
348         // Return
349         LOG("*EntryPoint = 0x%x", *EntryPoint);
350         LEAVE('x', base);
351         return base;    // Pass the base as an argument to the user if there is an interpreter
352 }
353
354 /**
355  * \brief Finds a matching binary entry
356  * \param MountID       Mountpoint ID of binary file
357  * \param InodeID       Inode ID of the file
358  * \return Pointer to the binary definition (if already loaded)
359  */
360 tBinary *Binary_GetInfo(tMount MountID, tInode InodeID)
361 {
362         tBinary *pBinary;
363         for(pBinary = glLoadedBinaries; pBinary; pBinary = pBinary->Next)
364         {
365                 if(pBinary->MountID == MountID && pBinary->Inode == InodeID)
366                         return pBinary;
367         }
368         return NULL;
369 }
370
371 /**
372  * \brief Maps an already-loaded binary into an address space.
373  * \param Binary        Pointer to globally stored binary definition
374  * \param Path  Path to the binary's file (for debug)
375  * \param LoadMin       Lowest location to map to
376  * \param LoadMax       Highest location to map to
377  * \return Base load address
378  */
379 tVAddr Binary_MapIn(tBinary *Binary, const char *Path, tVAddr LoadMin, tVAddr LoadMax)
380 {
381         tVAddr  base;
382          int    i, fd;
383
384         ENTER("pBinary sPath pLoadMin pLoadMax", Binary, Path, LoadMin, LoadMax);
385
386         // Reference Executable (Makes sure that it isn't unloaded)
387         Binary->ReferenceCount ++;
388         
389         // Get Binary Base
390         base = Binary->Base;
391         
392         // Check if base is free
393         if(base != 0)
394         {
395                 LOG("Checking base %p", base);
396                 for( i = 0; i < Binary->NumSections; i ++ )
397                 {
398                         if( Binary_int_CheckMemFree( Binary->LoadSections[i].Virtual, Binary->LoadSections[i].MemSize ) )
399                         {
400                                 base = 0;
401                                 LOG("Address 0x%x is taken\n", Binary->LoadSections[i].Virtual);
402                                 break;
403                         }
404                 }
405         }
406         
407         // Check if the executable has no base or it is not free
408         if(base == 0)
409         {
410                 // If so, give it a base
411                 base = LoadMax;
412                 while(base >= LoadMin)
413                 {
414                         for( i = 0; i < Binary->NumSections; i ++ )
415                         {
416                                 tVAddr  addr = Binary->LoadSections[i].Virtual - Binary->Base + base;
417                                 size_t  size = Binary->LoadSections[i].MemSize;
418                                 if( addr + size > LoadMax )
419                                         break;
420                                 if( Binary_int_CheckMemFree( addr, size ) )
421                                         break;
422                         }
423                         // If space was found, break
424                         if(i == Binary->NumSections)            break;
425                         // Else decrement pointer and try again
426                         base -= BIN_GRANUALITY;
427                 }
428                 LOG("Allocated base %p", base);
429         }
430         
431         // Error Check
432         if(base < LoadMin) {
433                 Log_Warning("Binary", "Executable '%s' cannot be loaded, no space", Path);
434                 LEAVE('i', 0);
435                 return 0;
436         }
437         
438         // Map Executable In
439         if( Binary->MountID )
440                 fd = VFS_OpenInode(Binary->MountID, Binary->Inode, VFS_OPENFLAG_READ);
441         else
442                 fd = VFS_Open(Path, VFS_OPENFLAG_READ);
443         for( i = 0; i < Binary->NumSections; i ++ )
444         {
445                 tBinarySection  *sect = &Binary->LoadSections[i];
446                 Uint    protflags, mapflags;
447                 tVAddr  addr = sect->Virtual - Binary->Base + base;
448                 LOG("%i - %p, 0x%x bytes from offset 0x%llx (%x)", i, addr, sect->FileSize, sect->Offset, sect->Flags);
449
450                 protflags = MMAP_PROT_READ;
451                 mapflags = MMAP_MAP_FIXED;
452
453                 if( sect->Flags & BIN_SECTFLAG_EXEC )
454                         protflags |= MMAP_PROT_EXEC;
455                 // Read only pages are COW
456                 if( sect->Flags & BIN_SECTFLAG_RO  ) {
457                         VFS_MMap( (void*)addr, sect->FileSize, protflags, MMAP_MAP_SHARED|mapflags, fd, sect->Offset );
458                 }
459                 else {
460                         protflags |= MMAP_PROT_WRITE;
461                         VFS_MMap( (void*)addr, sect->FileSize, protflags, MMAP_MAP_PRIVATE|mapflags, fd, sect->Offset );
462                 }
463                 
464                 // Apply anonymous memory for BSS
465                 if( sect->FileSize < sect->MemSize ) {
466                         mapflags |= MMAP_MAP_ANONYMOUS;
467                         VFS_MMap(
468                                 (void*)(addr + sect->FileSize), sect->MemSize - sect->FileSize,
469                                 protflags, MMAP_MAP_PRIVATE|mapflags,
470                                 0, 0
471                                 );
472                 }
473         }
474         
475         Log_Debug("Binary", "PID %i - Mapped '%s' to %p", Threads_GetPID(), Path, base);
476         VFS_Close(fd);
477         
478         LEAVE('p', base);
479         return base;
480 }
481
482 #if 0
483 /**
484  * \fn Uint Binary_IsMapped(tBinary *binary)
485  * \brief Check if a binary is already mapped into the address space
486  * \param binary        Binary information to check
487  * \return Current Base or 0
488  */
489 Uint Binary_IsMapped(tBinary *binary)
490 {
491         Uint    iBase;
492         
493         // Check prefered base
494         iBase = binary->Base;
495         if(MM_GetPage( iBase ) == (binary->Pages[0].Physical & ~0xFFF))
496                 return iBase;
497         
498         for(iBase = BIN_HIGHEST;
499                 iBase >= BIN_LOWEST;
500                 iBase -= BIN_GRANUALITY)
501         {
502                 if(MM_GetPage( iBase ) == (binary->Pages[0].Physical & ~0xFFF))
503                         return iBase;
504         }
505         
506         return 0;
507 }
508 #endif
509
510 /**
511  * \fn tBinary *Binary_DoLoad(char *truePath)
512  * \brief Loads a binary file into memory
513  * \param truePath      Absolute filename of binary
514  */
515 tBinary *Binary_DoLoad(tMount MountID, tInode Inode, const char *Path)
516 {
517         tBinary *pBinary;
518          int    fp;
519         Uint32  ident;
520         tBinaryType     *bt = gRegBinTypes;
521         
522         ENTER("iMountID XInode sPath", MountID, Inode, Path);
523         
524         // Open File
525         if( MountID )
526         {
527                 fp = VFS_OpenInode(MountID, Inode, VFS_OPENFLAG_READ);
528         }
529         else
530         {
531                 fp = VFS_Open(Path, VFS_OPENFLAG_READ);
532         }
533         if(fp == -1) {
534                 LOG("Unable to load file, access denied");
535                 LEAVE('n');
536                 return NULL;
537         }
538
539         LOG("fp = 0x%x", fp);
540         
541         // Read File Type
542         VFS_Read(fp, 4, &ident);
543         VFS_Seek(fp, 0, SEEK_SET);
544
545         LOG("ident = 0x%x", ident);
546
547         // Determine the type   
548         for(; bt; bt = bt->Next)
549         {
550                 if( (ident & bt->Mask) != (Uint32)bt->Ident )
551                         continue;
552                 LOG("bt = %p (%s)", bt, bt->Name);
553                 pBinary = bt->Load(fp);
554                 break;
555         }
556
557         // Close File
558         VFS_Close(fp);
559         
560         // Catch errors
561         if(!bt) {
562                 Log_Warning("Binary", "'%s' is an unknown file type. (%02x %02x %02x %02x)",
563                         Path, ident&0xFF, (ident>>8)&0xFF, (ident>>16)&0xFF, (ident>>24)&0xFF);
564                 LEAVE('n');
565                 return NULL;
566         }
567         
568         LOG("pBinary = %p", pBinary);
569         
570         // Error Check
571         if(pBinary == NULL) {
572                 LEAVE('n');
573                 return NULL;
574         }
575         
576         // Initialise Structure
577         pBinary->ReferenceCount = 0;
578         pBinary->MountID = MountID;
579         pBinary->Inode = Inode;
580         
581         // Debug Information
582         LOG("Interpreter: '%s'", pBinary->Interpreter);
583         LOG("Base: 0x%x, Entry: 0x%x", pBinary->Base, pBinary->Entry);
584         LOG("NumSections: %i", pBinary->NumSections);
585         
586         // Add to the list
587         SHORTLOCK(&glBinListLock);
588         pBinary->Next = glLoadedBinaries;
589         glLoadedBinaries = pBinary;
590         SHORTREL(&glBinListLock);
591
592         // TODO: Register the path with the binary      
593
594         // Return
595         LEAVE('p', pBinary);
596         return pBinary;
597 }
598
599 /**
600  * \fn void Binary_Unload(void *Base)
601  * \brief Unload / Unmap a binary
602  * \param Base  Loaded Base
603  * \note Currently used only for kernel libaries
604  */
605 void Binary_Unload(void *Base)
606 {
607         tKernelBin      *pKBin;
608         tKernelBin      *prev = NULL;
609          int    i;
610         
611         if((Uint)Base < 0xC0000000)
612         {
613                 // TODO: User Binaries
614                 Log_Warning("BIN", "Unloading user binaries is currently unimplemented");
615                 return;
616         }
617         
618         // Kernel Libraries
619         for(pKBin = glLoadedKernelLibs;
620                 pKBin;
621                 prev = pKBin, pKBin = pKBin->Next)
622         {
623                 // Check the base
624                 if(pKBin->Base != Base) continue;
625                 // Deallocate Memory
626                 for(i = 0; i < pKBin->Info->NumSections; i++)
627                 {
628                         // TODO: VFS_MUnmap();
629                 }
630                 // Dereference Binary
631                 Binary_Dereference( pKBin->Info );
632                 // Remove from list
633                 if(prev)        prev->Next = pKBin->Next;
634                 else            glLoadedKernelLibs = pKBin->Next;
635                 // Free Kernel Lib
636                 free(pKBin);
637                 return;
638         }
639 }
640
641 /**
642  * \fn void Binary_Dereference(tBinary *Info)
643  * \brief Dereferences and if nessasary, deletes a binary
644  * \param Info  Binary information structure
645  */
646 void Binary_Dereference(tBinary *Info)
647 {
648         // Decrement reference count
649         Info->ReferenceCount --;
650         
651         // Check if it is still in use
652         if(Info->ReferenceCount)        return;
653         
654         /// \todo Implement binary freeing
655 }
656
657 /**
658  * \fn char *Binary_RegInterp(char *Path)
659  * \brief Registers an Interpreter
660  * \param Path  Path to interpreter provided by executable
661  */
662 char *Binary_RegInterp(char *Path)
663 {
664          int    i;
665         // NULL Check Argument
666         if(Path == NULL)        return NULL;
667         // NULL Check the array
668         if(gsaRegInterps == NULL)
669         {
670                 giRegInterps = 1;
671                 gsaRegInterps = malloc( sizeof(char*) );
672                 gsaRegInterps[0] = malloc( strlen(Path) );
673                 strcpy(gsaRegInterps[0], Path);
674                 return gsaRegInterps[0];
675         }
676         
677         // Scan Array
678         for( i = 0; i < giRegInterps; i++ )
679         {
680                 if(strcmp(gsaRegInterps[i], Path) == 0)
681                         return gsaRegInterps[i];
682         }
683         
684         // Interpreter is not in list
685         giRegInterps ++;
686         gsaRegInterps = malloc( sizeof(char*)*giRegInterps );
687         gsaRegInterps[i] = malloc( strlen(Path) );
688         strcpy(gsaRegInterps[i], Path);
689         return gsaRegInterps[i];
690 }
691
692 // ============
693 // Kernel Binary Handling
694 // ============
695 /**
696  * \fn void *Binary_LoadKernel(const char *File)
697  * \brief Load a binary into kernel space
698  * \note This function shares much with #Binary_Load, but does it's own mapping
699  * \param File  File to load into the kernel
700  */
701 void *Binary_LoadKernel(const char *File)
702 {
703         tBinary *pBinary;
704         tKernelBin      *pKBinary;
705         tVAddr  base = -1;
706         tMount  mount_id;
707         tInode  inode;
708
709         ENTER("sFile", File);
710         
711         // Sanity Check Argument
712         if(File == NULL) {
713                 LEAVE('n');
714                 return 0;
715         }
716
717         {
718                 int fd = VFS_Open(File, VFS_OPENFLAG_READ);
719                 tFInfo  info;
720                 if(fd == -1) {
721                         LOG("Opening failed");
722                         LEAVE('n');
723                         return NULL;
724                 }
725                 VFS_FInfo(fd, &info, 0);
726                 mount_id = info.mount;
727                 inode = info.inode;
728                 VFS_Close(fd);
729                 LOG("Mount %i, Inode %lli", mount_id, inode);
730         }
731         
732         // Check if the binary has already been loaded
733         if( (pBinary = Binary_GetInfo(mount_id, inode)) )
734         {
735                 for(pKBinary = glLoadedKernelLibs;
736                         pKBinary;
737                         pKBinary = pKBinary->Next )
738                 {
739                         if(pKBinary->Info == pBinary) {
740                                 LOG("Already loaded");
741                                 LEAVE('p', pKBinary->Base);
742                                 return pKBinary->Base;
743                         }
744                 }
745         }
746         else
747                 pBinary = Binary_DoLoad(mount_id, inode, File); // Else load it
748         
749         // Error Check
750         if(pBinary == NULL) {
751                 LEAVE('n');
752                 return NULL;
753         }
754         
755         LOG("Loaded as %p", pBinary);
756         // --------------
757         // Now pBinary is valid (either freshly loaded or only user mapped)
758         // So, map it into kernel space
759         // --------------
760         
761         // Reference Executable (Makes sure that it isn't unloaded)
762         pBinary->ReferenceCount ++;
763
764         base = Binary_MapIn(pBinary, File, KLIB_LOWEST, KLIB_HIGHEST);
765         if( base == 0 ) {
766                 LEAVE('n');
767                 return 0;
768         }
769
770         // Add to list
771         // TODO: Could this cause race conditions if a binary isn't fully loaded when used
772         pKBinary = malloc(sizeof(*pKBinary));
773         pKBinary->Base = (void*)base;
774         pKBinary->Info = pBinary;
775         SHORTLOCK( &glKBinListLock );
776         pKBinary->Next = glLoadedKernelLibs;
777         glLoadedKernelLibs = pKBinary;
778         SHORTREL( &glKBinListLock );
779
780         LEAVE('p', base);
781         return (void*)base;
782 }
783
784 /**
785  * \fn Uint Binary_Relocate(void *Base)
786  * \brief Relocates a loaded binary (used by kernel libraries)
787  * \param Base  Loaded base address of binary
788  * \return Boolean Success
789  */
790 Uint Binary_Relocate(void *Base)
791 {
792         Uint32  ident = *(Uint32*) Base;
793         tBinaryType     *bt = gRegBinTypes;
794         
795         for( ; bt; bt = bt->Next)
796         {
797                 if( (ident & bt->Mask) == (Uint)bt->Ident )
798                         return bt->Relocate( (void*)Base);
799         }
800         
801         Log_Warning("BIN", "%p is an unknown file type. (%02x %02x %02x %02x)",
802                 Base, ident&0xFF, (ident>>8)&0xFF, (ident>>16)&0xFF, (ident>>24)&0xFF);
803         return 0;
804 }
805
806 /**
807  * \fn int Binary_GetSymbol(char *Name, Uint *Val)
808  * \brief Get a symbol value
809  * \return Value of symbol or -1 on error
810  * 
811  * Gets the value of a symbol from either the currently loaded
812  * libraries or the kernel's exports.
813  */
814 int Binary_GetSymbol(const char *Name, Uint *Val)
815 {
816         if( Binary_GetSymbolEx(Name, Val) )     return 1;
817         return 0;
818 }
819
820 /**
821  * \fn Uint Binary_GetSymbolEx(char *Name, Uint *Value)
822  * \brief Get a symbol value
823  * 
824  * Gets the value of a symbol from either the currently loaded
825  * libraries or the kernel's exports.
826  */
827 Uint Binary_GetSymbolEx(const char *Name, Uint *Value)
828 {
829         tKernelBin      *pKBin;
830          int    numKSyms = ((Uint)&gKernelSymbolsEnd-(Uint)&gKernelSymbols)/sizeof(tKernelSymbol);
831         
832         // Scan Kernel
833         for( int i = 0; i < numKSyms; i++ )
834         {
835                 if(strcmp(Name, gKernelSymbols[i].Name) == 0) {
836                         LOG("KSym %s = %p", gKernelSymbols[i].Name, gKernelSymbols[i].Value);
837                         *Value = gKernelSymbols[i].Value;
838                         return 1;
839                 }
840         }
841         
842         
843         // Scan Loaded Libraries
844         for(pKBin = glLoadedKernelLibs;
845                 pKBin;
846                 pKBin = pKBin->Next )
847         {
848                 if( Binary_FindSymbol(pKBin->Base, Name, Value) ) {
849                         return 1;
850                 }
851         }
852         
853         Log_Warning("BIN", "Unable to find symbol '%s'", Name);
854         return 0;
855 }
856
857 /**
858  * \fn Uint Binary_FindSymbol(void *Base, char *Name, Uint *Val)
859  * \brief Get a symbol from the specified library
860  * \param Base  Base address
861  * \param Name  Name of symbol to find
862  * \param Val   Pointer to place final value
863  */
864 Uint Binary_FindSymbol(void *Base, const char *Name, Uint *Val)
865 {
866         Uint32  ident = *(Uint32*) Base;
867         tBinaryType     *bt = gRegBinTypes;
868         
869         for(; bt; bt = bt->Next)
870         {
871                 if( (ident & bt->Mask) == (Uint)bt->Ident )
872                         return bt->GetSymbol(Base, Name, Val);
873         }
874         
875         Log_Warning("BIN", "Binary_FindSymbol - %p is an unknown file type. (%02x %02x %02x %02x)",
876                 Base, ident&0xFF, ident>>8, ident>>16, ident>>24);
877         return 0;
878 }
879
880 /**
881  * \brief Check if a range of memory is fully free
882  * \return Inverse boolean free (0 if all pages are unmapped)
883  */
884 int Binary_int_CheckMemFree( tVAddr _start, size_t _len )
885 {
886         ENTER("p_start x_len", _start, _len);
887
888         _len += _start & (PAGE_SIZE-1);
889         _len = (_len + PAGE_SIZE - 1) & ~(PAGE_SIZE-1);
890         _start &= ~(PAGE_SIZE-1);
891         LOG("_start = %p, _len = 0x%x", _start, _len);
892         for( ; _len > PAGE_SIZE; _len -= PAGE_SIZE, _start += PAGE_SIZE ) {
893                 if( MM_GetPhysAddr( (void*)_start ) != 0 ) {
894                         LEAVE('i', 1);
895                         return 1;
896                 }
897         }
898         if( _len == PAGE_SIZE && MM_GetPhysAddr( (void*)_start ) != 0 ) {
899                 LEAVE('i', 1);
900                 return 1;
901         }
902         LEAVE('i', 0);
903         return 0;
904 }
905
906
907 // === EXPORTS ===
908 EXPORT(Binary_FindSymbol);
909 EXPORT(Binary_Unload);

UCC git Repository :: git.ucc.asn.au