|  | /* See COPYRIGHT for copyright information. */ | 
|  |  | 
|  | #ifdef __SHARC__ | 
|  | #pragma nosharc | 
|  | #endif | 
|  |  | 
|  | #include <smp.h> | 
|  |  | 
|  | #include <arch/mptables.h> | 
|  | #include <arch/pci.h> | 
|  | #include <arch/ioapic.h> | 
|  | #include <arch/console.h> | 
|  | #include <arch/perfmon.h> | 
|  | #include <arch/init.h> | 
|  | #include <console.h> | 
|  | #include <monitor.h> | 
|  |  | 
|  | struct ancillary_state x86_default_fpu; | 
|  |  | 
|  | #define capchar2ctl(x) ((x) - '@') | 
|  |  | 
|  | /* irq handler for the console (kb, serial, etc) */ | 
|  | static void irq_console(struct hw_trapframe *hw_tf, void *data) | 
|  | { | 
|  | uint8_t c; | 
|  | struct cons_dev *cdev = (struct cons_dev*)data; | 
|  | assert(cdev); | 
|  | if (cons_get_char(cdev, &c)) | 
|  | return; | 
|  | /* Control code intercepts */ | 
|  | switch (c) { | 
|  | case capchar2ctl('G'): | 
|  | /* traditional 'shift-g', will put you in the monitor gracefully */ | 
|  | send_kernel_message(core_id(), __run_mon, 0, 0, 0, KMSG_ROUTINE); | 
|  | return; | 
|  | case capchar2ctl('Q'): | 
|  | /* force you into the monitor.  you might deadlock. */ | 
|  | printk("\nForcing entry to the monitor\n"); | 
|  | monitor(hw_tf); | 
|  | return; | 
|  | case capchar2ctl('B'): | 
|  | /* backtrace / debugging for the core receiving the irq */ | 
|  | printk("\nForced trapframe and backtrace for core %d\n", core_id()); | 
|  | print_trapframe(hw_tf); | 
|  | backtrace_kframe(hw_tf); | 
|  | return; | 
|  | } | 
|  | /* Do our work in an RKM, instead of interrupt context.  Note the RKM will | 
|  | * cast 'c' to a char. */ | 
|  | if (c == 'G') | 
|  | send_kernel_message(core_id(), __run_mon, 0, 0, 0, KMSG_ROUTINE); | 
|  | else | 
|  | send_kernel_message(core_id(), __cons_add_char, (long)&cons_buf, | 
|  | (long)c, 0, KMSG_ROUTINE); | 
|  | } | 
|  |  | 
|  | static void cons_irq_init(void) | 
|  | { | 
|  | struct cons_dev *i; | 
|  | /* Register interrupt handlers for all console devices */ | 
|  | SLIST_FOREACH(i, &cdev_list, next) | 
|  | register_dev_irq(i->irq, irq_console, i); | 
|  | } | 
|  |  | 
|  | void arch_init() | 
|  | { | 
|  | /* need to reinit before saving, in case boot agents used the FPU or it is | 
|  | * o/w dirty.  had this happen on c89, which had a full FP stack after | 
|  | * booting. */ | 
|  | asm volatile ("fninit"); | 
|  | save_fp_state(&x86_default_fpu); /* used in arch/trap.h for fpu init */ | 
|  | pci_init(); | 
|  | #ifdef CONFIG_ENABLE_MPTABLES | 
|  | mptables_parse(); | 
|  | ioapic_init(); // MUST BE AFTER PCI/ISA INIT! | 
|  | // TODO: move these back to regular init.  requires fixing the | 
|  | // CONFIG_NETWORKING inits to not need multiple cores running. | 
|  | #endif | 
|  | // this returns when all other cores are done and ready to receive IPIs | 
|  | #ifdef CONFIG_SINGLE_CORE | 
|  | smp_percpu_init(); | 
|  | #else | 
|  | smp_boot(); | 
|  | #endif | 
|  | proc_init(); | 
|  |  | 
|  | /* EXPERIMENTAL NETWORK FUNCTIONALITY | 
|  | * To enable, define CONFIG_NETWORKING in your Makelocal | 
|  | * If enabled, will load the rl8168 driver (if device exists) | 
|  | * and will a boot into userland matrix, so remote syscalls can be performed. | 
|  | * If in simulation, will do some debugging information with the ne2k device | 
|  | * | 
|  | * Note: If you use this, you should also define the mac address of the | 
|  | * teathered machine via USER_MAC_ADDRESS in Makelocal. | 
|  | * | 
|  | * Additionally, you should have a look at the syscall server in the tools directory | 
|  | */ | 
|  | #ifdef CONFIG_NETWORKING | 
|  | #ifdef CONFIG_SINGLE_CORE | 
|  | warn("You currently can't have networking if you boot into single core mode!!\n"); | 
|  | #else | 
|  | /* TODO: use something like linux's device_init() to call these. */ | 
|  | #ifdef CONFIG_RL8168 | 
|  | extern void rl8168_init(void); | 
|  | rl8168_init(); | 
|  | #endif | 
|  | #ifdef CONFIG_NE2K | 
|  | extern void ne2k_init(void); | 
|  | ne2k_init(); | 
|  | #endif | 
|  | #ifdef CONFIG_E1000 | 
|  | extern void e1000_init(void); | 
|  | e1000_init(); | 
|  | #endif | 
|  | #endif // CONFIG_SINGLE_CORE | 
|  | #endif // CONFIG_NETWORKING | 
|  |  | 
|  | perfmon_init(); | 
|  | cons_irq_init(); | 
|  | check_timing_stability(); | 
|  | } |