Microkernel thing OS experiment (Zig ⚡)
1//! The entire Interrupt Descriptor Table (IDT) structure for AMD64, 2//! including all the necessary ISR entries. Each of the defined 3//! ISRs is meant for a specific type of exception, while the 4//! array at the end of the IDT can be used for whatever is necessary. 5const std = @import("std"); 6const arch = @import("../root.zig"); 7const StandardGdt = arch.structures.gdt.StandardGdt; 8 9/// Faulty division (mostly divide by zero) 10divide_error: Entry(.handler), 11/// AMD64 Debug Exception, either a fault or a trap 12debug_exception: Entry(.handler), 13/// Non Maskable Interrupt 14non_maskable_interrupt: Entry(.handler), 15/// Breakpoint (int3) trap 16breakpoint: Entry(.handler), 17/// Overflow trap (INTO instruction) 18overflow: Entry(.handler), 19/// Bound Range Exception (BOUND instruction) 20bound_range_exceeded: Entry(.handler), 21/// Invalid Opcode Exception 22invalid_opcode: Entry(.handler), 23/// Device Not Available (FPU instructions when FPU disabled) 24device_not_available: Entry(.handler), 25/// Double Fault Exception 26double_fault: Entry(.abort_with_err_code), 27_coprocessor_segment_overrun: Entry(.handler), 28/// Invalid TSS: bad segment selector 29invalid_tss: Entry(.handler_with_err_code), 30/// Segment Not Present 31segment_not_present: Entry(.handler_with_err_code), 32/// Stack Segment Fault 33stack_segment_fault: Entry(.handler_with_err_code), 34/// General Protection Fault 35general_protection_fault: Entry(.handler_with_err_code), 36/// Page Fault 37page_fault: Entry(.handler_with_err_code), 38 39_reserved1: Entry(.handler), 40/// x87 Floating Point Exception 41x87_floating_point: Entry(.handler), 42/// Alignment Check Exception 43alignment_check: Entry(.handler_with_err_code), 44/// Machine Check Exception (MCE) 45machine_check: Entry(.abort), 46/// SIMD Floating Point Exception 47simd_floating_point: Entry(.handler), 48/// Virtualization Exception 49virtualization: Entry(.handler), 50/// Control Protection Exception 51control_protection: Entry(.handler_with_err_code), 52_reserved2: [10]Entry(.handler), 53/// User Accessible Interrupts 54interrupts: [256 - 32]Entry(.handler), 55 56/// An ISR Entry in the IDT 57pub const EntryType = union(enum) { 58 abort: void, 59 abort_with_err_code: void, 60 handler: void, 61 handler_with_err_code: void, 62 handler_with_custom_err_code: type, 63}; 64pub fn Entry(comptime entry_type: EntryType) type { 65 const return_type = switch (entry_type) { 66 .abort, .abort_with_err_code => noreturn, 67 .handler, .handler_with_err_code, .handler_with_custom_err_code => void, 68 }; 69 const params: []const std.builtin.Type.Fn.Param = switch (entry_type) { 70 .handler, .abort => &.{ 71 // Interrupt stack frame 72 .{ .is_generic = false, .is_noalias = false, .type = *InterruptStackFrame }, 73 }, 74 .handler_with_err_code, .abort_with_err_code => &.{ 75 // Interrupt stack frame 76 .{ .is_generic = false, .is_noalias = false, .type = *InterruptStackFrame }, 77 // Error code 78 .{ .is_generic = false, .is_noalias = false, .type = u64 }, 79 }, 80 .handler_with_custom_err_code => |err_code_type| &.{ 81 // Interrupt stack frame 82 .{ .is_generic = false, .is_noalias = false, .type = *InterruptStackFrame }, 83 // Custom Error code 84 .{ .is_generic = false, .is_noalias = false, .type = err_code_type }, 85 }, 86 }; 87 const FunctionTypeInfo: std.builtin.Type = .{ 88 .@"fn" = .{ 89 .calling_convention = .{ .x86_64_interrupt = .{} }, 90 .is_generic = false, 91 .is_var_args = false, 92 .return_type = return_type, 93 .params = params, 94 }, 95 }; 96 97 // The actual IDT entry structure 98 return extern struct { 99 func_low: u16, 100 gdt_selector: u16, 101 options: Options, 102 func_mid: u16, 103 func_high: u32, 104 _reserved: u32 = 0, 105 106 const FuncType = @Type(FunctionTypeInfo); 107 108 pub const Options = packed struct { 109 /// Interrupt Stack Table Index 110 ist_index: u3, 111 _reserved: u5 = 0, 112 disable_interrupts: bool, 113 must_be_one: u3 = 0b111, 114 must_be_zero: u1 = 0, 115 /// Descriptor Privilege Level 116 dpl: u2, 117 present: bool, 118 }; 119 120 const Self = @This(); 121 122 pub fn installHandler(self: *Self, func: *const FuncType) void { 123 // Fetch the Code Segment 124 const func_ptr = @intFromPtr(func); 125 self.* = .{ 126 // Set the function pointer 127 .func_low = @truncate(func_ptr & 0xFFFF), 128 .func_mid = @truncate((func_ptr >> 16) & 0xFFFF), 129 .func_high = @truncate((func_ptr >> 32) & 0xFFFF_FFFF), 130 .gdt_selector = StandardGdt.selectors.kernel_code, 131 .options = .{ 132 // No Interrupt Stack Table yet 133 .ist_index = 0, 134 // Mask interrupts while running ISR handler 135 .disable_interrupts = true, 136 // Ring 3 Minimum privilege level 137 .dpl = 3, 138 // Mark as present 139 .present = true, 140 }, 141 }; 142 } 143 }; 144} 145 146/// IDT Register 147pub const Idtr = packed struct { 148 limit: u16, 149 addr: u64, 150 151 /// Load the IDT Register 152 pub fn load(self: *const Idtr) void { 153 asm volatile ("lidt (%[idtr_addr])" 154 : 155 : [idtr_addr] "r" (self), 156 ); 157 } 158}; 159 160/// Interrupt Stack Frame 161/// TODO: maybe move this somewhere else 162pub const InterruptStackFrame = extern struct { 163 instruction_pointer: u64, 164 code_segment: u16, 165 _reserved1: [6]u8, 166 cpu_flags: u64, 167 stack_pointer: u64, 168 stack_segment: u16, 169 _reserved2: [6]u8, 170};