apic_vector.s revision 122620
1275970Scy/*- 2275970Scy * Copyright (c) 1989, 1990 William F. Jolitz. 3275970Scy * Copyright (c) 1990 The Regents of the University of California. 4275970Scy * All rights reserved. 5275970Scy * 6275970Scy * Redistribution and use in source and binary forms, with or without 7275970Scy * modification, are permitted provided that the following conditions 8275970Scy * are met: 9275970Scy * 1. Redistributions of source code must retain the above copyright 10275970Scy * notice, this list of conditions and the following disclaimer. 11275970Scy * 2. Redistributions in binary form must reproduce the above copyright 12275970Scy * notice, this list of conditions and the following disclaimer in the 13275970Scy * documentation and/or other materials provided with the distribution. 14275970Scy * 3. All advertising materials mentioning features or use of this software 15275970Scy * must display the following acknowledgement: 16275970Scy * This product includes software developed by the University of 17275970Scy * California, Berkeley and its contributors. 18275970Scy * 4. Neither the name of the University nor the names of its contributors 19275970Scy * may be used to endorse or promote products derived from this software 20275970Scy * without specific prior written permission. 21275970Scy * 22275970Scy * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23275970Scy * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24275970Scy * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25275970Scy * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26275970Scy * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27275970Scy * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28275970Scy * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29275970Scy * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30275970Scy * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31275970Scy * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32275970Scy * SUCH DAMAGE. 33275970Scy * 34275970Scy * from: vector.s, 386BSD 0.1 unknown origin 35275970Scy * $FreeBSD: head/sys/i386/i386/apic_vector.s 122620 2003-11-13 18:16:37Z jhb $ 36275970Scy */ 37275970Scy 38275970Scy/* 39275970Scy * Interrupt entry points for external interrupts triggered by I/O APICs 40275970Scy * as well as IPI handlers. 41275970Scy */ 42275970Scy 43275970Scy#include <machine/asmacros.h> 44275970Scy#include <machine/apicreg.h> 45275970Scy#include <machine/smptests.h> 46275970Scy 47275970Scy#include "assym.s" 48275970Scy 49275970Scy/* 50275970Scy * Macros to create and destroy a trap frame. 51275970Scy */ 52275970Scy#define PUSH_FRAME \ 53275970Scy pushl $0 ; /* dummy error code */ \ 54275970Scy pushl $0 ; /* dummy trap type */ \ 55275970Scy pushal ; /* 8 ints */ \ 56275970Scy pushl %ds ; /* save data and extra segments ... */ \ 57275970Scy pushl %es ; \ 58275970Scy pushl %fs 59275970Scy 60275970Scy#define POP_FRAME \ 61275970Scy popl %fs ; \ 62275970Scy popl %es ; \ 63275970Scy popl %ds ; \ 64275970Scy popal ; \ 65275970Scy addl $4+4,%esp 66275970Scy 67275970Scy/* 68275970Scy * I/O Interrupt Entry Point. Rather than having one entry point for 69275970Scy * each interrupt source, we use one entry point for each 32-bit word 70275970Scy * in the ISR. The handler determines the highest bit set in the ISR, 71275970Scy * translates that into a vector, and passes the vector to the 72275970Scy * lapic_handle_intr() function. 73275970Scy */ 74275970Scy#define ISR_VEC(index, vec_name) \ 75275970Scy .text ; \ 76275970Scy SUPERALIGN_TEXT ; \ 77275970ScyIDTVEC(vec_name) ; \ 78275970Scy PUSH_FRAME ; \ 79275970Scy movl $KDSEL, %eax ; /* reload with kernel's data segment */ \ 80275970Scy mov %ax, %ds ; \ 81275970Scy mov %ax, %es ; \ 82275970Scy movl $KPSEL, %eax ; /* reload with per-CPU data segment */ \ 83275970Scy mov %ax, %fs ; \ 84275970Scy movl lapic, %edx ; /* pointer to local APIC */ \ 85275970Scy movl LA_ISR + 16 * (index)(%edx), %eax ; /* load ISR */ \ 86275970Scy bsrl %eax, %eax ; /* index of highset set bit in ISR */ \ 87275970Scy jz 2f ; \ 88275970Scy addl $(32 * index),%eax ; \ 89275970Scy1: ; \ 90275970Scy FAKE_MCOUNT(13*4(%esp)) ; /* XXX avoid double count */ \ 91275970Scy pushl %eax ; /* pass the IRQ */ \ 92275970Scy call lapic_handle_intr ; \ 93275970Scy addl $4, %esp ; /* discard parameter */ \ 94275970Scy MEXITCOUNT ; \ 95275970Scy jmp doreti ; \ 96275970Scy2: movl $-1, %eax ; /* send a vector of -1 */ \ 97275970Scy jmp 1b 98275970Scy 99275970Scy/* 100275970Scy * Handle "spurious INTerrupts". 101275970Scy * Notes: 102275970Scy * This is different than the "spurious INTerrupt" generated by an 103275970Scy * 8259 PIC for missing INTs. See the APIC documentation for details. 104275970Scy * This routine should NOT do an 'EOI' cycle. 105275970Scy */ 106275970Scy .text 107275970Scy SUPERALIGN_TEXT 108275970ScyIDTVEC(spuriousint) 109275970Scy 110275970Scy /* No EOI cycle used here */ 111275970Scy 112275970Scy iret 113275970Scy 114275970ScyMCOUNT_LABEL(bintr2) 115275970Scy ISR_VEC(1, apic_isr1) 116275970Scy ISR_VEC(2, apic_isr2) 117275970Scy ISR_VEC(3, apic_isr3) 118275970Scy ISR_VEC(4, apic_isr4) 119275970Scy ISR_VEC(5, apic_isr5) 120275970ScyMCOUNT_LABEL(eintr2) 121275970Scy 122275970Scy#ifdef SMP 123275970Scy/* 124275970Scy * Global address space TLB shootdown. 125275970Scy */ 126275970Scy .text 127275970Scy SUPERALIGN_TEXT 128275970ScyIDTVEC(invltlb) 129275970Scy pushl %eax 130275970Scy pushl %ds 131275970Scy movl $KDSEL, %eax /* Kernel data selector */ 132275970Scy mov %ax, %ds 133275970Scy 134275970Scy#ifdef COUNT_XINVLTLB_HITS 135275970Scy pushl %fs 136275970Scy movl $KPSEL, %eax /* Private space selector */ 137275970Scy mov %ax, %fs 138275970Scy movl PCPU(CPUID), %eax 139275970Scy popl %fs 140275970Scy incl xhits_gbl(,%eax,4) 141275970Scy#endif /* COUNT_XINVLTLB_HITS */ 142275970Scy 143275970Scy movl %cr3, %eax /* invalidate the TLB */ 144275970Scy movl %eax, %cr3 145275970Scy 146275970Scy movl lapic, %eax 147275970Scy movl $0, LA_EOI(%eax) /* End Of Interrupt to APIC */ 148275970Scy 149275970Scy lock 150275970Scy incl smp_tlb_wait 151275970Scy 152275970Scy popl %ds 153275970Scy popl %eax 154275970Scy iret 155275970Scy 156275970Scy/* 157275970Scy * Single page TLB shootdown 158275970Scy */ 159275970Scy .text 160275970Scy SUPERALIGN_TEXT 161275970ScyIDTVEC(invlpg) 162275970Scy pushl %eax 163275970Scy pushl %ds 164275970Scy movl $KDSEL, %eax /* Kernel data selector */ 165275970Scy mov %ax, %ds 166275970Scy 167275970Scy#ifdef COUNT_XINVLTLB_HITS 168275970Scy pushl %fs 169275970Scy movl $KPSEL, %eax /* Private space selector */ 170275970Scy mov %ax, %fs 171275970Scy movl PCPU(CPUID), %eax 172275970Scy popl %fs 173275970Scy incl xhits_pg(,%eax,4) 174275970Scy#endif /* COUNT_XINVLTLB_HITS */ 175275970Scy 176275970Scy movl smp_tlb_addr1, %eax 177275970Scy invlpg (%eax) /* invalidate single page */ 178275970Scy 179275970Scy movl lapic, %eax 180275970Scy movl $0, LA_EOI(%eax) /* End Of Interrupt to APIC */ 181275970Scy 182275970Scy lock 183275970Scy incl smp_tlb_wait 184275970Scy 185275970Scy popl %ds 186275970Scy popl %eax 187275970Scy iret 188275970Scy 189275970Scy/* 190275970Scy * Page range TLB shootdown. 191275970Scy */ 192275970Scy .text 193275970Scy SUPERALIGN_TEXT 194275970ScyIDTVEC(invlrng) 195275970Scy pushl %eax 196275970Scy pushl %edx 197275970Scy pushl %ds 198275970Scy movl $KDSEL, %eax /* Kernel data selector */ 199275970Scy mov %ax, %ds 200275970Scy 201275970Scy#ifdef COUNT_XINVLTLB_HITS 202275970Scy pushl %fs 203275970Scy movl $KPSEL, %eax /* Private space selector */ 204275970Scy mov %ax, %fs 205275970Scy movl PCPU(CPUID), %eax 206275970Scy popl %fs 207275970Scy incl xhits_rng(,%eax,4) 208275970Scy#endif /* COUNT_XINVLTLB_HITS */ 209275970Scy 210275970Scy movl smp_tlb_addr1, %edx 211275970Scy movl smp_tlb_addr2, %eax 212275970Scy1: invlpg (%edx) /* invalidate single page */ 213275970Scy addl $PAGE_SIZE, %edx 214275970Scy cmpl %eax, %edx 215275970Scy jb 1b 216275970Scy 217275970Scy movl lapic, %eax 218275970Scy movl $0, LA_EOI(%eax) /* End Of Interrupt to APIC */ 219275970Scy 220275970Scy lock 221275970Scy incl smp_tlb_wait 222275970Scy 223275970Scy popl %ds 224275970Scy popl %edx 225275970Scy popl %eax 226275970Scy iret 227275970Scy 228275970Scy/* 229275970Scy * Forward hardclock to another CPU. Pushes a clockframe and calls 230275970Scy * forwarded_hardclock(). 231275970Scy */ 232275970Scy .text 233275970Scy SUPERALIGN_TEXT 234275970ScyIDTVEC(hardclock) 235275970Scy PUSH_FRAME 236275970Scy movl $KDSEL, %eax /* reload with kernel's data segment */ 237275970Scy mov %ax, %ds 238275970Scy mov %ax, %es 239275970Scy movl $KPSEL, %eax 240275970Scy mov %ax, %fs 241275970Scy 242275970Scy movl lapic, %edx 243275970Scy movl $0, LA_EOI(%edx) /* End Of Interrupt to APIC */ 244275970Scy 245275970Scy pushl $0 /* XXX convert trapframe to clockframe */ 246275970Scy call forwarded_hardclock 247275970Scy addl $4, %esp /* XXX convert clockframe to trapframe */ 248275970Scy MEXITCOUNT 249275970Scy jmp doreti 250275970Scy 251275970Scy/* 252275970Scy * Forward statclock to another CPU. Pushes a clockframe and calls 253275970Scy * forwarded_statclock(). 254275970Scy */ 255275970Scy .text 256275970Scy SUPERALIGN_TEXT 257275970ScyIDTVEC(statclock) 258275970Scy PUSH_FRAME 259275970Scy movl $KDSEL, %eax /* reload with kernel's data segment */ 260275970Scy mov %ax, %ds 261275970Scy mov %ax, %es 262275970Scy movl $KPSEL, %eax 263275970Scy mov %ax, %fs 264275970Scy 265275970Scy movl lapic, %edx 266275970Scy movl $0, LA_EOI(%edx) /* End Of Interrupt to APIC */ 267275970Scy 268275970Scy FAKE_MCOUNT(13*4(%esp)) 269275970Scy 270275970Scy pushl $0 /* XXX convert trapframe to clockframe */ 271275970Scy call forwarded_statclock 272275970Scy addl $4, %esp /* XXX convert clockframe to trapframe */ 273275970Scy MEXITCOUNT 274275970Scy jmp doreti 275275970Scy 276275970Scy/* 277275970Scy * Executed by a CPU when it receives an Xcpuast IPI from another CPU, 278275970Scy * 279275970Scy * The other CPU has already executed aston() or need_resched() on our 280275970Scy * current process, so we simply need to ack the interrupt and return 281275970Scy * via doreti to run ast(). 282275970Scy */ 283275970Scy 284275970Scy .text 285275970Scy SUPERALIGN_TEXT 286275970ScyIDTVEC(cpuast) 287275970Scy PUSH_FRAME 288275970Scy movl $KDSEL, %eax 289275970Scy mov %ax, %ds /* use KERNEL data segment */ 290275970Scy mov %ax, %es 291275970Scy movl $KPSEL, %eax 292275970Scy mov %ax, %fs 293275970Scy 294275970Scy movl lapic, %edx 295275970Scy movl $0, LA_EOI(%edx) /* End Of Interrupt to APIC */ 296275970Scy 297275970Scy FAKE_MCOUNT(13*4(%esp)) 298275970Scy 299275970Scy MEXITCOUNT 300275970Scy jmp doreti 301275970Scy 302275970Scy/* 303275970Scy * Executed by a CPU when it receives an Xcpustop IPI from another CPU, 304275970Scy * 305275970Scy * - Signals its receipt. 306275970Scy * - Waits for permission to restart. 307275970Scy * - Signals its restart. 308275970Scy */ 309275970Scy .text 310275970Scy SUPERALIGN_TEXT 311275970ScyIDTVEC(cpustop) 312275970Scy pushl %ebp 313275970Scy movl %esp, %ebp 314275970Scy pushl %eax 315275970Scy pushl %ecx 316275970Scy pushl %edx 317275970Scy pushl %ds /* save current data segment */ 318275970Scy pushl %es 319275970Scy pushl %fs 320275970Scy 321275970Scy movl $KDSEL, %eax 322275970Scy mov %ax, %ds /* use KERNEL data segment */ 323275970Scy mov %ax, %es 324275970Scy movl $KPSEL, %eax 325275970Scy mov %ax, %fs 326275970Scy 327275970Scy movl lapic, %eax 328275970Scy movl $0, LA_EOI(%eax) /* End Of Interrupt to APIC */ 329275970Scy 330275970Scy movl PCPU(CPUID), %eax 331275970Scy imull $PCB_SIZE, %eax 332275970Scy leal CNAME(stoppcbs)(%eax), %eax 333275970Scy pushl %eax 334275970Scy call CNAME(savectx) /* Save process context */ 335275970Scy addl $4, %esp 336275970Scy 337275970Scy movl PCPU(CPUID), %eax 338275970Scy 339275970Scy lock 340275970Scy btsl %eax, CNAME(stopped_cpus) /* stopped_cpus |= (1<<id) */ 341275970Scy1: 342275970Scy btl %eax, CNAME(started_cpus) /* while (!(started_cpus & (1<<id))) */ 343275970Scy jnc 1b 344275970Scy 345275970Scy lock 346275970Scy btrl %eax, CNAME(started_cpus) /* started_cpus &= ~(1<<id) */ 347275970Scy lock 348275970Scy btrl %eax, CNAME(stopped_cpus) /* stopped_cpus &= ~(1<<id) */ 349275970Scy 350275970Scy test %eax, %eax 351275970Scy jnz 2f 352275970Scy 353 movl CNAME(cpustop_restartfunc), %eax 354 test %eax, %eax 355 jz 2f 356 movl $0, CNAME(cpustop_restartfunc) /* One-shot */ 357 358 call *%eax 3592: 360 popl %fs 361 popl %es 362 popl %ds /* restore previous data segment */ 363 popl %edx 364 popl %ecx 365 popl %eax 366 movl %ebp, %esp 367 popl %ebp 368 iret 369 370/* 371 * Executed by a CPU when it receives a RENDEZVOUS IPI from another CPU. 372 * 373 * - Calls the generic rendezvous action function. 374 */ 375 .text 376 SUPERALIGN_TEXT 377IDTVEC(rendezvous) 378 PUSH_FRAME 379 movl $KDSEL, %eax 380 mov %ax, %ds /* use KERNEL data segment */ 381 mov %ax, %es 382 movl $KPSEL, %eax 383 mov %ax, %fs 384 385 call smp_rendezvous_action 386 387 movl lapic, %eax 388 movl $0, LA_EOI(%eax) /* End Of Interrupt to APIC */ 389 POP_FRAME 390 iret 391 392/* 393 * Clean up when we lose out on the lazy context switch optimization. 394 * ie: when we are about to release a PTD but a cpu is still borrowing it. 395 */ 396 SUPERALIGN_TEXT 397IDTVEC(lazypmap) 398 PUSH_FRAME 399 movl $KDSEL, %eax 400 mov %ax, %ds /* use KERNEL data segment */ 401 mov %ax, %es 402 movl $KPSEL, %eax 403 mov %ax, %fs 404 405 call pmap_lazyfix_action 406 407 movl lapic, %eax 408 movl $0, LA_EOI(%eax) /* End Of Interrupt to APIC */ 409 POP_FRAME 410 iret 411#endif /* SMP */ 412