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

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