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

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