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?