| git.druid.rocks | index | druid520 | kaboom | src/ | kernel/ | idt_asm.s |
src/kernel/idt_asm.s
/*
* per-vector isr stubs + one common trampoline. nsc has no function
* pointers, so there's no way to build a jump table in nsc code -- the
* cpu jumps to a fixed address per vector regardless, so each vector
* needs its own tiny stub either way. every stub just normalizes the
* stack (pushing a dummy error code for the vectors that don't get a
* real one from the cpu) and falls into one shared trampoline that
* saves every general-purpose register, calls into nsc, restores
* them, and returns.
*
* vectors 8, 10-14, 17, 21, 29, 30 get a real error code pushed by the
* cpu automatically; every other vector needs one pushed here so the
* stack layout is identical no matter which vector fired.
*
* only ring0 exists right now (no user-mode processes yet), so every
* interrupt is a same-privilege-level interrupt: the cpu's own pushed
* frame is just [rip, cs, rflags], no ss/rsp, no stack switch. that
* changes the day a ring3 process exists and needs its own tss/ist --
* noted here so it isn't quietly forgotten later.
*/
.section .text
.global load_idt
.type load_idt, @function
load_idt:
lidt (%rdi)
ret
.macro ISR_NOERR num
.global isr\num
isr\num:
pushq $0
pushq $\num
jmp isr_common_stub
.endm
.macro ISR_ERR num
.global isr\num
isr\num:
pushq $\num
jmp isr_common_stub
.endm
ISR_NOERR 0
ISR_NOERR 1
ISR_NOERR 2
ISR_NOERR 3
ISR_NOERR 4
ISR_NOERR 5
ISR_NOERR 6
ISR_NOERR 7
ISR_ERR 8
ISR_NOERR 9
ISR_ERR 10
ISR_ERR 11
ISR_ERR 12
ISR_ERR 13
ISR_ERR 14
ISR_NOERR 15
ISR_NOERR 16
ISR_ERR 17
ISR_NOERR 18
ISR_NOERR 19
ISR_NOERR 20
ISR_ERR 21
ISR_NOERR 22
ISR_NOERR 23
ISR_NOERR 24
ISR_NOERR 25
ISR_NOERR 26
ISR_NOERR 27
ISR_NOERR 28
ISR_ERR 29
ISR_ERR 30
ISR_NOERR 31
/* hardware irqs, remapped by pic_remap() (idt.nsc) to land at 32-47
* instead of colliding with the cpu exception vectors above. */
ISR_NOERR 32
ISR_NOERR 33
ISR_NOERR 34
ISR_NOERR 35
ISR_NOERR 36
ISR_NOERR 37
ISR_NOERR 38
ISR_NOERR 39
ISR_NOERR 40
ISR_NOERR 41
ISR_NOERR 42
ISR_NOERR 43
ISR_NOERR 44
ISR_NOERR 45
ISR_NOERR 46
ISR_NOERR 47
/* syscall gate. */
ISR_NOERR 128
isr_common_stub:
pushq %rax
pushq %rbx
pushq %rcx
pushq %rdx
pushq %rsi
pushq %rdi
pushq %rbp
pushq %r8
pushq %r9
pushq %r10
pushq %r11
pushq %r12
pushq %r13
pushq %r14
pushq %r15
/* our own two pushes (vector, then error code, in that push
* order -- so error code ends up above vector on the stack) sit
* right above the 15 just-saved registers: 15*8 = 120 bytes up. */
movq 120(%rsp), %rdi /* vector number -> isr_dispatch arg1 */
movq 128(%rsp), %rsi /* error code -> isr_dispatch arg2 */
movq %rsp, %rdx /* pointer to the saved-register block -> arg3 */
call isr_dispatch
popq %r15
popq %r14
popq %r13
popq %r12
popq %r11
popq %r10
popq %r9
popq %r8
popq %rbp
popq %rdi
popq %rsi
popq %rdx
popq %rcx
popq %rbx
popq %rax
addq $16, %rsp /* drop our vector + error code pushes */
iretq
/*
* nsc has no way to reference a function's address as a value at all
* (confirmed empirically: even &funcname is rejected as an undeclared
* identifier -- function names only resolve in call position). idt.nsc
* needs each stub's real runtime address to build the idt table, so
* these tiny generated functions are the only way to hand it one: each
* just resolves its own stub's address via a rip-relative lea (a real
* link-time relocation, unlike trying to compute this in a data
* directive, which doesn't work -- a label's address isn't known until
* link time, and the bit-shifting an idt entry needs isn't expressible
* as a relocation) and returns it as a plain ptr.
*/
.macro GETADDR num
.global get_isr\num\()_addr
.type get_isr\num\()_addr, @function
get_isr\num\()_addr:
leaq isr\num(%rip), %rax
ret
.endm
GETADDR 0
GETADDR 1
GETADDR 2
GETADDR 3
GETADDR 4
GETADDR 5
GETADDR 6
GETADDR 7
GETADDR 8
GETADDR 9
GETADDR 10
GETADDR 11
GETADDR 12
GETADDR 13
GETADDR 14
GETADDR 15
GETADDR 16
GETADDR 17
GETADDR 18
GETADDR 19
GETADDR 20
GETADDR 21
GETADDR 22
GETADDR 23
GETADDR 24
GETADDR 25
GETADDR 26
GETADDR 27
GETADDR 28
GETADDR 29
GETADDR 30
GETADDR 31
GETADDR 32
GETADDR 33
GETADDR 34
GETADDR 35
GETADDR 36
GETADDR 37
GETADDR 38
GETADDR 39
GETADDR 40
GETADDR 41
GETADDR 42
GETADDR 43
GETADDR 44
GETADDR 45
GETADDR 46
GETADDR 47
GETADDR 128