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

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