apic_vector.s revision 125161
1/*- 2 * Copyright (c) 1989, 1990 William F. Jolitz. 3 * Copyright (c) 1990 The Regents of the University of California. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by the University of 17 * California, Berkeley and its contributors. 18 * 4. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * from: vector.s, 386BSD 0.1 unknown origin 35 * $FreeBSD: head/sys/i386/i386/apic_vector.s 125161 2004-01-28 20:44:08Z jhb $ 36 */ 37 38/* 39 * Interrupt entry points for external interrupts triggered by I/O APICs 40 * as well as IPI handlers. 41 */ 42 43#include <machine/asmacros.h> 44#include <machine/apicreg.h> 45#include <machine/smptests.h> 46 47#include "assym.s" 48 49/* 50 * Macros to create and destroy a trap frame. 51 */ 52#define PUSH_FRAME \ 53 pushl $0 ; /* dummy error code */ \ 54 pushl $0 ; /* dummy trap type */ \ 55 pushal ; /* 8 ints */ \ 56 pushl %ds ; /* save data and extra segments ... */ \ 57 pushl %es ; \ 58 pushl %fs 59 60#define PUSH_FRAME_AND_SET_SEGS \ 61 PUSH_FRAME ; \ 62 mov %fs,%ax ; /* get current per-cpu selector */ \ 63 cmp $KPSEL,%ax ; /* are we already in the kernel? */ \ 64 je 1f ; /* skip expensive segment reloads */ \ 65 mov $KDSEL,%ax ; /* load kernel ds, es and fs */ \ 66 mov %ax,%ds ; \ 67 mov %ax,%es ; \ 68 mov $KPSEL,%ax ; \ 69 mov %ax,%fs ; \ 701: 71 72#define POP_FRAME \ 73 popl %fs ; \ 74 popl %es ; \ 75 popl %ds ; \ 76 popal ; \ 77 addl $4+4,%esp 78 79/* 80 * I/O Interrupt Entry Point. Rather than having one entry point for 81 * each interrupt source, we use one entry point for each 32-bit word 82 * in the ISR. The handler determines the highest bit set in the ISR, 83 * translates that into a vector, and passes the vector to the 84 * lapic_handle_intr() function. 85 */ 86#define ISR_VEC(index, vec_name) \ 87 .text ; \ 88 SUPERALIGN_TEXT ; \ 89IDTVEC(vec_name) ; \ 90 PUSH_FRAME_AND_SET_SEGS ; \ 91 FAKE_MCOUNT(13*4(%esp)) ; \ 92 movl lapic, %edx ; /* pointer to local APIC */ \ 93 movl LA_ISR + 16 * (index)(%edx), %eax ; /* load ISR */ \ 94 bsrl %eax, %eax ; /* index of highset set bit in ISR */ \ 95 jz 2f ; \ 96 addl $(32 * index),%eax ; \ 971: ; \ 98 pushl %eax ; /* pass the IRQ */ \ 99 call lapic_handle_intr ; \ 100 addl $4, %esp ; /* discard parameter */ \ 101 MEXITCOUNT ; \ 102 jmp doreti ; \ 1032: movl $-1, %eax ; /* send a vector of -1 */ \ 104 jmp 1b 105 106/* 107 * Handle "spurious INTerrupts". 108 * Notes: 109 * This is different than the "spurious INTerrupt" generated by an 110 * 8259 PIC for missing INTs. See the APIC documentation for details. 111 * This routine should NOT do an 'EOI' cycle. 112 */ 113 .text 114 SUPERALIGN_TEXT 115IDTVEC(spuriousint) 116 117 /* No EOI cycle used here */ 118 119 iret 120 121MCOUNT_LABEL(bintr2) 122 ISR_VEC(1, apic_isr1) 123 ISR_VEC(2, apic_isr2) 124 ISR_VEC(3, apic_isr3) 125 ISR_VEC(4, apic_isr4) 126 ISR_VEC(5, apic_isr5) 127 ISR_VEC(6, apic_isr6) 128 ISR_VEC(7, apic_isr7) 129MCOUNT_LABEL(eintr2) 130 131#ifdef SMP 132/* 133 * Global address space TLB shootdown. 134 */ 135 .text 136 SUPERALIGN_TEXT 137IDTVEC(invltlb) 138 pushl %eax 139 pushl %ds 140 mov %ds,%ax /* get current data selector */ 141 cmp $KDSEL,%ax /* are we already in the kernel? */ 142 je 1f /* skip expensive segment reload */ 143 movl $KDSEL, %eax /* Kernel data selector */ 144 mov %ax, %ds 1451: 146#ifdef COUNT_XINVLTLB_HITS 147 pushl %fs 148 movl $KPSEL, %eax /* Private space selector */ 149 mov %ax, %fs 150 movl PCPU(CPUID), %eax 151 popl %fs 152 incl xhits_gbl(,%eax,4) 153#endif /* COUNT_XINVLTLB_HITS */ 154 155 movl %cr3, %eax /* invalidate the TLB */ 156 movl %eax, %cr3 157 158 movl lapic, %eax 159 movl $0, LA_EOI(%eax) /* End Of Interrupt to APIC */ 160 161 lock 162 incl smp_tlb_wait 163 164 popl %ds 165 popl %eax 166 iret 167 168/* 169 * Single page TLB shootdown 170 */ 171 .text 172 SUPERALIGN_TEXT 173IDTVEC(invlpg) 174 pushl %eax 175 pushl %ds 176 mov %ds,%ax /* get current data selector */ 177 cmp $KDSEL,%ax /* are we already in the kernel? */ 178 je 1f /* skip expensive segment reload */ 179 movl $KDSEL, %eax /* Kernel data selector */ 180 mov %ax, %ds 1811: 182#ifdef COUNT_XINVLTLB_HITS 183 pushl %fs 184 movl $KPSEL, %eax /* Private space selector */ 185 mov %ax, %fs 186 movl PCPU(CPUID), %eax 187 popl %fs 188 incl xhits_pg(,%eax,4) 189#endif /* COUNT_XINVLTLB_HITS */ 190 191 movl smp_tlb_addr1, %eax 192 invlpg (%eax) /* invalidate single page */ 193 194 movl lapic, %eax 195 movl $0, LA_EOI(%eax) /* End Of Interrupt to APIC */ 196 197 lock 198 incl smp_tlb_wait 199 200 popl %ds 201 popl %eax 202 iret 203 204/* 205 * Page range TLB shootdown. 206 */ 207 .text 208 SUPERALIGN_TEXT 209IDTVEC(invlrng) 210 pushl %eax 211 pushl %edx 212 pushl %ds 213 mov %ds,%ax /* get current data selector */ 214 cmp $KDSEL,%ax /* are we already in the kernel? */ 215 je 1f /* skip expensive segment reload */ 216 movl $KDSEL, %eax /* Kernel data selector */ 217 mov %ax, %ds 2181: 219#ifdef COUNT_XINVLTLB_HITS 220 pushl %fs 221 movl $KPSEL, %eax /* Private space selector */ 222 mov %ax, %fs 223 movl PCPU(CPUID), %eax 224 popl %fs 225 incl xhits_rng(,%eax,4) 226#endif /* COUNT_XINVLTLB_HITS */ 227 228 movl smp_tlb_addr1, %edx 229 movl smp_tlb_addr2, %eax 2301: invlpg (%edx) /* invalidate single page */ 231 addl $PAGE_SIZE, %edx 232 cmpl %eax, %edx 233 jb 1b 234 235 movl lapic, %eax 236 movl $0, LA_EOI(%eax) /* End Of Interrupt to APIC */ 237 238 lock 239 incl smp_tlb_wait 240 241 popl %ds 242 popl %edx 243 popl %eax 244 iret 245 246/* 247 * Forward hardclock to another CPU. Pushes a clockframe and calls 248 * forwarded_hardclock(). 249 */ 250 .text 251 SUPERALIGN_TEXT 252IDTVEC(hardclock) 253 PUSH_FRAME_AND_SET_SEGS 254 255 movl lapic, %edx 256 movl $0, LA_EOI(%edx) /* End Of Interrupt to APIC */ 257 258 pushl $0 /* XXX convert trapframe to clockframe */ 259 call forwarded_hardclock 260 addl $4, %esp /* XXX convert clockframe to trapframe */ 261 MEXITCOUNT 262 jmp doreti 263 264/* 265 * Forward statclock to another CPU. Pushes a clockframe and calls 266 * forwarded_statclock(). 267 */ 268 .text 269 SUPERALIGN_TEXT 270IDTVEC(statclock) 271 PUSH_FRAME_AND_SET_SEGS 272 273 movl lapic, %edx 274 movl $0, LA_EOI(%edx) /* End Of Interrupt to APIC */ 275 276 FAKE_MCOUNT(13*4(%esp)) 277 278 pushl $0 /* XXX convert trapframe to clockframe */ 279 call forwarded_statclock 280 addl $4, %esp /* XXX convert clockframe to trapframe */ 281 MEXITCOUNT 282 jmp doreti 283 284/* 285 * Executed by a CPU when it receives an Xcpuast IPI from another CPU, 286 * 287 * The other CPU has already executed aston() or need_resched() on our 288 * current process, so we simply need to ack the interrupt and return 289 * via doreti to run ast(). 290 */ 291 292 .text 293 SUPERALIGN_TEXT 294IDTVEC(cpuast) 295 PUSH_FRAME_AND_SET_SEGS 296 297 movl lapic, %edx 298 movl $0, LA_EOI(%edx) /* End Of Interrupt to APIC */ 299 300 FAKE_MCOUNT(13*4(%esp)) 301 302 MEXITCOUNT 303 jmp doreti 304 305/* 306 * Executed by a CPU when it receives an Xcpustop IPI from another CPU, 307 * 308 * - Signals its receipt. 309 * - Waits for permission to restart. 310 * - Signals its restart. 311 */ 312 .text 313 SUPERALIGN_TEXT 314IDTVEC(cpustop) 315 pushl %ebp 316 movl %esp, %ebp 317 pushl %eax 318 pushl %ecx 319 pushl %edx 320 pushl %ds /* save current data segment */ 321 pushl %es 322 pushl %fs 323 324 movl $KDSEL, %eax 325 mov %ax, %ds /* use KERNEL data segment */ 326 mov %ax, %es 327 movl $KPSEL, %eax 328 mov %ax, %fs 329 330 movl lapic, %eax 331 movl $0, LA_EOI(%eax) /* End Of Interrupt to APIC */ 332 333 movl PCPU(CPUID), %eax 334 imull $PCB_SIZE, %eax 335 leal CNAME(stoppcbs)(%eax), %eax 336 pushl %eax 337 call CNAME(savectx) /* Save process context */ 338 addl $4, %esp 339 340 movl PCPU(CPUID), %eax 341 342 lock 343 btsl %eax, CNAME(stopped_cpus) /* stopped_cpus |= (1<<id) */ 3441: 345 btl %eax, CNAME(started_cpus) /* while (!(started_cpus & (1<<id))) */ 346 jnc 1b 347 348 lock 349 btrl %eax, CNAME(started_cpus) /* started_cpus &= ~(1<<id) */ 350 lock 351 btrl %eax, CNAME(stopped_cpus) /* stopped_cpus &= ~(1<<id) */ 352 353 test %eax, %eax 354 jnz 2f 355 356 movl CNAME(cpustop_restartfunc), %eax 357 test %eax, %eax 358 jz 2f 359 movl $0, CNAME(cpustop_restartfunc) /* One-shot */ 360 361 call *%eax 3622: 363 popl %fs 364 popl %es 365 popl %ds /* restore previous data segment */ 366 popl %edx 367 popl %ecx 368 popl %eax 369 movl %ebp, %esp 370 popl %ebp 371 iret 372 373/* 374 * Executed by a CPU when it receives a RENDEZVOUS IPI from another CPU. 375 * 376 * - Calls the generic rendezvous action function. 377 */ 378 .text 379 SUPERALIGN_TEXT 380IDTVEC(rendezvous) 381 PUSH_FRAME_AND_SET_SEGS 382 383 call smp_rendezvous_action 384 385 movl lapic, %eax 386 movl $0, LA_EOI(%eax) /* End Of Interrupt to APIC */ 387 POP_FRAME 388 iret 389 390/* 391 * Clean up when we lose out on the lazy context switch optimization. 392 * ie: when we are about to release a PTD but a cpu is still borrowing it. 393 */ 394 SUPERALIGN_TEXT 395IDTVEC(lazypmap) 396 PUSH_FRAME_AND_SET_SEGS 397 398 call pmap_lazyfix_action 399 400 movl lapic, %eax 401 movl $0, LA_EOI(%eax) /* End Of Interrupt to APIC */ 402 POP_FRAME 403 iret 404#endif /* SMP */ 405