diff options
Diffstat (limited to 'x86_64/interrupt.S')
-rw-r--r-- | x86_64/interrupt.S | 82 |
1 files changed, 60 insertions, 22 deletions
diff --git a/x86_64/interrupt.S b/x86_64/interrupt.S index fccf6e28..6fb77727 100644 --- a/x86_64/interrupt.S +++ b/x86_64/interrupt.S @@ -28,30 +28,38 @@ /* * Generic interrupt handler. * - * On entry, %rax contains the irq number. + * On entry, %eax contains the irq number. + * + * Note: kdb_kintr needs to know our stack usage */ + +#define S_REGS 24(%rsp) +#define S_RET 16(%rsp) +#define S_IRQ 8(%rsp) +#define S_IPL 0(%rsp) + ENTRY(interrupt) #ifdef APIC cmpl $255,%eax /* was this a spurious intr? */ - je _no_eoi /* if so, just return */ + jne 1f + ret /* if so, just return */ +1: #endif - pushq %rax /* save irq number */ + subq $16,%rsp /* Two local variables */ + movl %eax,S_IRQ /* save irq number */ + call spl7 /* set ipl */ - pushq %rax /* save previous ipl */ - movl 8(%esp),%edx /* set irq number as 3rd arg */ - movl %edx,%ebx /* copy irq number */ - shll $2,%ebx /* irq * 4 */ - movl EXT(iunit)(%ebx),%edi /* get device unit number as 1st arg */ - movl %eax, %esi /* previous ipl as 2nd arg */ - movq 16(%esp), %rcx /* return address as 4th arg */ - movq 24(%esp), %r8 /* address of interrupted registers as 5th arg */ - shll $1,%ebx /* irq * 8 */ - call *EXT(ivect)(%ebx) /* call interrupt handler */ - popq %rdi /* restore previous ipl */ - call splx_cli /* restore previous ipl */ + movl %eax,S_IPL /* save previous ipl */ - cli /* XXX no more nested interrupts */ - popq %rcx /* restore irq number */ + movl S_IRQ,%ecx /* restore irq number */ + +#if NCPUS > 1 + cmpl $CALL_PMAP_UPDATE,%ecx /* was this a SMP pmap_update request? */ + je _call_single + + cmpl $CALL_AST_CHECK,%ecx /* was this a SMP remote -> local ast request? */ + je _call_local_ast +#endif #ifndef APIC movl $1,%eax @@ -89,14 +97,44 @@ ENTRY(interrupt) movl EXT(curr_pic_mask),%eax /* restore original mask */ outb %al,$(PIC_MASTER_OCW) /* unmask master */ 2: - ret #else - cmpl $16,%ecx /* was this a low ISA intr? */ - jge _no_eoi /* no, must be PCI (let irq_ack handle EOI) */ -_isa_eoi: movl %ecx,%edi /* load irq number as 1st arg */ call EXT(ioapic_irq_eoi) /* ioapic irq specific EOI */ -_no_eoi: +#endif + + ; + movq S_IPL,S_ARG1 /* previous ipl as 2nd arg */ + + ; + movq S_RET,S_ARG2 /* return address as 3th arg */ + + ; + movq S_REGS,S_ARG3 /* address of interrupted registers as 4th arg */ + + movl S_IRQ,%eax /* copy irq number */ + shll $2,%eax /* irq * 4 */ + movl EXT(iunit)(%rax),%edi /* get device unit number as 1st arg */ + + shll $1,%eax /* irq * 8 */ + call *EXT(ivect)(%rax) /* call interrupt handler */ + +_completed: + movl S_IPL,%edi /* restore previous ipl */ + call splx_cli /* restore previous ipl */ + + addq $16,%rsp /* pop local variables */ ret + +#if NCPUS > 1 +_call_single: + call EXT(lapic_eoi) /* lapic EOI before the handler to allow extra update */ + call EXT(pmap_update_interrupt) + jmp _completed + +_call_local_ast: + call EXT(lapic_eoi) /* lapic EOI */ + call EXT(ast_check) /* AST check on this cpu */ + jmp _completed + #endif END(interrupt) |