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

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