This is the mail archive of the gcc-bugs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Bug target/66960] Add interrupt attribute to x86 backend


https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66960

--- Comment #13 from Goswin von Brederlow <goswin-v-b at web dot de> ---
(In reply to H.J. Lu from comment #12)
> (In reply to Goswin von Brederlow from comment #11)
> > I think the design is fundamentally lacking in the following points:
> > 
> >     1. interrupt handler must be declared with a mandatory pointer argument:
> > 
> >     struct interrupt_frame;
> > 
> >     __attribute__ ((interrupt))
> >     void
> >     f (struct interrupt_frame *frame)
> >     {
> >     ...
> >     }
> > 
> >     and user must properly define the structure the pointer pointing to.
> > 
> > First how does one define the struct interrupt_frame properly? What is in
> > there? Is that just the data the CPU pushes to the stack? If so then gcc
> > should define the structure somewhere so code can be written cpu independent.
> 
> interrupt data is pushed onto stack by CPU:
> 
> struct interrupt_frame
> {
>   uword_t ip;
>   uword_t cs;
>   uword_t flags;
>   uword_t sp;
>   uword_t ss;
> };
> 
> However, void * works if you need to access interrupt data.  Interrupt
> handler should provide its working definition.
> 
> > Since the frame pointer is passed as argument I assume the function prolog
> > will save the first argument register (on amd64) to stack. Is that to be
> > included in the struct interrupt_frame?
> 
> No.  The interrupt frame pointer points to interrupt data on stack
> pushed by CPU.
> 
> > Secondly how does one access the original register contents? Some kernel
> > designs use a single kernel stack and switch tasks when returning to user
> > space. That means that one has to copy all the user registers into the
> > thread structure and reload a new set of user registers from the new thread
> > on exit from the interrupt handler. The above interface would not allow this.
> 
> The interrupt attribute provides a way to access interrupt data on stack
> pushed by CPU, nothing more and nothing less.

That design seriously limits the usability of this feature.

> > 
> >     2. exception handler:
> > 
> >     The exception handler is very similar to the interrupt handler with a
> > different mandatory function signature:
> > 
> >     typedef unsigned int uword_t __attribute__ ((mode (__word__)));
> > 
> >     struct interrupt_frame;
> > 
> >     __attribute__ ((interrupt))
> >     void
> >     f (struct interrupt_frame *frame, uword_t error_code)
> >     {
> >     ...
> >     }
> > 
> >     and compiler pops the error code off stack before the 'IRET' instruction.
> > 
> > In a kernel there will always be some exception that simply prints a
> > register dump and stack backtrace. So again how do you access the original
> > register contents?
> 
> You need to do that yourself.

Which means __attribute__ ((interrupt)) can't be used for exceptions half the
time.

> > Secondly why pass error_code as argument if is already on the stack and
> > could be accessed through the frame pointer? The argument register (amd64)
> > would have to be saved on the stack too causing an extra push/pop. But if it
> > is passed as argument then why not pop it before the call to keep the stack
> > frame the same as for interrupts (assuming the saved registers are not
> > included in the frame)?
> 
> error_code is a pseudo parameter, which is mapped to error code on stack
> pushed by CPU.  You can write a simple code to see it yourself.

Couldn't the same trick be used for registers? Pass them as pseudo parameters
and they either resolve to the location on the stack where gcc did save them or
become the original register unchanged.

> > If it is not poped or saved registers are included in the frame then the
> > exception stack frame differs from the interrupt frame (extra error_code and
> > extra register). They should not use the same structure, that's just
> > confusing.
> > 
> >     'no_caller_saved_registers' attribute
> > 
> >     Use this attribute to indicate that the specified function has no
> >     caller-saved registers.  That is, all registers are callee-saved.
> > 
> > Does that include the argument registers (if the function takes arguments)?
> 
> Yes.
> 
> > Wouldn't it be more flexible to define a list of registers that the function
> > will clobber?
> 
> How do programmer know which registers will be clobbered?

The programmer writes the function. He declares what registers will be
clobbered and gcc will add the necessary code to preserve any other registers
it uses inside the function.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]