1/* 2 * Copyright (c) 2009 Corey Tabaka 3 * Copyright (c) 2015 Intel Corporation 4 * Copyright (c) 2016 Travis Geiselbrecht 5 * 6 * Use of this source code is governed by a MIT-style 7 * license that can be found in the LICENSE file or at 8 * https://opensource.org/licenses/MIT 9 */ 10#include <lk/asm.h> 11#include <arch/x86/descriptor.h> 12 13#define NUM_INT 0x31 14#define NUM_EXC 0x14 15 16.text 17 18/* interrupt service routine stubs */ 19_isr: 20 21.set i, 0 22.rept NUM_INT 23 24.set isr_stub_start, . 25 26.if i == 8 || (i >= 10 && i <= 14) || i == 17 27 nop /* error code pushed by exception */ 28 nop /* 2 nops are the same length as push byte */ 29 pushl $i /* interrupt number */ 30 jmp interrupt_common 31.else 32 pushl $0 /* fill in error code in iframe */ 33 pushl $i /* interrupt number */ 34 jmp interrupt_common 35.endif 36 37/* figure out the length of a single isr stub (usually 6 or 9 bytes) */ 38.set isr_stub_len, . - isr_stub_start 39 40.set i, i + 1 41.endr 42 43/* annoying, but force AS to use the same (longer) encoding of jmp for all of the stubs */ 44.fill 256 45 46FUNCTION(interrupt_common) 47 cld 48 pushl %gs /* save segment registers */ 49 pushl %fs 50 pushl %es 51 pushl %ds 52 pusha /* save general purpose registers */ 53 movl $DATA_SELECTOR, %eax /* put known good value in segment registers */ 54 movl %eax, %gs 55 movl %eax, %fs 56 movl %eax, %es 57 movl %eax, %ds 58 59 movl %esp, %eax /* store pointer to iframe */ 60 pushl %eax 61 62 call x86_exception_handler 63 64 popl %eax /* drop pointer to iframe */ 65 66 popa /* restore general purpose registers */ 67 popl %ds /* restore segment registers */ 68 popl %es 69 popl %fs 70 popl %gs 71 addl $8, %esp /* drop exception number and error code */ 72 iret 73 74FUNCTION(setup_idt) 75 /* setup isr stub descriptors in the idt */ 76 movl $_isr, %esi 77 movl $_idt, %edi 78 movl $NUM_INT, %ecx 79 80.Lloop: 81 movl %esi, %ebx 82 movw %bx, (%edi) /* low word in IDT(n).low */ 83 shrl $16, %ebx 84 movw %bx, 6(%edi) /* high word in IDT(n).high */ 85 86 addl $isr_stub_len, %esi/* index the next ISR stub */ 87 addl $8, %edi /* index the next IDT entry */ 88 89 loop .Lloop 90 91 lidt _idtr 92 93 ret 94 95.data 96 97.align 8 98.global _idtr 99_idtr: 100 .short _idt_end - _idt - 1 /* IDT limit */ 101 .int _idt 102 103/* interrupt descriptor table (IDT) */ 104.global _idt 105_idt: 106 107.set i, 0 108.rept NUM_INT-1 109 .short 0 /* low 16 bits of ISR offset (_isr#i & 0FFFFh) */ 110 .short CODE_SELECTOR /* selector */ 111 .byte 0 112 .byte 0x8e /* present, ring 0, 32-bit interrupt gate */ 113 .short 0 /* high 16 bits of ISR offset (_isr#i / 65536) */ 114 115.set i, i + 1 116.endr 117 118/* syscall int (ring 3) */ 119_idt30: 120 .short 0 /* low 16 bits of ISR offset (_isr#i & 0FFFFh) */ 121 .short CODE_SELECTOR /* selector */ 122 .byte 0 123 .byte 0xee /* present, ring 3, 32-bit interrupt gate */ 124 .short 0 /* high 16 bits of ISR offset (_isr#i / 65536) */ 125 126.global _idt_end 127_idt_end: 128 129 130