1/**
2 * \file
3 * \brief x86-64 interrupt/exception handling utility functions
4 */
5
6/*
7 * Copyright (c) 2007, 2008, 2009, 2010, 2011, 2013, ETH Zurich.
8 * All rights reserved.
9 *
10 * This file is distributed under the terms in the attached LICENSE file.
11 * If you do not find this file, copies can be found by writing to:
12 * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
13 */
14
15/*********************************************************************
16 *
17 * Copyright (C) 2003-2004,  Karlsruhe University
18 *
19 * File path:     glue/v4-amd64/hwirq.h
20 * Description:   Macros to define interrupt handler stubs for AMD64
21 *
22 * Redistribution and use in source and binary forms, with or without
23 * modification, are permitted provided that the following conditions
24 * are met:
25 * 1. Redistributions of source code must retain the above copyright
26 *    notice, this list of conditions and the following disclaimer.
27 * 2. Redistributions in binary form must reproduce the above copyright
28 *    notice, this list of conditions and the following disclaimer in the
29 *    documentation and/or other materials provided with the distribution.
30 *
31 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
32 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
33 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
34 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
35 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
39 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
40 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
41 * SUCH DAMAGE.
42 *
43 * $Id: hwirq.h,v 1.3 2006/10/19 22:57:35 ud3 Exp $
44 *
45 ********************************************************************/
46
47#include <kernel.h>
48#include <stdio.h>
49#include <string.h>
50#include <irq.h>
51#include <exec.h>
52#include <gdb_stub.h>
53#include <arch_gdb_stub.h>
54#include <x86.h>
55#include <dispatch.h>
56#include <wakeup.h>
57#include <arch/x86/perfmon.h>
58#include <arch/x86/barrelfish_kpi/perfmon.h>
59#include <arch/x86/pic.h>
60#include <arch/x86/apic.h>
61#include <barrelfish_kpi/dispatcher_shared_target.h>
62#include <asmoffsets.h>
63#include <trace/trace.h>
64#include <trace_definitions/trace_defs.h>
65#include <arch/x86/timing.h>
66#include <arch/x86/syscall.h>
67#include <arch/x86/ipi_notify.h>
68#include <barrelfish_kpi/cpu_arch.h>
69#include <kcb.h>
70#include <mdb/mdb_tree.h>
71#include <sys_debug.h>
72#include <systime.h>
73
74#include <dev/ia32_dev.h>
75
76static const char *idt_descs[] =
77{
78    [IDT_DE]    = "#DE: Divide Error",
79    [IDT_DB]    = "#DB: Debug",
80    [IDT_NMI]   = "Nonmaskable External Interrupt",
81    [IDT_BP]    = "#BP: Breakpoint",
82    [IDT_OF]    = "#OF: Overflow",
83    [IDT_BR]    = "#BR: Bound Range Exceeded",
84    [IDT_UD]    = "#UD: Undefined/Invalid Opcode",
85    [IDT_NM]    = "#NM: No Math Coprocessor",
86    [IDT_DF]    = "#DF: Double Fault",
87    [IDT_FPUGP] = "Coprocessor Segment Overrun",
88    [IDT_TS]    = "#TS: Invalid TSS",
89    [IDT_NP]    = "#NP: Segment Not Present",
90    [IDT_SS]    = "#SS: Stack Segment Fault",
91    [IDT_GP]    = "#GP: General Protection Fault",
92    [IDT_PF]    = "#PF: Page Fault",
93    [IDT_MF]    = "#MF: FPU Floating-Point Error",
94    [IDT_AC]    = "#AC: Alignment Check",
95    [IDT_MC]    = "#MC: Machine Check",
96    [IDT_XF]    = "#XF: SIMD Floating-Point Exception",
97};
98
99/**
100 * \brief Define IRQ handler number 'num'.
101 *
102 * This defines an interrupt handler for vector #num. The way this is done is
103 * quite tricky: A block of assembly is emitted, with a label pointing to
104 * the beginning of that block. The label is made known as a symbol by
105 * having a C function _declaration_ directly in front of the block. The
106 * symbol has to be defined extern, so it is global, but its ELF visibility
107 * is set "hidden", so that the symbol does not end up in the GOT. This is
108 * very important for keeping the code position-independent.
109 *
110 * The NOERR/ERR variants depend on whether the hardware delivers an error code.
111 */
112#define HW_EXCEPTION_NOERR(num)                                         \
113    void __attribute__ ((visibility ("hidden"))) hwexc_##num(void);     \
114    __asm (                                                             \
115           "\t.text                                        \n\t"        \
116           "\t.type hwexc_"#num",@function                 \n\t"        \
117           "hwexc_"#num":                                  \n\t"        \
118           "pushq $0                /* dummy error code */ \n\t"        \
119           "pushq $"#num"           /* vector number */    \n\t"        \
120           "jmp    hwexc_common     /* common stuff */     \n\t"        \
121                                                                        )
122
123#define HW_EXCEPTION_ERR(num)                                           \
124    void __attribute__ ((visibility ("hidden"))) hwexc_##num(void);     \
125    __asm (                                                             \
126           "\t.text                                        \n\t"        \
127           "\t.type hwexc_"#num",@function                 \n\t"        \
128           "hwexc_"#num":                                  \n\t"        \
129           "pushq $"#num"           /* vector number */    \n\t"        \
130           "jmp    hwexc_common     /* common stuff */     \n\t"        \
131                                                                        )
132
133#define XHW_IRQ(num)                                                    \
134    void __attribute__ ((visibility ("hidden"))) hwirq_##num(void);     \
135    __asm (                                                             \
136           "\t.text                                        \n\t"        \
137           "\t.type hwirq_"#num",@function                 \n\t"        \
138           "hwirq_"#num":                                  \n\t"        \
139           "pushq $"#num"           /* vector number */    \n\t"        \
140           "jmp    hwirq_common     /* common stuff */     \n\t"        \
141                                                                        )
142/// Noop wrapper for HW_IRQ to deal with CPP stringification problems
143#define HW_IRQ(num) XHW_IRQ(num)
144
145#define STR(x) #x
146#define XTR(x) STR(x)
147
148__asm (
149    ".text                                              \n\t"
150    "   .type hwexc_common ,@function                   \n\t"
151    "hwexc_common:                                      \n\t"
152    "testb $3, 24(%rsp) /* if CS.CPL == 0 */            \n\t"
153    "jz kernel_fault                                    \n\t"
154
155    /* User exception: save full state and return to the user.
156     * This path could be optimized by only saving the non-volatile
157     * registers (since the kernel's C path will maintain them), and
158     * having the user-mode code save them if needed. Since the
159     * current user code always does need them, we just save the full
160     * set here. */
161
162    /* decide where to save the state, the options are:
163     *    pagefault and enabled -> enabled save area
164     *    pagefault while disabled or any other trap -> trap save area
165     */
166    "pushq %rcx                                         \n\t"
167    "movq dcb_current(%rip), %rcx /* rcx = dcb_current */       \n\t"
168    "movq "XTR(OFFSETOF_DCB_DISP)"(%rcx), %rcx /* rcx = dcb_current->disp */\n\t"
169    "cmpq $14, 8(%rsp)       /* is pagefault? */        \n\t"
170    "jne save_trap                                      \n\t"
171    "cmpl $0, "XTR(OFFSETOF_DISP_DISABLED)"(%rcx) /* disp->disabled ? */\n\t"
172    "jne save_trap                                      \n\t"
173    "pushq %rbx                                         \n\t"
174    "movq 4*8(%rsp), %rbx     /* rbx = faulting IP */   \n\t"
175    "cmpq "XTR(OFFSETOF_DISP_X86_64_CRIT_PC_LOW)"(%rcx), %rbx /* crit_pc_low <= rip? */\n\t"
176    "jae disabled_test                                  \n\t"
177    "\nsave_enabled:                                    \n\t"
178    "popq %rbx                                          \n\t"
179    "addq $"XTR(OFFSETOF_DISP_X86_64_ENABLED_AREA)", %rcx /* rcx = enabled_save_area */\n\t"
180    "jmp do_save                                        \n\t"
181    "\ndisabled_test:                                   \n\t"
182    "cmpq "XTR(OFFSETOF_DISP_X86_64_CRIT_PC_HIGH)"(%rcx), %rbx /* crit_pc_high > rip? */\n\t"
183    "jae save_enabled                                   \n\t"
184    "popq %rbx                                          \n\t"
185    "\nsave_trap:                                       \n\t"
186    "addq $"XTR(OFFSETOF_DISP_X86_64_TRAP_AREA)", %rcx /* trap_save_area */\n\t"
187
188    /* save to the save area. at this point, rcx = save area ptr,
189     * rsp+8 = exception num, rsp+16 = CPU-stacked error and registers */
190    "\ndo_save:                                         \n\t"
191    "movq %rax,  0*8(%rcx)                              \n\t"
192    "popq %rax                    /* original rcx */    \n\t"
193    "movq %rbx,  1*8(%rcx)                              \n\t"
194    "movq %rax,  2*8(%rcx)                              \n\t"
195    "movq %rdx,  3*8(%rcx)                              \n\t"
196    "movq %rsi,  4*8(%rcx)                              \n\t"
197    "movq %rdi,  5*8(%rcx)                              \n\t"
198    "movq %rbp,  6*8(%rcx)                              \n\t"
199    "movq %r8,   8*8(%rcx)                              \n\t"
200    "movq %r9,   9*8(%rcx)                              \n\t"
201    "movq %r10, 10*8(%rcx)                              \n\t"
202    "movq %r11, 11*8(%rcx)                              \n\t"
203    "movq %r12, 12*8(%rcx)                              \n\t"
204    "movq %r13, 13*8(%rcx)                              \n\t"
205    "movq %r14, 14*8(%rcx)                              \n\t"
206    "movq %r15, 15*8(%rcx)                              \n\t"
207    "mov %fs, "XTR(OFFSETOF_FS_REG)"(%rcx)              \n\t"
208    "mov %gs, "XTR(OFFSETOF_GS_REG)"(%rcx)              \n\t"
209    "fxsave "XTR(OFFSETOF_FXSAVE_AREA)"(%rcx)           \n\t"
210    "popq %rdi                    /* vector number */   \n\t"
211    "popq %rsi                    /* error code */      \n\t"
212    "movq %rsp, %rdx              /* CPU save area */   \n\t"
213    "callq generic_handle_user_exception                \n\t"
214    "iretq                                              \n\t"
215
216    /* a kernel fault means something bad happened, so we stack
217     * everything for the debugger to use, in the GDB frame format */
218    "\nkernel_fault:                                    \n\t"
219    "pushq 6*8(%rsp) /* SS */                           \n\t"
220    "pushq 4*8(%rsp) /* CS */                           \n\t"
221    "pushq 7*8(%rsp) /* EFLAGS */                       \n\t"
222    "pushq 5*8(%rsp) /* RIP */                          \n\t"
223    /* TODO: extend frame size and save FS/GS so we can resume afterwards */
224    "pushq %r15                                         \n\t"
225    "pushq %r14                                         \n\t"
226    "pushq %r13                                         \n\t"
227    "pushq %r12                                         \n\t"
228    "pushq %r11                                         \n\t"
229    "pushq %r10                                         \n\t"
230    "pushq %r9                                          \n\t"
231    "pushq %r8                                          \n\t"
232    "pushq 17*8(%rsp) /* RSP */                         \n\t"
233    "pushq %rbp                                         \n\t"
234    "pushq %rdi                                         \n\t"
235    "pushq %rsi                                         \n\t"
236    "pushq %rdx                                         \n\t"
237    "pushq %rcx                                         \n\t"
238    "pushq %rbx                                         \n\t"
239    "pushq %rax                                         \n\t"
240    "movq 20*8(%rsp), %rdi  /* vector number */         \n\t"
241    "movq 21*8(%rsp), %rsi  /* error code   */          \n\t"
242    "movq %rsp, %rdx       /* save area ptr*/           \n\t"
243    "jmp generic_handle_kernel_exception                \n\t"
244
245
246    /* (Device) interrupt. */
247    "   .type hwirq_common ,@function                   \n\t"
248    "hwirq_common:                                      \n\t"
249    /* If it happened in kernel_mode, simply make userspace runnable.
250     * This is a special case, since interrupts are normally disabled when
251     * entering the kernel. However, they are enabled when there is nothing
252     * to do, and the kernel goes to sleep using wait_for_interrupts() */
253    "testb $3, 16(%rsp) /* if CS.CPL == 0 */            \n\t"
254    "jz call_handle_irq                                 \n\t"
255
256    /* Happened in user mode.
257     * we need to save everything to the dispatcher. */
258    /* decide where to save the state, either enabled or disabled save areas */
259    "pushq %rdx                                         \n\t"
260    "movq dcb_current(%rip), %rdx /* rdx = dcb_current */       \n\t"
261    "movq "XTR(OFFSETOF_DCB_DISP)"(%rdx), %rdx /* rdx = dcb_current->disp */\n\t"
262    "cmpl $0, "XTR(OFFSETOF_DISP_DISABLED)"(%rdx) /* disp->disabled ? */\n\t"
263    "jne irq_save_disabled                              \n\t"
264    "pushq %rbx                                         \n\t"
265    "movq 24(%rsp), %rbx     /* rbx = faulting IP */    \n\t"
266    "cmpq "XTR(OFFSETOF_DISP_X86_64_CRIT_PC_LOW)"(%rdx), %rbx /* crit_pc_low <= rip? */\n\t"
267    "jae irq_disabled_test                              \n\t"
268    "\nirq_save_enabled:                                \n\t"
269    "popq %rbx                                          \n\t"
270    "addq $"XTR(OFFSETOF_DISP_X86_64_ENABLED_AREA)", %rdx /* rdx = enabled_save_area */\n\t"
271    "jmp irq_do_save                                    \n\t"
272    "\nirq_disabled_test:                               \n\t"
273    "cmpq "XTR(OFFSETOF_DISP_X86_64_CRIT_PC_HIGH)"(%rdx), %rbx /* crit_pc_high > rip? */\n\t"
274    "jae irq_save_enabled                               \n\t"
275    "popq %rbx                                          \n\t"
276    "\nirq_save_disabled:                               \n\t"
277    "addq $"XTR(OFFSETOF_DISP_X86_64_DISABLED_AREA)", %rdx /* disabled_save_area */\n\t"
278
279    /* save to the save area. at this point, rdx = save area ptr,
280     * rsp+8 = vector number, rsp+16 = CPU-stacked regisers */
281    "\nirq_do_save:                                     \n\t"
282    "movq %rax,  0*8(%rdx)                              \n\t"
283    "movq %rbx,  1*8(%rdx)                              \n\t"
284    "movq %rcx,  2*8(%rdx)                              \n\t"
285    "popq %rax                    /* original rdx */    \n\t"
286    "movq %rax,  3*8(%rdx)                              \n\t"
287    "movq %rsi,  4*8(%rdx)                              \n\t"
288    "movq %rdi,  5*8(%rdx)                              \n\t"
289    "movq %rbp,  6*8(%rdx)                              \n\t"
290    "movq %r8,   8*8(%rdx)                              \n\t"
291    "movq %r9,   9*8(%rdx)                              \n\t"
292    "movq %r10, 10*8(%rdx)                              \n\t"
293    "movq %r11, 11*8(%rdx)                              \n\t"
294    "movq %r12, 12*8(%rdx)                              \n\t"
295    "movq %r13, 13*8(%rdx)                              \n\t"
296    "movq %r14, 14*8(%rdx)                              \n\t"
297    "movq %r15, 15*8(%rdx)                              \n\t"
298    "mov %fs, "XTR(OFFSETOF_FS_REG)"(%rdx)              \n\t"
299    "mov %gs, "XTR(OFFSETOF_GS_REG)"(%rdx)              \n\t"
300    "fxsave "XTR(OFFSETOF_FXSAVE_AREA)"(%rdx)           \n\t"
301    "popq %rdi                    /* vector number */   \n\t"
302    "movq %rsp, %rsi              /* CPU save area */   \n\t"
303    "jmp generic_handle_irq /* NB: rdx = disp save ptr*/\n\t"
304
305    "\ncall_handle_irq:                                 \n\t"
306    "popq %rdi                                          \n\t"
307    "callq handle_irq                                   \n\t"
308);
309
310// CPU exceptions
311HW_EXCEPTION_NOERR(0);
312HW_EXCEPTION_NOERR(1);
313HW_EXCEPTION_NOERR(2);
314HW_EXCEPTION_NOERR(3);
315HW_EXCEPTION_NOERR(4);
316HW_EXCEPTION_NOERR(5);
317HW_EXCEPTION_NOERR(6);
318HW_EXCEPTION_NOERR(7);
319HW_EXCEPTION_ERR(8);
320HW_EXCEPTION_NOERR(9);
321HW_EXCEPTION_ERR(10);
322HW_EXCEPTION_ERR(11);
323HW_EXCEPTION_ERR(12);
324HW_EXCEPTION_ERR(13);
325HW_EXCEPTION_ERR(14);
326HW_EXCEPTION_NOERR(16);
327HW_EXCEPTION_ERR(17);
328HW_EXCEPTION_NOERR(18);
329HW_EXCEPTION_NOERR(19);
330
331// Classic PIC interrupts
332HW_IRQ(32);
333HW_IRQ(33);
334HW_IRQ(34);
335HW_IRQ(35);
336HW_IRQ(36);
337HW_IRQ(37);
338HW_IRQ(38);
339HW_IRQ(39);
340HW_IRQ(40);
341HW_IRQ(41);
342HW_IRQ(42);
343HW_IRQ(43);
344HW_IRQ(44);
345HW_IRQ(45);
346HW_IRQ(46);
347HW_IRQ(47);
348
349// Generic interrupts
350HW_IRQ(48);
351HW_IRQ(49);
352HW_IRQ(50);
353HW_IRQ(51);
354HW_IRQ(52);
355HW_IRQ(53);
356HW_IRQ(54);
357HW_IRQ(55);
358HW_IRQ(56);
359HW_IRQ(57);
360HW_IRQ(58);
361HW_IRQ(59);
362HW_IRQ(60);
363HW_IRQ(61);
364
365// Trace IPIs
366HW_IRQ(62);
367HW_IRQ(63);
368
369// Local APIC interrupts
370HW_IRQ(248);
371HW_IRQ(249);
372HW_IRQ(250);
373HW_IRQ(251);
374HW_IRQ(252);
375HW_IRQ(253);
376HW_IRQ(254);
377
378// Reserved as "unhandled exception" handler
379HW_EXCEPTION_NOERR(666);
380
381#define ERR_PF_PRESENT          (1 << 0)
382#define ERR_PF_READ_WRITE       (1 << 1)
383#define ERR_PF_USER_SUPERVISOR  (1 << 2)
384#define ERR_PF_RESERVED         (1 << 3)
385#define ERR_PF_INSTRUCTION      (1 << 4)
386
387/**
388 * \brief Interrupt Descriptor Table (IDT) for processor this kernel is running
389 * on.
390 */
391static struct gate_descriptor idt[NIDT] __attribute__ ((aligned (16)));
392
393static int timer_fired = 0;
394
395#if CONFIG_TRACE && NETWORK_STACK_TRACE
396#define TRACE_ETHERSRV_MODE 1
397#endif // CONFIG_TRACE && NETWORK_STACK_TRACE
398
399
400static inline bool bitmap_get(uint8_t * bitmap, int idx){
401    return (bitmap[idx/8] >> (idx % 8)) & 1;
402}
403
404static inline void bitmap_set_true(uint8_t * bitmap, int idx){
405    bitmap[idx/8] |= (1 << (idx % 8));
406}
407
408
409/**
410 * \brief Send interrupt notification to user-space listener.
411 *
412 * Sends an interrupt notification IDC to a local endpoint that
413 * listens for IRQ notifications.
414 *
415 * \param irq   IRQ# to send in notification.
416 */
417static uint32_t pkt_interrupt_count = 0;
418static void send_user_interrupt(int irq)
419{
420    assert(irq >= 0 && irq < NDISPATCH);
421    struct kcb *k = kcb_current;
422    do {
423        if (k->irq_dispatch[irq].cap.type == ObjType_EndPoint) {
424            break;
425        }
426        k = k->next;
427    } while (k && k != kcb_current);
428    // if k == NULL we don't need to switch as we only have a single kcb
429    if (k) {
430        switch_kcb(k);
431    }
432    // from here: kcb_current is the kcb for which the interrupt was intended
433    struct capability *cap = &kcb_current->irq_dispatch[irq].cap;
434
435    // Return on null cap (unhandled interrupt)
436    if(cap->type == ObjType_Null) {
437        printk(LOG_WARN, "unhandled IRQ %d\n", irq);
438        return;
439    } else if (cap->type > ObjType_Num) {
440        // XXX: HACK: this doesn't fix the root cause of having weird entries
441        // in kcb_current->irq_dispatch[], but it allows us to test the system
442        // more reliably for now. -SG
443        // Also complain to SG if this gets checked in to the main tree!
444        printk(LOG_WARN, "receiver type > %d, %d, assume unhandled\n", ObjType_Num, cap->type);
445        return;
446    }
447
448    if (irq == 0) {
449        ++pkt_interrupt_count;
450#if NETWORK_STACK_TRACE
451    trace_event(TRACE_SUBSYS_NNET, TRACE_EVENT_NNET_UIRQ, pkt_interrupt_count);
452#endif // NETWORK_STACK_TRACE
453
454    }
455    // Otherwise, cap needs to be an endpoint
456    assert(cap->type == ObjType_EndPoint);
457
458    // send empty message as notification
459    errval_t err = lmp_deliver_notification(cap);
460    if (err_is_fail(err)) {
461        if (err_no(err) == SYS_ERR_LMP_BUF_OVERFLOW) {
462            struct dispatcher_shared_generic *disp =
463                get_dispatcher_shared_generic(cap->u.endpoint.listener->disp);
464            printk(LOG_WARN, "%.*s: IRQ message buffer overflow on IRQ %d\n",
465                   DISP_NAME_LEN, disp->name, irq);
466        } else {
467            printk(LOG_ERR, "Unexpected error delivering IRQ\n");
468        }
469    }
470
471#ifdef SCHEDULER_RR
472    /* XXX: run the handler dispatcher immediately
473     * we shouldn't do this (we should let the scheduler decide), but because
474     * our default scheduler is braindead, this is a quick hack to make sure
475     * that mostly-sane things happen
476     */
477    dispatch(cap->u.endpoint.listener);
478#else
479    dispatch(schedule());
480#endif
481}
482
483/*
484 * This interface is deprecated. Use irq_table_alloc_dest_caps
485 */
486errval_t irq_table_alloc(int *outvec)
487{
488    printk(LOG_WARN, "irq_table_alloc is deprecated\n");
489    assert(outvec);
490    // XXX: this is O(#kcb*NDISPATCH)
491    int i;
492    for (i = 0; i < NDISPATCH; i++) {
493        struct kcb *k = kcb_current;
494        bool found_free = true;
495        do {
496            if (k->irq_dispatch[i].cap.type == ObjType_EndPoint) {
497                found_free = false;
498                break;
499            }
500            k = k->next;
501        } while(k && k != kcb_current);
502        if (found_free) {
503            break;
504        }
505    }
506    if (i == NDISPATCH) {
507        *outvec = -1;
508        return SYS_ERR_IRQ_NO_FREE_VECTOR;
509    } else {
510        *outvec = i;
511        return SYS_ERR_OK;
512    }
513}
514
515errval_t irq_table_alloc_dest_cap(uint8_t dcn_level, capaddr_t dcn, capaddr_t out_cap_addr)
516{
517    errval_t err;
518
519    int i;
520    bool i_usable = false;
521    for (i = NEXCEPTIONS+1; i < NDISPATCH; i++) {
522        i_usable = true;
523        //Iterate over all kcbs
524        struct kcb *k = kcb_current;
525        do {
526            if(bitmap_get(k->irq_in_use, i)){
527                i_usable = false;
528                break;
529            }
530            k = k->next;
531        } while (k && k != kcb_current);
532        if(i_usable) break; // Skip increment
533    }
534
535    if (i == NDISPATCH) {
536        return SYS_ERR_IRQ_NO_FREE_VECTOR;
537    } else {
538        struct cte out_cap;
539        memset(&out_cap, 0, sizeof(struct cte));
540        bitmap_set_true(kcb_current->irq_in_use, i);
541
542        out_cap.cap.type = ObjType_IRQDest;
543        out_cap.cap.u.irqdest.cpu = my_core_id;
544        out_cap.cap.u.irqdest.vector = i;
545
546        struct cte * cn;
547        err = caps_lookup_slot(&dcb_current->cspace.cap, dcn, dcn_level,
548                               &cn, CAPRIGHTS_WRITE);
549        if(err_is_fail(err)){
550            return err;
551        }
552
553        caps_copy_to_cnode(cn, out_cap_addr, &out_cap, 0, 0, 0);
554        //printk(LOG_NOTE, "irq: Allocated cap for vec: %d\n", i);
555        return SYS_ERR_OK;
556    }
557}
558
559errval_t irq_connect(struct capability *dest_cap, capaddr_t endpoint_adr)
560{
561    errval_t err;
562    struct cte *endpoint;
563
564    // Lookup & check message endpoint cap
565    err = caps_lookup_slot(&dcb_current->cspace.cap, endpoint_adr,
566                           2, &endpoint, CAPRIGHTS_WRITE);
567    if (err_is_fail(err)) {
568        return err_push(err, SYS_ERR_IRQ_LOOKUP_EP);
569    }
570
571    assert(endpoint != NULL);
572
573    // Return w/error if cap is not an endpoint
574    if(endpoint->cap.type != ObjType_EndPoint) {
575        return SYS_ERR_IRQ_NOT_ENDPOINT;
576    }
577
578    // Return w/error if no listener on endpoint
579    if(endpoint->cap.u.endpoint.listener == NULL) {
580        return SYS_ERR_IRQ_NO_LISTENER;
581    }
582
583    assert(dest_cap->type == ObjType_IRQDest);
584    if(dest_cap->u.irqdest.cpu != my_core_id){
585        return SYS_ERR_IRQ_WRONG_CONTROLLER;
586    }
587
588    uint64_t dest_vec = dest_cap->u.irqdest.vector - 32;
589    assert(kcb_current->irq_dispatch[dest_vec].cap.type == ObjType_Null);
590    caps_copy_to_cte(&kcb_current->irq_dispatch[dest_vec],
591            endpoint,0,0,0);
592
593    //printk(LOG_NOTE, "irq: connected vec: %"PRIu64"\n", dest_vec);
594    return SYS_ERR_OK;
595}
596
597/**
598 * Deprecated. Use capabilities.
599 */
600errval_t irq_table_set(unsigned int nidt, capaddr_t endpoint)
601{
602    printk(LOG_ERR, "Used deprecated irq_table_set. Not setting interrupt\n");
603    return SYS_ERR_IRQ_INVALID;
604}
605
606errval_t irq_table_delete(unsigned int nidt)
607{
608    printk(LOG_ERR, "Used deprecated irq_table_delete. Not setting interrupt\n");
609    return SYS_ERR_IRQ_INVALID;
610}
611
612errval_t irq_table_notify_domains(struct kcb *kcb)
613{
614    uintptr_t msg[] = { 1 };
615    for (int i = 0; i < NDISPATCH; i++) {
616        if (kcb->irq_dispatch[i].cap.type == ObjType_EndPoint) {
617            struct capability *cap = &kcb->irq_dispatch[i].cap;
618            // 1 word message as notification
619            errval_t err = lmp_deliver_payload(cap, NULL, msg, 1, false, false);
620            if (err_is_fail(err)) {
621                if (err_no(err) == SYS_ERR_LMP_BUF_OVERFLOW) {
622                    struct dispatcher_shared_generic *disp =
623                        get_dispatcher_shared_generic(cap->u.endpoint.listener->disp);
624                    printk(LOG_DEBUG, "%.*s: IRQ message buffer overflow\n",
625                            DISP_NAME_LEN, disp->name);
626                } else {
627                    printk(LOG_ERR, "Unexpected error delivering IRQ\n");
628                }
629            }
630        }
631        kcb->irq_dispatch[i].cap.type = ObjType_Null;
632    }
633    return SYS_ERR_OK;
634}
635
636/**
637 * \brief Handles kernel exceptions
638 *
639 * \param vec   Vector number of exception
640 * \param error Error code from CPU, or 0 for an exception without an error code
641 * \param gdb_save_frame Pointer to save area for registers stacked by trap handler
642 */
643static __attribute__ ((used,noreturn))
644    void generic_handle_kernel_exception(uint64_t vec, uint64_t error,
645                                         uintptr_t *gdb_save_frame)
646{
647    lvaddr_t fault_address;
648    char *descr;
649
650    if (vec == 666) {
651        panic("unhandled kernel exception (vector 666)");
652    }
653
654    assert(vec < NEXCEPTIONS);
655
656    printk(LOG_PANIC, "exception %d (error code 0x%lx): ", (int)vec, error);
657
658    if (vec == ia32_vec_pf) {
659        printf("%s page fault due to %s%s, while in %s mode%s\n",
660               error & ERR_PF_READ_WRITE ? "write" : "read",
661               error & ERR_PF_PRESENT ? "access violation" : "page not present",
662               error & ERR_PF_RESERVED ? ", reserved bits set in page table"
663               : "",
664               error & ERR_PF_USER_SUPERVISOR ? "user" : "supervisor",
665               error & ERR_PF_INSTRUCTION ? ", by instruction fetch" : "");
666
667        __asm volatile("mov %%cr2, %[fault_address]"
668                       : [fault_address] "=r" (fault_address));
669        printf("Address that caused the fault: 0x%lx\n", fault_address);
670
671    } else if ((descr = ia32_exc_vec_describe(vec))) {
672        printf("%s\n", descr);
673    } else {
674        printf("unhandled exception!\n");
675    }
676
677    // Print faulting instruction pointer
678    uintptr_t rip = gdb_save_frame[GDB_X86_64_RIP_REG];
679    printf("Faulting instruction pointer (or next instruction): 0x%lx\n", rip);
680    printf("  => i.e. unrelocated kernel address 0x%lx\n",
681           rip - (uintptr_t)&_start_kernel + START_KERNEL_PHYS);
682
683    printf("Registers:\n");
684    printf(" rax: 0x%016lx  r8 : 0x%016lx\n",
685           gdb_save_frame[GDB_X86_64_RAX_REG],
686           gdb_save_frame[GDB_X86_64_R8_REG]);
687    printf(" rbx: 0x%016lx  r9 : 0x%016lx\n",
688           gdb_save_frame[GDB_X86_64_RBX_REG],
689           gdb_save_frame[GDB_X86_64_R9_REG]);
690    printf(" rcx: 0x%016lx  r10: 0x%016lx\n",
691           gdb_save_frame[GDB_X86_64_RCX_REG],
692           gdb_save_frame[GDB_X86_64_R10_REG]);
693    printf(" rdx: 0x%016lx  r11: 0x%016lx\n",
694           gdb_save_frame[GDB_X86_64_RDX_REG],
695           gdb_save_frame[GDB_X86_64_R11_REG]);
696    printf(" rsp: 0x%016lx  r12: 0x%016lx\n",
697           gdb_save_frame[GDB_X86_64_RSP_REG],
698           gdb_save_frame[GDB_X86_64_R12_REG]);
699    printf(" rdi: 0x%016lx  r13: 0x%016lx\n",
700           gdb_save_frame[GDB_X86_64_RDI_REG],
701           gdb_save_frame[GDB_X86_64_R13_REG]);
702    printf(" rsi: 0x%016lx  r14: 0x%016lx\n",
703           gdb_save_frame[GDB_X86_64_RSI_REG],
704           gdb_save_frame[GDB_X86_64_R14_REG]);
705    printf(" rip: 0x%016lx  r15: 0x%016lx\n",
706           gdb_save_frame[GDB_X86_64_RIP_REG],
707           gdb_save_frame[GDB_X86_64_R15_REG]);
708    printf(" rsp: 0x%016lx  rbp: 0x%016lx\n",
709           gdb_save_frame[GDB_X86_64_RSP_REG],
710           gdb_save_frame[GDB_X86_64_RBP_REG]);
711
712    // Print the top 10 stack words
713    printf("Top o' stack:\n");
714    for(int i = 0; i < 10; i++) {
715        unsigned long *p = (unsigned long *)gdb_save_frame[GDB_X86_64_RSP_REG] + i;
716        printf(" %d \t 0x%016lx (%lu)\n", i, *p, *p);
717    }
718
719    // Drop to the debugger
720    gdb_handle_exception(vec, gdb_save_frame);
721    panic("gdb_handle_exception returned");
722}
723
724/**
725 * \brief copies CPU-stacked registers to a dispatcher save area
726 */
727static void copy_cpu_frame_to_dispatcher(
728    uintptr_t * NONNULL COUNT(X86_SAVE_AREA_SIZE) cpu_save_area,
729    struct registers_x86_64 *disp_save_area)
730{
731    // sanity checks
732    assert((cpu_save_area[X86_SAVE_EFLAGS] & USER_EFLAGS) == USER_EFLAGS);
733
734    disp_save_area->rsp = cpu_save_area[X86_SAVE_RSP];
735    disp_save_area->eflags = cpu_save_area[X86_SAVE_EFLAGS];
736    disp_save_area->rip = cpu_save_area[X86_SAVE_RIP];
737}
738
739/**
740 * \brief Handles user-mode exceptions
741 *
742 * \param vec   Vector number of exception
743 * \param error Error code from CPU, or 0 for an exception without an error code
744 * \param cpu_save_area  Pointer to save area for registers stacked by CPU
745 * \param disp_save_area Pointer to save area in dispatcher
746 */
747static __attribute__ ((used))
748    void generic_handle_user_exception(int vec, uint64_t error,
749                uintptr_t * NONNULL COUNT(X86_SAVE_AREA_SIZE) cpu_save_area,
750                struct registers_x86_64 *disp_save_area)
751{
752    assert(dcb_current->disp_cte.cap.type == ObjType_Frame);
753    dispatcher_handle_t handle = dcb_current->disp;
754    struct dispatcher_shared_generic *disp =
755        get_dispatcher_shared_generic(handle);
756    uint64_t rip = cpu_save_area[X86_SAVE_RIP];
757    uint64_t rsp = cpu_save_area[X86_SAVE_RSP];
758    lvaddr_t fault_address, handler = 0, param = 0;
759
760    assert(vec < NEXCEPTIONS);
761    assert((cpu_save_area[X86_SAVE_CS] & 0x3) != 0); // CS.CPL > 0
762
763    copy_cpu_frame_to_dispatcher(cpu_save_area, disp_save_area);
764
765    bool disabled = dispatcher_is_disabled_ip(handle, rip);
766    dcb_current->disabled = disabled;
767
768    if (disabled) {
769        dcb_current->faults_taken++;
770    }
771
772    if (vec == IDT_PF) { // Page fault
773        // Get fault address
774        __asm volatile("mov %%cr2, %[fault_address]"
775                       : [fault_address] "=r" (fault_address));
776
777        printk(LOG_WARN, "user page fault%s in '%.*s': addr %lx IP %lx SP %lx "
778                         "error 0x%lx\n",
779               disabled ? " WHILE DISABLED" : "", DISP_NAME_LEN,
780               disp->name, fault_address, rip, rsp, error);
781
782        /* sanity-check that the trap handler saved in the right place */
783        assert((disabled && disp_save_area == dispatcher_get_trap_save_area(handle))
784               || (!disabled && disp_save_area == dispatcher_get_enabled_save_area(handle)));
785        if (disabled) {
786            handler = disp->dispatcher_pagefault_disabled;
787        } else {
788            handler = disp->dispatcher_pagefault;
789        }
790        param = fault_address;
791    } else if (vec == IDT_NMI) {
792        printk(LOG_WARN, "NMI - ignoring\n");
793        dispatch(dcb_current);
794    } else if (vec == IDT_MF) {
795        uint16_t fpu_status;
796
797        __asm volatile("fnstsw %0" : "=a" (fpu_status));
798
799        printk(LOG_WARN, "FPU error%s in '%.*s': IP %" PRIxPTR " FPU status %x\n",
800               disabled ? " WHILE DISABLED" : "", DISP_NAME_LEN,
801               disp->name, rip, fpu_status);
802
803        handler = disp->dispatcher_trap;
804        param = vec;
805    } else if (vec == IDT_MC) {
806        // TODO: provide more useful information about the cause
807        panic("machine check exception while in user mode");
808    } else { // All other traps
809        printk(LOG_WARN, "user trap #%d: %s%s in '%.*s': IP %lx, error %lx\n",
810               vec, idt_descs[vec], disabled ? " WHILE DISABLED" : "",
811               DISP_NAME_LEN, disp->name, rip, error);
812        assert(disp_save_area == dispatcher_get_trap_save_area(handle));
813        if (disabled) {
814            if (vec == IDT_DB) { // debug exception: just continue
815                resume(dispatcher_get_trap_save_area(handle));
816            } else {
817                // can't handle a trap while disabled: nowhere safe to deliver it
818                scheduler_remove(dcb_current);
819                dispatch(schedule());
820            }
821        } else {
822            handler = disp->dispatcher_trap;
823            param = vec;
824        }
825    }
826
827    // Make unrunnable if it has taken too many faults
828    if (dcb_current->faults_taken > 2) {
829        printk(LOG_WARN, "generic_handle_user_exception: too many faults, "
830               "making domain unrunnable\n");
831        dcb_current->faults_taken = 0; // just in case it gets restarted
832        scheduler_remove(dcb_current);
833        dispatch(schedule());
834    }
835
836    /* resume user to save area */
837    disp->disabled = 1;
838    if (handler == 0) {
839        printk(LOG_WARN, "no suitable handler for this type of fault, "
840               "making domain unrunnable\n");
841        scheduler_remove(dcb_current);
842        dispatch(schedule());
843    } else {
844        cpu_save_area[X86_SAVE_RIP] = handler;
845        cpu_save_area[X86_SAVE_EFLAGS] = USER_EFLAGS;
846    }
847
848    /* XXX: get GCC to load up the argument registers before returning */
849    register uintptr_t arg0 __asm ("%rdi") = disp->udisp;
850    register uintptr_t arg1 __asm ("%rsi") = param;
851    register uintptr_t arg2 __asm ("%rdx") = error;
852    register uintptr_t arg3 __asm ("%rcx") = rip;
853    __asm volatile("" :: "r" (arg0), "r" (arg1), "r" (arg2), "r" (arg3));
854}
855
856/// Handle an IRQ that arrived, either while in user or kernel mode (HLT)
857static __attribute__ ((used)) void handle_irq(int vector)
858{
859    int irq = vector - NEXCEPTIONS;
860    debug(SUBSYS_DISPATCH, "IRQ vector %d (irq %d) while %s\n", vector, irq,
861          dcb_current ? (dcb_current->disabled ? "disabled": "enabled") : "in kernel");
862
863
864    // if we were in wait_for_interrupt(), unmask timer before running userspace
865    if (dcb_current == NULL && kernel_ticks_enabled) {
866        apic_unmask_timer();
867    }
868
869#if TRACE_ETHERSRV_MODE
870    trace_event(TRACE_SUBSYS_NNET, TRACE_EVENT_NNET_IRQ, vector);
871#endif // TRACE_ETHERSRV_MODE
872
873    // APIC timer interrupt: handle in kernel and reschedule
874    if (vector == APIC_TIMER_INTERRUPT_VECTOR) {
875        // count time slices
876        timer_fired ++;
877        static uint64_t last = 0;
878        systime_t now = systime_now();
879
880        last = now;
881
882        // switch kcb every other timeslice
883        if (!kcb_sched_suspended && timer_fired % 2 == 0 && kcb_current->next) {
884            //printk(LOG_NOTE, "switching from kcb(%p) to kcb(%p)\n", kcb_current, kcb_current->next);
885            switch_kcb(kcb_current->next);
886        }
887
888        apic_eoi();
889	    assert(kernel_ticks_enabled);
890        trace_event(TRACE_SUBSYS_KERNEL, TRACE_EVENT_KERNEL_TIMER, now);
891        wakeup_check(now + kcb_current->kernel_off);
892#ifndef CONFIG_ONESHOT_TIMER
893        systime_set_timeout(now + kernel_timeslice);
894#endif
895    } else if (vector == APIC_PERFORMANCE_INTERRUPT_VECTOR) {
896        // Handle performance counter overflow
897        // Reset counters
898        perfmon_measure_reset();
899        if(dcb_current!=NULL) {
900            // Get faulting instruction pointer
901            struct registers_x86_64 *disp_save_area = dcb_current->disabled ?
902                dispatcher_get_disabled_save_area(dcb_current->disp) :
903                dispatcher_get_enabled_save_area(dcb_current->disp);
904            struct dispatcher_shared_generic *disp =
905                get_dispatcher_shared_generic(dcb_current->disp);
906
907            // Setup data structure for LMP transfer to user level handler
908            struct perfmon_overflow_data data = {
909                .ip = disp_save_area->rip
910            };
911            strncpy(data.name, disp->name, PERFMON_DISP_NAME_LEN);
912
913            // Call overflow handler represented by endpoint
914            extern struct capability perfmon_callback_ep;
915            size_t payload_len = sizeof(struct perfmon_overflow_data)/ sizeof(uintptr_t)+1;
916	        errval_t err = lmp_deliver_payload(&perfmon_callback_ep,
917                             NULL,
918                             (uintptr_t*) &data,
919                             payload_len,
920                             false, false);
921
922            // Make sure delivery was okay. SYS_ERR_LMP_BUF_OVERFLOW is okay for now
923            assert(err_is_ok(err) || err_no(err)==SYS_ERR_LMP_BUF_OVERFLOW);
924        } else {
925            // This should never happen, as interrupts are disabled in kernel
926            printf("Performance counter overflow interrupt from "
927                   "apic in kernel level\n");
928        }
929        apic_eoi();
930    } else if (vector == APIC_ERROR_INTERRUPT_VECTOR) {
931        printk(LOG_ERR, "APIC error interrupt fired!\n");
932        xapic_esr_t esr = apic_get_esr();
933        char str[256];
934        xapic_esr_prtval(str, 256, esr);
935        printf("%s\n", str);
936        apic_eoi();
937    } else if (vector == APIC_INTER_CORE_VECTOR) {
938        apic_eoi();
939        ipi_handle_notify();
940    } else if (vector == APIC_INTER_HALT_VECTOR) {
941        apic_eoi();
942        // Update kernel_off for all KCBs
943        struct kcb *k = kcb_current;
944        do{
945            k->kernel_off = systime_now();
946            k = k->next;
947        } while(k && k!=kcb_current);
948        // Stop the core
949        halt();
950    } else if (vector == APIC_SPURIOUS_INTERRUPT_VECTOR) {
951        // ignore
952        printk(LOG_DEBUG, "spurious interrupt\n");
953    }
954
955#if 0
956 else if (irq >= 0 && irq <= 15) { // classic PIC device interrupt
957     printk(LOG_NOTE, "got interrupt %d!\n", irq);
958
959        apic_eoi();
960
961        // only handle PIC interrupts on the BSP core
962        if (apic_is_bsp()) {
963            if (pic_have_interrupt(irq)) {
964                pic_eoi(irq);
965                send_user_interrupt(irq);
966            } else { // no interrupt pending, check for a different one (!)
967                irq = pic_pending_interrupt();
968                if (irq == -1) { // really nothing pending
969                    printk(LOG_NOTE, "spurious interrupt (IRQ %d)\n", irq);
970                } else { // why does this happen?! -AB
971                    printk(LOG_NOTE, "IRQ %d reported on wrong vector (%d)\n",
972                           irq, vector - NEXCEPTIONS);
973                    pic_eoi(irq);
974                    send_user_interrupt(irq);
975                }
976            }
977        }
978    }
979#endif
980    else { // APIC device interrupt (or IPI)
981        //printk(LOG_NOTE, "interrupt %d vector %d!\n", irq, vector);
982        apic_eoi();
983        send_user_interrupt(irq);
984    }
985
986    // reschedule (because the runnable processes may have changed) and dispatch
987    /* FIXME: the round-robin scheduler doesn't do the best thing here:
988     * it always picks the next task, but we only really want to do that on
989     * a timer tick
990     */
991    dispatch(schedule());
992    panic("dispatch() returned");
993}
994
995/**
996 * \brief Handles device interrupts that arrive while in user mode
997 *
998 * \param vector    Vector number
999 * \param cpu_save_area  Pointer to save area for registers stacked by CPU
1000 * \param disp_save_area Pointer to save area in dispatcher
1001 */
1002static __attribute__ ((used, noreturn)) void
1003generic_handle_irq(int vector,
1004                   uintptr_t * NONNULL COUNT(X86_SAVE_AREA_SIZE) cpu_save_area,
1005                   struct registers_x86_64 *disp_save_area)
1006{
1007    assert(dcb_current->disp_cte.cap.type == ObjType_Frame);
1008    dispatcher_handle_t handle = dcb_current->disp;
1009    uint64_t rip = cpu_save_area[X86_SAVE_RIP];
1010    assert(vector < NIDT && vector >= NEXCEPTIONS);
1011
1012    // Copy CPU-saved registers to dispatcher save area
1013    copy_cpu_frame_to_dispatcher(cpu_save_area, disp_save_area);
1014
1015    /* sanity-check that the trap handler saved in the right place,
1016     * and update disabled flag in DCB */
1017    if (disp_save_area == dispatcher_get_disabled_save_area(handle)) {
1018        assert(dispatcher_is_disabled_ip(handle, rip));
1019        dcb_current->disabled = true;
1020    } else {
1021        assert(disp_save_area == dispatcher_get_enabled_save_area(handle));
1022        assert(!dispatcher_is_disabled_ip(handle, rip));
1023        dcb_current->disabled = false;
1024    }
1025
1026    handle_irq(vector);
1027    resume(disp_save_area);
1028}
1029
1030/* Utility function for code below; initialises a gate_descriptor */
1031static void setgd(struct gate_descriptor *gd, void (* handler)(void),
1032                  int ist, int type, int dpl, int selector)
1033{
1034    memset(gd, 0, sizeof(struct gate_descriptor));
1035    gd->gd_looffset = (uintptr_t)handler & ((1UL << 16) - 1);
1036    gd->gd_hioffset = (uintptr_t)handler >> 16;
1037    gd->gd_selector = selector;
1038    gd->gd_ist = ist;
1039    gd->gd_type = type;
1040    gd->gd_dpl = dpl;
1041    gd->gd_p = 1;
1042}
1043
1044/**
1045 * \brief Sets up the default IDT for current CPU.
1046 */
1047void setup_default_idt(void)
1048{
1049    struct region_descriptor region = {         // set default IDT
1050        .rd_limit = NIDT * sizeof(idt[0]) - 1,
1051        .rd_base = (uint64_t)&idt
1052    };
1053    int i;
1054
1055    // reset IDT
1056    memset((void *)&idt, 0, NIDT * sizeof(idt[0]));
1057
1058    // initialize IDT with default generic handlers
1059    for (i = 0; i < NIDT; i++)
1060        setgd(&idt[i], hwexc_666, 0, SDT_SYSIGT, SEL_KPL,
1061              GSEL(KCODE_SEL, SEL_KPL));
1062
1063    /* Setup exception handlers */
1064    setgd(&idt[0], hwexc_0, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1065    setgd(&idt[1], hwexc_1, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1066    setgd(&idt[2], hwexc_2, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1067    setgd(&idt[3], hwexc_3, 0, SDT_SYSIGT, SEL_UPL, GSEL(KCODE_SEL, SEL_KPL));
1068    setgd(&idt[4], hwexc_4, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1069    setgd(&idt[5], hwexc_5, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1070    setgd(&idt[6], hwexc_6, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1071    setgd(&idt[7], hwexc_7, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1072    setgd(&idt[8], hwexc_8, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1073    setgd(&idt[9], hwexc_9, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1074    setgd(&idt[10], hwexc_10, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1075    setgd(&idt[11], hwexc_11, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1076    setgd(&idt[12], hwexc_12, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1077    setgd(&idt[13], hwexc_13, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1078    setgd(&idt[14], hwexc_14, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1079    // Interrupt 15 is undefined
1080    setgd(&idt[16], hwexc_16, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1081    setgd(&idt[17], hwexc_17, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1082    setgd(&idt[18], hwexc_18, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1083    setgd(&idt[19], hwexc_19, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1084    // Interrupts 20 - 31 are reserved
1085
1086    /* Setup classic PIC interrupt handlers */
1087    setgd(&idt[32], hwirq_32, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1088    setgd(&idt[33], hwirq_33, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1089    setgd(&idt[34], hwirq_34, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1090    setgd(&idt[35], hwirq_35, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1091    setgd(&idt[36], hwirq_36, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1092    setgd(&idt[37], hwirq_37, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1093    setgd(&idt[38], hwirq_38, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1094    setgd(&idt[39], hwirq_39, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1095    setgd(&idt[40], hwirq_40, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1096    setgd(&idt[41], hwirq_41, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1097    setgd(&idt[42], hwirq_42, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1098    setgd(&idt[43], hwirq_43, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1099    setgd(&idt[44], hwirq_44, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1100    setgd(&idt[45], hwirq_45, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1101    setgd(&idt[46], hwirq_46, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1102    setgd(&idt[47], hwirq_47, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1103
1104    // Setup generic interrupt handlers
1105    setgd(&idt[48], hwirq_48, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1106    setgd(&idt[49], hwirq_49, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1107    setgd(&idt[50], hwirq_50, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1108    setgd(&idt[50], hwirq_50, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1109    setgd(&idt[51], hwirq_51, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1110    setgd(&idt[52], hwirq_52, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1111    setgd(&idt[53], hwirq_53, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1112    setgd(&idt[54], hwirq_54, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1113    setgd(&idt[55], hwirq_55, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1114    setgd(&idt[56], hwirq_56, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1115    setgd(&idt[57], hwirq_57, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1116    setgd(&idt[58], hwirq_58, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1117    setgd(&idt[59], hwirq_59, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1118    setgd(&idt[60], hwirq_60, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1119    setgd(&idt[61], hwirq_61, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1120
1121    // XXX Interrupts used for TRACE IPIs
1122    setgd(&idt[62], hwirq_62, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1123    setgd(&idt[63], hwirq_63, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1124
1125    // Setup local APIC interrupt handlers
1126    setgd(&idt[248], hwirq_248, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1127    setgd(&idt[249], hwirq_249, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1128    setgd(&idt[250], hwirq_250, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1129    setgd(&idt[251], hwirq_251, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1130    setgd(&idt[252], hwirq_252, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1131    setgd(&idt[253], hwirq_253, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1132    setgd(&idt[254], hwirq_254, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
1133
1134    /* Load IDT register */
1135    __asm volatile("lidt %0" :: "m" (region));
1136}
1137