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

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