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

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