//! The entire Interrupt Descriptor Table (IDT) structure for AMD64, //! including all the necessary ISR entries. Each of the defined //! ISRs is meant for a specific type of exception, while the //! array at the end of the IDT can be used for whatever is necessary. const std = @import("std"); const arch = @import("../root.zig"); const StandardGdt = arch.structures.gdt.StandardGdt; /// Faulty division (mostly divide by zero) divide_error: Entry(.handler), /// AMD64 Debug Exception, either a fault or a trap debug_exception: Entry(.handler), /// Non Maskable Interrupt non_maskable_interrupt: Entry(.handler), /// Breakpoint (int3) trap breakpoint: Entry(.handler), /// Overflow trap (INTO instruction) overflow: Entry(.handler), /// Bound Range Exception (BOUND instruction) bound_range_exceeded: Entry(.handler), /// Invalid Opcode Exception invalid_opcode: Entry(.handler), /// Device Not Available (FPU instructions when FPU disabled) device_not_available: Entry(.handler), /// Double Fault Exception double_fault: Entry(.abort_with_err_code), _coprocessor_segment_overrun: Entry(.handler), /// Invalid TSS: bad segment selector invalid_tss: Entry(.handler_with_err_code), /// Segment Not Present segment_not_present: Entry(.handler_with_err_code), /// Stack Segment Fault stack_segment_fault: Entry(.handler_with_err_code), /// General Protection Fault general_protection_fault: Entry(.handler_with_err_code), /// Page Fault page_fault: Entry(.handler_with_err_code), _reserved1: Entry(.handler), /// x87 Floating Point Exception x87_floating_point: Entry(.handler), /// Alignment Check Exception alignment_check: Entry(.handler_with_err_code), /// Machine Check Exception (MCE) machine_check: Entry(.abort), /// SIMD Floating Point Exception simd_floating_point: Entry(.handler), /// Virtualization Exception virtualization: Entry(.handler), /// Control Protection Exception control_protection: Entry(.handler_with_err_code), _reserved2: [10]Entry(.handler), /// User Accessible Interrupts interrupts: [256 - 32]Entry(.handler), /// An ISR Entry in the IDT pub const EntryType = union(enum) { abort: void, abort_with_err_code: void, handler: void, handler_with_err_code: void, handler_with_custom_err_code: type, }; pub fn Entry(comptime entry_type: EntryType) type { const return_type = switch (entry_type) { .abort, .abort_with_err_code => noreturn, .handler, .handler_with_err_code, .handler_with_custom_err_code => void, }; const params: []const std.builtin.Type.Fn.Param = switch (entry_type) { .handler, .abort => &.{ // Interrupt stack frame .{ .is_generic = false, .is_noalias = false, .type = *InterruptStackFrame }, }, .handler_with_err_code, .abort_with_err_code => &.{ // Interrupt stack frame .{ .is_generic = false, .is_noalias = false, .type = *InterruptStackFrame }, // Error code .{ .is_generic = false, .is_noalias = false, .type = u64 }, }, .handler_with_custom_err_code => |err_code_type| &.{ // Interrupt stack frame .{ .is_generic = false, .is_noalias = false, .type = *InterruptStackFrame }, // Custom Error code .{ .is_generic = false, .is_noalias = false, .type = err_code_type }, }, }; const FunctionTypeInfo: std.builtin.Type = .{ .@"fn" = .{ .calling_convention = .{ .x86_64_interrupt = .{} }, .is_generic = false, .is_var_args = false, .return_type = return_type, .params = params, }, }; // The actual IDT entry structure return extern struct { func_low: u16, gdt_selector: u16, options: Options, func_mid: u16, func_high: u32, _reserved: u32 = 0, const FuncType = @Type(FunctionTypeInfo); pub const Options = packed struct(u16) { /// Interrupt Stack Table Index ist_index: u3, _reserved: u5 = 0, disable_interrupts: bool, must_be_one: u3 = 0b111, must_be_zero: u1 = 0, /// Descriptor Privilege Level dpl: u2, present: bool, }; const Self = @This(); pub fn installHandler(self: *Self, func: *const FuncType) void { // Fetch the Code Segment const func_ptr = @intFromPtr(func); self.* = .{ // Set the function pointer .func_low = @truncate(func_ptr & 0xFFFF), .func_mid = @truncate((func_ptr >> 16) & 0xFFFF), .func_high = @truncate((func_ptr >> 32) & 0xFFFF_FFFF), .gdt_selector = StandardGdt.selectors.kernel_code, .options = .{ // No Interrupt Stack Table yet .ist_index = 0, // Mask interrupts while running ISR handler .disable_interrupts = true, // Ring 3 Minimum privilege level .dpl = 3, // Mark as present .present = true, }, }; } }; } /// IDT Register pub const Idtr = packed struct(u80) { limit: u16, addr: u64, /// Load the IDT Register pub fn load(self: *const Idtr) void { asm volatile ("lidt (%[idtr_addr])" : : [idtr_addr] "r" (self), ); } }; /// Interrupt Stack Frame /// TODO: maybe move this somewhere else pub const InterruptStackFrame = extern struct { instruction_pointer: u64, code_segment: u16, _reserved1: [6]u8, cpu_flags: u64, stack_pointer: u64, stack_segment: u16, _reserved2: [6]u8, };