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

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