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

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