public inbox for gcc@gcc.gnu.org
 help / color / mirror / Atom feed
* ARM interrupts
@ 2003-01-22 18:22 Eric de Jong
  2003-01-22 18:46 ` Richard Earnshaw
  2003-01-23 18:08 ` Nick Clifton
  0 siblings, 2 replies; 7+ messages in thread
From: Eric de Jong @ 2003-01-22 18:22 UTC (permalink / raw)
  To: gcc; +Cc: ericdejong

Hello,

When I compile the following c program:

void at91_default_irq_handler() __attribute__
((interrupt ("FIQ")));

void at91_default_irq_handler()
{
}

Then I get the following assembly code:

entry code:
1) str ip, [sp, #-4]!
2) mov ip, sp
3) sub lr, lr, #4
4) stmfd sp!, {fp, ip, lr, pc}
5) sub fp, ip, #4
... (user code)

exit code:
6) ldmea fp, {fp, ip, pc}^

Explanation:
ip = r12
fp = r11 (frame pointer)
sp = r13 (spack pointer, banked = free register for
irq)
lr = r14 (return addres + 4)
pc = r15 = program counter

When an interrupt occurs, 
1) ip is pushed on the private stack
2) sp is copied to ip
3) lr (return address) is adjusted (arm dependend)
4) pc, lr, ip, fp are pushed on the stack in that
order
5) fp = ip - 4 (points to org. sp - 8)

6) values are read from stack, where (see point 4)
pc = lr (return address, arm equvalent for return)
ip = ip
fp = fp
(cpsr is restored, the status flags before the
interrupt)

What I see is, that:
1) sp is never restored, there still are 5 long words
on the private stack
2) ip is never restored, it contains sp+4 (from point
2)

Who can explain this?

Eric de Jong
The Netherlands

__________________________________________________
Do you Yahoo!?
Yahoo! Mail Plus - Powerful. Affordable. Sign up now.
http://mailplus.yahoo.com

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: ARM interrupts
  2003-01-22 18:22 ARM interrupts Eric de Jong
@ 2003-01-22 18:46 ` Richard Earnshaw
  2003-01-23 18:08 ` Nick Clifton
  1 sibling, 0 replies; 7+ messages in thread
From: Richard Earnshaw @ 2003-01-22 18:46 UTC (permalink / raw)
  To: Eric de Jong; +Cc: gcc, ericdejong, Richard.Earnshaw

> Hello,
> 
> When I compile the following c program:
> 
> void at91_default_irq_handler() __attribute__
> ((interrupt ("FIQ")));
> 
> void at91_default_irq_handler()
> {
> }

It's broken.  My best advise is don't use it.  You'd be better off writing 
a wrapper in assembly code.

