blob: e8bccf01123c19d2bbf9650693a68178c638f05c [file] [log] [blame] [edit]
/* 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();
}