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

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