Kernel - TODO: Kernel-mode shell
[tpg/acess2.git] / KernelLand / Kernel / system.c
1 /*
2  * Acess 2 Kernel
3  * - By John Hodge (thePowersGang)
4  * system.c
5  * - Architecture Independent System Init
6  */
7 #define DEBUG   1
8 #include <acess.h>
9 #include <hal_proc.h>
10
11 // === IMPORTS ===
12 extern void     Arch_LoadBootModules(void);
13 extern int      Modules_LoadBuiltins(void);
14 extern void     Modules_SetBuiltinParams(char *Name, char *ArgString);
15 extern void     Debug_SetKTerminal(const char *File);
16 extern void     Timer_CallbackThread(void *);
17
18 // === PROTOTYPES ===
19 void    System_Init(char *Commandline);
20 void    System_ParseCommandLine(char *ArgString);
21 void    System_ExecuteCommandLine(void);
22 void    System_ParseVFS(char *Arg);
23 void    System_ParseModuleArgs(char *Arg);
24 void    System_ParseSetting(char *Arg);
25 void    System_EmergencyConsole(void);
26
27 // === GLOBALS ===
28 const char      *gsInitBinary = "/Acess/SBin/init";
29 char    *argv[32];
30  int    argc;
31
32 // === CODE ===
33 void System_Init(char *CommandLine)
34 {
35         Proc_SpawnWorker(Timer_CallbackThread, NULL);
36
37         // Parse Kernel's Command Line
38         System_ParseCommandLine(CommandLine);
39         
40         // Initialise modules
41         Log_Log("Config", "Initialising builtin modules...");
42         Modules_LoadBuiltins();
43         Arch_LoadBootModules();
44         
45         Log_Log("Config", "Running command line '%s", CommandLine);
46         System_ExecuteCommandLine();
47         
48         // - Execute the Config Script
49         Log_Log("Config", "Spawning init '%s'", gsInitBinary);
50         if(Proc_Clone(CLONE_VM|CLONE_NOUSER) == 0)
51         {
52                 const char      *args[] = {gsInitBinary, 0};
53                 VFS_Open("/Devices/pts/vt0", VFS_OPENFLAG_READ|VFS_OPENFLAG_USER);      // 0: stdin
54                 VFS_Open("/Devices/pts/vt0", VFS_OPENFLAG_WRITE|VFS_OPENFLAG_USER);     // 1: stdout
55                 VFS_DuplicateFD(1, 2);  // 2: stderr
56                 Proc_Execve(gsInitBinary, args, &args[1], 0);
57                 
58                 System_EmergencyConsole();
59                 
60                 Log_KernelPanic("System", "Unable to spawn init '%s'", gsInitBinary);
61         }
62         
63         // Set the debug to be echoed to the terminal
64         Log_Log("Config", "Kernel now echoes to VT7 (Ctrl-Alt-F8)");
65         Debug_SetKTerminal("/Devices/pts/vt7");
66         
67         // Run a thread to reap unowned threads
68         for( ;; )
69         {
70                  int    status;
71                 // TODO: Inform init when a thread dies
72                 int tid = Threads_WaitTID(-1, &status);
73                 Log_Debug("Thread0", "Thread %i exited with status %i", tid, status);
74         }
75 }
76
77 /**
78  * \fn void System_ParseCommandLine(char *ArgString)
79  * \brief Parses the kernel's command line and sets the environment
80  */
81 void System_ParseCommandLine(char *ArgString)
82 {
83          int    i;
84         char    *str;
85         
86         Log_Log("Config", "Kernel Invocation (%p) \"%s\"", ArgString, ArgString);
87         
88         // --- Get Arguments ---
89         str = ArgString;
90         for( argc = 0; argc < 32; argc++ )
91         {
92                 // Eat Whitespace
93                 while(*str == ' ')      str++;
94                 // Check for the end of the string
95                 if(*str == '\0') {
96                         argc--;
97                         break;
98                 }
99                 argv[argc] = str;
100                 if(*str == '"') {
101                         while(*str && !(*str == '"' && str[-1] != '\\'))
102                                 str ++;
103                 }
104                 else {
105                         while(*str && *str != ' ')
106                                 str++;
107                 }
108                 if(*str == '\0')        break;  // Check for EOS
109                 *str = '\0';    // Cap off argument string
110                 str ++; // and increment the string pointer
111         }
112         if(argc < 32)
113                 argc ++;        // Count last argument
114         
115         // --- Parse Arguments (Pass 1) ---
116         for( i = 1; i < argc; i++ )
117         {
118                 switch(argv[i][0])
119                 {
120                 // --- VFS ---
121                 // Ignored on this pass
122                 case '/':
123                         break;
124                 
125                 // --- Module Paramaters ---
126                 // -VTerm:Width=640,Height=480,Scrollback=2
127                 case '-':
128                         System_ParseModuleArgs( argv[i] );
129                         break;
130                 // --- Config Options ---
131                 // SCRIPT=/Acess/Conf/BootConf.cfg
132                 default:
133                         System_ParseSetting( argv[i] );
134                         break;
135                 }
136         }
137 }
138
139 void System_ExecuteCommandLine(void)
140 {
141          int    i;
142         if(argc > 0)
143                 LOG("Invocation '%s'", argv[0]);
144         for( i = 1; i < argc; i++ )
145         {
146                 LOG("argv[%i] = '%s'", i, argv[i]);
147                 switch(argv[i][0])
148                 {
149                 // --- VFS ---
150                 // Mount    /System=ext2:/Devices/ATA/A1
151                 // Symlink  /Acess=/System/Acess2
152                 case '/':
153                         System_ParseVFS( argv[i] );
154                         break;
155                 }
156         }
157 }
158
159 /**
160  * \fn void System_ParseVFS(char *Arg)
161  */
162 void System_ParseVFS(char *Arg)
163 {
164         char    *value;
165          int    fd;
166         
167         value = Arg;
168         // Search for the '=' token
169         while( *value && *value != '=' )
170                 value++;
171         
172         // Check if the equals was found
173         if( *value == '\0' ) {
174                 Log_Warning("Config", "Expected '=' in the string '%s'", Arg);
175                 return ;
176         }
177         
178         // Edit string
179         *value = '\0';  value ++;
180         
181         // Check assignment type
182         // - Symbolic Link <link>=<destination>
183         if(value[0] == '/')
184         {
185 //              Log_Log("Config", "Symbolic link '%s' pointing to '%s'", Arg, value);
186                 VFS_Symlink(Arg, value);
187         }
188         // - Mount <mountpoint>=<fs>:<device>
189         else
190         {
191                 char    *dev = value;
192                 // Find colon
193                 while(*dev && *dev != ':')      dev++;
194                 if(*dev) {
195                         *dev = '\0';
196                         dev++;  // Eat ':'
197                 }
198                 // Create Mountpoint
199                 if( (fd = VFS_Open(Arg, 0)) == -1 ) {
200 //                      Log_Log("Config", "Creating directory '%s'", Arg, value);
201                         VFS_MkDir( Arg );
202                 } else {
203                         VFS_Close(fd);
204                 }
205                 // Mount
206 //              Log_Log("Config", "Mounting '%s' to '%s' ('%s')", dev, Arg, value);
207                 VFS_Mount(dev, Arg, value, "");
208         }
209 }
210
211 /**
212  * \brief Parse a module argument string
213  * \param Arg   Argument string
214  */
215 void System_ParseModuleArgs(char *Arg)
216 {
217         char    *name, *args;
218          int    i;
219         
220         // Remove '-'   
221         name = Arg + 1;
222         
223         // Find the start of the args
224         i = strpos(name, ':');
225         if( i == -1 ) {
226                 Log_Warning("Config", "Module spec with no arguments");
227                 #if 1
228                 return ;
229                 #else
230                 i = strlen(name);
231                 args = name + i;
232                 #endif
233         }
234         else {
235                 name[i] = '\0';
236                 args = name + i + 1;
237         }
238         
239         Log_Log("Config", "Setting boot parameters for '%s' to '%s'", name, args);
240         Modules_SetBuiltinParams(name, args);
241 }
242
243 /**
244  * \fn void System_ParseSetting(char *Arg)
245  */
246 void System_ParseSetting(char *Arg)
247 {
248         char    *value;
249         value = Arg;
250
251         // Search for the '=' token
252         while( *value && *value != '=' )
253                 value++;
254         
255         // Check for boolean/flag (no '=')
256         if(*value == '\0')
257         {
258                 //if(strcmp(Arg, "") == 0) {
259                 //} else {
260                         Log_Warning("Config", "Kernel flag '%s' is not recognised", Arg);
261                 //}
262         }
263         else
264         {
265                 *value = '\0';  // Remove '='
266                 value ++;       // and eat it's position
267                 
268                 if(strcmp(Arg, "INIT") == 0) {
269                         Log_Log("Config", "Init binary: '%s'", value);
270                         if(strlen(value) == 0)
271                                 gsInitBinary = NULL;
272                         else
273                                 gsInitBinary = value;
274                 }
275                 else {
276                         Log_Warning("Config", "Kernel config setting '%s' is not recognised", Arg);
277                 }
278                 
279         }
280 }
281
282 void System_EmergencyConsole(void)
283 {
284         // TODO: Support an emergency kernel-land console (with FS viewing support)
285 }

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