x86: use setters/getters for MSR_{FS,GS}_BASE
[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 #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         /* TODO: switch between XSAVEOPT and pre-XSAVE FP ops */
92         if (!cpu_has_feat(CPU_FEAT_X86_XSAVEOPT))
93                 panic("No XSAVEOPT support! Refusing to boot.\n");
94
95         // Next determine the user state components supported
96         // by the processor and set x86_default_xcr0.
97         cpuid(0x0d, 0x00, &eax, 0, 0, &edx);
98         proc_supported_features = ((uint64_t)edx << 32) | eax;
99
100         // Intersection of processor-supported and Akaros-supported
101         // features is the Akaros-wide default at runtime.
102         x86_default_xcr0 = X86_MAX_XCR0 & proc_supported_features;
103
104         /*
105          *      Make sure CR4.OSXSAVE is set and set the local xcr0 to the default.
106          *      We will do both of these things again during per-cpu init,
107          *      but we are about to use XSAVE to build our default extended state
108          *      record, so we need them enabled.
109          *      You must set CR4_OSXSAVE before setting xcr0, or a #UD fault occurs.
110          */
111         lcr4(rcr4() | CR4_OSXSAVE);
112         lxcr0(x86_default_xcr0);
113
114         /*
115          *      Build a default set of extended state values that we can later use to
116          *      initialize extended state on other cores, or restore on this core.
117          *      We need to use FNINIT to reset the FPU before saving, in case boot
118          *      agents used the FPU or it is dirty for some reason. An old comment that
119          *      used to be here said "had this happen on c89, which had a full FP stack
120          *      after booting." Note that FNINIT does not clear the data registers,
121          *      but it tags them all as empty (0b11).
122          */
123
124         asm volatile ("fninit");
125
126         // Zero the default extended state memory region before saving.
127         memset(&x86_default_fpu, 0x00, sizeof(struct ancillary_state));
128
129         /*
130          *      Save only the x87 FPU state so that the extended state registers
131          *      remain zeroed in the default. There is a caveat to this that involves
132          *  the MXCSR register, this is handled below.
133          *      We use XSAVE64 instead of XSAVEOPT64 (save_fp_state uses XSAVEOPT64),
134          *      because XSAVEOPT64 may decide to skip saving a state component
135          *      if that state component is in its initial configuration, and
136          *      we just used FNINIT to put the x87 in its initial configuration.
137          *      We can be confident that the x87 bit (bit 0) is set in xcr0, because
138          *      Intel requires it to be set at all times.
139          */
140         edx = 0x0;
141         eax = 0x1;
142         asm volatile("xsave64 %0" : : "m"(x86_default_fpu), "a"(eax), "d"(edx));
143
144         /* We must set the MXCSR field in the default state struct to its
145          * power-on value of 0x1f80. This masks all SIMD floating
146          * point exceptions and clears all SIMD floating-point exception
147          * flags, sets rounding control to round-nearest, disables
148          * flush-to-zero mode, and disables denormals-are-zero mode.
149          *
150          * We don't actually have to set the MXCSR itself here,
151          * because it will be set from the default state struct when
152          * we perform per-cpu init.
153          *
154          * Right now, we set the MXCSR through fp_head_64d. Since
155          * the mxcsr is at the same offset in all fp header formats
156          * implemented for Akaros, this will function correctly for
157          * all supported operating modes.
158          */
159          x86_default_fpu.fp_head_64d.mxcsr = 0x1f80;
160 }
161
162 void arch_init(void)
163 {
164         ancillary_state_init();
165         pci_init();
166         vmm_init();
167         perfmon_global_init();
168         // this returns when all other cores are done and ready to receive IPIs
169         #ifdef CONFIG_SINGLE_CORE
170                 smp_percpu_init();
171         #else
172                 smp_boot();
173         #endif
174         proc_init();
175
176         cons_irq_init();
177         intel_lpc_init();
178 #ifdef CONFIG_ENABLE_LEGACY_USB
179         printk("Legacy USB support enabled, expect SMM interference!\n");
180 #else
181         usb_disable_legacy();
182 #endif
183         check_timing_stability();
184 }