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

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