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};