0

Hi I'm writing some interrupt processes.

I'm on Ubuntu 18.04 and using gcc -7.3.0.

Currently I use the following prefix and suffix to pack up my Interrupt Service Routine(without error code):

#define Ent_Int __asm__ __volatile__ ("\
    pushq   %rax\n\t\
    movq    %es, %rax\n\t\
    pushq   %rax\n\t\
    movq    %ds, %rax\n\t\
    pushq   %rax\n\t\
    pushq   %rbx\n\t\
    pushq   %rcx\n\t\
    pushq   %rdx\n\t\
    pushq   %rbp\n\t\
    pushq   %rdi\n\t\
    pushq   %rsi\n\t\
    pushq   %r8\n\t\
    pushq   %r9\n\t\
    pushq   %r10\n\t\
    pushq   %r11\n\t\
    pushq   %r12\n\t\
    pushq   %r13\n\t\
    pushq   %r14\n\t\
    pushq   %r15\n\t\
    movq    $0x10, %rdi\n\t\
    movq    %rdi, %es\n\t\
    movq    %rdi, %ds\n\t");
#define Ret_Int __asm__ __volatile__ ("\
    popq    %r15\n\t\
    popq    %r14\n\t\
    popq    %r13\n\t\
    popq    %r12\n\t\
    popq    %r11\n\t\
    popq    %r10\n\t\
    popq    %r9\n\t\
    popq    %r8\n\t\
    popq    %rsi\n\t\
    popq    %rdi\n\t\
    popq    %rbp\n\t\
    popq    %rdx\n\t\
    popq    %rcx\n\t\
    popq    %rbx\n\t\
    popq    %rax\n\t\
    movq    %rax, %ds\n\t\
    popq    %rax\n\t\
    movq    %rax, %es\n\t\
    popq    %rax\n\t\
    leave\n\t\
    iretq");

And the function looks like this:

void Div_Eorr(Int_Info_No_Err STK)
{
    Ent_Int;
    color_printk(RED,BLACK,"do_divide_error(0),ERROR_CODE:%#016lx,RSP:%#016lx,RIP:%#016lx\n", 0, STK.RSP, *((unsigned long *)(&STK)-1));
    while(1);
    Ret_Int;
}

However from OSDEV, I found that attribute((interrupt)) could make life easier.

However when I compile the function, there is an error message:

./OSFiles/Codes/INT.c:288:1: sorry, unimplemented: SSE instructions aren't allowed in interrupt service routine

However, there is no SSE instruction inside of the function. So I would like to ask:

1, How should I correctly compile the ISR

2, How would gcc distinguish INT with/without error code.

Would be really grateful if any one can illustrate what are the detailed differences of compiled assembly with or without interrupt attribute.

Shore
  • 827
  • 9
  • 24
  • Is that an error message from GCC? It doesn't look like it, and you haven't told gcc this is an interrupt service routine. So where is that error message from? Obviously not from running on real hardware, it would either fault or just allow compiler-generated code to trash the XMM registers, maybe when copying some memory 16 bytes at a time? – Peter Cordes Mar 31 '19 at 04:42
  • Using inline asm this way is not safe: you change RSP without telling the compiler. And your inline asm runs *after* any compiler-generated function prologue (like in un-optimized code, `push %rbp` / `mov %rsp, %rbp`). See [How to remove "noise" from GCC/clang assembly output?](//stackoverflow.com/q/38552116) for how to look at the asm yourself, to see if the compiler is emitting the instructions that you want to make a suitable ISR. – Peter Cordes Mar 31 '19 at 04:46
  • 2
    You will want to compile your kernel code with `-mno-mmx -mno-sse -mno-sse2 -mno-sse3 -mno-3dnow -mno-red-zone`, or you could use `-mgeneral-regs-only -mno-red-zone` . `-mgeneral-regs-only` is what is recommended by GCC when using `attribute((interrupt))` – Michael Petch Mar 31 '19 at 09:38
  • As for exceptions with or without error codes. The [GCC documentation](https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#x86-Function-Attributes) describes that. There are two forms a function can take. One with just a frame parameter and one with a frame parameter and an error code. – Michael Petch Mar 31 '19 at 09:42
  • Things to note: if using attribute((interrupt)) not all registers are pushed, only the non-volatile registers that may be clobbered. If you are looking to gain access to ALL the general purpose registers on the interrupt stack frame from your interrupt handler then you can't use this method. – Michael Petch Mar 31 '19 at 09:49
  • In this SO answer: https://stackoverflow.com/a/43311525/3857942 there is a mechanism to create a wrapper for interrupts on compilers that don't support the attribute((interrupt)) or where that mechanism doesn't suit your needs. It can be adapted for 64-bit (as there is no pusha/popa) – Michael Petch Mar 31 '19 at 09:54
  • 1
    It is generally easier to code interrupt entry points in an assembly language file. They would.setup the interrupt stack frame etc and then call into a _C_ function to do the processing and then unwind the interrupts stack and do an IRETQ. – Michael Petch Mar 31 '19 at 10:12
  • @PeterCordes : It is a GCC error and it occurs when you use attribute((interrupt)) without disabling use of SIMD instructions (there is a similar one for 80387 as well) – Michael Petch Mar 31 '19 at 10:18
  • @MichaelPetch: oh, I see. The question was confusing because the C code block didn't actually use the attribute. I honestly thought it was asking if that attribute would fix that error that they were getting *without* the attribute. (And gcc error messages usually don't say "sorry".) – Peter Cordes Mar 31 '19 at 23:06
  • 1
    @PeterCordes : The "Unimplemented" errors usually say sorry. There are a number of them. Another one is using an i686/i386 cross compiler and you attempt to use `-m64`, that error is _sorry, unimplemented: 64-bit mode not compiled in_ – Michael Petch Mar 31 '19 at 23:42
  • Thank you all, as according to @Michaelpetch, it seems not really ideal method and the best way seems to be create entries in asm files, which is pretty alike to my current method. Hmmmmm, would you like to post your answer and I'll accept it. thanks lol – Shore Apr 01 '19 at 13:35

0 Answers0