Open llvmbot opened 13 years ago
Hi,
Being a kernel developer, and developing my kernel with gcc, setting up interrupts with a assembly stub is a pain in the arse. My experience shows that it complicates the entire interrupt subsystem, and overall makes the thing slower (by a few instructions - always matters).
Therefore, I agree with Michael on the whole. Not only would it help me (by making me switch to clang, and using __interrupt), but would help various other developers, who are using assembly stubs for interrupt handlers.
That's all folks; hope you implement this "easy" feature soon enough.
Regards, Shikhin
Is it rathen LLVM X86 Codegen issue than clang?
It would need to be implemented in both sides, but primarily the codegen is where processing calling conventions resides.
Is it rathen LLVM X86 Codegen issue than clang?
Extended Description
An interrupt calling convention for the compiler for x86 and x86-64 platforms would be useful. It will also promote developers to switch to clang as this feature will simplify interrupts and kernel development. There are several ways it could be implemented, and neither should be very difficult or time consuming.
Attribute parameters may be used to specify whether certain registers or groups of registers (general registers, SSE, etc) need to be saved and restored. Register should also be exposed by symbols. These symbols would point to the location on the stack where the registers were saved. These symbols would be read and writable. If a register was not flagged to be saved within the attribute parameter but is read from, it should be saved. If it is written to, it should be saved and then have the new value set, and restored.
It could also be implemented in a manner that saves/restores all registers indiscriminately, and they could also be accessed as fields of a struct, with the struct being a parameter, with the parameters address being [rsb-wherever it is].
The attribute could also have the simpler mnemonic "__interrupt".
Example assembly for an interrupt function that saves all of the general registers (nothing below this point is set, it is just a suggestion):
; Save registers mov [rsp-0x08], r15 mov [rsp-0x10], r14 mov [rsp-0x18], r13 mov [rsp-0x20], r12 mov [rsp-0x28], r11 mov [rsp-0x30], r10 mov [rsp-0x38], r9 mov [rsp-0x40], r8 mov [rsp-0x48], rdi mov [rsp-0x50], rsi mov [rsp-0x58], rbp mov [rsp-0x60], rsp mov [rsp-0x68], rdx mov [rsp-0x70], rcx mov [rsp-0x78], rbx mov [rsp-0x80], rax ; Save segments. Only fs and gs matter on AMD64. Possible have ds/es savable if specified. mov ax, fs mov [rsp-0x82], ax mov ax, gs mov [rsp-0x84], ax ; Save the stack mov rbp, rsp ; Push the stack sub rsp, + 0x84
; Execute function
...
; Restore the stack mov rsp, rbp ; Restore segments mov ax, [rsp-0x84] mov gs, ax mov ax, [rsp-0x82] mov fs, ax ; Restore registers mov r15, [rsp-0x08] mov r14, [rsp-0x10] mov r13, [rsp-0x18] mov r12, [rsp-0x20] mov r11, [rsp-0x28] mov r10, [rsp-0x30] mov r9, [rsp-0x38] mov r8, [rsp-0x40] mov rdi, [rsp-0x48] mov rsi, [rsp-0x50] mov rbp, [rsp-0x58] mov rsp, [rsp-0x60] mov rdx, [rsp-0x68] mov rcx, [rsp-0x70] mov rbx, [rsp-0x78] mov rax, [rsp-0x80] ; interrupt return iretq
In this example, symbols such as _rax and _rbx (or however they are declared) would point to [rbp-0x80] and [rbp-0x78], respectively.
__attribute((interrupt(rax))) void int () { kprintf("rax: %Lu", _rax); _rax = -1; }
would output:
; Save registers mov [rsp-0x08], rax ; Save segments. Only fs and gs matter on AMD64 Only fs and gs matter on AMD64. Possible have ds/es savable if specified. mov ax, fs mov [rsp-0x10], ax mov ax, gs mov [rsp-0x18], ax ; Save the stack mov rbp, rsp ; Push the stack sub rsp, + 0x0C
; Execute function
;kprintf mov rax, [rbp-0x08] push rax call kprintf ;rax = -1 mov [rbp-0x08], -1
; Restore the stack mov rsp, rbp ; Restore segments mov ax, [rsp-0x10] mov gs, ax mov ax, [rsp-0x18] mov fs, ax ; Restore registers mov rax, [rsp-0x08] ; interrupt return iretq
with _rax pointing to [rbp-0x08], and the value of register rax being uint64_t(-1) after returning.