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

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