Kernel - Implementing SysSpawn
[tpg/acess2.git] / Kernel / binary.c
1 /*
2  * Acess2
3  * Common Binary Loader
4  */
5 #define DEBUG   0
6 #include <acess.h>
7 #include <binary.h>
8 #include <mm_virt.h>
9 #include <hal_proc.h>
10 #include <vfs_threads.h>
11
12 // === CONSTANTS ===
13 #define BIN_LOWEST      MM_USER_MIN             // 1MiB
14 #define BIN_GRANUALITY  0x10000         // 64KiB
15 #define BIN_HIGHEST     (USER_LIB_MAX-BIN_GRANUALITY)           // Just below the kernel
16 #define KLIB_LOWEST     MM_MODULE_MIN
17 #define KLIB_GRANUALITY 0x10000         // 32KiB
18 #define KLIB_HIGHEST    (MM_MODULE_MAX-KLIB_GRANUALITY)
19
20 // === TYPES ===
21 typedef struct sKernelBin {
22         struct sKernelBin       *Next;
23         void    *Base;
24         tBinary *Info;
25 } tKernelBin;
26
27 // === IMPORTS ===
28 extern char     *Threads_GetName(int ID);
29 extern tKernelSymbol    gKernelSymbols[];
30 extern tKernelSymbol    gKernelSymbolsEnd[];
31 extern tBinaryType      gELF_Info;
32
33 // === PROTOTYPES ===
34  int    Binary_int_CacheArgs(const char **Path, const char ***ArgV, const char ***EnvP, void *DestBuffer);
35 tVAddr  Binary_Load(const char *Path, tVAddr *EntryPoint);
36 tBinary *Binary_GetInfo(tMount MountID, tInode InodeID);
37 tVAddr  Binary_MapIn(tBinary *Binary, const char *Path, tVAddr LoadMin, tVAddr LoadMax);
38 tVAddr  Binary_IsMapped(tBinary *Binary);
39 tBinary *Binary_DoLoad(tMount MountID, tInode Inode, const char *Path);
40 void    Binary_Dereference(tBinary *Info);
41 #if 0
42 Uint    Binary_Relocate(void *Base);
43 #endif
44 Uint    Binary_GetSymbolEx(const char *Name, Uint *Value);
45 #if 0
46 Uint    Binary_FindSymbol(void *Base, const char *Name, Uint *Val);
47 #endif
48  int    Binary_int_CheckMemFree( tVAddr _start, size_t _len );
49
50 // === GLOBALS ===
51 tShortSpinlock  glBinListLock;
52 tBinary *glLoadedBinaries = NULL;
53 char    **gsaRegInterps = NULL;
54  int    giRegInterps = 0;
55 tShortSpinlock  glKBinListLock;
56 tKernelBin      *glLoadedKernelLibs;
57 tBinaryType     *gRegBinTypes = &gELF_Info;
58  
59 // === FUNCTIONS ===
60 /**
61  * \brief Registers a binary type
62  */
63 int Binary_RegisterType(tBinaryType *Type)
64 {
65         Type->Next = gRegBinTypes;
66         gRegBinTypes = Type;
67         return 1;
68 }
69
70 /**
71  * \fn int Proc_Spawn(const char *Path)
72  */
73 int Proc_Spawn(const char *Path)
74 {
75         char    stackPath[strlen(Path)+1];
76         ENTER("sPath", Path);
77         
78         strcpy(stackPath, Path);
79         
80         LOG("stackPath = '%s'", stackPath);
81         
82         if(Proc_Clone(CLONE_VM|CLONE_NOUSER) == 0)
83         {
84                 // CHILD
85                 const char      *args[2] = {stackPath, NULL};
86                 LOG("stackPath = '%s'", stackPath);
87                 Proc_Execve(stackPath, args, &args[1], 0);
88                 for(;;);
89         }
90         LEAVE('i', 0);
91         return 0;
92 }
93
94 /**
95  * \todo Document
96  */
97 int Binary_int_CacheArgs(const char **Path, const char ***ArgV, const char ***EnvP, void *DestBuffer)
98 {
99          int    size, argc=0, envc=0;
100          int    i;
101         char    *strbuf;
102         const char      **arrays;
103         
104         // Calculate size
105         size = 0;
106         if( ArgV && *ArgV )
107         {
108                 const char      **argv = *ArgV;
109                 for( argc = 0; argv[argc]; argc ++ )
110                         size += strlen( argv[argc] ) + 1;
111         }
112         if( EnvP && *EnvP )
113         {
114                 const char      **envp = *EnvP;
115                 for( envc = 0; envp[envc]; envc ++ )
116                         size += strlen( envp[envc] ) + 1;
117         }
118         size = (size + sizeof(void*)-1) & ~(sizeof(void*)-1);   // Word align
119         size += (argc+1+envc+1)*sizeof(void*);  // Arrays
120         if( Path )
121         {
122                 size += strlen( *Path ) + 1;
123         }
124
125         if( DestBuffer )        
126         {
127                 arrays = DestBuffer;
128                 strbuf = (void*)&arrays[argc+1+envc+1];
129         
130                 // Fill ArgV
131                 if( ArgV && *ArgV )
132                 {
133                         const char      **argv = *ArgV;
134                         for( i = 0; argv[i]; i ++ )
135                         {
136                                 arrays[i] = strbuf;
137                                 strcpy(strbuf, argv[i]);
138                                 strbuf += strlen( argv[i] ) + 1;
139                         }
140                         *ArgV = arrays;
141                         arrays += i;
142                 }
143                 *arrays++ = NULL;
144                 // Fill EnvP
145                 if( EnvP && *EnvP )
146                 {
147                         const char      **envp = *EnvP;
148                         for( i = 0; envp[i]; i ++ )
149                         {
150                                 arrays[i] = strbuf;
151                                 strcpy(strbuf, envp[i]);
152                                 strbuf += strlen( envp[i] ) + 1;
153                         }
154                         *EnvP = arrays;
155                         arrays += i;
156                 }
157                 *arrays++ = NULL;
158                 // Fill path
159                 if( Path )
160                 {
161                         strcpy(strbuf, *Path);
162                         *Path = strbuf;
163                 }
164         }
165         
166         return size;
167 }
168
169 /**
170  * \brief Create a new process with the specified set of file descriptors
171  */
172 int Proc_SysSpawn(const char *Binary, const char **ArgV, const char **EnvP, int nFD, int *FDs)
173 {
174         void    *handles;
175         void    *cachebuf;
176          int    size;
177         tPID    ret;
178         
179         // --- Save File, ArgV and EnvP
180         size = Binary_int_CacheArgs( &Binary, &ArgV, &EnvP, NULL );
181         cachebuf = alloca( size );
182         Binary_int_CacheArgs( &Binary, &ArgV, &EnvP, cachebuf );
183
184         // Cache the VFS handles        
185         handles = VFS_SaveHandles(nFD, FDs);
186
187         // Create new process   
188         ret = Proc_Clone(CLONE_VM|CLONE_NOUSER);
189         if( ret == 0 )
190         {
191                 VFS_RestoreHandles(nFD, handles);
192                 VFS_FreeSavedHandles(nFD, handles);
193                 Proc_Execve(Binary, ArgV, EnvP, size);
194                 for(;;);
195         }
196         if( ret < 0 )
197         {
198                 VFS_FreeSavedHandles(nFD, handles);
199         }
200         
201         return ret;
202 }
203
204 /**
205  * \brief Replace the current user image with another
206  * \param File  File to load as the next image
207  * \param ArgV  Arguments to pass to user
208  * \param EnvP  User's environment
209  * \note Called Proc_ for historical reasons
210  */
211 int Proc_Execve(const char *File, const char **ArgV, const char **EnvP, int DataSize)
212 {
213         void    *cachebuf;
214         tVAddr  entry;
215         Uint    base;   // Uint because Proc_StartUser wants it
216          int    argc;
217         
218         ENTER("sFile pArgV pEnvP", File, ArgV, EnvP);
219         
220         // --- Save File, ArgV and EnvP
221         if( DataSize == 0 )
222         {
223                 DataSize = Binary_int_CacheArgs( &File, &ArgV, &EnvP, NULL );
224                 cachebuf = malloc( DataSize );
225                 Binary_int_CacheArgs( &File, &ArgV, &EnvP, cachebuf );
226         }
227
228         // --- Get argc 
229         for( argc = 0; ArgV && ArgV[argc]; argc ++ );
230         
231         // --- Set Process Name
232         Threads_SetName(File);
233         
234         // --- Clear User Address space
235         MM_ClearUser();
236         
237         // --- Load new binary
238         base = Binary_Load(File, &entry);
239         if(base == 0)
240         {
241                 Log_Warning("Binary", "Proc_Execve - Unable to load '%s'", File);
242                 LEAVE('-');
243                 Threads_Exit(0, -10);
244                 for(;;);
245         }
246         
247         LOG("entry = 0x%x, base = 0x%x", entry, base);
248         LEAVE('-');
249         // --- And... Jump to it
250         Proc_StartUser(entry, base, argc, ArgV, DataSize);
251         for(;;);        // Tell GCC that we never return
252 }
253
254 /**
255  * \brief Load a binary into the current address space
256  * \param Path  Path to binary to load
257  * \param EntryPoint    Pointer for exectuable entry point
258  * \return Virtual address where the binary has been loaded
259  */
260 tVAddr Binary_Load(const char *Path, tVAddr *EntryPoint)
261 {
262         tMount  mount_id;
263         tInode  inode;
264         tBinary *pBinary;
265         tVAddr  base = -1;
266
267         ENTER("sPath pEntryPoint", Path, EntryPoint);
268         
269         // Sanity Check Argument
270         if(Path == NULL) {
271                 LEAVE('x', 0);
272                 return 0;
273         }
274
275         // Check if this path has been loaded before.
276         #if 0
277         // TODO: Implement a list of string/tBinary pairs for loaded bins
278         #endif
279
280         // Get Inode
281         {
282                 int fd;
283                 tFInfo  info;
284                 fd = VFS_Open(Path, VFS_OPENFLAG_READ|VFS_OPENFLAG_EXEC);
285                 if( fd == -1 ) {
286                         LOG("%s does not exist", Path);
287                         LEAVE_RET('x', 0);
288                 }
289                 VFS_FInfo(fd, &info, 0);
290                 VFS_Close(fd);
291                 mount_id = info.mount;
292                 inode = info.inode;
293                 LOG("mount_id = %i, inode = %i", mount_id, inode);
294         }
295
296         // TODO: Also get modifcation time?
297
298         // Check if the binary has already been loaded
299         if( !(pBinary = Binary_GetInfo(mount_id, inode)) )
300                 pBinary = Binary_DoLoad(mount_id, inode, Path); // Else load it
301         
302         // Error Check
303         if(pBinary == NULL) {
304                 LEAVE('x', 0);
305                 return 0;
306         }
307         
308         // Map into process space
309         base = Binary_MapIn(pBinary, Path, BIN_LOWEST, BIN_HIGHEST);
310         
311         // Check for errors
312         if(base == 0) {
313                 LEAVE('x', 0);
314                 return 0;
315         }
316         
317         // Interpret
318         if(pBinary->Interpreter) {
319                 tVAddr  start;
320                 if( Binary_Load(pBinary->Interpreter, &start) == 0 ) {
321                         LEAVE('x', 0);
322                         return 0;
323                 }
324                 *EntryPoint = start;
325         }
326         else
327                 *EntryPoint = pBinary->Entry - pBinary->Base + base;
328         
329         // Return
330         LOG("*EntryPoint = 0x%x", *EntryPoint);
331         LEAVE('x', base);
332         return base;    // Pass the base as an argument to the user if there is an interpreter
333 }
334
335 /**
336  * \brief Finds a matching binary entry
337  * \param MountID       Mountpoint ID of binary file
338  * \param InodeID       Inode ID of the file
339  * \return Pointer to the binary definition (if already loaded)
340  */
341 tBinary *Binary_GetInfo(tMount MountID, tInode InodeID)
342 {
343         tBinary *pBinary;
344         for(pBinary = glLoadedBinaries; pBinary; pBinary = pBinary->Next)
345         {
346                 if(pBinary->MountID == MountID && pBinary->Inode == InodeID)
347                         return pBinary;
348         }
349         return NULL;
350 }
351
352 /**
353  * \brief Maps an already-loaded binary into an address space.
354  * \param Binary        Pointer to globally stored binary definition
355  * \param Path  Path to the binary's file (for debug)
356  * \param LoadMin       Lowest location to map to
357  * \param LoadMax       Highest location to map to
358  * \return Base load address
359  */
360 tVAddr Binary_MapIn(tBinary *Binary, const char *Path, tVAddr LoadMin, tVAddr LoadMax)
361 {
362         tVAddr  base;
363          int    i, fd;
364
365         ENTER("pBinary sPath pLoadMin pLoadMax", Binary, Path, LoadMin, LoadMax);
366
367         // Reference Executable (Makes sure that it isn't unloaded)
368         Binary->ReferenceCount ++;
369         
370         // Get Binary Base
371         base = Binary->Base;
372         
373         // Check if base is free
374         if(base != 0)
375         {
376                 LOG("Checking base %p", base);
377                 for( i = 0; i < Binary->NumSections; i ++ )
378                 {
379                         if( Binary_int_CheckMemFree( Binary->LoadSections[i].Virtual, Binary->LoadSections[i].MemSize ) )
380                         {
381                                 base = 0;
382                                 LOG("Address 0x%x is taken\n", Binary->LoadSections[i].Virtual);
383                                 break;
384                         }
385                 }
386         }
387         
388         // Check if the executable has no base or it is not free
389         if(base == 0)
390         {
391                 // If so, give it a base
392                 base = LoadMax;
393                 while(base >= LoadMin)
394                 {
395                         for( i = 0; i < Binary->NumSections; i ++ )
396                         {
397                                 tVAddr  addr = Binary->LoadSections[i].Virtual - Binary->Base + base;
398                                 if( Binary_int_CheckMemFree( addr, Binary->LoadSections[i].MemSize ) )
399                                         break;
400                         }
401                         // If space was found, break
402                         if(i == Binary->NumSections)            break;
403                         // Else decrement pointer and try again
404                         base -= BIN_GRANUALITY;
405                 }
406                 LOG("Allocated base %p", base);
407         }
408         
409         // Error Check
410         if(base < LoadMin) {
411                 Log_Warning("Binary", "Executable '%s' cannot be loaded, no space", Path);
412                 LEAVE('i', 0);
413                 return 0;
414         }
415         
416         // Map Executable In
417         fd = VFS_OpenInode(Binary->MountID, Binary->Inode, VFS_OPENFLAG_READ);
418         for( i = 0; i < Binary->NumSections; i ++ )
419         {
420                 tBinarySection  *sect = &Binary->LoadSections[i];
421                 Uint    protflags, mapflags;
422                 tVAddr  addr = sect->Virtual - Binary->Base + base;
423                 LOG("%i - %p to offset 0x%llx (%x)", i, addr, sect->Offset, sect->Flags);
424
425                 protflags = MMAP_PROT_READ;
426                 mapflags = MMAP_MAP_FIXED;
427
428                 if( sect->Flags & BIN_SECTFLAG_EXEC )
429                         protflags |= MMAP_PROT_EXEC;
430                 // Read only pages are COW
431                 if( sect->Flags & BIN_SECTFLAG_RO  ) {
432                         VFS_MMap( (void*)addr, sect->FileSize, protflags, MMAP_MAP_SHARED|mapflags, fd, sect->Offset );
433                 }
434                 else {
435                         protflags |= MMAP_PROT_WRITE;
436                         VFS_MMap( (void*)addr, sect->FileSize, protflags, MMAP_MAP_PRIVATE|mapflags, fd, sect->Offset );
437                 }
438                 
439                 // Apply anonymous memory for BSS
440                 if( sect->FileSize < sect->MemSize ) {
441                         mapflags |= MMAP_MAP_ANONYMOUS;
442                         VFS_MMap(
443                                 (void*)(addr + sect->FileSize), sect->MemSize - sect->FileSize,
444                                 protflags, MMAP_MAP_PRIVATE|mapflags,
445                                 0, 0
446                                 );
447                 }
448         }
449         
450         Log_Debug("Binary", "PID %i - Mapped '%s' to %p", Threads_GetPID(), Path, base);
451         VFS_Close(fd);
452         
453         LEAVE('p', base);
454         return base;
455 }
456
457 #if 0
458 /**
459  * \fn Uint Binary_IsMapped(tBinary *binary)
460  * \brief Check if a binary is already mapped into the address space
461  * \param binary        Binary information to check
462  * \return Current Base or 0
463  */
464 Uint Binary_IsMapped(tBinary *binary)
465 {
466         Uint    iBase;
467         
468         // Check prefered base
469         iBase = binary->Base;
470         if(MM_GetPage( iBase ) == (binary->Pages[0].Physical & ~0xFFF))
471                 return iBase;
472         
473         for(iBase = BIN_HIGHEST;
474                 iBase >= BIN_LOWEST;
475                 iBase -= BIN_GRANUALITY)
476         {
477                 if(MM_GetPage( iBase ) == (binary->Pages[0].Physical & ~0xFFF))
478                         return iBase;
479         }
480         
481         return 0;
482 }
483 #endif
484
485 /**
486  * \fn tBinary *Binary_DoLoad(char *truePath)
487  * \brief Loads a binary file into memory
488  * \param truePath      Absolute filename of binary
489  */
490 tBinary *Binary_DoLoad(tMount MountID, tInode Inode, const char *Path)
491 {
492         tBinary *pBinary;
493          int    fp;
494         Uint32  ident;
495         tBinaryType     *bt = gRegBinTypes;
496         
497         ENTER("iMountID XInode sPath", MountID, Inode, Path);
498         
499         // Open File
500         fp = VFS_OpenInode(MountID, Inode, VFS_OPENFLAG_READ);
501         if(fp == -1) {
502                 LOG("Unable to load file, access denied");
503                 LEAVE('n');
504                 return NULL;
505         }
506
507         LOG("fp = 0x%x", fp);
508         
509         // Read File Type
510         VFS_Read(fp, 4, &ident);
511         VFS_Seek(fp, 0, SEEK_SET);
512
513         LOG("ident = 0x%x", ident);
514
515         // Determine the type   
516         for(; bt; bt = bt->Next)
517         {
518                 if( (ident & bt->Mask) != (Uint32)bt->Ident )
519                         continue;
520                 LOG("bt = %p (%s)", bt, bt->Name);
521                 pBinary = bt->Load(fp);
522                 break;
523         }
524
525         // Close File
526         VFS_Close(fp);
527         
528         // Catch errors
529         if(!bt) {
530                 Log_Warning("Binary", "'%s' is an unknown file type. (%02x %02x %02x %02x)",
531                         Path, ident&0xFF, (ident>>8)&0xFF, (ident>>16)&0xFF, (ident>>24)&0xFF);
532                 LEAVE('n');
533                 return NULL;
534         }
535         
536         LOG("pBinary = %p", pBinary);
537         
538         // Error Check
539         if(pBinary == NULL) {
540                 LEAVE('n');
541                 return NULL;
542         }
543         
544         // Initialise Structure
545         pBinary->ReferenceCount = 0;
546         pBinary->MountID = MountID;
547         pBinary->Inode = Inode;
548         
549         // Debug Information
550         LOG("Interpreter: '%s'", pBinary->Interpreter);
551         LOG("Base: 0x%x, Entry: 0x%x", pBinary->Base, pBinary->Entry);
552         LOG("NumSections: %i", pBinary->NumSections);
553         
554         // Add to the list
555         SHORTLOCK(&glBinListLock);
556         pBinary->Next = glLoadedBinaries;
557         glLoadedBinaries = pBinary;
558         SHORTREL(&glBinListLock);
559
560         // TODO: Register the path with the binary      
561
562         // Return
563         LEAVE('p', pBinary);
564         return pBinary;
565 }
566
567 /**
568  * \fn void Binary_Unload(void *Base)
569  * \brief Unload / Unmap a binary
570  * \param Base  Loaded Base
571  * \note Currently used only for kernel libaries
572  */
573 void Binary_Unload(void *Base)
574 {
575         tKernelBin      *pKBin;
576         tKernelBin      *prev = NULL;
577          int    i;
578         
579         if((Uint)Base < 0xC0000000)
580         {
581                 // TODO: User Binaries
582                 Log_Warning("BIN", "Unloading user binaries is currently unimplemented");
583                 return;
584         }
585         
586         // Kernel Libraries
587         for(pKBin = glLoadedKernelLibs;
588                 pKBin;
589                 prev = pKBin, pKBin = pKBin->Next)
590         {
591                 // Check the base
592                 if(pKBin->Base != Base) continue;
593                 // Deallocate Memory
594                 for(i = 0; i < pKBin->Info->NumSections; i++)
595                 {
596                         // TODO: VFS_MUnmap();
597                 }
598                 // Dereference Binary
599                 Binary_Dereference( pKBin->Info );
600                 // Remove from list
601                 if(prev)        prev->Next = pKBin->Next;
602                 else            glLoadedKernelLibs = pKBin->Next;
603                 // Free Kernel Lib
604                 free(pKBin);
605                 return;
606         }
607 }
608
609 /**
610  * \fn void Binary_Dereference(tBinary *Info)
611  * \brief Dereferences and if nessasary, deletes a binary
612  * \param Info  Binary information structure
613  */
614 void Binary_Dereference(tBinary *Info)
615 {
616         // Decrement reference count
617         Info->ReferenceCount --;
618         
619         // Check if it is still in use
620         if(Info->ReferenceCount)        return;
621         
622         /// \todo Implement binary freeing
623 }
624
625 /**
626  * \fn char *Binary_RegInterp(char *Path)
627  * \brief Registers an Interpreter
628  * \param Path  Path to interpreter provided by executable
629  */
630 char *Binary_RegInterp(char *Path)
631 {
632          int    i;
633         // NULL Check Argument
634         if(Path == NULL)        return NULL;
635         // NULL Check the array
636         if(gsaRegInterps == NULL)
637         {
638                 giRegInterps = 1;
639                 gsaRegInterps = malloc( sizeof(char*) );
640                 gsaRegInterps[0] = malloc( strlen(Path) );
641                 strcpy(gsaRegInterps[0], Path);
642                 return gsaRegInterps[0];
643         }
644         
645         // Scan Array
646         for( i = 0; i < giRegInterps; i++ )
647         {
648                 if(strcmp(gsaRegInterps[i], Path) == 0)
649                         return gsaRegInterps[i];
650         }
651         
652         // Interpreter is not in list
653         giRegInterps ++;
654         gsaRegInterps = malloc( sizeof(char*)*giRegInterps );
655         gsaRegInterps[i] = malloc( strlen(Path) );
656         strcpy(gsaRegInterps[i], Path);
657         return gsaRegInterps[i];
658 }
659
660 // ============
661 // Kernel Binary Handling
662 // ============
663 /**
664  * \fn void *Binary_LoadKernel(const char *File)
665  * \brief Load a binary into kernel space
666  * \note This function shares much with #Binary_Load, but does it's own mapping
667  * \param File  File to load into the kernel
668  */
669 void *Binary_LoadKernel(const char *File)
670 {
671         tBinary *pBinary;
672         tKernelBin      *pKBinary;
673         tVAddr  base = -1;
674         tMount  mount_id;
675         tInode  inode;
676
677         ENTER("sFile", File);
678         
679         // Sanity Check Argument
680         if(File == NULL) {
681                 LEAVE('n');
682                 return 0;
683         }
684
685         {
686                 int fd = VFS_Open(File, VFS_OPENFLAG_READ);
687                 tFInfo  info;
688                 if(fd == -1) {
689                         LEAVE('n');
690                         return NULL;
691                 }
692                 VFS_FInfo(fd, &info, 0);
693                 mount_id = info.mount;
694                 inode = info.inode;
695                 VFS_Close(fd);
696         }
697         
698         // Check if the binary has already been loaded
699         if( (pBinary = Binary_GetInfo(mount_id, inode)) )
700         {
701                 for(pKBinary = glLoadedKernelLibs;
702                         pKBinary;
703                         pKBinary = pKBinary->Next )
704                 {
705                         if(pKBinary->Info == pBinary) {
706                                 LEAVE('p', pKBinary->Base);
707                                 return pKBinary->Base;
708                         }
709                 }
710         }
711         else
712                 pBinary = Binary_DoLoad(mount_id, inode, File); // Else load it
713         
714         // Error Check
715         if(pBinary == NULL) {
716                 LEAVE('n');
717                 return NULL;
718         }
719         
720         // --------------
721         // Now pBinary is valid (either freshly loaded or only user mapped)
722         // So, map it into kernel space
723         // --------------
724         
725         // Reference Executable (Makes sure that it isn't unloaded)
726         pBinary->ReferenceCount ++;
727
728         Binary_MapIn(pBinary, File, KLIB_LOWEST, KLIB_HIGHEST);
729
730         // Relocate Library
731         if( !Binary_Relocate( (void*)base ) )
732         {
733                 Log_Warning("Binary", "Relocation of '%s' failed, unloading", File);
734                 Binary_Unload( (void*)base );
735                 Binary_Dereference( pBinary );
736                 LEAVE('n');
737                 return 0;
738         }
739         
740         // Add to list (relocator must look at itself manually, not via Binary_GetSymbol)
741         pKBinary = malloc(sizeof(*pKBinary));
742         pKBinary->Base = (void*)base;
743         pKBinary->Info = pBinary;
744         SHORTLOCK( &glKBinListLock );
745         pKBinary->Next = glLoadedKernelLibs;
746         glLoadedKernelLibs = pKBinary;
747         SHORTREL( &glKBinListLock );
748         
749         LEAVE('p', base);
750         return (void*)base;
751 }
752
753 /**
754  * \fn Uint Binary_Relocate(void *Base)
755  * \brief Relocates a loaded binary (used by kernel libraries)
756  * \param Base  Loaded base address of binary
757  * \return Boolean Success
758  */
759 Uint Binary_Relocate(void *Base)
760 {
761         Uint32  ident = *(Uint32*) Base;
762         tBinaryType     *bt = gRegBinTypes;
763         
764         for(; bt; bt = bt->Next)
765         {
766                 if( (ident & bt->Mask) == (Uint)bt->Ident )
767                         return bt->Relocate( (void*)Base);
768         }
769         
770         Log_Warning("BIN", "%p is an unknown file type. (%02x %02x %02x %02x)",
771                 Base, ident&0xFF, (ident>>8)&0xFF, (ident>>16)&0xFF, (ident>>24)&0xFF);
772         return 0;
773 }
774
775 /**
776  * \fn int Binary_GetSymbol(char *Name, Uint *Val)
777  * \brief Get a symbol value
778  * \return Value of symbol or -1 on error
779  * 
780  * Gets the value of a symbol from either the currently loaded
781  * libraries or the kernel's exports.
782  */
783 int Binary_GetSymbol(const char *Name, Uint *Val)
784 {
785         if( Binary_GetSymbolEx(Name, Val) )     return 1;
786         return 0;
787 }
788
789 /**
790  * \fn Uint Binary_GetSymbolEx(char *Name, Uint *Value)
791  * \brief Get a symbol value
792  * 
793  * Gets the value of a symbol from either the currently loaded
794  * libraries or the kernel's exports.
795  */
796 Uint Binary_GetSymbolEx(const char *Name, Uint *Value)
797 {
798          int    i;
799         tKernelBin      *pKBin;
800          int    numKSyms = ((Uint)&gKernelSymbolsEnd-(Uint)&gKernelSymbols)/sizeof(tKernelSymbol);
801         
802         // Scan Kernel
803         for( i = 0; i < numKSyms; i++ )
804         {
805                 if(strcmp(Name, gKernelSymbols[i].Name) == 0) {
806                         *Value = gKernelSymbols[i].Value;
807                         return 1;
808                 }
809         }
810         
811         // Scan Loaded Libraries
812         for(pKBin = glLoadedKernelLibs;
813                 pKBin;
814                 pKBin = pKBin->Next )
815         {
816                 if( Binary_FindSymbol(pKBin->Base, Name, Value) ) {
817                         return 1;
818                 }
819         }
820         
821         Log_Warning("BIN", "Unable to find symbol '%s'", Name);
822         return 0;
823 }
824
825 /**
826  * \fn Uint Binary_FindSymbol(void *Base, char *Name, Uint *Val)
827  * \brief Get a symbol from the specified library
828  * \param Base  Base address
829  * \param Name  Name of symbol to find
830  * \param Val   Pointer to place final value
831  */
832 Uint Binary_FindSymbol(void *Base, const char *Name, Uint *Val)
833 {
834         Uint32  ident = *(Uint32*) Base;
835         tBinaryType     *bt = gRegBinTypes;
836         
837         for(; bt; bt = bt->Next)
838         {
839                 if( (ident & bt->Mask) == (Uint)bt->Ident )
840                         return bt->GetSymbol(Base, Name, Val);
841         }
842         
843         Log_Warning("BIN", "Binary_FindSymbol - %p is an unknown file type. (%02x %02x %02x %02x)",
844                 Base, ident&0xFF, ident>>8, ident>>16, ident>>24);
845         return 0;
846 }
847
848 /**
849  * \brief Check if a range of memory is fully free
850  * \return Inverse boolean free (0 if all pages are unmapped)
851  */
852 int Binary_int_CheckMemFree( tVAddr _start, size_t _len )
853 {
854         _len += _start & (PAGE_SIZE-1);
855         _len = (_len + PAGE_SIZE - 1) & ~(PAGE_SIZE-1);
856         _start &= ~(PAGE_SIZE-1);
857         for( ; _len > PAGE_SIZE; _len -= PAGE_SIZE, _start += PAGE_SIZE ) {
858                 if( MM_GetPhysAddr(_start) != 0 )
859                         return 1;
860         }
861         if( _len == PAGE_SIZE && MM_GetPhysAddr(_start) != 0 )
862                 return 1;
863         return 0;
864 }
865
866
867 // === EXPORTS ===
868 EXPORT(Binary_FindSymbol);
869 EXPORT(Binary_Unload);

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