astryon/core/src/arch/x86_64/interrupts.zig
Gabriel 13ec4bee87 Ready. Set. Go!
Microkernel development in Zig, should be fun! =]
2025-02-13 22:39:48 +01:00

148 lines
3.4 KiB
Zig

const std = @import("std");
const pic = @import("pic.zig");
const debug = @import("../debug.zig");
const sys = @import("../../sys/syscall.zig");
pub const InterruptStackFrame = packed struct {
r15: u64,
r14: u64,
r13: u64,
r12: u64,
r11: u64,
r10: u64,
r9: u64,
r8: u64,
rbp: u64,
rdi: u64,
rsi: u64,
rdx: u64,
rcx: u64,
rbx: u64,
rax: u64,
isr: u64,
error_or_irq: u64,
rip: u64,
cs: u64,
rflags: u64,
rsp: u64,
ss: u64,
};
const IRQHandler = *const fn (u32, *InterruptStackFrame) void;
var irq_handlers: [16]?IRQHandler = std.mem.zeroes([16]?IRQHandler);
export fn asmInterruptEntry() callconv(.Naked) void {
asm volatile (
\\ push %rax
\\ push %rbx
\\ push %rcx
\\ push %rdx
\\ push %rsi
\\ push %rdi
\\ push %rbp
\\ push %r8
\\ push %r9
\\ push %r10
\\ push %r11
\\ push %r12
\\ push %r13
\\ push %r14
\\ push %r15
\\ cld
\\ mov %rsp, %rdi
\\ call interruptEntry
\\asmInterruptExit:
\\ pop %r15
\\ pop %r14
\\ pop %r13
\\ pop %r12
\\ pop %r11
\\ pop %r10
\\ pop %r9
\\ pop %r8
\\ pop %rbp
\\ pop %rdi
\\ pop %rsi
\\ pop %rdx
\\ pop %rcx
\\ pop %rbx
\\ pop %rax
\\ add $16, %rsp
\\ iretq
);
}
const SYSCALL_INTERRUPT = 66;
export fn interruptEntry(frame: *InterruptStackFrame) callconv(.C) void {
debug.print("Caught interrupt {d}\n", .{frame.isr});
switch (frame.isr) {
SYSCALL_INTERRUPT => {
var args = sys.Arguments{ .arg0 = frame.rdi, .arg1 = frame.rsi, .arg2 = frame.rdx, .arg3 = frame.r10, .arg4 = frame.r8, .arg5 = frame.r9 };
sys.invokeSyscall(frame.rax, frame, &args, @ptrFromInt(@as(usize, @intFromPtr(&frame.rax))));
},
else => {},
}
}
/// Disable interrupts (except for NMIs).
pub fn disableInterrupts() void {
asm volatile ("cli");
}
/// Enable interrupts.
pub fn enableInterrupts() void {
asm volatile ("sti");
}
/// Check whether interrupts are enabled.
pub fn saveInterrupts() bool {
var flags: u64 = 0;
asm volatile ("pushfq; pop %[flags]"
: [flags] "=r" (flags),
);
return (flags & 0x200) != 0;
}
/// Enable or disable interrupts depending on the boolean value passed.
pub fn restoreInterrupts(saved: bool) void {
switch (saved) {
true => {
enableInterrupts();
},
false => {
disableInterrupts();
},
}
}
/// Update the PIC masks according to which IRQ handlers are registered.
pub fn syncInterrupts() void {
var pic1_mask: u8 = 0b11111111;
var pic2_mask: u8 = 0b11111111;
var i: u8 = 0;
while (i < 8) : (i += 1) {
if (irq_handlers[i] != null) pic1_mask &= (~(@as(u8, 1) << @as(u3, @intCast(i))));
if (irq_handlers[i + 8] != null) pic2_mask &= (~(@as(u8, 1) << @as(u3, @intCast(i))));
}
if (pic2_mask != 0b11111111) pic1_mask &= 0b11111011;
const saved: bool = saveInterrupts();
disableInterrupts();
pic.changePICMasks(pic1_mask, pic2_mask);
restoreInterrupts(saved);
}
/// Register an IRQ handler.
pub fn registerIRQ(num: u32, handler: IRQHandler) bool {
if (irq_handlers[num] != null) return false;
irq_handlers[num] = handler;
syncInterrupts();
return true;
}