1/* 2 * Copyright (c) 2009 Corey Tabaka 3 * Copyright (c) 2015 Intel Corporation 4 * Copyright (c) 2016 Travis Geiselbrecht 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining 7 * a copy of this software and associated documentation files 8 * (the "Software"), to deal in the Software without restriction, 9 * including without limitation the rights to use, copy, modify, merge, 10 * publish, distribute, sublicense, and/or sell copies of the Software, 11 * and to permit persons to whom the Software is furnished to do so, 12 * subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be 15 * included in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 21 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 */ 25#include <asm.h> 26#include <arch/x86/descriptor.h> 27 28#define NUM_INT 0x31 29#define NUM_EXC 0x14 30 31.text 32 33/* interrupt service routine stubs */ 34_isr: 35 36.set i, 0 37.rept NUM_INT 38 39.set isr_stub_start, . 40 41.if i == 8 || (i >= 10 && i <= 14) || i == 17 42 nop /* error code pushed by exception */ 43 nop /* 2 nops are the same length as push byte */ 44 pushl $i /* interrupt number */ 45 jmp interrupt_common 46.else 47 pushl $0 /* fill in error code in iframe */ 48 pushl $i /* interrupt number */ 49 jmp interrupt_common 50.endif 51 52/* figure out the length of a single isr stub (usually 6 or 9 bytes) */ 53.set isr_stub_len, . - isr_stub_start 54 55.set i, i + 1 56.endr 57 58/* annoying, but force AS to use the same (longer) encoding of jmp for all of the stubs */ 59.fill 256 60 61FUNCTION(interrupt_common) 62 pushl %gs /* save segment registers */ 63 pushl %fs 64 pushl %es 65 pushl %ds 66 pusha /* save general purpose registers */ 67 movl $DATA_SELECTOR, %eax /* put known good value in segment registers */ 68 movl %eax, %gs 69 movl %eax, %fs 70 movl %eax, %es 71 movl %eax, %ds 72 73 movl %esp, %eax /* store pointer to iframe */ 74 pushl %eax 75 76 call x86_exception_handler 77 78 popl %eax /* drop pointer to iframe */ 79 80 popa /* restore general purpose registers */ 81 popl %ds /* restore segment registers */ 82 popl %es 83 popl %fs 84 popl %gs 85 addl $8, %esp /* drop exception number and error code */ 86 iret 87 88FUNCTION(setup_idt) 89 /* setup isr stub descriptors in the idt */ 90 movl $_isr, %esi 91 movl $_idt, %edi 92 movl $NUM_INT, %ecx 93 94.Lloop: 95 movl %esi, %ebx 96 movw %bx, (%edi) /* low word in IDT(n).low */ 97 shrl $16, %ebx 98 movw %bx, 6(%edi) /* high word in IDT(n).high */ 99 100 addl $isr_stub_len, %esi/* index the next ISR stub */ 101 addl $8, %edi /* index the next IDT entry */ 102 103 loop .Lloop 104 105 lidt _idtr 106 107 ret 108 109.data 110 111.align 8 112.global _idtr 113_idtr: 114 .short _idt_end - _idt - 1 /* IDT limit */ 115 .int _idt 116 117/* interrupt descriptor table (IDT) */ 118.global _idt 119_idt: 120 121.set i, 0 122.rept NUM_INT-1 123 .short 0 /* low 16 bits of ISR offset (_isr#i & 0FFFFh) */ 124 .short CODE_SELECTOR /* selector */ 125 .byte 0 126 .byte 0x8e /* present, ring 0, 32-bit interrupt gate */ 127 .short 0 /* high 16 bits of ISR offset (_isr#i / 65536) */ 128 129.set i, i + 1 130.endr 131 132/* syscall int (ring 3) */ 133_idt30: 134 .short 0 /* low 16 bits of ISR offset (_isr#i & 0FFFFh) */ 135 .short CODE_SELECTOR /* selector */ 136 .byte 0 137 .byte 0xee /* present, ring 3, 32-bit interrupt gate */ 138 .short 0 /* high 16 bits of ISR offset (_isr#i / 65536) */ 139 140.global _idt_end 141_idt_end: 142 143 144