Microkernel thing OS experiment (Zig ⚡)
at dev 6.8 kB view raw
1pub const apic = @import("apic.zig"); 2pub const pic = @import("pic.zig"); 3pub const pit = @import("pit.zig"); 4pub const idt = @import("idt.zig"); 5const std = @import("std"); 6const log = std.log.scoped(.interrupts); 7const arch = @import("../root.zig"); 8const common = @import("common"); 9 10pub inline fn enable() void { 11 asm volatile ("sti"); 12} 13pub inline fn disable() void { 14 asm volatile ("cli"); 15} 16 17const syscall_entry = @extern(*anyopaque, .{ 18 .name = "syscall_entry", 19}); 20 21export fn syscall_handler(rdi: usize, rsi: usize) callconv(.c) void { 22 std.log.info("Got a syscall! rdi=0x{x}, rsi=0x{x}", .{ rdi, rsi }); 23} 24 25pub fn init_syscalls() void { 26 // Set up the STAR MSR with the segment descriptors 27 const IA32_STAR = arch.registers.MSR(u64, 0xC0000081); 28 const star_value: u64 = 0 | @as(u64, arch.structures.gdt.StandardGdt.selectors.kernel_code) << 32 | (@as(u64, arch.structures.gdt.StandardGdt.selectors.tss_desc + 8) | 3) << 48; 29 IA32_STAR.write(star_value); 30 31 // Set up the EFER MSR with SCE (System Call Enable) 32 const IA32_EFER = arch.registers.MSR(u64, 0xC0000080); 33 const efer_val = IA32_EFER.read() | 0b1; 34 IA32_EFER.write(efer_val); 35 36 // Set up LSTAR with the syscall handler and FMASK to clear interrupts 37 const IA32_LSTAR = arch.registers.MSR(u64, 0xC0000082); 38 IA32_LSTAR.write(@intFromPtr(syscall_entry)); 39 40 const IA32_FMASK = arch.registers.MSR(u64, 0xC0000084); 41 IA32_FMASK.write(1 << 9); 42} 43 44pub fn print_regs(frame: *idt.InterruptFrame(u64)) void { 45 std.log.err("CR3: 0x{x:0>16}", .{frame.cr3}); 46 std.log.err("RAX: 0x{x:0>16}, RBX: 0x{x:0>16}, RCX: 0x{x:0>16}, RDX: 0x{x:0>16}", .{ frame.regs.rax, frame.regs.rbx, frame.regs.rcx, frame.regs.rdx }); 47 std.log.err("RSI: 0x{x:0>16}, RDI: 0x{x:0>16}, RBP: 0x{x:0>16}, RSP: 0x{x:0>16}", .{ frame.regs.rsi, frame.regs.rdi, frame.regs.rbp, frame.rsp }); 48 std.log.err("R8: 0x{x:0>16}, R9: 0x{x:0>16}, R10: 0x{x:0>16}, R11: 0x{x:0>16}", .{ frame.regs.r8, frame.regs.r9, frame.regs.r10, frame.regs.r11 }); 49 std.log.err("R12: 0x{x:0>16}, R13: 0x{x:0>16}, R14: 0x{x:0>16}, R15: 0x{x:0>16}", .{ frame.regs.r12, frame.regs.r13, frame.regs.r14, frame.regs.r15 }); 50 std.log.err("RFL: 0x{x:0>16}, RIP: 0x{x:0>16}, CS: 0x{x:0>16}, SS: 0x{x:0>16}", .{ frame.eflags, frame.rip, frame.cs, frame.ss }); 51} 52 53pub fn unhandled_interrupt(frame: *idt.InterruptFrame(u64)) callconv(idt.CallConv) void { 54 if (std.enums.tagName(idt.Exception, frame.int_num.exception)) |exception_name| { 55 std.log.err("Unhandled interrupt (0x{x} : {s})!!!", .{ frame.int_num.interrupt, exception_name }); 56 } else { 57 std.log.err("Unhandled interrupt (0x{x})!!!", .{frame.int_num.interrupt}); 58 } 59 60 print_regs(frame); 61 62 arch.interrupts.disable(); 63 arch.instructions.die(); 64} 65 66pub fn breakpoint(stack_frame: *idt.InterruptFrame(u64)) callconv(idt.CallConv) void { 67 std.log.warn("Breakpoint @ 0x{x}, returning execution...", .{stack_frame.rip}); 68} 69 70pub fn double_fault(stack_frame: *idt.InterruptFrame(u64)) callconv(idt.CallConv) void { 71 std.log.err("Double fault @ 0x{x}, dying!!!", .{stack_frame.rip}); 72 print_regs(stack_frame); 73 arch.interrupts.disable(); 74 arch.instructions.die(); 75} 76 77pub fn general_protection_fault(stack_frame: *idt.InterruptFrame(idt.SelectorErrorCode)) callconv(idt.CallConv) void { 78 arch.interrupts.disable(); 79 std.log.warn("General Protection Fault @ 0x{x}", .{stack_frame.rip}); 80 81 const target = stack_frame.error_code.parse(); 82 switch (target) { 83 .interrupt => |int| { 84 if (std.enums.tagName(idt.Exception, int.exception)) |exc_name| { 85 std.log.warn("Caused by interrupt 0x{x} ({s})", .{ int.interrupt, exc_name }); 86 } else { 87 std.log.warn("Caused by interrupt 0x{x}", .{int.interrupt}); 88 } 89 }, 90 .gdt_sel => |gdt_sel| { 91 std.log.warn("GDT selector: 0x{x}", .{gdt_sel}); 92 }, 93 .ldt_sel => |ldt_sel| { 94 std.log.warn("LDT selector: 0x{x}", .{ldt_sel}); 95 }, 96 } 97 print_regs(stack_frame.normalize()); 98 arch.instructions.die(); 99} 100 101// Start scheduling 102pub fn startScheduling() noreturn { 103 // 1. Pop off the task to run 104 const task = common.scheduler.getNextTask() orelse { 105 std.log.scoped(.startScheduling).err("No root task!", .{}); 106 @panic("startScheduling"); 107 }; 108 // 2. Apply the paging context 109 task.getPagingContext().apply(); 110 // 3. Give a slice of 1000ms and fire away 111 apic.armTimer(20); 112 enter_userspace(task.rip, 0x69, task.rsp); 113} 114 115// Set up the IDT, PIC, TSC, and APIC 116pub fn init() void { 117 // Set up the IDT and associated vectors 118 idt.init(); 119 idt.add_handler(.{ .exception = .breakpoint }, u64, arch.interrupts.breakpoint, 3, 0); 120 idt.add_handler(.{ .exception = .double_fault }, u64, arch.interrupts.double_fault, 0, 0); 121 idt.add_handler(.{ .exception = .general_protection_fault }, idt.SelectorErrorCode, arch.interrupts.general_protection_fault, 0, 0); 122 idt.add_handler(.{ .exception = .page_fault }, u64, arch.mm.paging.page_fault_handler, 0, 0); 123 // Set up the 8254's (we need 8259 timer to calibrate tsc) 124 pic.init(); 125 // Calibrate the TSC against the 8259 126 arch.tsc.calibrate_pit() catch |err| { 127 log.err("Failed to calibrate TSC: {}", .{err}); 128 }; 129 // Set up everything needed to arm the timer 130 apic.init.initialSetup(); 131} 132 133// TODO: make this slightly less shit 134pub fn enter_userspace(entry: u64, arg: u64, stack: u64) noreturn { 135 log.info("usercode64 GDT 0x{x}, userdata64 GDT 0x{x}", .{ arch.structures.gdt.StandardGdt.selectors.user_code, arch.structures.gdt.StandardGdt.selectors.user_data }); 136 const cr3 = arch.registers.ControlRegisters.Cr3.read(); 137 arch.registers.ControlRegisters.Cr3.write(cr3); 138 asm volatile ( 139 \\ push %[userdata64] 140 \\ push %[stack] 141 \\ push $0x202 142 \\ push %[usercode64] 143 \\ push %[entry] 144 \\ 145 \\ mov %[userdata64], %%rax 146 \\ mov %%rax, %%es 147 \\ mov %%rax, %%ds 148 \\ 149 \\ xor %%rsi, %%rsi 150 \\ xor %%rax, %%rax 151 \\ xor %%rdx, %%rdx 152 \\ xor %%rcx, %%rcx 153 \\ xor %%rbp, %%rbp 154 \\ xor %%rbx, %%rbx 155 \\ 156 \\ xor %%r8, %%r8 157 \\ xor %%r9, %%r9 158 \\ xor %%r10, %%r10 159 \\ xor %%r11, %%r11 160 \\ xor %%r12, %%r12 161 \\ xor %%r13, %%r13 162 \\ xor %%r14, %%r14 163 \\ xor %%r15, %%r15 164 \\ 165 \\ iretq 166 \\ 167 : 168 : [arg] "{rdi}" (arg), 169 [stack] "r" (stack), 170 [entry] "r" (entry), 171 [userdata64] "i" (arch.structures.gdt.StandardGdt.selectors.user_data), 172 [usercode64] "i" (arch.structures.gdt.StandardGdt.selectors.user_code), 173 ); 174 unreachable; 175}