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