2eba4232e7f83ac702a4dc37976e4e91cfe4db61
[akaros.git] / kern / arch / x86 / init.c
1 /* See COPYRIGHT for copyright information. */
2
3 #include <smp.h>
4
5 #include <arch/x86.h>
6 #include <arch/pci.h>
7 #include <arch/console.h>
8 #include <arch/perfmon.h>
9 #include <arch/init.h>
10 #include <console.h>
11 #include <monitor.h>
12 #include <arch/usb.h>
13 #include <assert.h>
14
15 /*
16  *      x86_default_xcr0 is the Akaros-wide
17  *      default value for the xcr0 register.
18  *
19  *      It is set on every processor during
20  *      per-cpu init.
21  */
22 uint64_t x86_default_xcr0;
23 struct ancillary_state x86_default_fpu;
24 uint32_t kerndate;
25
26 #define capchar2ctl(x) ((x) - '@')
27
28 /* irq handler for the console (kb, serial, etc) */
29 static void irq_console(struct hw_trapframe *hw_tf, void *data)
30 {
31         uint8_t c;
32         struct cons_dev *cdev = (struct cons_dev*)data;
33         assert(cdev);
34         if (cons_get_char(cdev, &c))
35                 return;
36         /* Control code intercepts */
37         switch (c) {
38                 case capchar2ctl('G'):
39                         /* traditional 'ctrl-g', will put you in the monitor gracefully */
40                         send_kernel_message(core_id(), __run_mon, 0, 0, 0, KMSG_ROUTINE);
41                         return;
42                 case capchar2ctl('Q'):
43                         /* force you into the monitor.  you might deadlock. */
44                         printk("\nForcing entry to the monitor\n");
45                         monitor(hw_tf);
46                         return;
47                 case capchar2ctl('B'):
48                         /* backtrace / debugging for the core receiving the irq */
49                         printk("\nForced trapframe and backtrace for core %d\n", core_id());
50                         if (!hw_tf) {
51                                 printk("(no hw_tf, we probably polled the console)\n");
52                                 return;
53                         }
54                         print_trapframe(hw_tf);
55                         backtrace_hwtf(hw_tf);
56                         return;
57         }
58         /* Do our work in an RKM, instead of interrupt context.  Note the RKM will
59          * cast 'c' to a char. */
60         send_kernel_message(core_id(), __cons_add_char, (long)&cons_buf, (long)c,
61                             0, KMSG_ROUTINE);
62 }
63
64 static void cons_poller(void *arg)
65 {
66         while (1) {
67                 kthread_usleep(10000);
68                 irq_console(0, arg);
69         }
70 }
71
72 static void cons_irq_init(void)
73 {
74         struct cons_dev *i;
75         /* Register interrupt handlers for all console devices */
76         SLIST_FOREACH(i, &cdev_list, next) {
77                 register_irq(i->irq, irq_console, i, MKBUS(BusISA, 0, 0, 0));
78 #ifdef CONFIG_POLL_CONSOLE
79                 ktask("cons_poller", cons_poller, i);
80 #endif /* CONFIG_POLL_CONSOLE */
81         }
82 }
83
84 /* Init x86 processor extended state */
85 // TODO/XXX: Eventually consolidate all of our "cpu has" stuff.
86 #define CPUID_XSAVE_SUPPORT         (1 << 26)
87 #define CPUID_XSAVEOPT_SUPPORT      (1 << 0)
88 void ancillary_state_init(void)
89 {
90         uint32_t eax, ebx, ecx, edx;
91         uint64_t proc_supported_features; /* proc supported user state components */
92
93         /* Note: The cpuid function comes from arch/x86.h
94          * arg1 is eax input, arg2 is ecx input, then
95          * pointers to eax, ebx, ecx, edx output values.
96          */
97
98         // First check general XSAVE support. Die if not supported.
99         cpuid(0x01, 0x00, 0, 0, &ecx, 0);
100         if (!(CPUID_XSAVE_SUPPORT & ecx))
101                 panic("No XSAVE support! Refusing to boot.\n");
102
103
104         // Next check XSAVEOPT support. Die if not supported.
105         cpuid(0x0d, 0x01, &eax, 0, 0, 0);
106         if (!(CPUID_XSAVEOPT_SUPPORT & eax))
107                 panic("No XSAVEOPT support! Refusing to boot.\n");
108
109
110         // Next determine the user state components supported
111         // by the processor and set x86_default_xcr0.
112         cpuid(0x0d, 0x00, &eax, 0, 0, &edx);
113         proc_supported_features = ((uint64_t)edx << 32) | eax;
114
115         // Intersection of processor-supported and Akaros-supported
116         // features is the Akaros-wide default at runtime.
117         x86_default_xcr0 = X86_MAX_XCR0 & proc_supported_features;
118
119         /*
120          *      Make sure CR4.OSXSAVE is set and set the local xcr0 to the default.
121          *      We will do both of these things again during per-cpu init,
122          *      but we are about to use XSAVE to build our default extended state
123          *      record, so we need them enabled.
124          *      You must set CR4_OSXSAVE before setting xcr0, or a #UD fault occurs.
125          */
126         lcr4(rcr4() | CR4_OSXSAVE);
127         lxcr0(x86_default_xcr0);
128
129         /*
130          *      Build a default set of extended state values that we can later use to
131          *      initialize extended state on other cores, or restore on this core.
132          *      We need to use FNINIT to reset the FPU before saving, in case boot
133          *      agents used the FPU or it is dirty for some reason. An old comment that
134          *      used to be here said "had this happen on c89, which had a full FP stack
135          *      after booting." Note that FNINIT does not clear the data registers,
136          *      but it tags them all as empty (0b11).
137          */
138
139         asm volatile ("fninit");
140
141         // Zero the default extended state memory region before saving.
142         memset(&x86_default_fpu, 0x00, sizeof(struct ancillary_state));
143
144         /*
145          *      Save only the x87 FPU state so that the extended state registers
146          *      remain zeroed in the default.
147          *      We use XSAVE64 instead of XSAVEOPT64 (save_fp_state uses XSAVEOPT64),
148          *      because XSAVEOPT64 may decide to skip saving a state component
149          *      if that state component is in its initial configuration, and
150          *      we just used FNINIT to put the x87 in its initial configuration.
151          *      We can be confident that the x87 bit (bit 0) is set in xcr0, because
152          *      Intel requires it to be set at all times.
153          */
154         edx = 0x0;
155         eax = 0x1;
156         asm volatile("xsave64 %0" : : "m"(x86_default_fpu), "a"(eax), "d"(edx));
157 }
158
159 void arch_init(void)
160 {
161         ancillary_state_init();
162         pci_init();
163         vmm_init();
164         perfmon_global_init();
165         // this returns when all other cores are done and ready to receive IPIs
166         #ifdef CONFIG_SINGLE_CORE
167                 smp_percpu_init();
168         #else
169                 smp_boot();
170         #endif
171         proc_init();
172
173         cons_irq_init();
174         intel_lpc_init();
175 #ifdef CONFIG_ENABLE_LEGACY_USB
176         printk("Legacy USB support enabled, expect SMM interference!\n");
177 #else
178         usb_disable_legacy();
179 #endif
180         check_timing_stability();
181 }