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

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