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

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