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

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