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

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