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

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