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

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