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

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