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

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