bug-hurd
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH gnumach] Fix interrupt handling


From: Samuel Thibault
Subject: Re: [PATCH gnumach] Fix interrupt handling
Date: Tue, 3 Oct 2023 20:24:22 +0200
User-agent: NeoMutt/20170609 (1.8.3)

Applied, thanks!

Damien Zammit, le lun. 02 oct. 2023 03:39:13 +0000, a ecrit:
> Logic for interrupts:
> 
> - interrupt.S raises spl (thus IF cleared)
> - interrupt.S EOI
> - interrupt.S calls the handler
>    - for pure in-kernel handlers, they do whatever they want with IF
>      cleared.
>    - when a userland handler is registers, queue_intr masks the irq.
> - interrupt.S lowers spl with splx_cli, thus IF still cleared
> - iret, that clears the IF
> 
> - later on, userland acks the IRQ, that unmasks the irq
> 
> The key to this change is that all interrupts, including IPIs, are
> treated the same way. Eg. the spl level is now raised before an IPI and
> restored after. Also, EOI is not needed inside irq_acknowledge.
> 
> With this change and the experimental change not to dispatch threads
> direct to idle processors in the scheduler, I no longer observe kernel
> faults, but an occasional hang does occur.
> 
> ---
>  device/intr.c           | 16 ++++++++++++++--
>  i386/i386at/interrupt.S | 28 +++++++++++++---------------
>  x86_64/interrupt.S      | 28 +++++++++++++---------------
>  3 files changed, 40 insertions(+), 32 deletions(-)
> 
> diff --git a/device/intr.c b/device/intr.c
> index 15029440..97cfa377 100644
> --- a/device/intr.c
> +++ b/device/intr.c
> @@ -50,6 +50,20 @@ search_intr (struct irqdev *dev, ipc_port_t dst_port)
>    return NULL;
>  }
>  
> +
> +/*
> + * Interrupt handling logic:
> + *
> + * interrupt.S raises spl (thus IF cleared)
> + * interrupt.S EOI
> + * interrupt.S calls the handler
> + *   - for pure in-kernel handlers, they do whatever they want with IF 
> cleared.
> + *   - when a userland handler is registered, queue_intr masks the irq.
> + * interrupt.S lowers spl with splx_cli, thus IF still cleared
> + * iret, that also clears the IF
> + *
> + * later on, (irq_acknowledge), userland acks the IRQ, that unmasks the irq
> + */
>  kern_return_t
>  irq_acknowledge (ipc_port_t receive_port)
>  {
> @@ -76,8 +90,6 @@ irq_acknowledge (ipc_port_t receive_port)
>    if (ret)
>      return ret;
>  
> -  (*(irqtab.irqdev_ack)) (&irqtab, e->id);
> -
>    __enable_irq (irqtab.irq[e->id]);
>  
>    return D_SUCCESS;
> diff --git a/i386/i386at/interrupt.S b/i386/i386at/interrupt.S
> index 8ae6b97c..77424b43 100644
> --- a/i386/i386at/interrupt.S
> +++ b/i386/i386at/interrupt.S
> @@ -45,14 +45,6 @@ ENTRY(interrupt)
>       ret                             /* if so, just return */
>  1:
>  #endif
> -#if NCPUS > 1
> -     cmpl    $CALL_PMAP_UPDATE,%eax  /* was this a SMP pmap_update request? 
> */
> -     je      _call_single
> -
> -     cmpl    $CALL_AST_CHECK,%eax    /* was this a SMP remote -> local ast 
> request? */
> -     je      _call_local_ast
> -#endif
> -
>       subl    $24,%esp                /* Two local variables + 4 parameters */
>       movl    %eax,S_IRQ              /* save irq number */
>  
> @@ -61,6 +53,14 @@ ENTRY(interrupt)
>  
>       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
>       shll    %cl,%eax                /* get corresponding IRQ mask */
> @@ -98,11 +98,8 @@ ENTRY(interrupt)
>       outb    %al,$(PIC_MASTER_OCW)   /* unmask master */
>  2:
>  #else
> -     cmpl    $16,%ecx                /* was this a low ISA intr? */
> -     jge     _no_eoi                 /* no, must be PCI (let irq_ack handle 
> EOI) */
>       movl    %ecx,(%esp)             /* load irq number as 1st arg */
>       call    EXT(ioapic_irq_eoi)     /* ioapic irq specific EOI */
> -_no_eoi:
>  #endif
>  
>       movl    S_IPL,%eax
> @@ -122,6 +119,7 @@ _no_eoi:
>  
>       call    *EXT(ivect)(%eax)       /* call interrupt handler */
>  
> +_completed:
>       movl    S_IPL,%eax              /* restore previous ipl */
>       movl    %eax,(%esp)
>       call    splx_cli                /* restore previous ipl */
> @@ -131,14 +129,14 @@ _no_eoi:
>  
>  #if NCPUS > 1
>  _call_single:
> -     cli                             /* no nested interrupts */
>       call    EXT(lapic_eoi)          /* lapic EOI before the handler to 
> allow extra update */
>       call    EXT(pmap_update_interrupt)
> -     ret
> +     jmp     _completed
>  
>  _call_local_ast:
> -     call    EXT(ast_check)          /* AST check on this cpu */
>       call    EXT(lapic_eoi)          /* lapic EOI */
> -     ret
> +     call    EXT(ast_check)          /* AST check on this cpu */
> +     jmp     _completed
> +
>  #endif
>  END(interrupt)
> diff --git a/x86_64/interrupt.S b/x86_64/interrupt.S
> index fcd5a032..6fb77727 100644
> --- a/x86_64/interrupt.S
> +++ b/x86_64/interrupt.S
> @@ -45,14 +45,6 @@ ENTRY(interrupt)
>       ret                             /* if so, just return */
>  1:
>  #endif
> -#if NCPUS > 1
> -     cmpl    $CALL_PMAP_UPDATE,%eax  /* was this a SMP pmap_update request? 
> */
> -     je      _call_single
> -
> -     cmpl    $CALL_AST_CHECK,%eax    /* was this a SMP remote -> local ast 
> request? */
> -     je      _call_local_ast
> -#endif
> -
>       subq    $16,%rsp                /* Two local variables */
>       movl    %eax,S_IRQ              /* save irq number */
>  
> @@ -61,6 +53,14 @@ ENTRY(interrupt)
>  
>       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
>       shll    %cl,%eax                /* get corresponding IRQ mask */
> @@ -98,11 +98,8 @@ ENTRY(interrupt)
>       outb    %al,$(PIC_MASTER_OCW)   /* unmask master */
>  2:
>  #else
> -     cmpl    $16,%ecx                /* was this a low ISA intr? */
> -     jge      _no_eoi                /* no, must be PCI (let irq_ack handle 
> EOI) */
>       movl    %ecx,%edi               /* load irq number as 1st arg */
>       call    EXT(ioapic_irq_eoi)     /* ioapic irq specific EOI */
> -_no_eoi:
>  #endif
>  
>       ;
> @@ -121,6 +118,7 @@ _no_eoi:
>       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 */
>  
> @@ -129,14 +127,14 @@ _no_eoi:
>  
>  #if NCPUS > 1
>  _call_single:
> -     cli                             /* no nested interrupts */
>       call    EXT(lapic_eoi)          /* lapic EOI before the handler to 
> allow extra update */
>       call    EXT(pmap_update_interrupt)
> -     ret
> +     jmp     _completed
>  
>  _call_local_ast:
> -     call    EXT(ast_check)          /* AST check on this cpu */
>       call    EXT(lapic_eoi)          /* lapic EOI */
> -     ret
> +     call    EXT(ast_check)          /* AST check on this cpu */
> +     jmp     _completed
> +
>  #endif
>  END(interrupt)
> -- 
> 2.40.1
> 
> 
> 

-- 
Samuel
---
Pour une évaluation indépendante, transparente et rigoureuse !
Je soutiens la Commission d'Évaluation de l'Inria.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]