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

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