|  | /* See COPYRIGHT for copyright information. */ | 
|  |  | 
|  | #include <ros/common.h> | 
|  | #include <smp.h> | 
|  | #include <arch/x86.h> | 
|  | #include <arch/pci.h> | 
|  | #include <arch/console.h> | 
|  | #include <arch/perfmon.h> | 
|  | #include <arch/init.h> | 
|  | #include <monitor.h> | 
|  | #include <arch/usb.h> | 
|  | #include <assert.h> | 
|  | #include <ros/procinfo.h> | 
|  | #include <cpu_feat.h> | 
|  |  | 
|  |  | 
|  | struct ancillary_state x86_default_fpu; | 
|  | uint32_t kerndate; | 
|  |  | 
|  | #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 'ctrl-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()); | 
|  | if (!hw_tf) { | 
|  | printk("(no hw_tf, we probably polled the console)\n"); | 
|  | return; | 
|  | } | 
|  | print_trapframe(hw_tf); | 
|  | backtrace_hwtf(hw_tf); | 
|  | return; | 
|  | } | 
|  | cons_add_char(c); | 
|  | } | 
|  |  | 
|  | static void cons_poller(void *arg) | 
|  | { | 
|  | while (1) { | 
|  | kthread_usleep(10000); | 
|  | irq_console(0, arg); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void cons_irq_init(void) | 
|  | { | 
|  | struct cons_dev *i; | 
|  | /* Register interrupt handlers for all console devices */ | 
|  | SLIST_FOREACH(i, &cdev_list, next) { | 
|  | register_irq(i->irq, irq_console, i, MKBUS(BusISA, 0, 0, 0)); | 
|  | irq_console(0, i); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Init x86 processor extended state */ | 
|  | void ancillary_state_init(void) | 
|  | { | 
|  | uint32_t eax, ebx, ecx, edx; | 
|  | /* proc supported user state components */ | 
|  | uint64_t proc_supported_features; | 
|  |  | 
|  | // If you don't at least have FXSAVE and FXRSTOR | 
|  | // (includes OSFXSR), you don't boot. | 
|  | if (!cpu_has_feat(CPU_FEAT_X86_FXSR)) | 
|  | panic("No FXSAVE/FXRSTOR (FXSR) support! Refusing to boot."); | 
|  |  | 
|  | if (cpu_has_feat(CPU_FEAT_X86_XSAVE)) { | 
|  | // Next determine the user state components supported | 
|  | // by the processor and set x86_default_xcr0 in | 
|  | // proc_global_info. | 
|  | cpuid(0x0d, 0x00, &eax, 0, 0, &edx); | 
|  | proc_supported_features = ((uint64_t)edx << 32) | eax; | 
|  |  | 
|  | // Intersection of processor-supported and Akaros-supported | 
|  | // features is the Akaros-wide default at runtime. | 
|  | __proc_global_info.x86_default_xcr0 = X86_MAX_XCR0 & | 
|  | proc_supported_features; | 
|  |  | 
|  | /* | 
|  | * Make sure CR4.OSXSAVE is set and set the local xcr0 to the | 
|  | * default.  We will do both of these things again during | 
|  | * per-cpu init, but we are about to use XSAVE to build our | 
|  | * default extended state record, so we need them enabled.  You | 
|  | * must set CR4_OSXSAVE before setting xcr0, or a #UD fault | 
|  | * occurs. | 
|  | */ | 
|  | lcr4(rcr4() | CR4_OSXSAVE); | 
|  | lxcr0(__proc_global_info.x86_default_xcr0); | 
|  |  | 
|  | /* Build a default set of extended state values that we can | 
|  | * later use to initialize extended state on other cores, or | 
|  | * restore on this core.  FNINIT won't actually do it - if you | 
|  | * xsave after fninit, x87 will show up as active in | 
|  | * xstate_bv[0].  Instead, we just need the xstate_bv bits | 
|  | * zeroed (and memset the rest for sanity's sake). | 
|  | */ | 
|  | memset(&x86_default_fpu, 0x00, sizeof(struct ancillary_state)); | 
|  |  | 
|  | /* We must set the MXCSR field in the default state struct to | 
|  | * its power-on value of 0x1f80. This masks all SIMD floating | 
|  | * point exceptions and clears all SIMD floating-point exception | 
|  | * flags, sets rounding control to round-nearest, disables | 
|  | * flush-to-zero mode, and disables denormals-are-zero mode. | 
|  | * | 
|  | * We don't actually have to set the MXCSR itself here, | 
|  | * because it will be set from the default state struct when | 
|  | * we perform per-cpu init. | 
|  | * | 
|  | * Right now, we set the MXCSR through fp_head_64d. Since | 
|  | * the mxcsr is at the same offset in all fp header formats | 
|  | * implemented for Akaros, this will function correctly for | 
|  | * all supported operating modes. | 
|  | */ | 
|  | x86_default_fpu.fp_head_64d.mxcsr = 0x1f80; | 
|  | } else { | 
|  | // Since no program should try to use XSAVE features | 
|  | // on this processor, we set x86_default_xcr0 to 0x0 | 
|  | __proc_global_info.x86_default_xcr0 = 0x0; | 
|  |  | 
|  | /* | 
|  | * Build a default set of extended state values that we can | 
|  | * later use to initialize extended state on other cores, or | 
|  | * restore on this core.  We need to use FNINIT to reset the FPU | 
|  | * before saving, in case boot agents used the FPU or it is | 
|  | * dirty for some reason. An old comment that used to be here | 
|  | * said "had this happen on c89, which had a full FP stack after | 
|  | * booting." Note that FNINIT does not clear the data registers, | 
|  | * but it tags them all as empty (0b11). | 
|  | */ | 
|  |  | 
|  | // Zero the default extended state memory region before saving. | 
|  | // It may be possible for memset to clobber SSE registers. | 
|  | memset(&x86_default_fpu, 0x00, sizeof(struct ancillary_state)); | 
|  |  | 
|  | /* | 
|  | * FNINIT clears FIP and FDP and, even though it is technically | 
|  | * a control instruction, it clears FOP while initializing the | 
|  | * FPU. | 
|  | * | 
|  | * This marks the STX/MMX registers as empty in the FPU tag | 
|  | * word, but does not actually clear the values in the | 
|  | * registers, so we manually clear them in the xsave area after | 
|  | * saving. | 
|  | */ | 
|  | asm volatile ("fninit"); | 
|  |  | 
|  | // Save the x87 FPU state | 
|  | asm volatile("fxsave64 %0" : : "m"(x86_default_fpu)); | 
|  |  | 
|  | /* | 
|  | * Clear junk that might have been saved from the STX/MMX | 
|  | * registers. | 
|  | * | 
|  | * FXSAVE may have also saved junk from the XMM registers, | 
|  | * depending on how the hardware was implemented and the setting | 
|  | * of CR4.OSFXSR. So we clear that too. | 
|  | * | 
|  | * MMX: 128 bytes, XMM: 256 bytes | 
|  | */ | 
|  | memset(&(x86_default_fpu.st0_mm0), 0x00, 128 + 256); | 
|  |  | 
|  | /* | 
|  | * Finally, because Only the Paranoid Survive, we set the MXCSR | 
|  | * for our default state. It should have been saved by FXSAVE, | 
|  | * but who knows if the default value is still there at this | 
|  | * point in the boot process. | 
|  | */ | 
|  | x86_default_fpu.fp_head_64d.mxcsr = 0x1f80; | 
|  | } | 
|  |  | 
|  | } | 
|  |  | 
|  | void arch_init(void) | 
|  | { | 
|  | ancillary_state_init(); | 
|  | pci_init(); | 
|  | vmm_init(); | 
|  | perfmon_global_init(); | 
|  | // 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(); | 
|  |  | 
|  | cons_irq_init(); | 
|  | intel_lpc_init(); | 
|  | #ifdef CONFIG_ENABLE_LEGACY_USB | 
|  | printk("Legacy USB support enabled, expect SMM interference!\n"); | 
|  | #else | 
|  | usb_disable_legacy(); | 
|  | #endif | 
|  | check_timing_stability(); | 
|  | } |