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

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