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

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