Add proc_global_info (XCC)
[akaros.git] / kern / arch / x86 / trap.h
index 0ee5767..c842e24 100644 (file)
@@ -1,7 +1,10 @@
-#ifndef ROS_KERN_ARCH_TRAP_H
+#pragma once
+
 #define ROS_KERN_ARCH_TRAP_H
 
-#include "msr-index.h"
+#include <ros/arch/msr-index.h>
+#include <ros/errno.h>
+#include <arch/fixup.h>
 
 #define NUM_IRQS                                       256
 
@@ -13,7 +16,7 @@
 #define T_OFLOW      4         // overflow
 #define T_BOUND      5         // bounds check
 #define T_ILLOP      6         // illegal opcode
-#define T_DEVICE     7         // device not available 
+#define T_DEVICE     7         // device not available
 #define T_DBLFLT     8         // double fault
 /* #define T_COPROC  9 */      // reserved (not generated by recent processors)
 #define T_TSS       10         // invalid task switch segment
 #include <ros/trapframe.h>
 #include <arch/pci.h>
 #include <arch/pic.h>
-#include <arch/coreid.h>
+#include <arch/topology.h>
 #include <arch/io.h>
+#include <stdio.h>
 
 struct irq_handler {
        struct irq_handler *next;
@@ -151,30 +155,56 @@ extern taskstate_t ts;
 int bus_irq_setup(struct irq_handler *irq_h);  /* ioapic.c */
 extern const char *x86_trapname(int trapno);
 extern void sysenter_handler(void);
-void backtrace_kframe(struct hw_trapframe *hw_tf);
 
 /* Defined and set up in in arch/init.c, used for XMM initialization */
 extern struct ancillary_state x86_default_fpu;
+extern uint64_t x86_default_xcr0;
 
 static inline void save_fp_state(struct ancillary_state *silly)
 {
-       asm volatile("fxsave %0" : : "m"(*silly));
+       uint32_t eax, edx;
+
+       edx = x86_default_xcr0 >> 32;
+       eax = x86_default_xcr0;
+       asm volatile("xsaveopt64 %0" : : "m"(*silly), "a"(eax), "d"(edx));
 }
 
-/* TODO: this can trigger a GP fault if MXCSR reserved bits are set.  Callers
- * will need to handle intercepting the kernel fault. */
+static inline void init_fp_state(void);
 static inline void restore_fp_state(struct ancillary_state *silly)
 {
-       asm volatile("fxrstor %0" : : "m"(*silly));
+       int err = 0;
+       uint32_t eax, edx;
+
+       edx = x86_default_xcr0 >> 32;
+       eax = x86_default_xcr0;
+       asm volatile(ASM_STAC               ";"
+                        "1: xrstor64 %1         ;"
+                    "2: " ASM_CLAC "        ;"
+                    ".section .fixup, \"ax\";"
+                    "3: mov %4, %0          ;"
+                    "   jmp 2b              ;"
+                    ".previous              ;"
+                    _ASM_EXTABLE(1b, 3b)
+                    : "=r" (err)
+                    : "m"(*silly), "a"(eax), "d"(edx),
+                      "i" (-EINVAL), "0" (err));
+
+       if (err) {
+               printk("Error restoring fp state!");
+               printk("Likely a bad ancillary_state argument.\n");
+               printk("Re-initializing fp state to default due to error.\n");
+               init_fp_state();
+       }
 }
 
-/* A regular fninit will only initialize the x87 header part of the FPU, not the
- * st(n) (MMX) registers, the XMM registers, or the MXCSR state.  So to init,
- * we'll just keep around a copy of the default FPU state, which we grabbed
- * during boot, and can copy that over.
+/* A regular fninit only initializes the control, status, tag, ip,
+ * and data pointer registers. Since it leaves the data registers,
+ * MXCSR, etc. unchanged, we use init_fp_state to restore a default
+ * state that we save at boot time.
  *
- * Alternatively, we can fninit, ldmxcsr with the default value, and 0 out all
- * of the registers manually. */
+ * If you're looking for a workout, you could also fninit, ldmxcsr with
+ * a default value, and 0 all the registers by hand.
+ */
 static inline void init_fp_state(void)
 {
        restore_fp_state(&x86_default_fpu);
@@ -196,12 +226,6 @@ set_frame_pointer(uintptr_t fp)
 
 extern segdesc_t *gdt;
 
-#ifdef CONFIG_X86_64
 #include <arch/trap64.h>
-#else
-#include <arch/trap32.h>
-#endif
 
 #endif /* !__ASSEMBLER__ */
-
-#endif /* !ROS_INC_ARCH_TRAP_H */