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

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