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

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