Removed debug from Network/NE2000/ne2000.c
[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  \fn tBinary *Binary_GetInfo(char *truePath)\r
249  \brief Finds a matching binary entry\r
250  \param truePath        File Identifier (True path name)\r
251 */\r
252 tBinary *Binary_GetInfo(char *truePath)\r
253 {\r
254         tBinary *pBinary;\r
255         pBinary = glLoadedBinaries;\r
256         while(pBinary)\r
257         {\r
258                 if(strcmp(pBinary->TruePath, truePath) == 0)\r
259                         return pBinary;\r
260                 pBinary = pBinary->Next;\r
261         }\r
262         return NULL;\r
263 }\r
264 \r
265 /**\r
266  \fn Uint Binary_MapIn(tBinary *binary)\r
267  \brief Maps an already-loaded binary into an address space.\r
268  \param binary  Pointer to globally stored data.\r
269 */\r
270 Uint Binary_MapIn(tBinary *binary)\r
271 {\r
272         Uint    base;\r
273         Uint    addr;\r
274          int    i;\r
275         \r
276         // Reference Executable (Makes sure that it isn't unloaded)\r
277         binary->ReferenceCount ++;\r
278         \r
279         // Get Binary Base\r
280         base = binary->Base;\r
281         \r
282         // Check if base is free\r
283         if(base != 0)\r
284         {\r
285                 for(i=0;i<binary->NumPages;i++)\r
286                 {\r
287                         if( MM_GetPhysAddr( binary->Pages[i].Virtual & ~0xFFF ) ) {\r
288                                 base = 0;\r
289                                 LOG("Address 0x%x is taken\n", binary->Pages[i].Virtual & ~0xFFF);\r
290                                 break;\r
291                         }\r
292                 }\r
293         }\r
294         \r
295         // Check if the executable has no base or it is not free\r
296         if(base == 0)\r
297         {\r
298                 // If so, give it a base\r
299                 base = BIN_HIGHEST;\r
300                 while(base >= BIN_LOWEST)\r
301                 {\r
302                         for(i=0;i<binary->NumPages;i++)\r
303                         {\r
304                                 addr = binary->Pages[i].Virtual & ~0xFFF;\r
305                                 addr -= binary->Base;\r
306                                 addr += base;\r
307                                 if( MM_GetPhysAddr( addr ) )    break;\r
308                         }\r
309                         // If space was found, break\r
310                         if(i == binary->NumPages)               break;\r
311                         // Else decrement pointer and try again\r
312                         base -= BIN_GRANUALITY;\r
313                 }\r
314         }\r
315         \r
316         // Error Check\r
317         if(base < BIN_LOWEST) {\r
318                 Warning("[BIN ] Executable '%s' cannot be loaded, no space", binary->TruePath);\r
319                 return 0;\r
320         }\r
321         \r
322         // Map Executable In\r
323         for(i=0;i<binary->NumPages;i++)\r
324         {\r
325                 addr = binary->Pages[i].Virtual & ~0xFFF;\r
326                 addr -= binary->Base;\r
327                 addr += base;\r
328                 LOG("%i - 0x%x to 0x%x", i, addr, binary->Pages[i].Physical);\r
329                 MM_Map( addr, (Uint) (binary->Pages[i].Physical) );\r
330                 \r
331                 // Read-Only?\r
332                 if( binary->Pages[i].Flags & BIN_PAGEFLAG_RO)\r
333                         MM_SetFlags( addr, MM_PFLAG_RO, -1 );\r
334                 else\r
335                         MM_SetFlags( addr, MM_PFLAG_COW, -1 );\r
336                 \r
337                 // Execute?\r
338                 if( binary->Pages[i].Flags & BIN_PAGEFLAG_EXEC )\r
339                         MM_SetFlags( addr, MM_PFLAG_EXEC, -1 );\r
340                 else\r
341                         MM_SetFlags( addr, MM_PFLAG_EXEC, 0 );\r
342                 \r
343         }\r
344         \r
345         //Log("Mapped '%s' to 0x%x", binary->TruePath, base);\r
346         \r
347         //LOG("*0x%x = 0x%x\n", binary->Pages[0].Virtual, *(Uint*)binary->Pages[0].Virtual);\r
348         \r
349         return base;\r
350 }\r
351 \r
352 #if 0\r
353 /**\r
354  * \fn Uint Binary_IsMapped(tBinary *binary)\r
355  * \brief Check if a binary is already mapped into the address space\r
356  * \param binary        Binary information to check\r
357  * \return Current Base or 0\r
358  */\r
359 Uint Binary_IsMapped(tBinary *binary)\r
360 {\r
361         Uint    iBase;\r
362         \r
363         // Check prefered base\r
364         iBase = binary->Base;\r
365         if(MM_GetPage( iBase ) == (binary->Pages[0].Physical & ~0xFFF))\r
366                 return iBase;\r
367         \r
368         for(iBase = BIN_HIGHEST;\r
369                 iBase >= BIN_LOWEST;\r
370                 iBase -= BIN_GRANUALITY)\r
371         {\r
372                 if(MM_GetPage( iBase ) == (binary->Pages[0].Physical & ~0xFFF))\r
373                         return iBase;\r
374         }\r
375         \r
376         return 0;\r
377 }\r
378 #endif\r
379 \r
380 /**\r
381  * \fn tBinary *Binary_DoLoad(char *truePath)\r
382  * \brief Loads a binary file into memory\r
383  * \param truePath      Absolute filename of binary\r
384  */\r
385 tBinary *Binary_DoLoad(char *truePath)\r
386 {\r
387         tBinary *pBinary;\r
388          int    fp, i;\r
389         Uint    ident;\r
390         tBinaryType     *bt = gRegBinTypes;\r
391         \r
392         ENTER("struePath", truePath);\r
393         \r
394         // Open File\r
395         fp = VFS_Open(truePath, VFS_OPENFLAG_READ);\r
396         if(fp == -1) {\r
397                 LOG("Unable to load file, access denied");\r
398                 LEAVE('n');\r
399                 return NULL;\r
400         }\r
401         \r
402         // Read File Type\r
403         VFS_Read(fp, 4, &ident);\r
404         VFS_Seek(fp, 0, SEEK_SET);\r
405         \r
406         for(; bt; bt = bt->Next)\r
407         {\r
408                 if( (ident & bt->Mask) != (Uint)bt->Ident )\r
409                         continue;\r
410                 pBinary = bt->Load(fp);\r
411                 break;\r
412         }\r
413         if(!bt) {\r
414                 Warning("[BIN ] '%s' is an unknown file type. (0x%x 0x%x 0x%x 0x%x)",\r
415                         truePath, ident&0xFF, (ident>>8)&0xFF, (ident>>16)&0xFF, (ident>>24)&0xFF);\r
416                 LEAVE('n');\r
417                 return NULL;\r
418         }\r
419         \r
420         // Error Check\r
421         if(pBinary == NULL) {\r
422                 LEAVE('n');\r
423                 return NULL;\r
424         }\r
425         \r
426         // Initialise Structure\r
427         pBinary->ReferenceCount = 0;\r
428         pBinary->TruePath = malloc( strlen(truePath) + 1 );\r
429         strcpy(pBinary->TruePath, truePath);\r
430         \r
431         // Debug Information\r
432         LOG("Interpreter: '%s'", pBinary->Interpreter);\r
433         LOG("Base: 0x%x, Entry: 0x%x", pBinary->Base, pBinary->Entry);\r
434         LOG("NumPages: %i", pBinary->NumPages);\r
435         \r
436         // Read Data\r
437         for(i=0;i<pBinary->NumPages;i++)\r
438         {\r
439                 Uint    dest;\r
440                 tPAddr  paddr;\r
441                 paddr = (Uint)MM_AllocPhys();\r
442                 if(paddr == 0) {\r
443                         Warning("Binary_DoLoad - Physical memory allocation failed");\r
444                         for( ; i--; ) {\r
445                                 MM_DerefPhys( pBinary->Pages[i].Physical );\r
446                         }\r
447                         return NULL;\r
448                 }\r
449                 MM_RefPhys( paddr );    // Make sure it is _NOT_ freed until we want it to be\r
450                 dest = MM_MapTemp( paddr );\r
451                 dest += pBinary->Pages[i].Virtual & 0xFFF;\r
452                 LOG("dest = 0x%x, paddr = 0x%x", dest, paddr);\r
453                 LOG("Pages[%i]={Physical:0x%llx,Virtual:%p,Size:0x%x}",\r
454                         i, pBinary->Pages[i].Physical, pBinary->Pages[i].Virtual, pBinary->Pages[i].Size);\r
455                 \r
456                 // Pure Empty Page\r
457                 if(pBinary->Pages[i].Physical == -1) {\r
458                         LOG("%i - ZERO", i);\r
459                         memsetd( (void*)dest, 0, 1024 - (pBinary->Pages[i].Virtual & 0xFFF)/4 );\r
460                 }\r
461                 else\r
462                 {\r
463                         VFS_Seek( fp, pBinary->Pages[i].Physical, 1 );\r
464                         if(pBinary->Pages[i].Size != 0x1000) {\r
465                                 LOG("%i - 0x%llx - 0x%x bytes",\r
466                                         i, pBinary->Pages[i].Physical, pBinary->Pages[i].Size);\r
467                                 memset( (void*)dest, 0, 0x1000 -(dest&0xFFF) );\r
468                                 VFS_Read( fp, pBinary->Pages[i].Size, (void*)dest );\r
469                         } else {\r
470                                 LOG("%i - 0x%x", i, pBinary->Pages[i].Physical);\r
471                                 VFS_Read( fp, 0x1000, (void*)dest );\r
472                         }\r
473                 }\r
474                 pBinary->Pages[i].Physical = paddr;\r
475                 MM_FreeTemp( dest );\r
476         }\r
477         LOG("Page Count: %i", pBinary->NumPages);\r
478         \r
479         // Close File\r
480         VFS_Close(fp);\r
481         \r
482         // Add to the list\r
483         LOCK(&glBinListLock);\r
484         pBinary->Next = glLoadedBinaries;\r
485         glLoadedBinaries = pBinary;\r
486         RELEASE(&glBinListLock);\r
487         \r
488         // Return\r
489         LEAVE('p', pBinary);\r
490         return pBinary;\r
491 }\r
492 \r
493 /**\r
494  * \fn void Binary_Unload(void *Base)\r
495  * \brief Unload / Unmap a binary\r
496  * \param Base  Loaded Base\r
497  * \note Currently used only for kernel libaries\r
498  */\r
499 void Binary_Unload(void *Base)\r
500 {\r
501         tKernelBin      *pKBin;\r
502         tKernelBin      *prev = NULL;\r
503          int    i;\r
504         \r
505         if((Uint)Base < 0xC0000000)\r
506         {\r
507                 // TODO: User Binaries\r
508                 Warning("[BIN ] Unloading user binaries is currently unimplemented");\r
509                 return;\r
510         }\r
511         \r
512         // Kernel Libraries\r
513         for(pKBin = glLoadedKernelLibs;\r
514                 pKBin;\r
515                 prev = pKBin, pKBin = pKBin->Next)\r
516         {\r
517                 // Check the base\r
518                 if(pKBin->Base != Base) continue;\r
519                 // Deallocate Memory\r
520                 for(i = 0; i < pKBin->Info->NumPages; i++) {\r
521                         MM_Deallocate( (Uint)Base + (i << 12) );\r
522                 }\r
523                 // Dereference Binary\r
524                 Binary_Dereference( pKBin->Info );\r
525                 // Remove from list\r
526                 if(prev)        prev->Next = pKBin->Next;\r
527                 else            glLoadedKernelLibs = pKBin->Next;\r
528                 // Free Kernel Lib\r
529                 free(pKBin);\r
530                 return;\r
531         }\r
532 }\r
533 \r
534 /**\r
535  * \fn void Binary_Dereference(tBinary *Info)\r
536  * \brief Dereferences and if nessasary, deletes a binary\r
537  * \param Info  Binary information structure\r
538  */\r
539 void Binary_Dereference(tBinary *Info)\r
540 {\r
541         // Decrement reference count\r
542         Info->ReferenceCount --;\r
543         \r
544         // Check if it is still in use\r
545         if(Info->ReferenceCount)        return;\r
546         \r
547         /// \todo Implement binary freeing\r
548 }\r
549 \r
550 /**\r
551  \fn char *Binary_RegInterp(char *path)\r
552  \brief Registers an Interpreter\r
553  \param path    Path to interpreter provided by executable\r
554 */\r
555 char *Binary_RegInterp(char *path)\r
556 {\r
557          int    i;\r
558         // NULL Check Argument\r
559         if(path == NULL)        return NULL;\r
560         // NULL Check the array\r
561         if(gsaRegInterps == NULL)\r
562         {\r
563                 giRegInterps = 1;\r
564                 gsaRegInterps = malloc( sizeof(char*) );\r
565                 gsaRegInterps[0] = malloc( strlen(path) );\r
566                 strcpy(gsaRegInterps[0], path);\r
567                 return gsaRegInterps[0];\r
568         }\r
569         \r
570         // Scan Array\r
571         for( i = 0; i < giRegInterps; i++ )\r
572         {\r
573                 if(strcmp(gsaRegInterps[i], path) == 0)\r
574                         return gsaRegInterps[i];\r
575         }\r
576         \r
577         // Interpreter is not in list\r
578         giRegInterps ++;\r
579         gsaRegInterps = malloc( sizeof(char*)*giRegInterps );\r
580         gsaRegInterps[i] = malloc( strlen(path) );\r
581         strcpy(gsaRegInterps[i], path);\r
582         return gsaRegInterps[i];\r
583 }\r
584 \r
585 // ============\r
586 // Kernel Binary Handling\r
587 // ============\r
588 /**\r
589  * \fn void *Binary_LoadKernel(char *path)\r
590  * \brief Load a binary into kernel space\r
591  * \note This function shares much with #Binary_Load, but does it's own mapping\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_GetSymbolBin(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