From 89a1873e7cc7ef2c981da4870cfa970afc15ec47 Mon Sep 17 00:00:00 2001 From: ED Date: Wed, 6 Nov 2019 21:21:02 +0000 Subject: [PATCH] No more assembly Pure zig Added doc comments Feedback --- build.zig | 7 --- src/kernel/arch/x86/idt.zig | 6 +- src/kernel/arch/x86/interrupts.zig | 86 +++++++++++++++++++++++++++ src/kernel/arch/x86/irq.zig | 52 +++++------------ src/kernel/arch/x86/irq_asm.s | 70 ---------------------- src/kernel/arch/x86/isr.zig | 77 +++--------------------- src/kernel/arch/x86/isr_asm.s | 90 ----------------------------- test/mock/kernel/mock_framework.zig | 10 ++++ 8 files changed, 120 insertions(+), 278 deletions(-) create mode 100644 src/kernel/arch/x86/interrupts.zig delete mode 100644 src/kernel/arch/x86/irq_asm.s delete mode 100644 src/kernel/arch/x86/isr_asm.s diff --git a/build.zig b/build.zig index 70f36bc..0e8cd39 100644 --- a/build.zig +++ b/build.zig @@ -33,13 +33,6 @@ pub fn build(b: *Builder) !void { exec.addBuildOption(bool, "rt_test", rt_test); exec.setLinkerScriptPath("link.ld"); exec.setTheTarget(target); - switch (target.getArch()) { - .i386 => { - exec.addAssemblyFile("src/kernel/arch/x86/irq_asm.s"); - exec.addAssemblyFile("src/kernel/arch/x86/isr_asm.s"); - }, - else => unreachable, - } const iso_path = try fs.path.join(b.allocator, [_][]const u8{ b.exe_dir, "pluto.iso" }); const grub_build_path = try fs.path.join(b.allocator, [_][]const u8{ b.exe_dir, "iso", "boot" }); diff --git a/src/kernel/arch/x86/idt.zig b/src/kernel/arch/x86/idt.zig index ecc5aff..4dbd641 100644 --- a/src/kernel/arch/x86/idt.zig +++ b/src/kernel/arch/x86/idt.zig @@ -48,7 +48,7 @@ pub const IdtPtr = packed struct { base: u32, }; -pub const InterruptHandler = extern fn () void; +pub const InterruptHandler = nakedcc fn () void; /// The error set for the IDT pub const IdtError = error{ @@ -189,8 +189,8 @@ pub fn init() void { if (build_options.rt_test) runtimeTests(); } -extern fn testHandler0() void {} -extern fn testHandler1() void {} +nakedcc fn testHandler0() void {} +nakedcc fn testHandler1() void {} fn mock_lidt(ptr: *const IdtPtr) void { expectEqual(TABLE_SIZE, ptr.limit); diff --git a/src/kernel/arch/x86/interrupts.zig b/src/kernel/arch/x86/interrupts.zig new file mode 100644 index 0000000..606ea4c --- /dev/null +++ b/src/kernel/arch/x86/interrupts.zig @@ -0,0 +1,86 @@ +const arch = @import("arch.zig"); +const syscalls = @import("syscalls.zig"); +const irq = @import("irq.zig"); +const idt = @import("idt.zig"); + +extern fn irqHandler(ctx: *arch.InterruptContext) void; +extern fn isrHandler(ctx: *arch.InterruptContext) void; + +/// +/// The main handler for all exceptions and interrupts. This will then go and call the correct +/// handler for an ISR or IRQ. +/// +/// Arguments: +/// IN ctx: *arch.InterruptContext - Pointer to the exception context containing the contents +/// of the registers at the time of a exception. +/// +export fn handler(ctx: *arch.InterruptContext) void { + if (ctx.int_num < irq.IRQ_OFFSET or ctx.int_num == syscalls.INTERRUPT) { + isrHandler(ctx); + } else { + irqHandler(ctx); + } +} + +/// +/// The common assembly that all exceptions and interrupts will call. +/// +export nakedcc fn commonStub() void { + asm volatile ( + \\pusha + \\push %%ds + \\push %%es + \\push %%fs + \\push %%gs + \\mov $0x10, %%ax + \\mov %%ax, %%ds + \\mov %%ax, %%es + \\mov %%ax, %%fs + \\mov %%ax, %%gs + \\mov %%esp, %%eax + \\push %%eax + \\call handler + \\pop %%eax + \\pop %%gs + \\pop %%fs + \\pop %%es + \\pop %%ds + \\popa + \\add $0x8, %%esp + \\iret + ); +} + +/// +/// Generate the function that is the entry point for each exception/interrupt. This will then be +/// used as the handler for the corresponding IDT entry. +/// +/// Arguments: +/// IN interrupt_num: u32 - The interrupt number to generate the function for. +/// +/// Return: idt.InterruptHandler +/// The stub function that is called for each interrupt/exception. +/// +pub fn getInterruptStub(comptime interrupt_num: u32) idt.InterruptHandler { + return struct { + nakedcc fn func() void { + asm volatile ( + \\ cli + ); + + // These interrupts don't push an error code onto the stack, so will push a zero. + if (interrupt_num != 8 and !(interrupt_num >= 10 and interrupt_num <= 14) and interrupt_num != 17) { + asm volatile ( + \\ pushl $0 + ); + } + + asm volatile ( + \\ pushl %[nr] + \\ jmp commonStub + : + : [nr] "n" (interrupt_num) + ); + } + }.func; +} diff --git a/src/kernel/arch/x86/irq.zig b/src/kernel/arch/x86/irq.zig index 43a8d43..008b1a0 100644 --- a/src/kernel/arch/x86/irq.zig +++ b/src/kernel/arch/x86/irq.zig @@ -11,6 +11,7 @@ const idt = if (is_test) @import(mock_path ++ "idt_mock.zig") else @import("idt. const arch = if (is_test) @import(mock_path ++ "arch_mock.zig") else @import("arch.zig"); const log = if (is_test) @import(mock_path ++ "log_mock.zig") else @import("../../log.zig"); const pic = if (is_test) @import(mock_path ++ "pic_mock.zig") else @import("pic.zig"); +const interrupts = @import("interrupts.zig"); /// The error set for the IRQ. This will be from installing a IRQ handler. pub const IrqError = error{ @@ -24,33 +25,15 @@ pub const IrqError = error{ /// The total number of IRQ. const NUMBER_OF_ENTRIES: u16 = 16; -// The offset from the interrupt number where the IRQs are. -const IRQ_OFFSET: u16 = 32; - /// The type of a IRQ handler. A function that takes a interrupt context and returns void. const IrqHandler = fn (*arch.InterruptContext) void; +// The offset from the interrupt number where the IRQs are. +pub const IRQ_OFFSET: u16 = 32; + /// The list of IRQ handlers initialised to unhandled. var irq_handlers: [NUMBER_OF_ENTRIES]?IrqHandler = [_]?IrqHandler{null} ** NUMBER_OF_ENTRIES; -// The external assembly that is fist called to set up the interrupt handler. -extern fn irq0() void; -extern fn irq1() void; -extern fn irq2() void; -extern fn irq3() void; -extern fn irq4() void; -extern fn irq5() void; -extern fn irq6() void; -extern fn irq7() void; -extern fn irq8() void; -extern fn irq9() void; -extern fn irq10() void; -extern fn irq11() void; -extern fn irq12() void; -extern fn irq13() void; -extern fn irq14() void; -extern fn irq15() void; - /// /// The IRQ handler that each of the IRQs will call when a interrupt happens. /// @@ -60,6 +43,10 @@ extern fn irq15() void; /// export fn irqHandler(ctx: *arch.InterruptContext) void { // Get the IRQ index, by getting the interrupt number and subtracting the offset. + if (ctx.int_num < IRQ_OFFSET) { + panic(@errorReturnTrace(), "Not an IRQ number: {}\n", ctx.int_num); + } + const irq_offset = ctx.int_num - IRQ_OFFSET; if (isValidIrq(irq_offset)) { // IRQ index is valid so can truncate @@ -143,30 +130,17 @@ pub fn registerIrq(irq_num: u8, handler: IrqHandler) IrqError!void { pub fn init() void { log.logInfo("Init irq\n"); - // Open all the IRQs - openIrq(32, irq0); - openIrq(33, irq1); - openIrq(34, irq2); - openIrq(35, irq3); - openIrq(36, irq4); - openIrq(37, irq5); - openIrq(38, irq6); - openIrq(39, irq7); - openIrq(40, irq8); - openIrq(41, irq9); - openIrq(42, irq10); - openIrq(43, irq11); - openIrq(44, irq12); - openIrq(45, irq13); - openIrq(46, irq14); - openIrq(47, irq15); + comptime var i = IRQ_OFFSET; + inline while (i < IRQ_OFFSET + 16) : (i += 1) { + openIrq(i, interrupts.getInterruptStub(i)); + } log.logInfo("Done\n"); if (build_options.rt_test) runtimeTests(); } -extern fn testFunction0() void {} +nakedcc fn testFunction0() void {} fn testFunction1(ctx: *arch.InterruptContext) void {} fn testFunction2(ctx: *arch.InterruptContext) void {} diff --git a/src/kernel/arch/x86/irq_asm.s b/src/kernel/arch/x86/irq_asm.s deleted file mode 100644 index 3b6db39..0000000 --- a/src/kernel/arch/x86/irq_asm.s +++ /dev/null @@ -1,70 +0,0 @@ -.macro irqGenerator n - .align 4 - .type irq\n, @function - .global irq\n - irq\n: - cli - push $0 - push $\n+32 - jmp irqCommonStub -.endmacro - -irqCommonStub: - // Push all the registers - pusha - - // Push the additional segment regiters - push %ds - push %es - push %fs - push %gs - - // Set the kernel data segment - mov $0x10, %ax - mov %ax, %ds - mov %ax, %es - mov %ax, %fs - mov %ax, %gs - - // Push the stack, this is where all the registers are sported, points the interuptContect - mov %esp, %eax - push %eax - - // Call the handler - call irqHandler - - // Pop stack pointer to point to the registers pushed - pop %eax - - // Pop segment regiters inorder - pop %gs - pop %fs - pop %es - pop %ds - - // Pop all general registers - popa - - // Pop the error code and interrupt number - add $0x8, %esp - - // Pops 5 things at once: cs, eip, eflags, ss, and esp - iret -.type irqCommonStub, @function - -irqGenerator 0 -irqGenerator 1 -irqGenerator 2 -irqGenerator 3 -irqGenerator 4 -irqGenerator 5 -irqGenerator 6 -irqGenerator 7 -irqGenerator 8 -irqGenerator 9 -irqGenerator 10 -irqGenerator 11 -irqGenerator 12 -irqGenerator 13 -irqGenerator 14 -irqGenerator 15 diff --git a/src/kernel/arch/x86/isr.zig b/src/kernel/arch/x86/isr.zig index e03a3d1..2b0cbdb 100644 --- a/src/kernel/arch/x86/isr.zig +++ b/src/kernel/arch/x86/isr.zig @@ -11,6 +11,7 @@ const panic = if (is_test) @import(mock_path ++ "panic_mock.zig").panic else @im const idt = if (is_test) @import(mock_path ++ "idt_mock.zig") else @import("idt.zig"); const arch = if (is_test) @import(mock_path ++ "arch_mock.zig") else @import("arch.zig"); const log = if (is_test) @import(mock_path ++ "log_mock.zig") else @import("../../log.zig"); +const interrupts = @import("interrupts.zig"); /// The error set for the ISR. This will be from installing a ISR handler. pub const IsrError = error{ @@ -132,41 +133,6 @@ var isr_handlers: [NUMBER_OF_ENTRIES]?IsrHandler = [_]?IsrHandler{null} ** NUMBE /// The syscall hander. var syscall_handler: ?IsrHandler = null; -// The external assembly that is fist called to set up the exception handler. -extern fn isr0() void; -extern fn isr1() void; -extern fn isr2() void; -extern fn isr3() void; -extern fn isr4() void; -extern fn isr5() void; -extern fn isr6() void; -extern fn isr7() void; -extern fn isr8() void; -extern fn isr9() void; -extern fn isr10() void; -extern fn isr11() void; -extern fn isr12() void; -extern fn isr13() void; -extern fn isr14() void; -extern fn isr15() void; -extern fn isr16() void; -extern fn isr17() void; -extern fn isr18() void; -extern fn isr19() void; -extern fn isr20() void; -extern fn isr21() void; -extern fn isr22() void; -extern fn isr23() void; -extern fn isr24() void; -extern fn isr25() void; -extern fn isr26() void; -extern fn isr27() void; -extern fn isr28() void; -extern fn isr29() void; -extern fn isr30() void; -extern fn isr31() void; -extern fn isr128() void; - /// /// The exception handler that each of the exceptions will call when a exception happens. /// @@ -270,46 +236,19 @@ pub fn registerIsr(isr_num: u16, handler: IsrHandler) IsrError!void { pub fn init() void { log.logInfo("Init isr\n"); - openIsr(0, isr0); - openIsr(1, isr1); - openIsr(2, isr2); - openIsr(3, isr3); - openIsr(4, isr4); - openIsr(5, isr5); - openIsr(6, isr6); - openIsr(7, isr7); - openIsr(8, isr8); - openIsr(9, isr9); - openIsr(10, isr10); - openIsr(11, isr11); - openIsr(12, isr12); - openIsr(13, isr13); - openIsr(14, isr14); - openIsr(15, isr15); - openIsr(16, isr16); - openIsr(17, isr17); - openIsr(18, isr18); - openIsr(19, isr19); - openIsr(20, isr20); - openIsr(21, isr21); - openIsr(22, isr22); - openIsr(23, isr23); - openIsr(24, isr24); - openIsr(25, isr25); - openIsr(26, isr26); - openIsr(27, isr27); - openIsr(28, isr28); - openIsr(29, isr29); - openIsr(30, isr30); - openIsr(31, isr31); - openIsr(syscalls.INTERRUPT, isr128); + comptime var i = 0; + inline while (i < 32) : (i += 1) { + openIsr(i, interrupts.getInterruptStub(i)); + } + + openIsr(syscalls.INTERRUPT, interrupts.getInterruptStub(syscalls.INTERRUPT)); log.logInfo("Done\n"); if (build_options.rt_test) runtimeTests(); } -extern fn testFunction0() void {} +nakedcc fn testFunction0() void {} fn testFunction1(ctx: *arch.InterruptContext) void {} fn testFunction2(ctx: *arch.InterruptContext) void {} fn testFunction3(ctx: *arch.InterruptContext) void {} diff --git a/src/kernel/arch/x86/isr_asm.s b/src/kernel/arch/x86/isr_asm.s deleted file mode 100644 index d2eb91a..0000000 --- a/src/kernel/arch/x86/isr_asm.s +++ /dev/null @@ -1,90 +0,0 @@ -.macro isrGenerator n - .align 4 - .type isr\n, @function - .global isr\n - isr\n: - cli - // Push 0 if there is no interrupt error code - .if (\n != 8 && !(\n >= 10 && \n <= 14) && \n != 17) - push $0 - .endif - push $\n - jmp isrCommonStub -.endmacro - -isrCommonStub: - // Push all the registers - pusha - - // Push the additional segment regiters - push %ds - push %es - push %fs - push %gs - - // Set the kernel data segment - mov $0x10, %ax - mov %ax, %ds - mov %ax, %es - mov %ax, %fs - mov %ax, %gs - - // Push the stack, this is where all the registers are sported, points the interuptContect - mov %esp, %eax - push %eax - - // Call the handler - call isrHandler - - // Pop stack pointer to point to the registers pushed - pop %eax - - // Pop segment regiters inorder - pop %gs - pop %fs - pop %es - pop %ds - - // Pop all general registers - popa - - // Pop the error code and interrupt number - add $0x8, %esp - - // Pops 5 things at once: cs, eip, eflags, ss, and esp - iret -.type isrCommonStub, @function - -isrGenerator 0 -isrGenerator 1 -isrGenerator 2 -isrGenerator 3 -isrGenerator 4 -isrGenerator 5 -isrGenerator 6 -isrGenerator 7 -isrGenerator 8 -isrGenerator 9 -isrGenerator 10 -isrGenerator 11 -isrGenerator 12 -isrGenerator 13 -isrGenerator 14 -isrGenerator 15 -isrGenerator 16 -isrGenerator 17 -isrGenerator 18 -isrGenerator 19 -isrGenerator 20 -isrGenerator 21 -isrGenerator 22 -isrGenerator 23 -isrGenerator 24 -isrGenerator 25 -isrGenerator 26 -isrGenerator 27 -isrGenerator 28 -isrGenerator 29 -isrGenerator 30 -isrGenerator 31 -isrGenerator 128 diff --git a/test/mock/kernel/mock_framework.zig b/test/mock/kernel/mock_framework.zig index 7a3fc84..2d133a9 100644 --- a/test/mock/kernel/mock_framework.zig +++ b/test/mock/kernel/mock_framework.zig @@ -22,6 +22,7 @@ const DataElementType = enum { PTR_CONST_IdtPtr, ERROR_IDTERROR_VOID, EFN_OVOID, + NFN_OVOID, FN_OVOID, FN_OUSIZE, FN_OU16, @@ -34,6 +35,7 @@ const DataElementType = enum { FN_IU16_IU8_OVOID, FN_IU16_IU16_OVOID, FN_IU8_IEFNOVOID_OERRORIDTERRORVOID, + FN_IU8_INFNOVOID_OERRORIDTERRORVOID, FN_IPTRCONSTGDTPTR_OVOID, FN_IPTRCONSTIDTPTR_OVOID, }; @@ -53,6 +55,7 @@ const DataElement = union(DataElementType) { PTR_CONST_IdtPtr: *const idt.IdtPtr, ERROR_IDTERROR_VOID: idt.IdtError!void, EFN_OVOID: extern fn () void, + NFN_OVOID: nakedcc fn () void, FN_OVOID: fn () void, FN_OUSIZE: fn () usize, FN_OU16: fn () u16, @@ -65,6 +68,7 @@ const DataElement = union(DataElementType) { FN_IU16_IU8_OVOID: fn (u16, u8) void, FN_IU16_IU16_OVOID: fn (u16, u16) void, FN_IU8_IEFNOVOID_OERRORIDTERRORVOID: fn (u8, extern fn () void) idt.IdtError!void, + FN_IU8_INFNOVOID_OERRORIDTERRORVOID: fn (u8, nakedcc fn () void) idt.IdtError!void, FN_IPTRCONSTGDTPTR_OVOID: fn (*const gdt.GdtPtr) void, FN_IPTRCONSTIDTPTR_OVOID: fn (*const idt.IdtPtr) void, }; @@ -151,6 +155,7 @@ fn Mock() type { *const idt.IdtPtr => DataElement{ .PTR_CONST_IdtPtr = arg }, idt.IdtError!void => DataElement{ .ERROR_IDTERROR_VOID = arg }, extern fn () void => DataElement{ .EFN_OVOID = arg }, + nakedcc fn () void => DataElement{ .NFN_OVOID = arg }, fn () void => DataElement{ .FN_OVOID = arg }, fn () usize => DataElement{ .FN_OUSIZE = arg }, fn () u16 => DataElement{ .FN_OU16 = arg }, @@ -165,6 +170,7 @@ fn Mock() type { fn (*const gdt.GdtPtr) void => DataElement{ .FN_IPTRCONSTGDTPTR_OVOID = arg }, fn (*const idt.IdtPtr) void => DataElement{ .FN_IPTRCONSTIDTPTR_OVOID = arg }, fn (u8, extern fn () void) idt.IdtError!void => DataElement{ .FN_IU8_IEFNOVOID_OERRORIDTERRORVOID = arg }, + fn (u8, nakedcc fn () void) idt.IdtError!void => DataElement{ .FN_IU8_INFNOVOID_OERRORIDTERRORVOID = arg }, else => @compileError("Type not supported: " ++ @typeName(@typeOf(arg))), }; } @@ -189,6 +195,7 @@ fn Mock() type { *const idt.IdtPtr => DataElement.PTR_CONST_IdtPtr, idt.IdtError!void => DataElement.ERROR_IDTERROR_VOID, extern fn () void => DataElementType.EFN_OVOID, + nakedcc fn () void => DataElementType.NFN_OVOID, fn () void => DataElementType.FN_OVOID, fn () u16 => DataElementType.FN_OU16, fn (u8) bool => DataElementType.FN_IU8_OBOOL, @@ -202,6 +209,7 @@ fn Mock() type { fn (*const gdt.GdtPtr) void => DataElementType.FN_IPTRCONSTGDTPTR_OVOID, fn (*const idt.IdtPtr) void => DataElementType.FN_IPTRCONSTIDTPTR_OVOID, fn (u8, extern fn () void) idt.IdtError!void => DataElementType.FN_IU8_IEFNOVOID_OERRORIDTERRORVOID, + fn (u8, nakedcc fn () void) idt.IdtError!void => DataElementType.FN_IU8_INFNOVOID_OERRORIDTERRORVOID, else => @compileError("Type not supported: " ++ @typeName(T)), }; } @@ -228,6 +236,7 @@ fn Mock() type { *const idt.IdtPtr => element.PTR_CONST_IdtPtr, idt.IdtError!void => element.ERROR_IDTERROR_VOID, extern fn () void => element.EFN_OVOID, + nakedcc fn () void => element.NFN_OVOID, fn () void => element.FN_OVOID, fn () u16 => element.FN_OU16, fn (u8) bool => element.FN_IU8_OBOOL, @@ -241,6 +250,7 @@ fn Mock() type { fn (*const gdt.GdtPtr) void => element.FN_IPTRCONSTGDTPTR_OVOID, fn (*const idt.IdtPtr) void => element.FN_IPTRCONSTIDTPTR_OVOID, fn (u8, extern fn () void) idt.IdtError!void => element.FN_IU8_IEFNOVOID_OERRORIDTERRORVOID, + fn (u8, nakedcc fn () void) idt.IdtError!void => element.FN_IU8_INFNOVOID_OERRORIDTERRORVOID, else => @compileError("Type not supported: " ++ @typeName(T)), }; }