Updating drivers to use the Log_ functions instead of Log() and Warning()
[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         
140         // Remove from loading list
141         gLoadingModules = gLoadingModules->Next;
142         
143         // Add to loaded list
144         LOCK( &glModuleSpinlock );
145         Module->Next = gLoadedModules;
146         gLoadedModules = Module;
147         RELEASE( &glModuleSpinlock );
148         
149         LEAVE_RET('i', 0);
150 }
151
152 /**
153  * \brief Initialises builtin modules
154  */
155 int Modules_LoadBuiltins()
156 {
157          int    i;
158         
159         // Count modules
160         giNumBuiltinModules = (Uint)&gKernelModulesEnd - (Uint)&gKernelModules;
161         giNumBuiltinModules /= sizeof(tModule);
162         
163         for( i = 0; i < giNumBuiltinModules; i++ )
164         {
165                 Module_int_Initialise( &gKernelModules[i] );
166         }
167         
168         return 0;
169 }
170
171 /**
172  * \brief Registers a tModuleLoader with the kernel
173  * \param Loader        Pointer to loader structure (must be persistent)
174  */
175 int Module_RegisterLoader(tModuleLoader *Loader)
176 {
177         if(!Loader)     return 1;
178         
179         Loader->Next = gModule_Loaders;
180         gModule_Loaders = Loader;
181         
182         return 0;
183 }
184
185 /**
186  * \fn int Module_LoadMem(void *Buffer, Uint Length, char *ArgString)
187  * \brief Load a module from a memory location
188  */
189 int Module_LoadMem(void *Buffer, Uint Length, char *ArgString)
190 {
191         char    path[VFS_MEMPATH_SIZE];
192         
193         VFS_GetMemPath(path, Buffer, Length);
194         
195         return Module_LoadFile( path, ArgString );
196 }
197
198 /**
199  * \fn int Module_LoadFile(char *Path, char *ArgString)
200  * \brief Load a module from a file
201  */
202 int Module_LoadFile(char *Path, char *ArgString)
203 {
204         void    *base;
205         tModule *info;
206         
207         // Load Binary
208         base = Binary_LoadKernel(Path);
209         
210         // Error check
211         if(base == NULL) {
212                 Log_Warning("Module", "Module_LoadFile - Unable to load '%s'", Path);
213                 return 0;
214         }
215         
216         // Check for Acess Driver
217         if( Binary_FindSymbol(base, "DriverInfo", (Uint*)&info ) == 0 )
218         {
219                 tModuleLoader   *tmp;
220                 for( tmp = gModule_Loaders; tmp; tmp = tmp->Next)
221                 {
222                         if( tmp->Detector(base) == 0 )  continue;
223                         
224                         return tmp->Loader(base);
225                 }
226                 
227                 #if USE_EDI
228                 // Check for EDI Driver
229                 if( Binary_FindSymbol(base, "driver_init", NULL ) != 0 )
230                 {
231                         return Module_InitEDI( base );  // And intialise
232                 }
233                 #endif
234                 
235                 // Unknown module type?, return error
236                 Binary_Unload(base);
237                 #if USE_EDI
238                 Log_Warning("Module", "Module '%s' has neither a Module Info struct, nor an EDI entrypoint", Path);
239                 #else
240                 Log_Warning("Module", "Module '%s' does not have a Module Info struct", Path);
241                 #endif
242                 return 0;
243         }
244         
245         // Check magic number
246         if(info->Magic != MODULE_MAGIC)
247         {
248                 Log_Warning("Module", "Module's magic value is invalid (0x%x != 0x%x)", info->Magic, MODULE_MAGIC);
249                 return 0;
250         }
251         
252         // Check Architecture
253         if(info->Arch != MODULE_ARCH_ID)
254         {
255                 Log_Warning("Module", "Module is for a different architecture");
256                 return 0;
257         }
258         
259         #if 1
260         if( Module_int_Initialise( info ) )
261         {
262                 Binary_Unload(base);
263                 return 0;
264         }
265         #else
266         // Resolve Dependencies
267         if( !Module_int_ResolveDeps(info) ) {
268                 Binary_Unload(base);
269                 return 0;
270         }
271         
272         Log_Log("Module", "Initialising %p '%s' v%i.%i...",
273                                 info,
274                                 info->Name,
275                                 info->Version>>8, info->Version & 0xFF
276                                 );
277         
278         // Call Initialiser
279         //if( info->Init( ArgString ) != 0 )
280         if( info->Init( NULL ) == 0 )
281         {
282                 Binary_Unload(base);
283                 return 0;
284         }
285         
286         // Add to list
287         LOCK( &glModuleSpinlock );
288         info->Next = gLoadedModules;
289         gLoadedModules = info;
290         RELEASE( &glModuleSpinlock );
291         #endif
292         
293         return 1;
294 }
295
296 /**
297  * \fn int Module_int_ResolveDeps(tModule *Info)
298  * \brief Resolves the dependencies
299  * \todo Implement
300  * \note Currently does not resolve the dependencies, just checks them
301  */
302 int Module_int_ResolveDeps(tModule *Info)
303 {
304         char    **names = Info->Dependencies;
305         
306         // Walk dependencies array
307         for( ; *names; names++ )
308         {
309                 // Check if the module is loaded
310                 if( !Module_IsLoaded(*names) ) {
311                         Log_Warning("Module", "Module `%s' requires `%s', which is not loaded\n", Info->Name, *names);
312                         return 0;
313                 }
314         }
315         return 1;
316 }
317
318 /**
319  * \fn int Module_IsLoaded(char *Name)
320  * \brief Checks if a module is loaded
321  * \param Name  Name of module to find
322  */
323 int Module_IsLoaded(char *Name)
324 {
325         tModule *mod = gLoadedModules;
326         
327         // Scan loaded list
328         for( ; mod; mod = mod->Next )
329         {
330                 // If found, return true
331                 if(strcmp(mod->Name, Name) == 0)
332                         return 1;
333         }
334         // not found - return false
335         return 0;
336 }

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