Random fixes, disabled debug in vterm, random crash disappeared, also doing fixes...
[tpg/acess2.git] / Kernel / modules.c
1 /*
2  * Acess2
3  * - Module Loader
4  */
5 #define DEBUG   0
6 #include <acess.h>
7 #include <modules.h>
8
9 #define USE_EDI 0
10 #define USE_UDI 0
11
12 // === PROTOTYPES ===
13  int    Modules_LoadBuiltins(void);
14  int    Module_RegisterLoader(tModuleLoader *Loader);
15  int    Module_LoadMem(void *Buffer, Uint Length, char *ArgString);
16  int    Module_LoadFile(char *Path, char *ArgString);
17  int    Module_int_ResolveDeps(tModule *Info);
18  int    Module_IsLoaded(char *Name);
19
20 // === EXPORTS ===
21 EXPORT(Module_RegisterLoader);
22
23 // === IMPORTS ===
24 #if USE_UDI
25 extern int      UDI_LoadDriver(void *Base);
26 #endif
27 extern void     StartupPrint(char *Str);
28 extern tModule  gKernelModules[];
29 extern void     gKernelModulesEnd;
30
31 // === GLOBALS ===
32  int    giNumBuiltinModules = 0;
33 tSpinlock       glModuleSpinlock;
34 tModule *gLoadedModules = NULL;
35 tModuleLoader   *gModule_Loaders = NULL;
36 tModule *gLoadingModules = NULL;
37
38 // === CODE ===
39 /**
40  * \brief Initialises a module
41  * \param Module        Pointer to the module header
42  * \return Zero on success, eModuleErrors or -1 on error
43  * \retval -1   Returned if a dependency fails, or a circular dependency
44  *              exists.
45  * \retval 0    Returned on success
46  * \retval >0   Error code form the module's initialisation function
47  */
48 int Module_int_Initialise(tModule *Module)
49 {
50          int    i, j;
51          int    ret;
52         char    **deps;
53         tModule *mod;
54         
55         ENTER("pModule", Module);
56         
57         deps = Module->Dependencies;
58         
59         // Check if the module has been loaded
60         for( mod = gLoadedModules; mod; mod = mod->Next )
61         {
62                 if(mod == Module)       LEAVE_RET('i', 0);
63         }
64         
65         // Add to the "loading" (prevents circular deps)
66         Module->Next = gLoadingModules;
67         gLoadingModules = Module;
68         
69         // Scan dependency list
70         for( j = 0; deps && deps[j]; j++ )
71         {
72                 // Check if the module is already loaded
73                 for( mod = gLoadedModules; mod; mod = mod->Next )
74                 {
75                         if(strcmp(deps[j], mod->Name) == 0)
76                                 break;
77                 }
78                 if( mod )       continue;       // Dependency is loaded, check the rest
79                 
80                 // Ok, check if it's loading
81                 for( mod = gLoadingModules->Next; mod; mod = mod->Next )
82                 {
83                         if(strcmp(deps[j], mod->Name) == 0)
84                                 break;
85                 }
86                 if( mod ) {
87                         Log_Warning("Module", "Circular dependency detected");
88                         LEAVE_RET('i', -1);
89                 }
90                 
91                 // So, if it's not loaded, we better load it then
92                 for( i = 0; i < giNumBuiltinModules; i ++ )
93                 {
94                         if( strcmp(deps[j], gKernelModules[i].Name) == 0 )
95                                 break;
96                 }
97                 if( i == giNumBuiltinModules ) {
98                         Log_Warning("Module", "Dependency '%s' for module '%s' failed");
99                         return -1;
100                 }
101                 
102                 // Dependency is not loaded, so load it
103                 ret = Module_int_Initialise( &gKernelModules[i] );
104                 if( ret )
105                 {
106                         // The only "ok" error is NOTNEEDED
107                         if(ret != MODULE_ERR_NOTNEEDED)
108                                 LEAVE_RET('i', -1);
109                 }
110         }
111         
112         // All Dependencies OK? Initialise
113         StartupPrint(Module->Name);
114         Log_Log("Module", "Initialising %p '%s' v%i.%i...",
115                 Module, Module->Name,
116                 Module->Version >> 8, Module->Version & 0xFF
117                 );
118         
119         ret = Module->Init(NULL);
120         if( ret != MODULE_ERR_OK ) {
121                 switch(ret)
122                 {
123                 case MODULE_ERR_MISC:
124                         Log_Warning("Module", "Unable to load, reason: Miscelanious");
125                         break;
126                 case MODULE_ERR_NOTNEEDED:
127                         Log_Warning("Module", "Unable to load, reason: Module not needed");
128                         break;
129                 case MODULE_ERR_MALLOC:
130                         Log_Warning("Module", "Unable to load, reason: Error in malloc/realloc/calloc, probably not good");
131                         break;
132                 default:
133                         Log_Warning("Module", "Unable to load reason - Unknown code %i", ret);
134                         break;
135                 }
136                 LEAVE_RET('i', ret);
137                 return ret;
138         }
139         LOG("ret = %i", ret);
140         
141         // Remove from loading list
142         gLoadingModules = gLoadingModules->Next;
143         
144         // Add to loaded list
145         LOCK( &glModuleSpinlock );
146         Module->Next = gLoadedModules;
147         gLoadedModules = Module;
148         RELEASE( &glModuleSpinlock );
149         
150         LEAVE_RET('i', 0);
151 }
152
153 /**
154  * \brief Initialises builtin modules
155  */
156 int Modules_LoadBuiltins()
157 {
158          int    i;
159         
160         // Count modules
161         giNumBuiltinModules = (Uint)&gKernelModulesEnd - (Uint)&gKernelModules;
162         giNumBuiltinModules /= sizeof(tModule);
163         
164         for( i = 0; i < giNumBuiltinModules; i++ )
165         {
166                 Module_int_Initialise( &gKernelModules[i] );
167         }
168         
169         return 0;
170 }
171
172 /**
173  * \brief Registers a tModuleLoader with the kernel
174  * \param Loader        Pointer to loader structure (must be persistent)
175  */
176 int Module_RegisterLoader(tModuleLoader *Loader)
177 {
178         if(!Loader)     return 1;
179         
180         Loader->Next = gModule_Loaders;
181         gModule_Loaders = Loader;
182         
183         return 0;
184 }
185
186 /**
187  * \fn int Module_LoadMem(void *Buffer, Uint Length, char *ArgString)
188  * \brief Load a module from a memory location
189  */
190 int Module_LoadMem(void *Buffer, Uint Length, char *ArgString)
191 {
192         char    path[VFS_MEMPATH_SIZE];
193         
194         VFS_GetMemPath(path, Buffer, Length);
195         
196         return Module_LoadFile( path, ArgString );
197 }
198
199 /**
200  * \fn int Module_LoadFile(char *Path, char *ArgString)
201  * \brief Load a module from a file
202  */
203 int Module_LoadFile(char *Path, char *ArgString)
204 {
205         void    *base;
206         tModule *info;
207         
208         // Load Binary
209         base = Binary_LoadKernel(Path);
210         
211         // Error check
212         if(base == NULL) {
213                 Log_Warning("Module", "Module_LoadFile - Unable to load '%s'", Path);
214                 return 0;
215         }
216         
217         // Check for Acess Driver
218         if( Binary_FindSymbol(base, "DriverInfo", (Uint*)&info ) == 0 )
219         {
220                 tModuleLoader   *tmp;
221                 for( tmp = gModule_Loaders; tmp; tmp = tmp->Next)
222                 {
223                         if( tmp->Detector(base) == 0 )  continue;
224                         
225                         return tmp->Loader(base);
226                 }
227                 
228                 #if USE_EDI
229                 // Check for EDI Driver
230                 if( Binary_FindSymbol(base, "driver_init", NULL ) != 0 )
231                 {
232                         return Module_InitEDI( base );  // And intialise
233                 }
234                 #endif
235                 
236                 // Unknown module type?, return error
237                 Binary_Unload(base);
238                 #if USE_EDI
239                 Log_Warning("Module", "Module '%s' has neither a Module Info struct, nor an EDI entrypoint", Path);
240                 #else
241                 Log_Warning("Module", "Module '%s' does not have a Module Info struct", Path);
242                 #endif
243                 return 0;
244         }
245         
246         // Check magic number
247         if(info->Magic != MODULE_MAGIC)
248         {
249                 Log_Warning("Module", "Module's magic value is invalid (0x%x != 0x%x)", info->Magic, MODULE_MAGIC);
250                 return 0;
251         }
252         
253         // Check Architecture
254         if(info->Arch != MODULE_ARCH_ID)
255         {
256                 Log_Warning("Module", "Module is for a different architecture");
257                 return 0;
258         }
259         
260         #if 1
261         if( Module_int_Initialise( info ) )
262         {
263                 Binary_Unload(base);
264                 return 0;
265         }
266         #else
267         // Resolve Dependencies
268         if( !Module_int_ResolveDeps(info) ) {
269                 Binary_Unload(base);
270                 return 0;
271         }
272         
273         Log_Log("Module", "Initialising %p '%s' v%i.%i...",
274                                 info,
275                                 info->Name,
276                                 info->Version>>8, info->Version & 0xFF
277                                 );
278         
279         // Call Initialiser
280         //if( info->Init( ArgString ) != 0 )
281         if( info->Init( NULL ) == 0 )
282         {
283                 Binary_Unload(base);
284                 return 0;
285         }
286         
287         // Add to list
288         LOCK( &glModuleSpinlock );
289         info->Next = gLoadedModules;
290         gLoadedModules = info;
291         RELEASE( &glModuleSpinlock );
292         #endif
293         
294         return 1;
295 }
296
297 /**
298  * \fn int Module_int_ResolveDeps(tModule *Info)
299  * \brief Resolves the dependencies
300  * \todo Implement
301  * \note Currently does not resolve the dependencies, just checks them
302  */
303 int Module_int_ResolveDeps(tModule *Info)
304 {
305         char    **names = Info->Dependencies;
306         
307         // Walk dependencies array
308         for( ; *names; names++ )
309         {
310                 // Check if the module is loaded
311                 if( !Module_IsLoaded(*names) ) {
312                         Log_Warning("Module", "Module `%s' requires `%s', which is not loaded\n", Info->Name, *names);
313                         return 0;
314                 }
315         }
316         return 1;
317 }
318
319 /**
320  * \fn int Module_IsLoaded(char *Name)
321  * \brief Checks if a module is loaded
322  * \param Name  Name of module to find
323  */
324 int Module_IsLoaded(char *Name)
325 {
326         tModule *mod = gLoadedModules;
327         
328         // Scan loaded list
329         for( ; mod; mod = mod->Next )
330         {
331                 // If found, return true
332                 if(strcmp(mod->Name, Name) == 0)
333                         return 1;
334         }
335         // not found - return false
336         return 0;
337 }

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