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

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