f5be4f8d19b85fa5c9fb2b890397ebaf8b9203ed
[akaros.git] / kern / src / init.c
1 /* See COPYRIGHT for copyright information. */
2
3 #ifdef CONFIG_BSD_ON_CORE0
4 #error "Yeah, it's not possible to build ROS with BSD on Core 0, sorry......"
5 #else
6
7 #include <arch/arch.h>
8 #include <arch/topology.h>
9 #include <arch/console.h>
10 #include <multiboot.h>
11 #include <stab.h>
12 #include <smp.h>
13
14 #include <time.h>
15 #include <atomic.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <assert.h>
19 #include <monitor.h>
20 #include <pmap.h>
21 #include <process.h>
22 #include <trap.h>
23 #include <syscall.h>
24 #include <kclock.h>
25 #include <manager.h>
26 #include <testing.h>
27 #include <kmalloc.h>
28 #include <hashtable.h>
29 #include <radix.h>
30 #include <mm.h>
31 #include <frontend.h>
32 #include <ex_table.h>
33 #include <percpu.h>
34
35 #include <arch/init.h>
36 #include <bitmask.h>
37 #include <slab.h>
38 #include <kfs.h>
39 #include <vfs.h>
40 #include <devfs.h>
41 #include <blockdev.h>
42 #include <ext2fs.h>
43 #include <kthread.h>
44 #include <linker_func.h>
45 #include <ip.h>
46 #include <acpi.h>
47 #include <coreboot_tables.h>
48
49 #define MAX_BOOT_CMDLINE_SIZE 4096
50
51 #define ASSIGN_PTRVAL(prm, top, val)                    \
52         do {                                                                            \
53                 if (prm && (prm < top)) {                               \
54                         *prm = val;                                                     \
55                         prm++;                                                          \
56                 }                                                                               \
57         } while (0)
58
59 int booting = 1;
60 struct proc_global_info __proc_global_info;
61 struct sysinfo_t sysinfo;
62 static char boot_cmdline[MAX_BOOT_CMDLINE_SIZE];
63
64 static void run_linker_funcs(void);
65 static int run_init_script(void);
66
67 const char *get_boot_option(const char *base, const char *option, char *param,
68                                                         size_t max_param)
69 {
70         size_t optlen = strlen(option);
71         char *ptop = param + max_param - 1;
72         const char *opt, *arg;
73
74         if (!base)
75                 base = boot_cmdline;
76         for (;;) {
77                 opt = strstr(base, option);
78                 if (!opt)
79                         return NULL;
80                 if (((opt == base) || (opt[-1] == ' ')) &&
81                         ((opt[optlen] == 0) || (opt[optlen] == '=') ||
82                          (opt[optlen] == ' ')))
83                         break;
84                 base = opt + optlen;
85         }
86         arg = opt + optlen;
87         if (*arg == '=') {
88                 arg++;
89                 if (*arg == '\'') {
90                         arg++;
91                         for (; *arg; arg++) {
92                                 if (*arg == '\\')
93                                         arg++;
94                                 else if (*arg == '\'')
95                                         break;
96                                 ASSIGN_PTRVAL(param, ptop, *arg);
97                         }
98                 } else {
99                         for (; *arg && (*arg != ' '); arg++)
100                                 ASSIGN_PTRVAL(param, ptop, *arg);
101                 }
102         }
103         ASSIGN_PTRVAL(param, ptop, 0);
104
105         return arg;
106 }
107
108 static void extract_multiboot_cmdline(struct multiboot_info *mbi)
109 {
110         if (mbi && (mbi->flags & MULTIBOOT_INFO_CMDLINE) && mbi->cmdline) {
111                 const char *cmdln = (const char *) KADDR(mbi->cmdline);
112
113                 /* We need to copy the command line in a permanent buffer, since the
114                  * multiboot memory where it is currently residing will be part of the
115                  * free boot memory later on in the boot process.
116                  */
117                 strlcpy(boot_cmdline, cmdln, sizeof(boot_cmdline));
118         }
119 }
120
121 static void __kernel_init_part_deux(void *arg);
122
123 void kernel_init(multiboot_info_t *mboot_info)
124 {
125         extern char __start_bss[], __stop_bss[];
126
127         memset(__start_bss, 0, __stop_bss - __start_bss);
128         /* mboot_info is a physical address.  while some arches currently have the
129          * lower memory mapped, everyone should have it mapped at kernbase by now.
130          * also, it might be in 'free' memory, so once we start dynamically using
131          * memory, we may clobber it. */
132         multiboot_kaddr = (struct multiboot_info*)((physaddr_t)mboot_info
133                                                + KERNBASE);
134         extract_multiboot_cmdline(multiboot_kaddr);
135
136         cons_init();
137         print_cpuinfo();
138
139         printk("Boot Command Line: '%s'\n", boot_cmdline);
140
141         exception_table_init();
142         pmem_init(multiboot_kaddr);
143         kmem_cache_init();              // Sets up slab allocator
144         kmalloc_init();
145         hashtable_init();
146         radix_init();
147         acpiinit();
148         topology_init();
149         percpu_init();
150         kthread_init();                                 /* might need to tweak when this happens */
151         vmr_init();
152         file_init();
153         page_check();
154         idt_init();
155         /* After kthread_init and idt_init, we can use a real kstack. */
156         __use_real_kstack(__kernel_init_part_deux);
157 }
158
159 static void __kernel_init_part_deux(void *arg)
160 {
161         kernel_msg_init();
162         timer_init();
163         vfs_init();
164         devfs_init();
165         time_init();
166         arch_init();
167         block_init();
168         enable_irq();
169         run_linker_funcs();
170         /* reset/init devtab after linker funcs 3 and 4.  these run NIC and medium
171          * pre-inits, which need to happen before devether. */
172         devtabreset();
173         devtabinit();
174
175 #ifdef CONFIG_EXT2FS
176         mount_fs(&ext2_fs_type, "/dev_vfs/ramdisk", "/mnt", 0);
177 #endif /* CONFIG_EXT2FS */
178 #ifdef CONFIG_ETH_AUDIO
179         eth_audio_init();
180 #endif /* CONFIG_ETH_AUDIO */
181         get_coreboot_info(&sysinfo);
182         booting = 0;
183
184 #ifdef CONFIG_RUN_INIT_SCRIPT
185         if (run_init_script()) {
186                 printk("Configured to run init script, but no script specified!\n");
187                 manager();
188         }
189 #else
190         manager();
191 #endif
192 }
193
194 #ifdef CONFIG_RUN_INIT_SCRIPT
195 static int run_init_script(void)
196 {
197         /* If we have an init script path specified */
198         if (strlen(CONFIG_INIT_SCRIPT_PATH_AND_ARGS) != 0) {
199                 int vargs = 0;
200                 char *sptr = &CONFIG_INIT_SCRIPT_PATH_AND_ARGS[0];
201
202                 /* Figure out how many arguments there are, by finding the spaces */
203                 /* TODO: consider rewriting this stuff with parsecmd */
204                 while (*sptr != '\0') {
205                         if (*(sptr++) != ' ') {
206                                 vargs++;
207                                 while ((*sptr != ' ') && (*sptr != '\0'))
208                                         sptr++;
209                         }
210                 }
211
212                 /* Initialize l_argv with its first three arguments, but allocate space
213                  * for all arguments as calculated above */
214                 int static_args = 2;
215                 int total_args = vargs + static_args;
216                 char *l_argv[total_args];
217                 l_argv[0] = "/bin/bash";
218                 l_argv[1] = "bash";
219
220                 /* Initialize l_argv with the rest of the arguments */
221                 int i = static_args;
222                 sptr = &CONFIG_INIT_SCRIPT_PATH_AND_ARGS[0];
223                 while (*sptr != '\0') {
224                         if (*sptr != ' ') {
225                                 l_argv[i++] = sptr;
226                                 while ((*sptr != ' ') && (*sptr != '\0'))
227                                         sptr++;
228                                 if (*sptr == '\0')
229                                         break;
230                                 *sptr = '\0';
231                         }
232                         sptr++;
233                 }
234
235                 /* Run the script with its arguments */
236                 mon_bin_run(total_args, l_argv, NULL);
237         }
238         return -1;
239 }
240 #endif
241
242 /*
243  * Panic is called on unresolvable fatal errors.
244  * It prints "panic: mesg", and then enters the kernel monitor.
245  */
246 void _panic(const char *file, int line, const char *fmt,...)
247 {
248         va_list ap;
249         struct per_cpu_info *pcpui;
250         /* We're panicing, possibly in a place that can't handle the lock checker */
251         pcpui = &per_cpu_info[core_id_early()];
252         pcpui->__lock_checking_enabled--;
253         va_start(ap, fmt);
254         printk("kernel panic at %s:%d, from core %d: ", file, line,
255                core_id_early());
256         vcprintf(fmt, ap);
257         cprintf("\n");
258         va_end(ap);
259
260 dead:
261         monitor(NULL);
262         /* We could consider turning the lock checker back on here, but things are
263          * probably a mess anyways, and with it on we would probably lock up right
264          * away when we idle. */
265         //pcpui->__lock_checking_enabled++;
266         smp_idle();
267 }
268
269 /* like panic, but don't */
270 void _warn(const char *file, int line, const char *fmt,...)
271 {
272         va_list ap;
273
274         va_start(ap, fmt);
275         printk("kernel warning at %s:%d, from core %d: ", file, line,
276                core_id_early());
277         vcprintf(fmt, ap);
278         cprintf("\n");
279         va_end(ap);
280 }
281
282 static void run_links(linker_func_t *linkstart, linker_func_t *linkend)
283 {
284         /* Unlike with devtab, our linker sections for the function pointers are
285          * 8 byte aligned (4 on 32 bit) (done by the linker/compiler), so we don't
286          * have to worry about that.  */
287         printd("linkstart %p, linkend %p\n", linkstart, linkend);
288         for (int i = 0; &linkstart[i] < linkend; i++) {
289                 printd("i %d, linkfunc %p\n", i, linkstart[i]);
290                 linkstart[i]();
291         }
292 }
293
294 static void run_linker_funcs(void)
295 {
296         run_links(__linkerfunc1start, __linkerfunc1end);
297         run_links(__linkerfunc2start, __linkerfunc2end);
298         run_links(__linkerfunc3start, __linkerfunc3end);
299         run_links(__linkerfunc4start, __linkerfunc4end);
300 }
301
302 /* You need to reference PROVIDE symbols somewhere, or they won't be included.
303  * Only really a problem for debugging. */
304 void debug_linker_tables(void)
305 {
306         extern struct dev __devtabstart[];
307         extern struct dev __devtabend[];
308         printk("devtab %p %p\nlink1 %p %p\nlink2 %p %p\nlink3 %p %p\nlink4 %p %p\n",
309                __devtabstart,
310                __devtabend,
311                    __linkerfunc1start,
312                    __linkerfunc1end,
313                    __linkerfunc2start,
314                    __linkerfunc2end,
315                    __linkerfunc3start,
316                    __linkerfunc3end,
317                    __linkerfunc4start,
318                    __linkerfunc4end);
319 }
320
321 #endif //Everything For Free