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