1/* 2 * 3 * Copyright 2013 Google Inc. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 .align 4 30 .global exception_stack_end 31exception_stack_end: 32 .long 0 33 .global exception_state 34exception_state: 35 .long 0 36 37/* Some temporary variables which are used while saving exception state. */ 38vector: 39 .long 0 40error_code: 41 .long 0 42old_esp: 43 .long 0 44old_eax: 45 .long 0 46 47 .align 8 48 49/* 50 * Each exception vector has a small stub associated with it which sets aside 51 * the error code, if any, records which vector we entered from, and calls 52 * the common exception entry point. Some exceptions have error codes and some 53 * don't, so we have a macro for each type. 54 */ 55 56 .macro stub num 57exception_stub_\num: 58 movl $0, error_code 59 movl $\num, vector 60 jmp exception_common 61 .endm 62 63 .macro stub_err num 64exception_stub_\num: 65 popl error_code 66 movl $\num, vector 67 jmp exception_common 68 .endm 69 70 .altmacro 71 .macro user_defined_stubs from, to 72 stub \from 73 .if \to-\from 74 user_defined_stubs %(from+1),\to 75 .endif 76 .endm 77 78 stub 0 79 stub 1 80 stub 2 81 stub 3 82 stub 4 83 stub 5 84 stub 6 85 stub 7 86 stub_err 8 87 stub 9 88 stub_err 10 89 stub_err 11 90 stub_err 12 91 stub_err 13 92 stub_err 14 93 stub 15 94 stub 16 95 stub_err 17 96 stub 18 97 stub 19 98 stub 20 99 stub 21 100 stub 22 101 stub 23 102 stub 24 103 stub 25 104 stub 26 105 stub 27 106 stub 28 107 stub 29 108 stub_err 30 109 stub 31 110 /* Split the macro so we avoid a stack overflow. */ 111 user_defined_stubs 32, 63 112 user_defined_stubs 64, 127 113 user_defined_stubs 128, 191 114 user_defined_stubs 192, 255 115 116exception_common: 117 /* 118 * Save off the stack pointer and old eax value and install the 119 * exception stack. eax points to the old stack which has the 120 * exception ip, cs, and flags. 121 */ 122 mov %esp, old_esp 123 addl $12, old_esp 124 mov %eax, old_eax 125 mov %esp, %eax 126 mov exception_stack_end, %esp 127 128 /* 129 * Push values onto the top of the exception stack to form an 130 * exception state structure. 131 */ 132 pushl vector 133 pushl error_code 134 pushl %gs 135 pushl %fs 136 pushl %es 137 pushl %ds 138 pushl %ss 139 pushl 4(%eax) 140 pushl 8(%eax) 141 pushl (%eax) 142 pushl %edi 143 pushl %esi 144 pushl %ebp 145 pushl old_esp 146 pushl %ebx 147 pushl %edx 148 pushl %ecx 149 pushl old_eax 150 151 /* 152 * Call the C exception handler. It will find the exception state 153 * using the exception_state global pointer. Not 154 * passing parameters means we don't have to worry about what ABI 155 * is being used. 156 */ 157 mov %esp, exception_state 158 call exception_dispatch 159 160 /* 161 * Restore state from the exception state structure, including any 162 * changes that might have been made. 163 */ 164 popl old_eax 165 popl %ecx 166 popl %edx 167 popl %ebx 168 popl old_esp 169 170 mov old_esp, %eax 171 subl $12, %eax 172 173 popl %ebp 174 popl %esi 175 popl %edi 176 popl (%eax) 177 popl 8(%eax) 178 popl 4(%eax) 179 popl %ss 180 popl %ds 181 popl %es 182 popl %fs 183 popl %gs 184 185 mov %eax, %esp 186 mov old_eax, %eax 187 188 /* Return from the exception. */ 189 iretl 190 191/* 192 * We need segment selectors for the IDT, so we need to know where things are 193 * in the GDT. We set one up here which is pretty standard and largely copied 194 * from coreboot. 195 */ 196 .align 8 197gdt: 198 /* selgdt 0, unused */ 199 .word 0x0000, 0x0000 200 .byte 0x00, 0x00, 0x00, 0x00 201 202 /* selgdt 8, unused */ 203 .word 0x0000, 0x0000 204 .byte 0x00, 0x00, 0x00, 0x00 205 206 /* selgdt 0x10, flat 4GB code segment */ 207 .word 0xffff, 0x0000 208 .byte 0x00, 0x9b, 0xcf, 0x00 209 210 /* selgdt 0x18, flat 4GB data segment */ 211 .word 0xffff, 0x0000 212 .byte 0x00, 0x93, 0xcf, 0x00 213gdt_end: 214 215/* GDT pointer for use with lgdt */ 216gdt_ptr: 217 .word gdt_end - gdt - 1 218 .long gdt 219 220 /* 221 * Record the target and construct the actual entry at init time. This 222 * is necessary because the linker doesn't want to construct the entry 223 * for us. 224 */ 225 .macro interrupt_gate target 226 .long \target 227 .long \target 228 .endm 229 230 .altmacro 231 .macro user_defined_gates from, to 232 interrupt_gate exception_stub_\from 233 .if \to-\from 234 user_defined_gates %(from+1),\to 235 .endif 236 .endm 237 238 .align 8 239 .global idt 240idt: 241 interrupt_gate exception_stub_0 242 interrupt_gate exception_stub_1 243 interrupt_gate exception_stub_2 244 interrupt_gate exception_stub_3 245 interrupt_gate exception_stub_4 246 interrupt_gate exception_stub_5 247 interrupt_gate exception_stub_6 248 interrupt_gate exception_stub_7 249 interrupt_gate exception_stub_8 250 interrupt_gate exception_stub_9 251 interrupt_gate exception_stub_10 252 interrupt_gate exception_stub_11 253 interrupt_gate exception_stub_12 254 interrupt_gate exception_stub_13 255 interrupt_gate exception_stub_14 256 interrupt_gate exception_stub_15 257 interrupt_gate exception_stub_16 258 interrupt_gate exception_stub_17 259 interrupt_gate exception_stub_18 260 interrupt_gate exception_stub_19 261 interrupt_gate exception_stub_20 262 interrupt_gate exception_stub_21 263 interrupt_gate exception_stub_22 264 interrupt_gate exception_stub_23 265 interrupt_gate exception_stub_24 266 interrupt_gate exception_stub_25 267 interrupt_gate exception_stub_26 268 interrupt_gate exception_stub_27 269 interrupt_gate exception_stub_28 270 interrupt_gate exception_stub_29 271 interrupt_gate exception_stub_30 272 interrupt_gate exception_stub_31 273 user_defined_gates 32, 63 274 user_defined_gates 64, 127 275 user_defined_gates 128, 191 276 user_defined_gates 192, 255 277idt_end: 278 279/* IDT pointer for use with lidt */ 280idt_ptr: 281 .word idt_end - idt - 1 282 .long idt 283 284 .global exception_init_asm 285exception_init_asm: 286 /* Save eax so we can use it as a temporary variable. */ 287 pushl %eax 288 289 /* Install the GDT. */ 290 lgdt gdt_ptr 291 /* Load the segment registers from it. */ 292 ljmp $0x10, $1f 2931: movl $0x18, %eax 294 movl %eax, %ds 295 movl %eax, %es 296 movl %eax, %ss 297 movl %eax, %fs 298 movl %eax, %gs 299 300 /* 301 * Loop over the entries which start out as two copies of the target 302 * address. We can turn them into real interrupt gates by selectively 303 * replacing certain bit fields. 304 */ 305 movl $idt, %eax 3061: 307 andl $0x0000ffff, (%eax) 308 orl $0x00100000, (%eax) 309 andl $0xffff0000, 4(%eax) 310 orl $0x0000ee00, 4(%eax) 311 addl $8, %eax 312 cmp $idt_end, %eax 313 jne 1b 314 315 /* Install the IDT. */ 316 lidt idt_ptr 317 318 /* Restore eax and return to the caller. */ 319 popl %eax 320 ret 321