akaros/kern/arch/x86/trap.h
<<
>>
Prefs
   1#pragma once
   2
   3#define ROS_KERN_ARCH_TRAP_H
   4
   5#include <ros/arch/msr-index.h>
   6#include <ros/errno.h>
   7#include <arch/fixup.h>
   8
   9#define NUM_IRQS                                        256
  10
  11/* 0-31 are hardware traps */
  12#define T_DIVIDE     0          // divide error
  13#define T_DEBUG      1          // debug exception
  14#define T_NMI        2          // non-maskable interrupt
  15#define T_BRKPT      3          // breakpoint
  16#define T_OFLOW      4          // overflow
  17#define T_BOUND      5          // bounds check
  18#define T_ILLOP      6          // illegal opcode
  19#define T_DEVICE     7          // device not available
  20#define T_DBLFLT     8          // double fault
  21/* #define T_COPROC  9 */       // reserved (not generated by recent processors)
  22#define T_TSS       10          // invalid task switch segment
  23#define T_SEGNP     11          // segment not present
  24#define T_STACK     12          // stack exception
  25#define T_GPFLT     13          // genernal protection fault
  26#define T_PGFLT     14          // page fault
  27/* #define T_RES    15 */       // reserved
  28#define T_FPERR     16          // floating point error
  29#define T_ALIGN     17          // aligment check
  30#define T_MCHK      18          // machine check
  31#define T_SIMDERR   19          // SIMD floating point error
  32
  33/* 32-47 are PIC/8259 IRQ vectors */
  34#define IdtPIC                  32
  35#define IrqCLOCK                0
  36#define IrqKBD                  1
  37#define IrqUART1                3
  38#define IrqUART0                4
  39#define IrqPCMCIA               5
  40#define IrqFLOPPY               6
  41#define IrqLPT                  7
  42#define IrqAUX                  12      /* PS/2 port */
  43#define IrqIRQ13                13      /* coprocessor on 386 */
  44#define IrqATA0                 14
  45#define IrqATA1                 15
  46#define MaxIrqPIC               15
  47#define MaxIdtPIC               (IdtPIC + MaxIrqPIC)
  48
  49/* T_SYSCALL is defined by the following include (48) */
  50#include <ros/arch/syscall.h>
  51
  52/* 49-223 are IOAPIC routing vectors (from IOAPIC to LAPIC) */
  53#define IdtIOAPIC               (T_SYSCALL + 1)
  54#define MaxIdtIOAPIC            223
  55
  56/* 224-239 are OS IPI vectors (0xe0-0xef) */
  57/* smp_call_function IPIs, keep in sync with NUM_HANDLER_WRAPPERS.
  58 * SMP_CALL0 needs to be 16-aligned (we mask in x86/trap.c).  If you move these,
  59 * also change INIT_HANDLER_WRAPPER */
  60#define I_SMP_CALL0             224
  61#define I_SMP_CALL1             (I_SMP_CALL0 + 1)
  62#define I_SMP_CALL2             (I_SMP_CALL0 + 2)
  63#define I_SMP_CALL3             (I_SMP_CALL0 + 3)
  64#define I_SMP_CALL4             (I_SMP_CALL0 + 4)
  65#define I_SMP_CALL_LAST         I_SMP_CALL4
  66#define I_TESTING               236     /* Testing IPI (used in testing.c) */
  67#define I_POKE_GUEST            237
  68#define I_POKE_CORE             238
  69#define I_KERNEL_MSG            239
  70
  71/* 240-255 are LAPIC vectors (0xf0-0xff), hightest priority class */
  72#define IdtLAPIC                240
  73#define IdtLAPIC_TIMER          (IdtLAPIC + 0)
  74#define IdtLAPIC_THERMAL        (IdtLAPIC + 1)
  75#define IdtLAPIC_PCINT          (IdtLAPIC + 2)
  76#define IdtLAPIC_LINT0          (IdtLAPIC + 3)
  77#define IdtLAPIC_LINT1          (IdtLAPIC + 4)
  78#define IdtLAPIC_ERROR          (IdtLAPIC + 5)
  79/* Plan 9 apic note: the spurious vector number must have bits 3-0 0x0f
  80 * unless the Extended Spurious Vector Enable bit is set in the
  81 * HyperTransport Transaction Control register.  On some intel machines, those
  82 * bits are hardwired to 1s (SDM 3-10.9). */
  83#define IdtLAPIC_SPURIOUS       (IdtLAPIC + 0xf) /* Aka 255, 0xff */
  84#define MaxIdtLAPIC             (IdtLAPIC + 0xf)
  85
  86#define IdtMAX                  255
  87
  88#define T_DEFAULT   0x0000beef  // catchall
  89
  90/* Floating point constants */
  91#define FP_EXCP_IE              (1 << 0)        /* invalid op */
  92#define FP_EXCP_DE              (1 << 1)        /* denormalized op */
  93#define FP_EXCP_ZE              (1 << 2)        /* div by zero */
  94#define FP_EXCP_OE              (1 << 3)        /* numeric overflow */
  95#define FP_EXCP_UE              (1 << 4)        /* numeric underflow */
  96#define FP_EXCP_PE              (1 << 5)        /* precision */
  97
  98#define FP_SW_SF                (1 << 6)        /* stack fault */
  99#define FP_SW_ES                (1 << 7)        /* error summary status */
 100#define FP_SW_C0                (1 << 8)        /* condition codes */
 101#define FP_SW_C1                (1 << 9)
 102#define FP_SW_C2                (1 << 10)
 103#define FP_SW_C3                (1 << 14)
 104#define FP_CW_TOP_SHIFT         (11)
 105#define FP_CW_TOP_MASK          (7 << FP_CW_TOP_SHIFT)
 106
 107#define FP_CW_PC_SHIFT          (8)
 108#define FP_CW_PC_MASK           (3 << FP_CW_PC_SHIFT)
 109#define FP_CW_RC_SHIFT          (10)
 110#define FP_CW_RC_MASK           (3 << FP_CW_RC_SHIFT)
 111#define FP_CW_IC                (1 << 12)
 112
 113#ifndef __ASSEMBLER__
 114
 115#ifndef ROS_KERN_TRAP_H
 116#error "Do not include include arch/trap.h directly"
 117#endif
 118
 119#include <ros/common.h>
 120#include <arch/mmu.h>
 121#include <ros/trapframe.h>
 122#include <arch/pci.h>
 123#include <arch/pic.h>
 124#include <arch/topology.h>
 125#include <cpu_feat.h>
 126#include <arch/io.h>
 127#include <stdio.h>
 128
 129struct irq_handler {
 130        struct irq_handler *next;
 131        void (*isr)(struct hw_trapframe *hw_tf, void *data);
 132        void *data;
 133        int apic_vector;
 134
 135        /* all handlers in the chain need to have the same func pointers.  we
 136         * only really use the first one, and the latter are to catch bugs.
 137         * also, we won't be doing a lot of IRQ line sharing */
 138        bool (*check_spurious)(int);
 139        void (*eoi)(int);
 140        void (*mask)(struct irq_handler *irq_h, int vec);
 141        void (*unmask)(struct irq_handler *irq_h, int vec);
 142        void (*route_irq)(struct irq_handler *irq_h, int vec, int dest);
 143
 144        int tbdf;
 145        int dev_irq;
 146
 147        void *dev_private;
 148        char *type;
 149        #define IRQ_NAME_LEN 26
 150        char name[IRQ_NAME_LEN];
 151};
 152
 153/* The kernel's interrupt descriptor table */
 154extern gatedesc_t idt[];
 155extern pseudodesc_t idt_pd;
 156extern taskstate_t ts;
 157int bus_irq_setup(struct irq_handler *irq_h);   /* ioapic.c */
 158extern const char *x86_trapname(int trapno);
 159extern void sysenter_handler(void);
 160
 161/* Defined and set up in in arch/init.c, used for XMM initialization */
 162extern struct ancillary_state x86_default_fpu;
 163
 164static inline void save_fp_state(struct ancillary_state *silly)
 165{
 166        uint64_t x86_default_xcr0 = __proc_global_info.x86_default_xcr0;
 167        uint32_t eax, edx;
 168
 169        /* PLEASE NOTE:
 170         * AMD CPUs ignore the FOP/FIP/FDP fields when there is
 171         * no pending exception. When you are on AMD, we zero these fields in
 172         * the ancillary_state argument before saving. This way, if you are on
 173         * AMD and re-using an ancillary_state memory region, an old save's
 174         * information won't leak into your new data. The side-effect of this is
 175         * that you can't trust these fields to report accurate information on
 176         * AMD unless an exception was pending. Granted, AMD says that only
 177         * exception handlers should care about FOP/FIP/FDP, so that's probably
 178         * okay.
 179         *
 180         * You should also note that on newer Intel 64 processors, while the
 181         * value of the FOP is always saved and restored, it contains the opcode
 182         * of the most recent x87 FPU instruction that triggered an unmasked
 183         * exception, rather than simply the most recent opcode. Some older
 184         * Xeons and P4s had the fopcode compatibility mode feature, which you
 185         * could use to make the FOP update on every x87 non-control
 186         * instruction, but that has been eliminated in newer hardware.
 187         *
 188         */
 189        if (cpu_has_feat(CPU_FEAT_X86_VENDOR_AMD)) {
 190                silly->fp_head_64d.fop      = 0x0;
 191                silly->fp_head_64d.fpu_ip   = 0x0;
 192                silly->fp_head_64d.cs       = 0x0;
 193                // padding1 is FIP or rsvd, proc dep.
 194                silly->fp_head_64d.padding1 = 0x0;
 195                silly->fp_head_64d.fpu_dp   = 0x0;
 196                silly->fp_head_64d.ds       = 0x0;
 197                // padding2 is FDP or rsvd, proc dep.
 198                silly->fp_head_64d.padding2 = 0x0;
 199        }
 200
 201
 202        if (cpu_has_feat(CPU_FEAT_X86_XSAVEOPT)) {
 203                edx = x86_default_xcr0 >> 32;
 204                eax = x86_default_xcr0;
 205                asm volatile("xsaveopt64 %0" : : "m"(*silly), "a"(eax),
 206                             "d"(edx));
 207        } else if (cpu_has_feat(CPU_FEAT_X86_XSAVE)) {
 208                edx = x86_default_xcr0 >> 32;
 209                eax = x86_default_xcr0;
 210                asm volatile("xsave64 %0" : : "m"(*silly), "a"(eax), "d"(edx));
 211        } else {
 212                asm volatile("fxsave64 %0" : : "m"(*silly));
 213        }
 214}
 215
 216static inline void init_fp_state(void);
 217static inline void restore_fp_state(struct ancillary_state *silly)
 218{
 219        uint64_t x86_default_xcr0 = __proc_global_info.x86_default_xcr0;
 220        int err = 0;
 221        uint32_t eax, edx;
 222
 223        /*
 224         * Since AMD CPUs ignore the FOP/FIP/FDP fields when there is
 225         * no pending exception, we clear those fields before restoring
 226         * when we are both on AMD and there is no pending exception in
 227         * the ancillary_state argument to restore_fp_state.
 228         * If there is a pending exception in the ancillary_state,
 229         * these fields will be written to the FPU upon executing
 230         * a restore instruction, and there is nothing to worry about.
 231         *
 232         * See CVE-2006-1056 and CVE-2013-2076 on cve.mitre.org.
 233         *
 234         * We check for a pending exception by checking FSW.ES (bit 7)
 235         *
 236         * FNINIT clears FIP and FDP and, even though it is technically a
 237         * control instruction, it clears FOP because it is initializing the
 238         * FPU.
 239         *
 240         * NOTE: This might not be the most efficient way to do things, and
 241         *       could be an optimization target for context switch performance
 242         *       on AMD processors in the future.
 243         */
 244        if (!(silly->fp_head_64d.fsw & 0x80)
 245            && cpu_has_feat(CPU_FEAT_X86_VENDOR_AMD))
 246                asm volatile ("fninit;");
 247
 248        if (cpu_has_feat(CPU_FEAT_X86_XSAVE)) {
 249                edx = x86_default_xcr0 >> 32;
 250                eax = x86_default_xcr0;
 251                asm volatile(ASM_STAC               ";"
 252                             "1: xrstor64 %1         ;"
 253                             "2: " ASM_CLAC "        ;"
 254                             ".section .fixup, \"ax\";"
 255                             "3: mov %4, %0          ;"
 256                             "   jmp 2b              ;"
 257                             ".previous              ;"
 258                             _ASM_EXTABLE(1b, 3b)
 259                             : "=r" (err)
 260                             : "m"(*silly), "a"(eax), "d"(edx),
 261                               "i" (-EINVAL), "0" (err));
 262        } else {
 263                asm volatile(ASM_STAC               ";"
 264                             "1: fxrstor64 %1         ;"
 265                             "2: " ASM_CLAC "        ;"
 266                             ".section .fixup, \"ax\";"
 267                             "3: mov %2, %0          ;"
 268                             "   jmp 2b              ;"
 269                             ".previous              ;"
 270                             _ASM_EXTABLE(1b, 3b)
 271                             : "=r" (err)
 272                             : "m"(*silly),
 273                               "i" (-EINVAL), "0" (err));
 274        }
 275
 276
 277        if (err) {
 278                printk("Error restoring fp state!\n");
 279                printk("Likely a bad ancillary_state argument.\n");
 280                printk("Re-initializing fp state to default due to error.\n");
 281                init_fp_state();
 282        }
 283}
 284
 285/* A regular fninit only initializes the control, status, tag, ip,
 286 * and data pointer registers. Since it leaves the data registers,
 287 * MXCSR, etc. unchanged, we use init_fp_state to restore a default
 288 * state that we save at boot time.
 289 *
 290 * If you're looking for a workout, you could also fninit, ldmxcsr with
 291 * a default value, and 0 all the registers by hand.
 292 */
 293static inline void init_fp_state(void)
 294{
 295        restore_fp_state(&x86_default_fpu);
 296}
 297
 298static inline void __attribute__((always_inline))
 299set_stack_pointer(uintptr_t sp)
 300{
 301        asm volatile("mov %0,%%"X86_REG_SP"" : : "r"(sp)
 302                     : "memory", X86_REG_SP);
 303}
 304
 305static inline void __attribute__((always_inline))
 306set_frame_pointer(uintptr_t fp)
 307{
 308        /* note we can't list BP as a clobber - the compiler will flip out.
 309         * makes me wonder if clobbering SP above makes a difference (probably
 310         * not) */
 311        asm volatile("mov %0,%%"X86_REG_BP"" : : "r"(fp) : "memory");
 312}
 313
 314extern segdesc_t *gdt;
 315
 316#include <arch/trap64.h>
 317
 318#endif /* !__ASSEMBLER__ */
 319