R.


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: ARM interrupts
  2003-01-22 18:22 ARM interrupts Eric de Jong
  2003-01-22 18:46 ` Richard Earnshaw
@ 2003-01-23 18:08 ` Nick Clifton
  2003-01-23 18:25   ` Richard Earnshaw
  1 sibling, 1 reply; 7+ messages in thread
From: Nick Clifton @ 2003-01-23 18:08 UTC (permalink / raw)
  To: Eric de Jong; +Cc: gcc, ericdejong

Hi Eric,

> When I compile the following c program:
> 
>  void at91_default_irq_handler() __attribute__ ((interrupt ("FIQ")));
>  void at91_default_irq_handler() {}
> 
> Then I get the following assembly code:
> 
> entry code:
> 1) str ip, [sp, #-4]!
> 2) mov ip, sp
> 3) sub lr, lr, #4
> 4) stmfd sp!, {fp, ip, lr, pc}
> 5) sub fp, ip, #4
> 6) ldmea fp, {fp, ip, pc}^
 
> Who can explain this?

It is a bug in the compiler.  Gcc thought that it was able to use a
single instruction to return from the interrupt handler.  It had
forgotten to allow for the fact that IP had to be pushed before the
stack frame could be created.

Please try applying the following patch to your sources and rebuilding
gcc.  It should fix the problem.

Cheers
        Nick

2003-01-23  Nick Clifton  <nickc@redhat.com>

	* config/arm/arm.c (use_return_insn): Do not allow interrupt
	handlers with a stack frame to use a single instruction return
	- they need to pop the IP register. 
	(arm_expand_prologue): Do not pre-bias the LR register for
	interrupt handlers unless they are going to use a single
	instruction return.


Index: gcc/config/arm/arm.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/arm/arm.c,v
retrieving revision 1.247
diff -c -3 -p -w -r1.247 arm.c
*** gcc/config/arm/arm.c	22 Jan 2003 16:01:42 -0000	1.247
--- gcc/config/arm/arm.c	23 Jan 2003 10:31:33 -0000
*************** use_return_insn (iscond)
*** 935,940 ****
--- 935,944 ----
    if (func_type & (ARM_FT_VOLATILE | ARM_FT_NAKED))
      return 0;
  
+   /* So do interrupt functions that use the frame pointer.  */
+   if (IS_INTERRUPT (func_type) && frame_pointer_needed)
+     return 0;
+   
    /* As do variadic functions.  */
    if (current_function_pretend_args_size
        || cfun->machine->uses_anonymous_args
*************** arm_expand_prologue ()
*** 8639,8656 ****
        RTX_FRAME_RELATED_P (insn) = 1;
      }
  
!   /* If this is an interrupt service routine, and the link register is
!      going to be pushed, subtracting four now will mean that the
!      function return can be done with a single instruction.  */
    if ((func_type == ARM_FT_ISR || func_type == ARM_FT_FIQ)
!       && (live_regs_mask & (1 << LR_REGNUM)) != 0)
!     {
        emit_insn (gen_rtx_SET (SImode, 
  			      gen_rtx_REG (SImode, LR_REGNUM),
  			      gen_rtx_PLUS (SImode,
  				    gen_rtx_REG (SImode, LR_REGNUM),
  				    GEN_INT (-4))));
-     }
  
    if (live_regs_mask)
      {
--- 8643,8661 ----
        RTX_FRAME_RELATED_P (insn) = 1;
      }
  
!   /* If this is an interrupt service routine, and the link register
!      is going to be pushed, and we are not creating a stack frame,
!      (which would involve an extra push of IP and a pop in the epilogue)
!      subtracting four from LR now will mean that the function return
!      can be done with a single instruction.  */
    if ((func_type == ARM_FT_ISR || func_type == ARM_FT_FIQ)
!       && (live_regs_mask & (1 << LR_REGNUM)) != 0
!       && ! frame_pointer_needed)
      emit_insn (gen_rtx_SET (SImode, 
  			    gen_rtx_REG (SImode, LR_REGNUM),
  			    gen_rtx_PLUS (SImode,
  					  gen_rtx_REG (SImode, LR_REGNUM),
  					  GEN_INT (-4))));
  
    if (live_regs_mask)
      {

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: ARM interrupts
  2003-01-23 18:08 ` Nick Clifton
@ 2003-01-23 18:25   ` Richard Earnshaw
  2003-01-23 18:30     ` Richard Earnshaw
                       ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Richard Earnshaw @ 2003-01-23 18:25 UTC (permalink / raw)
  To: Nick Clifton; +Cc: Eric de Jong, gcc, ericdejong, Richard.Earnshaw

> Hi Eric,
> 
> > When I compile the following c program:
> > 
> >  void at91_default_irq_handler() __attribute__ ((interrupt ("FIQ")));
> >  void at91_default_irq_handler() {}
> > 
> > Then I get the following assembly code:
> > 
> > entry code:
> > 1) str ip, [sp, #-4]!
> > 2) mov ip, sp
> > 3) sub lr, lr, #4
> > 4) stmfd sp!, {fp, ip, lr, pc}
> > 5) sub fp, ip, #4
> > 6) ldmea fp, {fp, ip, pc}^
>  
> > Who can explain this?
> 
> It is a bug in the compiler.  Gcc thought that it was able to use a
> single instruction to return from the interrupt handler.  It had
> forgotten to allow for the fact that IP had to be pushed before the
> stack frame could be created.
> 
> Please try applying the following patch to your sources and rebuilding
> gcc.  It should fix the problem.
> 
> Cheers
>         Nick
> 
> 2003-01-23  Nick Clifton  <nickc@redhat.com>
> 
> 	* config/arm/arm.c (use_return_insn): Do not allow interrupt
> 	handlers with a stack frame to use a single instruction return
> 	- they need to pop the IP register. 
> 	(arm_expand_prologue): Do not pre-bias the LR register for
> 	interrupt handlers unless they are going to use a single
> 	instruction return.

