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        void (*cleanup)(struct irq_handler *irq_h);
 144
 145        int tbdf;
 146        int dev_irq;
 147
 148        void *dev_private;
 149        char *type;
 150        #define IRQ_NAME_LEN 26
 151        char name[IRQ_NAME_LEN];
 152};
 153
 154/* The kernel's interrupt descriptor table */
 155extern gatedesc_t idt[];
 156extern pseudodesc_t idt_pd;
 157extern taskstate_t ts;
 158int bus_irq_setup(struct irq_handler *irq_h);   /* ioapic.c */
 159extern const char *x86_trapname(int trapno);
 160extern void sysenter_handler(void);
 161
 162/* Defined and set up in in arch/init.c, used for XMM initialization */
 163extern struct ancillary_state x86_default_fpu;
 164
 165static inline void save_fp_state(struct ancillary_state *silly)
 166{
 167        uint64_t x86_default_xcr0 = __proc_global_info.x86_default_xcr0;
 168        uint32_t eax, edx;
 169
 170        /* PLEASE NOTE:
 171         * AMD CPUs ignore the FOP/FIP/FDP fields when there is
 172         * no pending exception. When you are on AMD, we zero these fields in
 173         * the ancillary_state argument before saving. This way, if you are on
 174         * AMD and re-using an ancillary_state memory region, an old save's
 175         * information won't leak into your new data. The side-effect of this is
 176         * that you can't trust these fields to report accurate information on
 177         * AMD unless an exception was pending. Granted, AMD says that only
 178         * exception handlers should care about FOP/FIP/FDP, so that's probably
 179         * okay.
 180         *
 181         * You should also note that on newer Intel 64 processors, while the
 182         * value of the FOP is always saved and restored, it contains the opcode
 183         * of the most recent x87 FPU instruction that triggered an unmasked
 184         * exception, rather than simply the most recent opcode. Some older
 185         * Xeons and P4s had the fopcode compatibility mode feature, which you
 186         * could use to make the FOP update on every x87 non-control
 187         * instruction, but that has been eliminated in newer hardware.
 188         *
 189         */
 190        if (cpu_has_feat(CPU_FEAT_X86_VENDOR_AMD)) {
 191                silly->fp_head_64d.fop      = 0x0;
 192                silly->fp_head_64d.fpu_ip   = 0x0;
 193                silly->fp_head_64d.cs       = 0x0;
 194                // padding1 is FIP or rsvd, proc dep.
 195                silly->fp_head_64d.padding1 = 0x0;
 196                silly->fp_head_64d.fpu_dp   = 0x0;
 197                silly->fp_head_64d.ds       = 0x0;
 198                // padding2 is FDP or rsvd, proc dep.
 199                silly->fp_head_64d.padding2 = 0x0;
 200        }
 201
 202
 203        if (cpu_has_feat(CPU_FEAT_X86_XSAVEOPT)) {
 204                edx = x86_default_xcr0 >> 32;
 205                eax = x86_default_xcr0;
 206                asm volatile("xsaveopt64 %0" : : "m"(*silly), "a"(eax),
 207                             "d"(edx));
 208        } else if (cpu_has_feat(CPU_FEAT_X86_XSAVE)) {
 209                edx = x86_default_xcr0 >> 32;
 210                eax = x86_default_xcr0;
 211                asm volatile("xsave64 %0" : : "m"(*silly), "a"(eax), "d"(edx));
 212        } else {
 213                asm volatile("fxsave64 %0" : : "m"(*silly));
 214        }
 215}
 216
 217static inline void init_fp_state(void);
 218static inline void restore_fp_state(struct ancillary_state *silly)
 219{
 220        uint64_t x86_default_xcr0 = __proc_global_info.x86_default_xcr0;
 221        int err = 0;
 222        uint32_t eax, edx;
 223
 224        /*
 225         * Since AMD CPUs ignore the FOP/FIP/FDP fields when there is
 226         * no pending exception, we clear those fields before restoring
 227         * when we are both on AMD and there is no pending exception in
 228         * the ancillary_state argument to restore_fp_state.
 229         * If there is a pending exception in the ancillary_state,
 230         * these fields will be written to the FPU upon executing
 231         * a restore instruction, and there is nothing to worry about.
 232         *
 233         * See CVE-2006-1056 and CVE-2013-2076 on cve.mitre.org.
 234         *
 235         * We check for a pending exception by checking FSW.ES (bit 7)
 236         *
 237         * FNINIT clears FIP and FDP and, even though it is technically a
 238         * control instruction, it clears FOP because it is initializing the
 239         * FPU.
 240         *
 241         * NOTE: This might not be the most efficient way to do things, and
 242         *       could be an optimization target for context switch performance
 243         *       on AMD processors in the future.
 244         */
 245        if (!(silly->fp_head_64d.fsw & 0x80)
 246            && cpu_has_feat(CPU_FEAT_X86_VENDOR_AMD))
 247                asm volatile ("fninit;");
 248
 249        if (cpu_has_feat(CPU_FEAT_X86_XSAVE)) {
 250                edx = x86_default_xcr0 >> 32;
 251                eax = x86_default_xcr0;
 252                asm volatile(ASM_STAC               ";"
 253                             "1: xrstor64 %1         ;"
 254                             "2: " ASM_CLAC "        ;"
 255                             ".section .fixup, \"ax\";"
 256                             "3: mov %4, %0          ;"
 257                             "   jmp 2b              ;"
 258                             ".previous              ;"
 259                             _ASM_EXTABLE(1b, 3b)
 260                             : "=r" (err)
 261                             : "m"(*silly), "a"(eax), "d"(edx),
 262                               "i" (-EINVAL), "0" (err));
 263        } else {
 264                asm volatile(ASM_STAC               ";"
 265                             "1: fxrstor64 %1         ;"
 266                             "2: " ASM_CLAC "        ;"
 267                             ".section .fixup, \"ax\";"
 268                             "3: mov %2, %0          ;"
 269                             "   jmp 2b              ;"
 270                             ".previous              ;"
 271                             _ASM_EXTABLE(1b, 3b)
 272                             : "=r" (err)
 273                             : "m"(*silly),
 274                               "i" (-EINVAL), "0" (err));
 275        }
 276
 277
 278        if (err) {
 279                printk("Error restoring fp state!\n");
 280                printk("Likely a bad ancillary_state argument.\n");
 281                printk("Re-initializing fp state to default due to error.\n");
 282                init_fp_state();
 283        }
 284}
 285
 286/* A regular fninit only initializes the control, status, tag, ip,
 287 * and data pointer registers. Since it leaves the data registers,
 288 * MXCSR, etc. unchanged, we use init_fp_state to restore a default
 289 * state that we save at boot time.
 290 *
 291 * If you're looking for a workout, you could also fninit, ldmxcsr with
 292 * a default value, and 0 all the registers by hand.
 293 */
 294static inline void init_fp_state(void)
 295{
 296        restore_fp_state(&x86_default_fpu);
 297}
 298
 299static inline void __attribute__((always_inline))
 300set_stack_pointer(uintptr_t sp)
 301{
 302        asm volatile("mov %0,%%"X86_REG_SP"" : : "r"(sp)
 303                     : "memory", X86_REG_SP);
 304}
 305
 306static inline void __attribute__((always_inline))
 307set_frame_pointer(uintptr_t fp)
 308{
 309        /* note we can't list BP as a clobber - the compiler will flip out.
 310         * makes me wonder if clobbering SP above makes a difference (probably
 311         * not) */
 312        asm volatile("mov %0,%%"X86_REG_BP"" : : "r"(fp) : "memory");
 313}
 314
 315extern segdesc_t *gdt;
 316
 317#include <arch/trap64.h>
 318
 319#endif /* !__ASSEMBLER__ */
 320