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

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