Sorry, but this is just gross.  Interrupt functions shouldn't even be
trying to produce APCS-style framed entry sequences.

The entry sequence should instead be something like

	sub	lr, lr, #4		/* If required for return sequence. */
	stmfd	sp!, {...,fp,sp,ip,lr}	/* Note, no pc.  */
	add	fp, sp, #16+sizeof(...)
#ifdef ATPCS_STACK_ALIGN
	bic	sp, sp, #7		/* If stack alignment required.  */
#endif

	...
	ldmea	fp, {...,fp,sp,ip,pc}^

Note that you have to use a "frame-pointer" if you want stack alignment.  If you don't then it's possible to compile a frameless entry sequence.

R.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: ARM interrupts
  2003-01-23 18:25   ` Richard Earnshaw
@ 2003-01-23 18:30     ` Richard Earnshaw
  2003-01-26 20:28     ` Nick Clifton
  2003-01-26 20:31     ` Nick Clifton
  2 siblings, 0 replies; 7+ messages in thread
From: Richard Earnshaw @ 2003-01-23 18:30 UTC (permalink / raw)
  To: Nick Clifton; +Cc: Eric de Jong, gcc, ericdejong, Richard.Earnshaw


> #ifdef ATPCS_STACK_ALIGN
> 	bic	sp, sp, #7		/* If stack alignment required.  */
> #endif

Thinking about this some more, this isn't needed with the current level of 
IRQ support that we provide.  We don't allow nested interrupts (we don't 
preserve the SPSR), so we can assume that the appropriate interrupt stack 
is correctly aligned on entry.  At most we need to add a normal stack 
adjustment.

R.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: ARM interrupts
  2003-01-23 18:25   ` Richard Earnshaw
  2003-01-23 18:30     ` Richard Earnshaw
@ 2003-01-26 20:28     ` Nick Clifton
  2003-01-26 20:31     ` Nick Clifton
  2 siblings, 0 replies; 7+ messages in thread
From: Nick Clifton @ 2003-01-26 20:28 UTC (permalink / raw)
  To: Richard.Earnshaw; +Cc: eric2work, gcc, ericdejong

Hi Richard,

: Sorry, but this is just gross.  Interrupt functions shouldn't even
: be trying to produce APCS-style framed entry sequences.

Agreed - although you can always use the -fomit-frame-pointer switch.
But then I also agree with your earlier comment about the fact that
you should not be using the compiler to create interrupt handlers in
the first place - they should be hand coded.

The point about the patch is that with it applied the compiler should
now produce working code for an interrupt handler, even if it is not
optimal.

Of course I have only inspected the code generated by eye - I have not
run it on real ARM hardware, hence I was asking Eric to test/verify
the patch before I applied it.

Cheers
	Nick

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: ARM interrupts
  2003-01-23 18:25   ` Richard Earnshaw
  2003-01-23 18:30     ` Richard Earnshaw
  2003-01-26 20:28     ` Nick Clifton
@ 2003-01-26 20:31     ` Nick Clifton
  2 siblings, 0 replies; 7+ messages in thread
From: Nick Clifton @ 2003-01-26 20:31 UTC (permalink / raw)
  To: Richard.Earnshaw; +Cc: eric2work, gcc, ericdejong

Hi Richard,

: Sorry, but this is just gross.  Interrupt functions shouldn't even
: be trying to produce APCS-style framed entry sequences.

Agreed - although you can always use the -fomit-frame-pointer switch.
But then I also agree with your earlier comment about the fact that
you should not be using the compiler to create interrupt handlers in
the first place - they should be hand coded.

The point about the patch is that with it applied the compiler should
now produce working code for an interrupt handler, even if it is not
optimal.

Of course I have only inspected the code generated by eye - I have not
run it on real ARM hardware, hence I was asking Eric to test/verify
the patch before I applied it.

Cheers
	Nick

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2003-01-26 15:36 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-01-22 18:22 ARM interrupts Eric de Jong
2003-01-22 18:46 ` Richard Earnshaw
2003-01-23 18:08 ` Nick Clifton
2003-01-23 18:25   ` Richard Earnshaw
2003-01-23 18:30     ` Richard Earnshaw
2003-01-26 20:28     ` Nick Clifton
2003-01-26 20:31     ` Nick Clifton

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).