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

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