aboutsummaryrefslogtreecommitdiff
path: root/x86_64
diff options
context:
space:
mode:
authorSamuel Thibault <samuel.thibault@ens-lyon.org>2022-09-17 20:05:26 +0200
committerSamuel Thibault <samuel.thibault@ens-lyon.org>2022-09-17 20:22:58 +0200
commite2fcf261076bfe00eed678dcfd2f86b4854b5516 (patch)
treedd9024f4e93ff0d74875ca2fed5b78bdf0fff0a7 /x86_64
parentf6a7b166a232949c21eb3c864bc299271add5e45 (diff)
downloadgnumach-e2fcf261076bfe00eed678dcfd2f86b4854b5516.tar.gz
gnumach-e2fcf261076bfe00eed678dcfd2f86b4854b5516.tar.bz2
gnumach-e2fcf261076bfe00eed678dcfd2f86b4854b5516.zip
interrupt: Fix saving irq/ipl when linux drivers are disabled
When Linux drivers are disabled, in hardclock() the linux_timer_intr() call is dropped, and gcc can tail-recursion-optimize the call to clock_interrupt(). To do so, it overwrites the hardclock() parameters to suit the clock_interrupt parameters layout. This however means it thrashes the backups that the interrupt() function had made of irq/ipl, leading to mayhem. interrupt should thus really properly separate its irq/ipl backups from the interrupt function parameters. Thanks a lot to Etienne Brateau for the tricky investigation!
Diffstat (limited to 'x86_64')
-rw-r--r--x86_64/interrupt.S44
1 files changed, 31 insertions, 13 deletions
diff --git a/x86_64/interrupt.S b/x86_64/interrupt.S
index 73151b06..56cd771b 100644
--- a/x86_64/interrupt.S
+++ b/x86_64/interrupt.S
@@ -28,30 +28,48 @@
/*
* Generic interrupt handler.
*
- * On entry, %rax contains the irq number.
+ * On entry, %eax contains the irq number.
*/
+
+#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 */
#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 %eax, %esi /* previous ipl as 2nd arg */
- movl 8(%esp),%edx /* set irq number as 3rd arg */
- movl %edx,%eax /* copy irq number */
+ movl %eax,S_IPL /* save previous ipl */
+
+ ;
+ movq S_IPL,S_ARG1 /* previous ipl as 2nd arg */
+
+ ;
+ movq S_IRQ,S_ARG2 /* irq number as 3rd arg */
+
+ ;
+ movq S_RET,S_ARG3 /* return address as 4th arg */
+
+ ;
+ movq S_REGS,S_ARG4 /* address of interrupted registers as 5th arg */
+
+ movl S_IRQ,%eax /* copy irq number */
shll $2,%eax /* irq * 4 */
movl EXT(iunit)(%eax),%edi /* get device unit number as 1st arg */
- movq 16(%esp), %rcx /* return address as 4th arg */
- movq 24(%esp), %r8 /* address of interrupted registers as 5th arg */
+
shll $1,%eax /* irq * 8 */
call *EXT(ivect)(%eax) /* call interrupt handler */
- popq %rdi /* restore previous ipl */
- call splx_cli /* restore previous ipl */
+ movl S_IPL,%edi /* restore previous ipl */
+ call splx_cli /* restore previous ipl */
cli /* XXX no more nested interrupts */
- popq %rcx /* restore irq number */
+
+ movl S_IRQ,%ecx /* restore irq number */
#ifndef APIC
movl $1,%eax
@@ -89,14 +107,14 @@ 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 */
+#endif
+ addq $16,%rsp /* pop local variables */
_no_eoi:
ret
-#endif
END(interrupt)