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