1// Copyright 2016 The Fuchsia Authors 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 <asm.h> 11#include <arch/x86/descriptor.h> 12 13#define NUM_INT 256 14 15/* 16 * Please note that the macro for generating interrupt routine stubs relies 17 * on the macro execution counter \@ which is shared by all invocations across 18 * this compilation unit. Be careful when adding additional macros to this 19 * file. In particular: 20 * 1) No macros can be executed before def_isr (so \@ starts at zero). 21 * 2) def_isr cannot have any macros (so \@ increments by one for each 22 * def_isr invocation). 23 */ 24 25.text 26 27/* interrupt service routine stubs */ 28_isr: 29.macro def_isr 30.pushsection .text 31FUNCTION_LABEL(_isr_\@) 32 .cfi_startproc simple 33 .cfi_signal_frame 34 /* Set CFA for an interrupt frame. */ 35.if \@ == 8 || (\@ >= 10 && \@ <= 14) || \@ == 17 36 .cfi_def_cfa %rsp, (8 * 6) 37.else 38 .cfi_def_cfa %rsp, (8 * 5) 39.endif 40 .cfi_offset %rip, -(5 * 8) 41 /* Mark each reg as having the same value as from the "calling" frame. 42 This is the default state for callee-saved registers, but for completeness 43 sake we do this for all of them. */ 44 ALL_CFI_SAME_VALUE 45 /* Clear the AC flag to prevent ring 0 from performing data accesses to 46 * ring 3 if SMAP is available. If it was set, it will get restored by 47 * iretd. DO NOT REMOVE THIS CLAC, code in idt.c assumes it is here. 48 * It MUST be the first instruction of this function. */ 49 clac 50 /* We can't use push_value here: it is a macro invocation and using it 51 * will screw up tracking of \@ == isr number. Instead we inline the .cfi 52 * directives. */ 53.if \@ == 8 || (\@ >= 10 && \@ <= 14) || \@ == 17 54 /* error code pushed by exception */ 55 pushq $\@ /* interrupt number */ 56 .cfi_adjust_cfa_offset 8 57 jmp interrupt_common 58.else 59 pushq $0 /* fill in error code in iframe */ 60 .cfi_adjust_cfa_offset 8 61 pushq $\@ /* interrupt number */ 62 .cfi_adjust_cfa_offset 8 63 jmp interrupt_common 64.endif 65END_FUNCTION(_isr_\@) 66.popsection 67.pushsection .rodata.isr 68.quad _isr_\@ 69.popsection 70.endm 71 72.pushsection .rodata.isr 73/* build a table of isr entry points */ 74.balign 8 75DATA(_isr_table) 76.popsection 77.rept NUM_INT 78def_isr 79.endr 80 81FUNCTION_LABEL(interrupt_common) 82 .cfi_startproc simple 83 .cfi_signal_frame 84 /* Set CFA for an interrupt frame. */ 85 .cfi_def_cfa %rsp, 7 * 8 /* hw + _isr_* push this many values */ 86 .cfi_offset %rip, -(5 * 8) 87 /* Mark each reg as having the same value as from the "calling" frame. 88 This is the default state for callee-saved registers, but for completeness 89 sake we do this for all of them. */ 90 ALL_CFI_SAME_VALUE 91 92 /* Clear the direction flag. Without this, uses of string 93 instructions, e.g. REP MOVS in memcpy() or inlined by the compiler, 94 can go wrong and copy in the wrong direction, since this code may 95 assume that the direction flag is unset. */ 96 cld 97 98 /* Check to see if we came from user space by testing the PL of the 99 * CS register that was saved on the stack automatically. Check for != 0. 100 */ 101 testb $3, 0x18(%rsp) 102 jz 1f 103 104 /* swap gs to kernel space */ 105 swapgs 106 1071: 108 /* save general purpose registers */ 109 push_reg %r15 110 push_reg %r14 111 push_reg %r13 112 push_reg %r12 113 push_reg %r11 114 push_reg %r10 115 push_reg %r9 116 push_reg %r8 117 push_reg %rax 118 push_reg %rcx 119 push_reg %rdx 120 push_reg %rbx 121 push_reg %rbp 122 push_reg %rsi 123 push_reg %rdi 124 125 movq %rsp, %rdi /* pass the iframe using rdi */ 126 127 call x86_exception_handler 128 129/* A label to assist gdb's backtracing through kernel exceptions. 130 When gdb sees this as the return address it knows it can fetch 131 x86_iframe_t from $rsp. See scripts/zircon.elf-gdb.py. */ 132interrupt_common_iframe_set_up_for_debugger: 133 134 /* restore general purpose registers */ 135 pop_reg %rdi 136 pop_reg %rsi 137 pop_reg %rbp 138 pop_reg %rbx 139 pop_reg %rdx 140 pop_reg %rcx 141 pop_reg %rax 142 pop_reg %r8 143 pop_reg %r9 144 pop_reg %r10 145 pop_reg %r11 146 pop_reg %r12 147 pop_reg %r13 148 pop_reg %r14 149 pop_reg %r15 150 151 /* check if we're returning to user space as per before */ 152 testb $3, 0x18(%rsp) 153 jz 1f 154 155 /* swap gs back to user space */ 156 swapgs 157 1581: 159 /* drop vector number and error code*/ 160 add_to_sp 16 161 162 iretq 163END_FUNCTION(interrupt_common) 164 165/* Call external interrupt handler manually without actually issuing interrupt. 166 * 167 * For external interrupts CPU doesn't store error code on stack so we use 0. We 168 * additionally use CODE_64_SELECTOR as CS, 0 as SS, RFLAGS value and current 169 * stack. 170 */ 171FUNCTION(x86_call_external_interrupt_handler) 172 /* save current RFLAGS value */ 173 pushfq 174 popq %r10 175 176 /* save current RSP value */ 177 movq %rsp, %r11 178 179 /* calculate exit address */ 180 leaq .Lexit(%rip), %rax 181 182 /* prepare interrupt stack frame in the from interrupt_common expects to see */ 183 sub_from_sp 0x38 184 movq %rdi, 0x00(%rsp) // rdi holds vector number 185 movq $0, 0x08(%rsp) // error code 186 movq %rax, 0x10(%rsp) // RIP (return address) 187 movq $CODE_64_SELECTOR, 0x18(%rsp) // CS 188 movq %r10, 0x20(%rsp) // RFLAGS 189 movq %r11, 0x28(%rsp) // RSP 190 movq $0, 0x30(%rsp) // SS 191 192 /* we can actually avoid this jump if we put this code above 193 * interrupt_common and just fall through, but benefits of doing this are 194 * not obvious so for now for the sake of clarity keep this jump 195 */ 196 jmp interrupt_common 197 198.Lexit: 199 ret 200END_FUNCTION(x86_call_external_interrupt_handler) 201