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

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