Changed the x86 architecture to have tPAddr be 64-bits always
[tpg/acess2.git] / Kernel / system.c
1 /*
2  * Acess 2
3  * Architecture Independent System Init
4  * system.c
5  */
6 #define DEBUG   1
7 #include <common.h>
8
9 // === TYPES ===
10 typedef struct
11 {
12          int    TrueLine;
13          int    nParts;
14         char    **Parts;
15 }       tConfigLine;
16 typedef struct
17 {
18          int    nLines;
19         tConfigLine     Lines[];
20 }       tConfigFile;
21
22 // === IMPORTS ===
23 extern int      Modules_LoadBuiltins();
24 extern int      PCI_Install();
25 extern void     DMA_Install();
26 extern void     Debug_SetKTerminal(char *File);
27 extern void     StartupPrint(char *Str);
28
29 // === PROTOTYPES ===
30 void    System_Init(char *ArgString);
31 void    System_ParseCommandLine(char *ArgString);
32 void    System_ParseVFS(char *Arg);
33 void    System_ParseSetting(char *Arg);
34 void    System_ExecuteScript();
35 tConfigFile     *System_Int_ParseFile(char *File);
36
37 // === GLOBALS ===
38 char    *gsConfigScript = "/Acess/Conf/BootConf.cfg";
39
40 // === CODE ===
41 void System_Init(char *ArgString)
42 {
43         // - Start Builtin Drivers & Filesystems
44         StartupPrint("Scanning PCI Bus...");
45         PCI_Install();
46         StartupPrint("Loading DMA...");
47         DMA_Install();
48         StartupPrint("Loading staticly compiled modules...");
49         Modules_LoadBuiltins();
50         
51         // Set the debug to be echoed to the terminal
52         StartupPrint("Kernel now echoes to VT6 (Ctrl-Alt-F7)");
53         Debug_SetKTerminal("/Devices/VTerm/6");
54         
55         // - Parse Kernel's Command Line
56         System_ParseCommandLine(ArgString);
57         
58         // - Execute the Config Script
59         Log("Executing config script...");
60         System_ExecuteScript();
61 }
62
63 /**
64  * \fn void System_ParseCommandLine(char *ArgString)
65  * \brief Parses the kernel's command line and sets the environment
66  */
67 void System_ParseCommandLine(char *ArgString)
68 {
69         char    *argv[32];
70          int    argc;
71          int    i;
72         char    *str;
73         
74         Log("Kernel Command Line: \"%s\"", ArgString);
75         
76         // --- Get Arguments ---
77         str = ArgString;
78         for( argc = 0; argc < 32; argc++ )
79         {
80                 while(*str == ' ')      str++;  // Eat Whitespace
81                 if(*str == '\0') {      argc--; break;} // End of string
82                 argv[argc] = str;
83                 while(*str && *str != ' ')
84                 {
85                         /*if(*str == '"') {
86                                 while(*str && !(*str == '"' && str[-1] != '\\'))
87                                         str ++;
88                         }*/
89                         str++;
90                 }
91                 if(*str == '\0')        break;  // End of string
92                 *str = '\0';    // Cap off argument string
93                 str ++; // and increment the string pointer
94         }
95         if(argc < 32)
96                 argc ++;        // Count last argument
97         
98         // --- Parse Arguments ---
99         for( i = 1; i < argc; i++ )
100         {
101                 if( argv[i][0] == '/' )
102                         System_ParseVFS( argv[i] );
103                 else
104                         System_ParseSetting( argv[i] );
105         }
106 }
107
108 /**
109  * \fn void System_ParseVFS(char *Arg)
110  */
111 void System_ParseVFS(char *Arg)
112 {
113         char    *value;
114          int    fd;
115         
116         value = Arg;
117         // Search for the '=' token
118         while( *value && *value != '=' )
119                 value++;
120         
121         // Check if the equals was found
122         if( *value == '\0' ) {
123                 Warning("Expected '=' in the string '%s'", Arg);
124                 return ;
125         }
126         
127         // Edit string
128         *value = '\0';  value ++;
129         
130         // Check assignment type
131         // - Symbolic Link <link>=<destination>
132         if(value[0] == '/')
133         {
134                 Log("Symbolic link '%s' pointing to '%s'", Arg, value);
135                 VFS_Symlink(Arg, value);
136         }
137         // - Mount <mountpoint>=<fs>:<device>
138         else
139         {
140                 char    *dev = value;
141                 // Find colon
142                 while(*dev && *dev != ':')      dev++;
143                 if(*dev) {
144                         *dev = '\0';
145                         dev++;  // Eat ':'
146                 }
147                 // Create Mountpoint
148                 if( (fd = VFS_Open(Arg, 0)) == -1 ) {
149                         Log("Creating directory '%s'", Arg, value);
150                         VFS_MkDir( Arg );
151                 } else {
152                         VFS_Close(fd);
153                 }
154                 // Mount
155                 Log("Mounting '%s' to '%s' ('%s')", dev, Arg, value);
156                 VFS_Mount(dev, Arg, value, "");
157         }
158 }
159
160 /**
161  * \fn void System_ParseSetting(char *Arg)
162  */
163 void System_ParseSetting(char *Arg)
164 {
165         char    *value;
166         value = Arg;
167
168         // Search for the '=' token
169         while( *value && *value != '=' )
170                 value++;
171         
172         // Check for boolean/flag (no '=')
173         if(*value == '\0')
174         {
175                 if(strcmp(Arg, "") == 0) {
176                 } else {
177                         Warning("Kernel flag '%s' is not recognised", Arg);
178                 }
179         }
180         else
181         {
182                 *value = '\0';  // Remove '='
183                 value ++;       // and eat it's position
184                 
185                 if(strcmp(Arg, "SCRIPT") == 0) {
186                         Log("Config Script: '%s'", value);
187                         gsConfigScript = value;
188                 } else {
189                         Warning("Kernel config setting '%s' is not recognised", Arg);
190                 }
191                 
192         }
193 }
194
195 /**
196  * \fn void System_ExecuteScript()
197  */
198 void System_ExecuteScript()
199 {
200          int    fp;
201          int    fLen = 0;
202          int    i;
203         char    *fData;
204         tConfigFile     *file;
205         tConfigLine     *line;
206         
207         // Open Script
208         fp = VFS_Open(gsConfigScript, VFS_OPENFLAG_READ);
209         if(fp == -1) {
210                 Warning("[CFG] Passed script '%s' does not exist", gsConfigScript);
211                 return;
212         }
213         
214         // Read into memory buffer
215         VFS_Seek(fp, 0, SEEK_END);
216         fLen = VFS_Tell(fp);
217         VFS_Seek(fp, 0, SEEK_SET);
218         fData = malloc(fLen+1);
219         VFS_Read(fp, fLen, fData);
220         fData[fLen] = '\0';
221         VFS_Close(fp);
222         
223         
224         
225         // Parse File
226         file = System_Int_ParseFile(fData);
227         
228         // Loop lines
229         for( i = 0; i < file->nLines; i++ )
230         {
231                 line = &file->Lines[i];
232                 if( line->nParts == 0 ) continue;       // Skip blank
233                 
234                 // Mount
235                 if( strcmp(line->Parts[0], "mount") == 0 ) {
236                         if( line->nParts != 4 ) {
237                                 Warning("Configuration command 'mount' requires 3 arguments, %i given",
238                                         line->nParts-1);
239                                 continue;
240                         }
241                         //Log("[CFG ] Mount '%s' to '%s' (%s)",
242                         //      line->Parts[1], line->Parts[2], line->Parts[3]);
243                         //! \todo Use an optional 4th argument for the options string
244                         VFS_Mount(line->Parts[1], line->Parts[2], line->Parts[3], "");
245                 }
246                 // Module
247                 else if(strcmp(line->Parts[0], "module") == 0) {
248                         if( line->nParts < 2 || line->nParts > 3 ) {
249                                 Warning("Configuration command 'module' requires 1 or 2 arguments, %i given",
250                                         line->nParts-1);
251                                 continue;
252                         }
253                         if( line->nParts == 3 )
254                                 Module_LoadFile(line->Parts[1], line->Parts[2]);
255                         else
256                                 Module_LoadFile(line->Parts[1], "");
257                 }
258                 // UDI Module
259                 else if(strcmp(line->Parts[0], "udimod") == 0) {
260                         if( line->nParts != 2 ) {
261                                 Warning("Configuration command 'udimod' requires 1 argument, %i given",
262                                         line->nParts-1);
263                                 continue;
264                         }
265                         Log("[CFG  ] Load UDI Module '%s'", line->Parts[1]);
266                         Module_LoadFile(line->Parts[1], "");
267                 }
268                 // EDI Module
269                 else if(strcmp(line->Parts[0], "edimod") == 0) {
270                         if( line->nParts != 2 ) {
271                                 Warning("Configuration command 'edimod' requires 1 argument, %i given",
272                                         line->nParts-1);
273                                 continue;
274                         }
275                         Log("[CFG  ] Load EDI Module '%s'", line->Parts[1]);
276                         Module_LoadFile(line->Parts[1], "");
277                 }
278                 // Symbolic Link
279                 else if(strcmp(line->Parts[0], "symlink") == 0) {
280                         if( line->nParts != 3 ) {
281                                 Warning("Configuration command 'symlink' requires 2 arguments, %i given",
282                                         line->nParts-1);
283                                 continue;
284                         }
285                         Log("[CFG  ] Symlink '%s' pointing to '%s'",
286                                 line->Parts[1], line->Parts[2]);
287                         VFS_Symlink(line->Parts[1], line->Parts[2]);
288                 }
289                 // Create Directory
290                 else if(strcmp(line->Parts[0], "mkdir") == 0) {
291                         if( line->nParts != 2 ) {
292                                 Warning("Configuration command 'mkdir' requires 1 argument, %i given",
293                                         line->nParts-1);
294                                 continue;
295                         }
296                         Log("[CFG  ] New Directory '%s'", line->Parts[1]);
297                         VFS_MkDir(line->Parts[1]);
298                 }
299                 // Spawn a process
300                 else if(strcmp(line->Parts[0], "spawn") == 0) {
301                         if( line->nParts != 2 ) {
302                                 Warning("Configuration command 'spawn' requires 1 argument, %i given",
303                                         line->nParts-1);
304                                 continue;
305                         }
306                         Log("[CFG  ] Starting '%s' as a new task", line->Parts[1]);
307                         Proc_Spawn(line->Parts[1]);
308                 }
309                 else {
310                         Warning("Unknown configuration command '%s' on line %i",
311                                 line->Parts[0],
312                                 line->TrueLine
313                                 );
314                 }
315         }
316         
317         // Clean up after ourselves
318         for( i = 0; i < file->nLines; i++ ) {
319                 if( file->Lines[i].nParts == 0 )        continue;       // Skip blank
320                 free( file->Lines[i].Parts );
321         }
322         free( file );
323         free( fData );
324 }
325
326 /**
327  * \brief Parses a config file
328  * \param FileData      Read/Write buffer containing the config file data
329  *                  (will be modified)
330  * \return ::tConfigFile structure that represents the original contents
331  *         of \a FileData
332  */
333 tConfigFile     *System_Int_ParseFile(char *FileData)
334 {
335         char    *ptr;
336         char    *start;
337          int    nLines = 1;
338          int    i, j;
339         tConfigFile     *ret;
340         
341         ENTER("pFileData", FileData);
342         
343         // Prescan and count the number of lines
344         for(ptr = FileData; *ptr; ptr++)
345         {               
346                 if(*ptr != '\n')        continue;
347                 
348                 if(ptr == FileData) {
349                         nLines ++;
350                         continue;
351                 }
352                 
353                 // Escaped EOL
354                 if(ptr[-1] == '\\')     continue;
355                 
356                 nLines ++;
357         }
358         
359         LOG("nLines = %i", nLines);
360         
361         // Ok so we have `nLines` lines, now to allocate our return
362         ret = malloc( sizeof(tConfigFile) + sizeof(tConfigLine)*nLines );
363         ret->nLines = nLines;
364         
365         // Read the file for real
366         for(
367                 ptr = FileData, i = 0;
368                 *ptr;
369                 i++
370                 )
371         {
372                 start = ptr;
373                 
374                 ret->Lines[i].nParts = 0;
375                 
376                 // Count parts
377                 for(;;)
378                 {
379                         // Read leading whitespace
380                         while( *ptr == '\t' || *ptr == ' ' )    ptr++;
381                         
382                         // End of line/file
383                         if( *ptr == '\0' || *ptr == '\n' ) {
384                                 if(*ptr == '\n')        ptr ++;
385                                 break;
386                         }
387                         // Comment
388                         if( *ptr == '#' || *ptr == ';' ) {
389                                 while( *ptr && *ptr != '\n' )   ptr ++;
390                                 if(*ptr == '\n')        ptr ++;
391                                 break;
392                         }
393                         
394                         ret->Lines[i].nParts ++;
395                         // Quoted
396                         if( *ptr == '"' ) {
397                                 ptr ++;
398                                 while( *ptr && !(*ptr == '"' && ptr[-1] == '\\') && *ptr != '\n' )
399                                         ptr++;
400                                 continue;
401                         }
402                         // Unquoted
403                         while( *ptr && !(*ptr == '\t' || *ptr == ' ') && *ptr != '\n' )
404                                 ptr++;
405                 }
406                 
407                 LOG("ret->Lines[%i].nParts = %i", i, ret->Lines[i].nParts);
408                 
409                 if( ret->Lines[i].nParts == 0 ) {
410                         ret->Lines[i].Parts = NULL;
411                         continue;
412                 }
413                 
414                 // Allocate part list
415                 ret->Lines[i].Parts = malloc( sizeof(char*) * ret->Lines[i].nParts );
416                 
417                 // Fill list
418                 for( ptr = start, j = 0; ; j++ )
419                 {
420                         // Read leading whitespace
421                         while( *ptr == '\t' || *ptr == ' ' )    ptr++;
422                         
423                         // End of line/file
424                         if( *ptr == '\0' || *ptr == '\n' ) {
425                                 if(*ptr == '\n')        ptr ++;
426                                 break;
427                         }
428                         // Comment
429                         if( *ptr == '#' || *ptr == ';' ) {
430                                 while( *ptr && *ptr != '\n' )   ptr ++;
431                                 if(*ptr == '\n')        ptr ++;
432                                 break;
433                         }
434                         
435                         ret->Lines[i].Parts[j] = ptr;
436                         
437                         // Quoted
438                         if( *ptr == '"' ) {
439                                 ptr ++;
440                                 while( *ptr && !(*ptr == '"' && ptr[-1] == '\\') && *ptr != '\n' )
441                                         ptr++;
442                         }
443                         // Unquoted
444                         else {
445                                 while( *ptr != '\t' && *ptr != ' ' && *ptr != '\n' )
446                                         ptr++;
447                         }
448                         
449                         // Break if we have reached NULL
450                         if( *ptr == '\0' ) {
451                                 LOG("ret->Lines[%i].Parts[%i] = '%s'", i, j, ret->Lines[i].Parts[j]);
452                                 break;
453                         }
454                         if( *ptr == '\n' ) {
455                                 *ptr = '\0';
456                                 LOG("ret->Lines[%i].Parts[%i] = '%s'", i, j, ret->Lines[i].Parts[j]);
457                                 ptr ++;
458                                 break;
459                         }
460                         *ptr = '\0';    // Cap off string
461                         LOG("ret->Lines[%i].Parts[%i] = '%s'", i, j, ret->Lines[i].Parts[j]);
462                         ptr ++; // And increment for the next round
463                 }
464         }
465         
466         LEAVE('p', ret);
467         return ret;
468 }

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