ebb33e7cf403a4c60c00f7b59a8dc3c34f252b40
[akaros.git] / kern / arch / x86 / init.c
1 /* See COPYRIGHT for copyright information. */
2
3 #include <ros/common.h>
4 #include <smp.h>
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 #include <cpu_feat.h>
15
16 /*
17  *      x86_default_xcr0 is the Akaros-wide
18  *      default value for the xcr0 register.
19  *
20  *      It is set on every processor during
21  *      per-cpu init.
22  */
23 uint64_t x86_default_xcr0;
24 struct ancillary_state x86_default_fpu;
25 uint32_t kerndate;
26
27 #define capchar2ctl(x) ((x) - '@')
28
29 /* irq handler for the console (kb, serial, etc) */
30 static void irq_console(struct hw_trapframe *hw_tf, void *data)
31 {
32         uint8_t c;
33         struct cons_dev *cdev = (struct cons_dev*)data;
34         assert(cdev);
35         if (cons_get_char(cdev, &c))
36                 return;
37         /* Control code intercepts */
38         switch (c) {
39                 case capchar2ctl('G'):
40                         /* traditional 'ctrl-g', will put you in the monitor gracefully */
41                         send_kernel_message(core_id(), __run_mon, 0, 0, 0, KMSG_ROUTINE);
42                         return;
43                 case capchar2ctl('Q'):
44                         /* force you into the monitor.  you might deadlock. */
45                         printk("\nForcing entry to the monitor\n");
46                         monitor(hw_tf);
47                         return;
48                 case capchar2ctl('B'):
49                         /* backtrace / debugging for the core receiving the irq */
50                         printk("\nForced trapframe and backtrace for core %d\n", core_id());
51                         if (!hw_tf) {
52                                 printk("(no hw_tf, we probably polled the console)\n");
53                                 return;
54                         }
55                         print_trapframe(hw_tf);
56                         backtrace_hwtf(hw_tf);
57                         return;
58         }
59         /* Do our work in an RKM, instead of interrupt context.  Note the RKM will
60          * cast 'c' to a char. */
61         send_kernel_message(core_id(), __cons_add_char, (long)&cons_buf, (long)c,
62                             0, KMSG_ROUTINE);
63 }
64
65 static void cons_poller(void *arg)
66 {
67         while (1) {
68                 kthread_usleep(10000);
69                 irq_console(0, arg);
70         }
71 }
72
73 static void cons_irq_init(void)
74 {
75         struct cons_dev *i;
76         /* Register interrupt handlers for all console devices */
77         SLIST_FOREACH(i, &cdev_list, next) {
78                 register_irq(i->irq, irq_console, i, MKBUS(BusISA, 0, 0, 0));
79 #ifdef CONFIG_POLL_CONSOLE
80                 ktask("cons_poller", cons_poller, i);
81 #endif /* CONFIG_POLL_CONSOLE */
82         }
83 }
84
85 /* Init x86 processor extended state */
86 void ancillary_state_init(void)
87 {
88         uint32_t eax, ebx, ecx, edx;
89         uint64_t proc_supported_features; /* proc supported user state components */
90
91         // If you don't at least have FXSAVE and FXRSTOR
92         // (includes OSFXSR), you don't boot.
93         if (!cpu_has_feat(CPU_FEAT_X86_FXSR))
94                 panic("No FXSAVE/FXRSTOR (FXSR) support! Refusing to boot.");
95
96         if (cpu_has_feat(CPU_FEAT_X86_XSAVEOPT)) {
97                 // Next determine the user state components supported
98                 // by the processor and set x86_default_xcr0.
99                 cpuid(0x0d, 0x00, &eax, 0, 0, &edx);
100                 proc_supported_features = ((uint64_t)edx << 32) | eax;
101
102                 // Intersection of processor-supported and Akaros-supported
103                 // features is the Akaros-wide default at runtime.
104                 x86_default_xcr0 = X86_MAX_XCR0 & proc_supported_features;
105
106                 /*
107                  * Make sure CR4.OSXSAVE is set and set the local xcr0 to the default.
108                  * We will do both of these things again during per-cpu init,
109                  * but we are about to use XSAVE to build our default extended state
110                  * record, so we need them enabled.
111                  * You must set CR4_OSXSAVE before setting xcr0, or a #UD fault occurs.
112                  */
113                 lcr4(rcr4() | CR4_OSXSAVE);
114                 lxcr0(x86_default_xcr0);
115
116                 /*
117                  * Build a default set of extended state values that we can later use
118                  * to initialize extended state on other cores, or restore on this
119                  * core. We need to use FNINIT to reset the FPU before saving, in case
120                  * boot agents used the FPU or it is dirty for some reason. An old
121                  * comment that used to be here said "had this happen on c89, which had
122                  * a full FP stack after booting." Note that FNINIT does not clear the
123                  * data registers, but it tags them all as empty (0b11).
124                  */
125
126                 // Zero the default extended state memory region before saving.
127                 // It may be possible for memset to clobber SSE registers.
128                 memset(&x86_default_fpu, 0x00, sizeof(struct ancillary_state));
129                 asm volatile ("fninit");
130
131                 /*
132                  * Save only the x87 FPU state so that the extended state registers
133                  * remain zeroed in the default. There is a caveat to this that
134                  * involves the MXCSR register, this is handled below.
135                  * We use XSAVE64 instead of XSAVEOPT64 (save_fp_state uses
136                  * XSAVEOPT64), because XSAVEOPT64 may decide to skip saving a state
137                  * component if that state component is in its initial configuration,
138                  * and we just used FNINIT to put the x87 in its initial configuration.
139                  * We can be confident that the x87 bit (bit 0) is set in xcr0, because
140                  * Intel requires it to be set at all times.
141                  */
142                 edx = 0x0;
143                 eax = 0x1;
144                 asm volatile("xsave64 %0" : : "m"(x86_default_fpu), "a"(eax), "d"(edx));
145
146                 /* We must set the MXCSR field in the default state struct to its
147                  * power-on value of 0x1f80. This masks all SIMD floating
148                  * point exceptions and clears all SIMD floating-point exception
149                  * flags, sets rounding control to round-nearest, disables
150                  * flush-to-zero mode, and disables denormals-are-zero mode.
151                  *
152                  * We don't actually have to set the MXCSR itself here,
153                  * because it will be set from the default state struct when
154                  * we perform per-cpu init.
155                  *
156                  * Right now, we set the MXCSR through fp_head_64d. Since
157                  * the mxcsr is at the same offset in all fp header formats
158                  * implemented for Akaros, this will function correctly for
159                  * all supported operating modes.
160                  */
161                  x86_default_fpu.fp_head_64d.mxcsr = 0x1f80;
162         } else {
163                 // Since no program should try to use XSAVE features
164                 // on this processor, we set x86_default_xcr0 to 0x0
165                 x86_default_xcr0 = 0x0;
166
167                 /*
168                  * Build a default set of extended state values that we can later use to
169                  * initialize extended state on other cores, or restore on this core.
170                  * We need to use FNINIT to reset the FPU before saving, in case boot
171                  * agents used the FPU or it is dirty for some reason. An old comment
172                  * that used to be here said "had this happen on c89, which had a full
173                  * FP stack after booting." Note that FNINIT does not clear the data
174                  * registers, but it tags them all as empty (0b11).
175                  */
176
177                 // Zero the default extended state memory region before saving.
178                 // It may be possible for memset to clobber SSE registers.
179                 memset(&x86_default_fpu, 0x00, sizeof(struct ancillary_state));
180                 asm volatile ("fninit");
181
182                 // Save the x87 FPU state
183                 asm volatile("fxsave64 %0" : : "m"(x86_default_fpu));
184
185                 /*
186                  * Because FXSAVE may have also saved junk from the XMM registers,
187                  * depending on how the hardware was implemented and the setting
188                  * of CR4.OSFXSR, we manually zero the region of the ancillary_state
189                  * containing those registers after saving FPU state. There are 16
190                  * XMM registers, each 128 bits, for a total size of 256 bytes.
191                  */
192                 memset(&(x86_default_fpu.xmm0), 0x00, 256);
193
194                 /*
195                  * Finally, because Only the Paranoid Survive, we set the MXCSR
196                  * for our default state. It should have been saved by FXSAVE,
197                  * but who knows if the default value is still there at this
198                  * point in the boot process.
199                  */
200                 x86_default_fpu.fp_head_64d.mxcsr = 0x1f80;
201         }
202
203 }
204
205 void arch_init(void)
206 {
207         ancillary_state_init();
208         pci_init();
209         vmm_init();
210         perfmon_global_init();
211         // this returns when all other cores are done and ready to receive IPIs
212         #ifdef CONFIG_SINGLE_CORE
213                 smp_percpu_init();
214         #else
215                 smp_boot();
216         #endif
217         proc_init();
218
219         cons_irq_init();
220         intel_lpc_init();
221 #ifdef CONFIG_ENABLE_LEGACY_USB
222         printk("Legacy USB support enabled, expect SMM interference!\n");
223 #else
224         usb_disable_legacy();
225 #endif
226         check_timing_stability();
227 }