| /* See COPYRIGHT for copyright information. */ |
| |
| #ifdef CONFIG_BSD_ON_CORE0 |
| #error "Yeah, it's not possible to build ROS with BSD on Core 0, sorry......" |
| #else |
| |
| #include <arch/arch.h> |
| #include <arch/topology.h> |
| #include <arch/console.h> |
| #include <multiboot.h> |
| #include <smp.h> |
| |
| #include <time.h> |
| #include <atomic.h> |
| #include <stdio.h> |
| #include <string.h> |
| #include <assert.h> |
| #include <monitor.h> |
| #include <pmap.h> |
| #include <process.h> |
| #include <trap.h> |
| #include <syscall.h> |
| #include <manager.h> |
| #include <testing.h> |
| #include <kmalloc.h> |
| #include <hashtable.h> |
| #include <radix.h> |
| #include <mm.h> |
| #include <ex_table.h> |
| #include <percpu.h> |
| |
| #include <arch/init.h> |
| #include <bitmask.h> |
| #include <slab.h> |
| #include <kthread.h> |
| #include <linker_func.h> |
| #include <net/ip.h> |
| #include <acpi.h> |
| #include <coreboot_tables.h> |
| #include <rcu.h> |
| |
| #define MAX_BOOT_CMDLINE_SIZE 4096 |
| |
| #define ASSIGN_PTRVAL(prm, top, val) \ |
| do { \ |
| if (prm && (prm < top)) { \ |
| *prm = val; \ |
| prm++; \ |
| } \ |
| } while (0) |
| |
| bool booting = TRUE; |
| struct proc_global_info __proc_global_info; |
| struct sysinfo_t sysinfo; |
| static char boot_cmdline[MAX_BOOT_CMDLINE_SIZE]; |
| |
| static void run_linker_funcs(void); |
| static int run_init_script(void); |
| |
| const char *get_boot_option(const char *base, const char *option, char *param, |
| size_t max_param) |
| { |
| size_t optlen = strlen(option); |
| char *ptop = param + max_param - 1; |
| const char *opt, *arg; |
| |
| if (!base) |
| base = boot_cmdline; |
| for (;;) { |
| opt = strstr(base, option); |
| if (!opt) |
| return NULL; |
| if (((opt == base) || (opt[-1] == ' ')) && |
| ((opt[optlen] == 0) || (opt[optlen] == '=') || |
| (opt[optlen] == ' '))) |
| break; |
| base = opt + optlen; |
| } |
| arg = opt + optlen; |
| if (*arg == '=') { |
| arg++; |
| if (*arg == '\'') { |
| arg++; |
| for (; *arg; arg++) { |
| if (*arg == '\\') |
| arg++; |
| else if (*arg == '\'') |
| break; |
| ASSIGN_PTRVAL(param, ptop, *arg); |
| } |
| } else { |
| for (; *arg && (*arg != ' '); arg++) |
| ASSIGN_PTRVAL(param, ptop, *arg); |
| } |
| } |
| ASSIGN_PTRVAL(param, ptop, 0); |
| |
| return arg; |
| } |
| |
| static void extract_multiboot_cmdline(struct multiboot_info *mbi) |
| { |
| if (mbi && (mbi->flags & MULTIBOOT_INFO_CMDLINE) && mbi->cmdline) { |
| const char *cmdln = (const char *) KADDR(mbi->cmdline); |
| |
| /* We need to copy the command line in a permanent buffer, since |
| * the multiboot memory where it is currently residing will be |
| * part of the free boot memory later on in the boot process. */ |
| strlcpy(boot_cmdline, cmdln, sizeof(boot_cmdline)); |
| } |
| } |
| |
| static void __kernel_init_part_deux(void *arg); |
| |
| void kernel_init(multiboot_info_t *mboot_info) |
| { |
| extern char __start_bss[], __stop_bss[]; |
| |
| memset(__start_bss, 0, __stop_bss - __start_bss); |
| /* mboot_info is a physical address. while some arches currently have |
| * the lower memory mapped, everyone should have it mapped at kernbase |
| * by now. also, it might be in 'free' memory, so once we start |
| * dynamically using memory, we may clobber it. */ |
| multiboot_kaddr = (struct multiboot_info*)((physaddr_t)mboot_info |
| + KERNBASE); |
| extract_multiboot_cmdline(multiboot_kaddr); |
| |
| cons_init(); |
| print_cpuinfo(); |
| |
| printk("Boot Command Line: '%s'\n", boot_cmdline); |
| |
| exception_table_init(); |
| num_cores = get_early_num_cores(); |
| pmem_init(multiboot_kaddr); |
| kmalloc_init(); |
| vmap_init(); |
| hashtable_init(); |
| radix_init(); |
| acpiinit(); |
| topology_init(); |
| percpu_init(); |
| kthread_init(); /* might need to tweak when this happens */ |
| vmr_init(); |
| page_check(); |
| idt_init(); |
| /* After kthread_init and idt_init, we can use a real kstack. */ |
| __use_real_kstack(__kernel_init_part_deux); |
| } |
| |
| static void __kernel_init_part_deux(void *arg) |
| { |
| kernel_msg_init(); |
| timer_init(); |
| time_init(); |
| arch_init(); |
| rcu_init(); |
| enable_irq(); |
| run_linker_funcs(); |
| /* reset/init devtab after linker funcs 3 and 4. these run NIC and |
| * medium pre-inits, which need to happen before devether. */ |
| devtabreset(); |
| devtabinit(); |
| |
| #ifdef CONFIG_ETH_AUDIO |
| eth_audio_init(); |
| #endif /* CONFIG_ETH_AUDIO */ |
| get_coreboot_info(&sysinfo); |
| booting = FALSE; |
| |
| #ifdef CONFIG_RUN_INIT_SCRIPT |
| if (run_init_script()) { |
| printk("Told to run init script, but no script specified\n"); |
| manager(); |
| } |
| #else |
| manager(); |
| #endif |
| } |
| |
| #ifdef CONFIG_RUN_INIT_SCRIPT |
| static int run_init_script(void) |
| { |
| /* If we have an init script path specified */ |
| if (strlen(CONFIG_INIT_SCRIPT_PATH_AND_ARGS) != 0) { |
| int vargs = 0; |
| char *sptr = &CONFIG_INIT_SCRIPT_PATH_AND_ARGS[0]; |
| |
| /* Figure out how many arguments there are, by finding the |
| * spaces */ |
| /* TODO: consider rewriting this stuff with parsecmd */ |
| while (*sptr != '\0') { |
| if (*(sptr++) != ' ') { |
| vargs++; |
| while ((*sptr != ' ') && (*sptr != '\0')) |
| sptr++; |
| } |
| } |
| |
| /* Initialize l_argv with its first three arguments, but |
| * allocate space for all arguments as calculated above */ |
| int static_args = 2; |
| int total_args = vargs + static_args; |
| char *l_argv[total_args]; |
| l_argv[0] = "/bin/bash"; |
| l_argv[1] = "bash"; |
| |
| /* Initialize l_argv with the rest of the arguments */ |
| int i = static_args; |
| |
| sptr = &CONFIG_INIT_SCRIPT_PATH_AND_ARGS[0]; |
| while (*sptr != '\0') { |
| if (*sptr != ' ') { |
| l_argv[i++] = sptr; |
| while ((*sptr != ' ') && (*sptr != '\0')) |
| sptr++; |
| if (*sptr == '\0') |
| break; |
| *sptr = '\0'; |
| } |
| sptr++; |
| } |
| |
| /* Run the script with its arguments */ |
| mon_bin_run(total_args, l_argv, NULL); |
| } |
| return -1; |
| } |
| #endif |
| |
| /* Multiple cores can panic concurrently. We could also panic recursively, |
| * which could deadlock. We also only want to automatically backtrace the first |
| * time through, since BTs are often the source of panics. Finally, we want to |
| * know when the other panicking cores are done (or likely to be done) before |
| * entering the monitor. |
| * |
| * We'll use the print_lock(), which is recursive, to protect panic_printing. */ |
| static bool panic_printing; |
| static DEFINE_PERCPU(int, panic_depth); |
| |
| /* |
| * Panic is called on unresolvable fatal errors. |
| * It prints "panic: mesg", and then enters the kernel monitor. |
| */ |
| void _panic(struct hw_trapframe *hw_tf, const char *file, int line, |
| const char *fmt, ...) |
| { |
| struct per_cpu_info *pcpui = &per_cpu_info[core_id_early()]; |
| va_list ap; |
| |
| print_lock(); |
| panic_printing = true; |
| PERCPU_VAR(panic_depth)++; |
| |
| va_start(ap, fmt); |
| printk("\nkernel panic at %s:%d, from core %d: ", file, line, |
| core_id_early()); |
| vcprintf(fmt, ap); |
| printk("\n"); |
| va_end(ap); |
| /* Recursive panics are usually backtrace problems. Possibly printk. |
| * Locking panics might recurse forever. */ |
| if (PERCPU_VAR(panic_depth) == 1) { |
| if (hw_tf) { |
| print_trapframe(hw_tf); |
| backtrace_hwtf(hw_tf); |
| } else { |
| backtrace(); |
| } |
| } else { |
| printk("\tRecursive kernel panic on core %d (depth %d)\n", |
| core_id_early(), PERCPU_VAR(panic_depth)); |
| } |
| printk("\n"); |
| |
| /* If we're here, we panicked and currently hold the print_lock. We |
| * might have panicked recursively. We must unlock unconditionally, |
| * since the initial panic (which grabbed the lock) will never run |
| * again. */ |
| panic_printing = false; |
| print_unlock_force(); |
| /* And we have to clear the depth, so that we lock again next time in. |
| * Otherwise, we'd be unlocking without locking (which is another |
| * panic). */ |
| PERCPU_VAR(panic_depth) = 0; |
| |
| /* Let's wait long enough for other printers to finish before entering |
| * the monitor. */ |
| do { |
| udelay(500000); |
| cmb(); |
| } while (panic_printing); |
| |
| /* Yikes! We're claiming to be not in IRQ/trap ctx and not holding any |
| * locks. Obviously we could be wrong, and could easily deadlock. We |
| * could be in an IRQ handler, an unhandled kernel fault, or just a |
| * 'normal' panic in a syscall - any of which can involve unrestore |
| * invariants. */ |
| pcpui->__ctx_depth = 0; |
| pcpui->lock_depth = 0; |
| /* And keep this off, for good measure. */ |
| pcpui->__lock_checking_enabled--; |
| |
| monitor(NULL); |
| |
| if (pcpui->cur_proc) { |
| printk("panic killing proc %d\n", pcpui->cur_proc->pid); |
| proc_destroy(pcpui->cur_proc); |
| } |
| if (pcpui->cur_kthread) |
| kth_panic_sysc(pcpui->cur_kthread); |
| smp_idle(); |
| } |
| |
| void _warn(const char *file, int line, const char *fmt,...) |
| { |
| va_list ap; |
| |
| print_lock(); |
| va_start(ap, fmt); |
| printk("\nkernel warning at %s:%d, from core %d: ", file, line, |
| core_id_early()); |
| vcprintf(fmt, ap); |
| printk("\n"); |
| va_end(ap); |
| backtrace(); |
| printk("\n"); |
| print_unlock(); |
| } |
| |
| static void run_links(linker_func_t *linkstart, linker_func_t *linkend) |
| { |
| /* Unlike with devtab, our linker sections for the function pointers are |
| * 8 byte aligned (4 on 32 bit) (done by the linker/compiler), so we |
| * don't have to worry about that. */ |
| printd("linkstart %p, linkend %p\n", linkstart, linkend); |
| for (int i = 0; &linkstart[i] < linkend; i++) { |
| printd("i %d, linkfunc %p\n", i, linkstart[i]); |
| linkstart[i](); |
| } |
| } |
| |
| static void run_linker_funcs(void) |
| { |
| run_links(__linkerfunc1start, __linkerfunc1end); |
| run_links(__linkerfunc2start, __linkerfunc2end); |
| run_links(__linkerfunc3start, __linkerfunc3end); |
| run_links(__linkerfunc4start, __linkerfunc4end); |
| } |
| |
| /* You need to reference PROVIDE symbols somewhere, or they won't be included. |
| * Only really a problem for debugging. */ |
| void debug_linker_tables(void) |
| { |
| extern struct dev __devtabstart[]; |
| extern struct dev __devtabend[]; |
| printk("devtab %p %p\nlink1 %p %p\nlink2 %p %p\nlink3 %p %p\nlink4 %p %p\n", |
| __devtabstart, |
| __devtabend, |
| __linkerfunc1start, |
| __linkerfunc1end, |
| __linkerfunc2start, |
| __linkerfunc2end, |
| __linkerfunc3start, |
| __linkerfunc3end, |
| __linkerfunc4start, |
| __linkerfunc4end); |
| } |
| |
| #endif //Everything For Free |