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

--- Comment #12 from H.J. Lu <hjl.tools at gmail dot com> ---
(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.

> 
>     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.

> 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.

> 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?

Reply via email to