Still some issues, but it seems to not crash anymore
[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 void     Threads_Exit(int, int);
29 extern Uint     MM_ClearUser(void);
30 extern void     Proc_StartUser(Uint Entrypoint, Uint *Bases, int ArgC, char **ArgV, char **EnvP, int DataSize);
31 extern tKernelSymbol    gKernelSymbols[];
32 extern void             gKernelSymbolsEnd;
33 extern tBinaryType      gELF_Info;
34
35 // === PROTOTYPES ===
36  int    Proc_Execve(char *File, char **ArgV, char **EnvP);
37 Uint    Binary_Load(char *file, Uint *entryPoint);
38 tBinary *Binary_GetInfo(char *truePath);
39 Uint    Binary_MapIn(tBinary *binary);
40 Uint    Binary_IsMapped(tBinary *binary);
41 tBinary *Binary_DoLoad(char *truePath);
42 void    Binary_Dereference(tBinary *Info);
43 Uint    Binary_Relocate(void *Base);
44 Uint    Binary_GetSymbolEx(char *Name, Uint *Value);
45 Uint    Binary_FindSymbol(void *Base, char *Name, Uint *Val);
46
47 // === GLOBALS ===
48 tShortSpinlock  glBinListLock;
49 tBinary *glLoadedBinaries = NULL;
50 char    **gsaRegInterps = NULL;
51  int    giRegInterps = 0;
52 tShortSpinlock  glKBinListLock;
53 tKernelBin      *glLoadedKernelLibs;
54 tBinaryType     *gRegBinTypes = &gELF_Info;
55  
56 // === FUNCTIONS ===
57 /**
58  * \brief Registers a binary type
59  */
60 int Binary_RegisterType(tBinaryType *Type)
61 {
62         Type->Next = gRegBinTypes;
63         gRegBinTypes = Type;
64         return 1;
65 }
66
67 /**
68  * \fn int Proc_Spawn(char *Path)
69  */
70 int Proc_Spawn(char *Path)
71 {
72         char    stackPath[strlen(Path)+1];
73         
74         strcpy(stackPath, Path);
75         
76         LOG("stackPath = '%s'\n", stackPath);
77         
78         if(Proc_Clone(NULL, CLONE_VM) == 0)
79         {
80                 // CHILD
81                 char    *args[2] = {stackPath, NULL};
82                 LOG("stackPath = '%s'\n", stackPath);
83                 Proc_Execve(stackPath, args, &args[1]);
84                 for(;;);
85         }
86         return 0;
87 }
88
89 /**
90  * \fn int Proc_Execve(char *File, char **ArgV, char **EnvP)
91  * \brief Replace the current user image with another
92  * \param File  File to load as the next image
93  * \param ArgV  Arguments to pass to user
94  * \param EnvP  User's environment
95  * \note Called Proc_ for historical reasons
96  */
97 int Proc_Execve(char *File, char **ArgV, char **EnvP)
98 {
99          int    argc, envc, i;
100          int    argenvBytes;
101         char    *argenvBuf, *strBuf;
102         char    **argvSaved, **envpSaved;
103         char    *savedFile;
104         Uint    entry;
105         Uint    bases[2] = {0};
106         
107         ENTER("sFile pArgV pEnvP", File, ArgV, EnvP);
108         
109         // --- Save File, ArgV and EnvP (also get argc)
110         
111         // Count Arguments, Environment Variables and total string sizes
112         argenvBytes = 0;
113         for( argc = 0; ArgV && ArgV[argc]; argc++ )
114                 argenvBytes += strlen(ArgV[argc])+1;
115         for( envc = 0; EnvP && EnvP[envc]; envc++ )
116                 argenvBytes += strlen(EnvP[envc])+1;
117         argenvBytes = (argenvBytes + sizeof(void*)-1) & ~(sizeof(void*)-1);
118         argenvBytes += (argc+1)*sizeof(void*) + (envc+1)*sizeof(void*);
119         
120         // Allocate
121         argenvBuf = malloc(argenvBytes);
122         if(argenvBuf == NULL) {
123                 Log_Error("BIN", "Proc_Execve - What the hell? The kernel is out of heap space");
124                 return 0;
125         }
126         strBuf = argenvBuf + (argc+1)*sizeof(void*) + (envc+1)*sizeof(void*);
127         
128         // Populate
129         argvSaved = (char **) argenvBuf;
130         for( i = 0; i < argc; i++ )
131         {
132                 argvSaved[i] = strBuf;
133                 strcpy(argvSaved[i], ArgV[i]);
134                 strBuf += strlen(ArgV[i])+1;
135         }
136         argvSaved[i] = NULL;
137         envpSaved = &argvSaved[i+1];
138         for( i = 0; i < envc; i++ )
139         {
140                 envpSaved[i] = strBuf;
141                 strcpy(envpSaved[i], EnvP[i]);
142                 strBuf += strlen(EnvP[i])+1;
143         }
144         envpSaved[i] = NULL;
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                 Log_Warning("BIN", "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                 Log_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                 Log_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_Debug("Binary", "PID %i - Mapped '%s' to 0x%x", Threads_GetPID(), 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                 Log_Warning("BIN", "'%s' is an unknown file type. (%02x %02x %02x %02x)",
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                         Log_Warning("BIN", "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 the address is not aligned, or the page is not full
464                         // sized, copy part of it
465                         if( (dest & 0xFFF) > 0 || pBinary->Pages[i].Size < 0x1000)
466                         {
467                                 // Validate the size to prevent Kernel page faults
468                                 // Clips to one page and prints a warning
469                                 if( pBinary->Pages[i].Size + (dest & 0xFFF) > 0x1000) {
470                                         Log_Warning("Binary", "Loader error: Page %i (%p) of '%s' is %i bytes (> 4096)",
471                                                 i, pBinary->Pages[i].Virtual, truePath,
472                                                 (dest&0xFFF) + pBinary->Pages[i].Size);
473                                         pBinary->Pages[i].Size = 0x1000 - (dest & 0xFFF);
474                                 }               
475                                 LOG("%i - 0x%llx - 0x%x bytes",
476                                         i, pBinary->Pages[i].Physical, pBinary->Pages[i].Size);
477                                 // Zero from `dest` to the end of the page
478                                 memset( (void*)dest, 0, 0x1000 - (dest&0xFFF) );
479                                 // Read in the data
480                                 VFS_Read( fp, pBinary->Pages[i].Size, (void*)dest );
481                         }
482                         // Full page
483                         else
484                         {
485                                 // Check if the page is oversized
486                                 if(pBinary->Pages[i].Size > 0x1000)
487                                         Log_Warning("Binary", "Loader error - Page %i (%p) of '%s' is %i bytes (> 4096)",
488                                                 i, pBinary->Pages[i].Virtual, truePath,
489                                                 pBinary->Pages[i].Size);
490                                 // Read data
491                                 LOG("%i - 0x%x", i, pBinary->Pages[i].Physical);
492                                 VFS_Read( fp, 0x1000, (void*)dest );
493                         }
494                 }
495                 pBinary->Pages[i].Physical = paddr;
496                 MM_FreeTemp( dest );
497         }
498         LOG("Page Count: %i", pBinary->NumPages);
499         
500         // Close File
501         VFS_Close(fp);
502         
503         // Add to the list
504         SHORTLOCK(&glBinListLock);
505         pBinary->Next = glLoadedBinaries;
506         glLoadedBinaries = pBinary;
507         SHORTREL(&glBinListLock);
508         
509         // Return
510         LEAVE('p', pBinary);
511         return pBinary;
512 }
513
514 /**
515  * \fn void Binary_Unload(void *Base)
516  * \brief Unload / Unmap a binary
517  * \param Base  Loaded Base
518  * \note Currently used only for kernel libaries
519  */
520 void Binary_Unload(void *Base)
521 {
522         tKernelBin      *pKBin;
523         tKernelBin      *prev = NULL;
524          int    i;
525         
526         if((Uint)Base < 0xC0000000)
527         {
528                 // TODO: User Binaries
529                 Log_Warning("BIN", "Unloading user binaries is currently unimplemented");
530                 return;
531         }
532         
533         // Kernel Libraries
534         for(pKBin = glLoadedKernelLibs;
535                 pKBin;
536                 prev = pKBin, pKBin = pKBin->Next)
537         {
538                 // Check the base
539                 if(pKBin->Base != Base) continue;
540                 // Deallocate Memory
541                 for(i = 0; i < pKBin->Info->NumPages; i++) {
542                         MM_Deallocate( (Uint)Base + (i << 12) );
543                 }
544                 // Dereference Binary
545                 Binary_Dereference( pKBin->Info );
546                 // Remove from list
547                 if(prev)        prev->Next = pKBin->Next;
548                 else            glLoadedKernelLibs = pKBin->Next;
549                 // Free Kernel Lib
550                 free(pKBin);
551                 return;
552         }
553 }
554
555 /**
556  * \fn void Binary_Dereference(tBinary *Info)
557  * \brief Dereferences and if nessasary, deletes a binary
558  * \param Info  Binary information structure
559  */
560 void Binary_Dereference(tBinary *Info)
561 {
562         // Decrement reference count
563         Info->ReferenceCount --;
564         
565         // Check if it is still in use
566         if(Info->ReferenceCount)        return;
567         
568         /// \todo Implement binary freeing
569 }
570
571 /**
572  * \fn char *Binary_RegInterp(char *Path)
573  * \brief Registers an Interpreter
574  * \param Path  Path to interpreter provided by executable
575  */
576 char *Binary_RegInterp(char *Path)
577 {
578          int    i;
579         // NULL Check Argument
580         if(Path == NULL)        return NULL;
581         // NULL Check the array
582         if(gsaRegInterps == NULL)
583         {
584                 giRegInterps = 1;
585                 gsaRegInterps = malloc( sizeof(char*) );
586                 gsaRegInterps[0] = malloc( strlen(Path) );
587                 strcpy(gsaRegInterps[0], Path);
588                 return gsaRegInterps[0];
589         }
590         
591         // Scan Array
592         for( i = 0; i < giRegInterps; i++ )
593         {
594                 if(strcmp(gsaRegInterps[i], Path) == 0)
595                         return gsaRegInterps[i];
596         }
597         
598         // Interpreter is not in list
599         giRegInterps ++;
600         gsaRegInterps = malloc( sizeof(char*)*giRegInterps );
601         gsaRegInterps[i] = malloc( strlen(Path) );
602         strcpy(gsaRegInterps[i], Path);
603         return gsaRegInterps[i];
604 }
605
606 // ============
607 // Kernel Binary Handling
608 // ============
609 /**
610  * \fn void *Binary_LoadKernel(char *File)
611  * \brief Load a binary into kernel space
612  * \note This function shares much with #Binary_Load, but does it's own mapping
613  * \param File  File to load into the kernel
614  */
615 void *Binary_LoadKernel(char *File)
616 {
617         char    *sTruePath;
618         tBinary *pBinary;
619         tKernelBin      *pKBinary;
620         Uint    base = -1;
621         Uint    addr;
622          int    i;
623
624         ENTER("sfile", File);
625         
626         // Sanity Check Argument
627         if(File == NULL) {
628                 LEAVE('n');
629                 return 0;
630         }
631
632         // Get True File Path
633         sTruePath = VFS_GetTruePath(File);
634         if(sTruePath == NULL) {
635                 LEAVE('n');
636                 return 0;
637         }
638         
639         // Check if the binary has already been loaded
640         if( (pBinary = Binary_GetInfo(sTruePath)) )
641         {
642                 for(pKBinary = glLoadedKernelLibs;
643                         pKBinary;
644                         pKBinary = pKBinary->Next )
645                 {
646                         if(pKBinary->Info == pBinary) {
647                                 LEAVE('p', pKBinary->Base);
648                                 return pKBinary->Base;
649                         }
650                 }
651         }
652         else
653                 pBinary = Binary_DoLoad(sTruePath);     // Else load it
654         
655         // Error Check
656         if(pBinary == NULL) {
657                 LEAVE('n');
658                 return NULL;
659         }
660         
661         // --------------
662         // Now pBinary is valid (either freshly loaded or only user mapped)
663         // So, map it into kernel space
664         // --------------
665         
666         // Reference Executable (Makes sure that it isn't unloaded)
667         pBinary->ReferenceCount ++;
668         
669         // Check compiled base
670         base = pBinary->Base;
671         // - Sanity Check
672         if(base < KLIB_LOWEST || base > KLIB_HIGHEST || base + (pBinary->NumPages<<12) > KLIB_HIGHEST) {
673                 base = 0;
674         }
675         // - Check if it is a valid base address
676         if(base != 0)
677         {
678                 for(i=0;i<pBinary->NumPages;i++)
679                 {
680                         if( MM_GetPhysAddr( pBinary->Pages[i].Virtual & ~0xFFF ) ) {
681                                 base = 0;
682                                 LOG("Address 0x%x is taken\n", pBinary->Pages[i].Virtual & ~0xFFF);
683                                 break;
684                         }
685                 }
686         }
687         
688         // Check if the executable has no base or it is not free
689         if(base == 0)
690         {
691                 // If so, give it a base
692                 base = KLIB_LOWEST;
693                 while(base < KLIB_HIGHEST)
694                 {
695                         for(i = 0; i < pBinary->NumPages; i++)
696                         {
697                                 addr = pBinary->Pages[i].Virtual & ~0xFFF;
698                                 addr -= pBinary->Base;
699                                 addr += base;
700                                 if( MM_GetPhysAddr( addr ) )    break;
701                         }
702                         // If space was found, break
703                         if(i == pBinary->NumPages)              break;
704                         // Else decrement pointer and try again
705                         base += KLIB_GRANUALITY;
706                 }
707         }
708         
709         // - Error Check
710         if(base >= KLIB_HIGHEST) {
711                 Log_Warning("BIN", "Executable '%s' cannot be loaded into kernel, no space", pBinary->TruePath);
712                 Binary_Dereference( pBinary );
713                 LEAVE('n');
714                 return 0;
715         }
716         
717         LOG("base = 0x%x", base);
718         
719         // - Map binary in
720         LOG("pBinary = {NumPages:%i, Pages=%p}", pBinary->NumPages, pBinary->Pages);
721         for(i = 0; i < pBinary->NumPages; i++)
722         {
723                 addr = pBinary->Pages[i].Virtual & ~0xFFF;
724                 addr -= pBinary->Base;
725                 addr += base;
726                 LOG("%i - 0x%x to 0x%x", i, addr, pBinary->Pages[i].Physical);
727                 MM_Map( addr, (Uint) (pBinary->Pages[i].Physical) );
728                 MM_SetFlags( addr, MM_PFLAG_KERNEL, MM_PFLAG_KERNEL );
729                 
730                 if( pBinary->Pages[i].Flags & BIN_PAGEFLAG_RO)  // Read-Only?
731                         MM_SetFlags( addr, MM_PFLAG_RO, MM_PFLAG_KERNEL );
732         }
733
734         // Relocate Library
735         if( !Binary_Relocate( (void*)base ) )
736         {
737                 Warning("[BIN ] Relocation of '%s' failed, unloading", sTruePath);
738                 Binary_Unload( (void*)base );
739                 Binary_Dereference( pBinary );
740                 LEAVE('n');
741                 return 0;
742         }
743         
744         // Add to list (relocator must look at itself manually, not via Binary_GetSymbol)
745         pKBinary = malloc(sizeof(*pKBinary));
746         pKBinary->Base = (void*)base;
747         pKBinary->Info = pBinary;
748         SHORTLOCK( &glKBinListLock );
749         pKBinary->Next = glLoadedKernelLibs;
750         glLoadedKernelLibs = pKBinary;
751         SHORTREL( &glKBinListLock );
752         
753         LEAVE('p', base);
754         return (void*)base;
755 }
756
757 /**
758  * \fn Uint Binary_Relocate(void *Base)
759  * \brief Relocates a loaded binary (used by kernel libraries)
760  * \param Base  Loaded base address of binary
761  * \return Boolean Success
762  */
763 Uint Binary_Relocate(void *Base)
764 {
765         Uint32  ident = *(Uint32*) Base;
766         tBinaryType     *bt = gRegBinTypes;
767         
768         for(; bt; bt = bt->Next)
769         {
770                 if( (ident & bt->Mask) == (Uint)bt->Ident )
771                         return bt->Relocate( (void*)Base);
772         }
773         
774         Log_Warning("BIN", "%p is an unknown file type. (%02x %02x %02x %02x)",
775                 Base, ident&0xFF, (ident>>8)&0xFF, (ident>>16)&0xFF, (ident>>24)&0xFF);
776         return 0;
777 }
778
779 /**
780  * \fn int Binary_GetSymbol(char *Name, Uint *Val)
781  * \brief Get a symbol value
782  * \return Value of symbol or -1 on error
783  * 
784  * Gets the value of a symbol from either the currently loaded
785  * libraries or the kernel's exports.
786  */
787 int Binary_GetSymbol(char *Name, Uint *Val)
788 {
789         if( Binary_GetSymbolEx(Name, Val) )     return 1;
790         return 0;
791 }
792
793 /**
794  * \fn Uint Binary_GetSymbolEx(char *Name, Uint *Value)
795  * \brief Get a symbol value
796  * 
797  * Gets the value of a symbol from either the currently loaded
798  * libraries or the kernel's exports.
799  */
800 Uint Binary_GetSymbolEx(char *Name, Uint *Value)
801 {
802          int    i;
803         tKernelBin      *pKBin;
804          int    numKSyms = ((Uint)&gKernelSymbolsEnd-(Uint)&gKernelSymbols)/sizeof(tKernelSymbol);
805         
806         // Scan Kernel
807         for( i = 0; i < numKSyms; i++ )
808         {
809                 if(strcmp(Name, gKernelSymbols[i].Name) == 0) {
810                         *Value = gKernelSymbols[i].Value;
811                         return 1;
812                 }
813         }
814         
815         // Scan Loaded Libraries
816         for(pKBin = glLoadedKernelLibs;
817                 pKBin;
818                 pKBin = pKBin->Next )
819         {
820                 if( Binary_FindSymbol(pKBin->Base, Name, Value) ) {
821                         return 1;
822                 }
823         }
824         
825         Log_Warning("BIN", "Unable to find symbol '%s'", Name);
826         return 0;
827 }
828
829 /**
830  * \fn Uint Binary_FindSymbol(void *Base, char *Name, Uint *Val)
831  * \brief Get a symbol from the specified library
832  * \param Base  Base address
833  * \param Name  Name of symbol to find
834  * \param Val   Pointer to place final value
835  */
836 Uint Binary_FindSymbol(void *Base, char *Name, Uint *Val)
837 {
838         Uint32  ident = *(Uint32*) Base;
839         tBinaryType     *bt = gRegBinTypes;
840         
841         for(; bt; bt = bt->Next)
842         {
843                 if( (ident & bt->Mask) == (Uint)bt->Ident )
844                         return bt->GetSymbol(Base, Name, Val);
845         }
846         
847         Log_Warning("BIN", "Binary_FindSymbol - %p is an unknown file type. (%02x %02x %02x %02x)",
848                 Base, ident&0xFF, ident>>8, ident>>16, ident>>24);
849         return 0;
850 }
851
852 // === EXPORTS ===
853 EXPORT(Binary_FindSymbol);
854 EXPORT(Binary_Unload);

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