diff --git a/build.zig b/build.zig index ff2650a..1707bb1 100644 --- a/build.zig +++ b/build.zig @@ -3,30 +3,19 @@ const builtin = @import("builtin"); const Builder = std.build.Builder; const LibExeObjStep = std.build.LibExeObjStep; const Step = std.build.Step; -const Target = std.build.Target; +const Target = std.Target; +const CrossTarget = std.zig.CrossTarget; const fs = std.fs; const Mode = builtin.Mode; pub fn build(b: *Builder) !void { - const target = Target{ - .Cross = Target.Cross{ - .arch = .i386, - .os = .freestanding, - .abi = .gnu, - .cpu_features = Target.CpuFeatures.initFromCpu(.i386, &builtin.Target.x86.cpu._i686), - }, + const target = CrossTarget{ + .cpu_arch = .i386, + .os_tag = .freestanding, + .cpu_model = .{ .explicit = &Target.x86.cpu._i686 }, }; - const test_target = Target{ - .Cross = Target.Cross{ - .arch = .i386, - .os = .linux, - .abi = .gnu, - .cpu_features = Target.CpuFeatures.initFromCpu(.i386, &builtin.Target.x86.cpu._i686), - }, - }; - - const target_str = switch (target.getArch()) { + const target_str = switch (target.getCpuArch()) { .i386 => "x86", else => unreachable, }; @@ -50,7 +39,7 @@ pub fn build(b: *Builder) !void { exec.addBuildOption(bool, "rt_test", rt_test); exec.setBuildMode(build_mode); exec.setLinkerScriptPath("link.ld"); - exec.setTheTarget(target); + exec.setTarget(target); const output_iso = try fs.path.join(b.allocator, &[_][]const u8{ b.exe_dir, "pluto.iso" }); const iso_dir_path = try fs.path.join(b.allocator, &[_][]const u8{ b.exe_dir, "iso" }); @@ -77,14 +66,9 @@ pub fn build(b: *Builder) !void { unit_tests.addBuildOption([]const u8, "mock_path", mock_path); unit_tests.addBuildOption([]const u8, "arch_mock_path", arch_mock_path); - const qemu_bin = switch (test_target.getArch()) { - .i386 => "qemu-i386", - else => unreachable, - }; + if (builtin.os.tag != .windows) unit_tests.enable_qemu = true; - // We need this as the build as the make() doesn't handle it properly - unit_tests.setExecCmd(&[_]?[]const u8{ qemu_bin, null }); - unit_tests.setTheTarget(test_target); + unit_tests.setTarget(.{ .cpu_arch = .i386 }); test_step.dependOn(&unit_tests.step); } @@ -92,7 +76,7 @@ pub fn build(b: *Builder) !void { const run_step = b.step("run", "Run with qemu"); const run_debug_step = b.step("debug-run", "Run with qemu and wait for a gdb connection"); - const qemu_bin = switch (target.getArch()) { + const qemu_bin = switch (target.getCpuArch()) { .i386 => "qemu-system-i386", else => unreachable, }; diff --git a/src/kernel/arch/x86/gdt.zig b/src/kernel/arch/x86/gdt.zig index 09a22d9..f615d46 100644 --- a/src/kernel/arch/x86/gdt.zig +++ b/src/kernel/arch/x86/gdt.zig @@ -425,6 +425,7 @@ pub fn setTssStack(esp0: u32) void { /// pub fn init() void { log.logInfo("Init gdt\n", .{}); + defer log.logInfo("Done gdt\n", .{}); // Initiate TSS gdt_entries[TSS_INDEX] = makeEntry(@ptrToInt(&tss), @sizeOf(TtsEntry) - 1, TSS_SEGMENT, NULL_FLAGS); @@ -437,8 +438,6 @@ pub fn init() void { // Load the TSS arch.ltr(TSS_OFFSET); - log.logInfo("Done\n", .{}); - if (build_options.rt_test) runtimeTests(); } diff --git a/src/kernel/arch/x86/idt.zig b/src/kernel/arch/x86/idt.zig index 64cbdb9..33c7b2a 100644 --- a/src/kernel/arch/x86/idt.zig +++ b/src/kernel/arch/x86/idt.zig @@ -180,11 +180,11 @@ pub fn openInterruptGate(index: u8, handler: InterruptHandler) IdtError!void { /// pub fn init() void { log.logInfo("Init idt\n", .{}); + defer log.logInfo("Done idt\n", .{}); idt_ptr.base = @ptrToInt(&idt_entries); arch.lidt(&idt_ptr); - log.logInfo("Done\n", .{}); if (build_options.rt_test) runtimeTests(); } diff --git a/src/kernel/arch/x86/irq.zig b/src/kernel/arch/x86/irq.zig index 9087df5..7ce9609 100644 --- a/src/kernel/arch/x86/irq.zig +++ b/src/kernel/arch/x86/irq.zig @@ -129,14 +129,13 @@ pub fn registerIrq(irq_num: u8, handler: IrqHandler) IrqError!void { /// pub fn init() void { log.logInfo("Init irq\n", .{}); + defer log.logInfo("Done irq\n", .{}); 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(); } diff --git a/src/kernel/arch/x86/isr.zig b/src/kernel/arch/x86/isr.zig index 4b5342d..b8fddd5 100644 --- a/src/kernel/arch/x86/isr.zig +++ b/src/kernel/arch/x86/isr.zig @@ -235,6 +235,7 @@ pub fn registerIsr(isr_num: u16, handler: IsrHandler) IsrError!void { /// pub fn init() void { log.logInfo("Init isr\n", .{}); + defer log.logInfo("Done isr\n", .{}); comptime var i = 0; inline while (i < 32) : (i += 1) { @@ -243,8 +244,6 @@ pub fn init() void { openIsr(syscalls.INTERRUPT, interrupts.getInterruptStub(syscalls.INTERRUPT)); - log.logInfo("Done\n", .{}); - if (build_options.rt_test) runtimeTests(); } diff --git a/src/kernel/arch/x86/paging.zig b/src/kernel/arch/x86/paging.zig index 5a5a114..d089600 100644 --- a/src/kernel/arch/x86/paging.zig +++ b/src/kernel/arch/x86/paging.zig @@ -293,6 +293,8 @@ fn pageFault(state: *arch.InterruptContext) void { /// pub fn init(mb_info: *multiboot.multiboot_info_t, mem_profile: *const MemProfile, allocator: *std.mem.Allocator) void { log.logInfo("Init paging\n", .{}); + defer log.logInfo("Done paging\n", .{}); + // Calculate start and end of mapping const v_start = std.mem.alignBackward(@ptrToInt(mem_profile.vaddr_start), PAGE_SIZE_4KB); const v_end = std.mem.alignForward(@ptrToInt(mem_profile.vaddr_end) + mem_profile.fixed_alloc_size, PAGE_SIZE_4KB); @@ -351,7 +353,6 @@ pub fn init(mb_info: *multiboot.multiboot_info_t, mem_profile: *const MemProfile isr.registerIsr(isr.PAGE_FAULT, if (options.rt_test) rt_pageFault else pageFault) catch |e| { panic(@errorReturnTrace(), "Failed to register page fault ISR: {}\n", .{e}); }; - log.logInfo("Done\n", .{}); if (options.rt_test) runtimeTests(v_end); } @@ -410,7 +411,7 @@ test "virtToTableEntryIdx" { } test "mapDirEntry" { - var allocator = std.heap.direct_allocator; + var allocator = std.heap.page_allocator; var dir: Directory = Directory{ .entries = [_]DirectoryEntry{0} ** ENTRIES_PER_DIRECTORY, .tables = [_]?*Table{null} ** ENTRIES_PER_DIRECTORY }; var phys: usize = 0 * PAGE_SIZE_4MB; const phys_end: usize = phys + PAGE_SIZE_4MB; @@ -425,7 +426,7 @@ test "mapDirEntry" { } test "mapDirEntry returns errors correctly" { - var allocator = std.heap.direct_allocator; + var allocator = std.heap.page_allocator; var dir = Directory{ .entries = [_]DirectoryEntry{0} ** ENTRIES_PER_DIRECTORY, .tables = undefined }; testing.expectError(PagingError.UnalignedVirtAddresses, mapDirEntry(&dir, 1, PAGE_SIZE_4KB + 1, 0, PAGE_SIZE_4KB, allocator)); testing.expectError(PagingError.UnalignedPhysAddresses, mapDirEntry(&dir, 0, PAGE_SIZE_4KB, 1, PAGE_SIZE_4KB + 1, allocator)); @@ -435,7 +436,7 @@ test "mapDirEntry returns errors correctly" { } test "mapDir" { - var allocator = std.heap.direct_allocator; + var allocator = std.heap.page_allocator; var dir = Directory{ .entries = [_]DirectoryEntry{0} ** ENTRIES_PER_DIRECTORY, .tables = [_]?*Table{null} ** ENTRIES_PER_DIRECTORY }; const phys_start: usize = PAGE_SIZE_4MB * 2; const virt_start: usize = PAGE_SIZE_4MB * 4; diff --git a/src/kernel/arch/x86/pic.zig b/src/kernel/arch/x86/pic.zig index aa99e64..a122658 100644 --- a/src/kernel/arch/x86/pic.zig +++ b/src/kernel/arch/x86/pic.zig @@ -433,6 +433,7 @@ pub fn clearMask(irq_num: u8) void { /// pub fn init() void { log.logInfo("Init pic\n", .{}); + defer log.logInfo("Done pic\n", .{}); // Initiate sendCommandMaster(ICW1_INITIALISATION | ICW1_EXPECT_ICW4); @@ -467,8 +468,6 @@ pub fn init() void { // Clear the IRQ for the slave clearMask(IRQ_CASCADE_FOR_SLAVE); - log.logInfo("Done\n", .{}); - if (build_options.rt_test) runtimeTests(); } diff --git a/src/kernel/arch/x86/pit.zig b/src/kernel/arch/x86/pit.zig index ebd31f7..ff0a617 100644 --- a/src/kernel/arch/x86/pit.zig +++ b/src/kernel/arch/x86/pit.zig @@ -371,6 +371,8 @@ pub fn getFrequency() u32 { /// pub fn init() void { log.logInfo("Init pit\n", .{}); + defer log.logInfo("Done pit\n", .{}); + // Set up counter 0 at 10000hz in a square wave mode counting in binary const freq: u32 = 10000; setupCounter(CounterSelect.Counter0, freq, OCW_MODE_SQUARE_WAVE_GENERATOR | OCW_BINARY_COUNT_BINARY) catch |e| { @@ -389,8 +391,6 @@ pub fn init() void { }, }; - log.logInfo("Done\n", .{}); - if (build_options.rt_test) runtimeTests(); } diff --git a/src/kernel/arch/x86/rtc.zig b/src/kernel/arch/x86/rtc.zig index 33c04e7..c61e1fe 100644 --- a/src/kernel/arch/x86/rtc.zig +++ b/src/kernel/arch/x86/rtc.zig @@ -252,6 +252,7 @@ fn enableInterrupts() void { /// pub fn init() void { log.logInfo("Init rtc\n", .{}); + defer log.logInfo("Done rtc\n", .{}); // Register the interrupt handler irq.registerIrq(pic.IRQ_REAL_TIME_CLOCK, rtcHandler) catch |err| switch (err) { @@ -276,16 +277,12 @@ pub fn init() void { // Enable RTC interrupts enableInterrupts(); - // Read status register C to clear any interrupts that may have happened during set up - //const reg_c = cmos.readStatusRegister(cmos.StatusRegister.C, false); - // Can now enable interrupts arch.enableInterrupts(); + // Read status register C to clear any interrupts that may have happened during set up const reg_c = cmos.readStatusRegister(cmos.StatusRegister.C, false); - log.logInfo("Done\n", .{}); - if (build_options.rt_test) runtimeTests(); } diff --git a/src/kernel/arch/x86/syscalls.zig b/src/kernel/arch/x86/syscalls.zig index 6d503d5..28caf31 100644 --- a/src/kernel/arch/x86/syscalls.zig +++ b/src/kernel/arch/x86/syscalls.zig @@ -238,8 +238,9 @@ inline fn syscallArg(ctx: *arch.InterruptContext, comptime arg_idx: u32) u32 { /// pub fn init() void { log.logInfo("Init syscalls\n", .{}); + defer log.logInfo("Done syscalls\n", .{}); + isr.registerIsr(INTERRUPT, handle) catch unreachable; - log.logInfo("Done\n", .{}); if (options.rt_test) runtimeTests(); } diff --git a/src/kernel/bitmap.zig b/src/kernel/bitmap.zig index 480637d..92d1fef 100644 --- a/src/kernel/bitmap.zig +++ b/src/kernel/bitmap.zig @@ -157,7 +157,7 @@ pub fn Bitmap(comptime BitmapType: type) type { } test "setEntry" { - var bmp = try Bitmap(u32).init(31, std.heap.direct_allocator); + var bmp = try Bitmap(u32).init(31, std.heap.page_allocator); testing.expectEqual(@as(u32, 31), bmp.num_free_entries); try bmp.setEntry(0); @@ -178,7 +178,7 @@ test "setEntry" { } test "clearEntry" { - var bmp = try Bitmap(u32).init(32, std.heap.direct_allocator); + var bmp = try Bitmap(u32).init(32, std.heap.page_allocator); testing.expectEqual(@as(u32, 32), bmp.num_free_entries); try bmp.setEntry(0); @@ -204,7 +204,7 @@ test "clearEntry" { } test "setFirstFree multiple bitmaps" { - var bmp = try Bitmap(u8).init(9, std.heap.direct_allocator); + var bmp = try Bitmap(u8).init(9, std.heap.page_allocator); // Allocate the first entry testing.expectEqual(bmp.setFirstFree() orelse unreachable, 0); @@ -239,7 +239,7 @@ test "setFirstFree multiple bitmaps" { testing.expectEqual(bmp.bitmaps[1], 1); } test "setFirstFree" { - var bmp = try Bitmap(u32).init(32, std.heap.direct_allocator); + var bmp = try Bitmap(u32).init(32, std.heap.page_allocator); // Allocate the first entry testing.expectEqual(bmp.setFirstFree() orelse unreachable, 0); @@ -260,7 +260,7 @@ test "setFirstFree" { } test "isSet" { - var bmp = try Bitmap(u32).init(32, std.heap.direct_allocator); + var bmp = try Bitmap(u32).init(32, std.heap.page_allocator); bmp.bitmaps[0] = 1; // Make sure that only the set entry is considered set @@ -292,7 +292,7 @@ test "isSet" { } test "indexToBit" { - var bmp = try Bitmap(u8).init(10, std.heap.direct_allocator); + var bmp = try Bitmap(u8).init(10, std.heap.page_allocator); testing.expectEqual(bmp.indexToBit(0), 1); testing.expectEqual(bmp.indexToBit(1), 2); testing.expectEqual(bmp.indexToBit(2), 4); diff --git a/src/kernel/kmain.zig b/src/kernel/kmain.zig index fc88663..568f7de 100644 --- a/src/kernel/kmain.zig +++ b/src/kernel/kmain.zig @@ -39,8 +39,9 @@ export fn kmain(mb_info: *multiboot.multiboot_info_t, mb_magic: u32) void { serial.init(serial.DEFAULT_BAUDRATE, serial.Port.COM1) catch |e| { panic_root.panic(@errorReturnTrace(), "Failed to initialise serial: {}", .{e}); }; - if (build_options.rt_test) - log.runtimeTests(); + + if (build_options.rt_test) log.runtimeTests(); + const mem_profile = mem.init(mb_info); var buffer = mem_profile.vaddr_end[0..mem_profile.fixed_alloc_size]; var fixed_allocator = std.heap.FixedBufferAllocator.init(buffer); @@ -56,6 +57,7 @@ export fn kmain(mb_info: *multiboot.multiboot_info_t, mb_magic: u32) void { tty.init(); log.logInfo("Init done\n", .{}); + tty.print("Hello Pluto from kernel :)\n", .{}); // The panic runtime tests must run last as they never return if (options.rt_test) panic_root.runtimeTests(); diff --git a/src/kernel/log.zig b/src/kernel/log.zig index b46a66f..450d7c1 100644 --- a/src/kernel/log.zig +++ b/src/kernel/log.zig @@ -1,5 +1,12 @@ const serial = @import("serial.zig"); -const fmt = @import("std").fmt; +const std = @import("std"); +const fmt = std.fmt; + +/// The errors that can occur when logging +const LoggingError = error{}; + +/// The OutStream for the format function +const OutStream = std.io.OutStream(void, LoggingError, logCallback); pub const Level = enum { INFO, @@ -8,8 +15,9 @@ pub const Level = enum { ERROR, }; -fn logCallback(context: void, str: []const u8) anyerror!void { +fn logCallback(context: void, str: []const u8) LoggingError!usize { serial.writeBytes(str, serial.Port.COM1); + return str.len; } /// @@ -21,7 +29,7 @@ fn logCallback(context: void, str: []const u8) anyerror!void { /// IN args: var - A struct of the parameters for the format string. /// pub fn log(comptime level: Level, comptime format: []const u8, args: var) void { - fmt.format({}, anyerror, logCallback, "[" ++ @tagName(level) ++ "] " ++ format, args) catch unreachable; + fmt.format(OutStream{ .context = {} }, "[" ++ @tagName(level) ++ "] " ++ format, args) catch unreachable; } /// diff --git a/src/kernel/mem.zig b/src/kernel/mem.zig index 0734326..b3594d6 100644 --- a/src/kernel/mem.zig +++ b/src/kernel/mem.zig @@ -53,36 +53,6 @@ const FIXED_ALLOC_SIZE: usize = 1024 * 1024; /// release-safe. This is a workaround until that is fixed. var ADDR_OFFSET: usize = undefined; -/// -/// Initialise the system's memory profile based on linker symbols and the multiboot info struct. -/// -/// Arguments: -/// IN mb_info: *multiboot.multiboot_info_t - The multiboot info passed by the bootloader. -/// -/// Return: MemProfile -/// The memory profile constructed from the exported linker symbols and the relevant multiboot info. -/// -pub fn init(mb_info: *multiboot.multiboot_info_t) MemProfile { - log.logInfo("Init mem\n", .{}); - defer log.logInfo("Done\n", .{}); - const mods_count = mb_info.mods_count; - ADDR_OFFSET = @ptrToInt(&KERNEL_ADDR_OFFSET); - const mmap_addr = mb_info.mmap_addr; - const num_mmap_entries = mb_info.mmap_length / @sizeOf(multiboot.multiboot_memory_map_t); - const mem_profile = MemProfile{ - .vaddr_end = @ptrCast([*]u8, &KERNEL_VADDR_END), - .vaddr_start = @ptrCast([*]u8, &KERNEL_VADDR_START), - .physaddr_end = @ptrCast([*]u8, &KERNEL_PHYSADDR_END), - .physaddr_start = @ptrCast([*]u8, &KERNEL_PHYSADDR_START), - // Total memory available including the initial 1MiB that grub doesn't include - .mem_kb = mb_info.mem_upper + mb_info.mem_lower + 1024, - .fixed_alloc_size = FIXED_ALLOC_SIZE, - .boot_modules = @intToPtr([*]multiboot.multiboot_mod_list, physToVirt(mb_info.mods_addr))[0..mods_count], - .mem_map = @intToPtr([*]multiboot.multiboot_memory_map_t, mmap_addr)[0..num_mmap_entries], - }; - return mem_profile; -} - /// /// Convert a virtual address to its physical counterpart by subtracting the kernel virtual offset from the virtual address. /// @@ -94,7 +64,7 @@ pub fn init(mb_info: *multiboot.multiboot_info_t) MemProfile { /// pub inline fn virtToPhys(virt: var) @TypeOf(virt) { const T = @TypeOf(virt); - return switch (@typeId(T)) { + return switch (@typeInfo(T)) { .Pointer => @intToPtr(T, @ptrToInt(virt) - ADDR_OFFSET), .Int => virt - ADDR_OFFSET, else => @compileError("Only pointers and integers are supported"), @@ -112,13 +82,43 @@ pub inline fn virtToPhys(virt: var) @TypeOf(virt) { /// pub inline fn physToVirt(phys: var) @TypeOf(phys) { const T = @TypeOf(phys); - return switch (@typeId(T)) { + return switch (@typeInfo(T)) { .Pointer => @intToPtr(T, @ptrToInt(phys) + ADDR_OFFSET), .Int => phys + ADDR_OFFSET, else => @compileError("Only pointers and integers are supported"), }; } +/// +/// Initialise the system's memory profile based on linker symbols and the multiboot info struct. +/// +/// Arguments: +/// IN mb_info: *multiboot.multiboot_info_t - The multiboot info passed by the bootloader. +/// +/// Return: MemProfile +/// The memory profile constructed from the exported linker symbols and the relevant multiboot info. +/// +pub fn init(mb_info: *multiboot.multiboot_info_t) MemProfile { + log.logInfo("Init mem\n", .{}); + defer log.logInfo("Done mem\n", .{}); + + const mods_count = mb_info.mods_count; + ADDR_OFFSET = @ptrToInt(&KERNEL_ADDR_OFFSET); + const mmap_addr = mb_info.mmap_addr; + const num_mmap_entries = mb_info.mmap_length / @sizeOf(multiboot.multiboot_memory_map_t); + return .{ + .vaddr_end = @ptrCast([*]u8, &KERNEL_VADDR_END), + .vaddr_start = @ptrCast([*]u8, &KERNEL_VADDR_START), + .physaddr_end = @ptrCast([*]u8, &KERNEL_PHYSADDR_END), + .physaddr_start = @ptrCast([*]u8, &KERNEL_PHYSADDR_START), + // Total memory available including the initial 1MiB that grub doesn't include + .mem_kb = mb_info.mem_upper + mb_info.mem_lower + 1024, + .fixed_alloc_size = FIXED_ALLOC_SIZE, + .boot_modules = @intToPtr([*]multiboot.multiboot_mod_list, physToVirt(mb_info.mods_addr))[0..mods_count], + .mem_map = @intToPtr([*]multiboot.multiboot_memory_map_t, mmap_addr)[0..num_mmap_entries], + }; +} + test "physToVirt" { ADDR_OFFSET = 0xC0000000; const offset: usize = ADDR_OFFSET; diff --git a/src/kernel/panic.zig b/src/kernel/panic.zig index 58ba85d..37a6932 100644 --- a/src/kernel/panic.zig +++ b/src/kernel/panic.zig @@ -77,11 +77,11 @@ const SymbolMap = struct { /// The function name associated with that program address, or null if one wasn't found. /// pub fn search(self: *const SymbolMap, addr: usize) ?[]const u8 { - if (self.symbols.len == 0) + if (self.symbols.items.len == 0) return null; // Find the first element whose address is greater than addr var previous_name: ?[]const u8 = null; - for (self.symbols.toSliceConst()) |entry| { + for (self.symbols.items) |entry| { if (entry.addr > addr) return previous_name; previous_name = entry.func_name; @@ -116,7 +116,7 @@ pub fn panic(trace: ?*builtin.StackTrace, comptime format: []const u8, args: var } else { const first_ret_addr = @returnAddress(); var last_addr: u64 = 0; - var it = std.debug.StackIterator.init(first_ret_addr); + var it = std.debug.StackIterator.init(first_ret_addr, null); while (it.next()) |ret_addr| { if (ret_addr != last_addr) logTraceAddress(ret_addr); last_addr = ret_addr; @@ -278,7 +278,8 @@ fn parseMapEntry(start: *[*]const u8, end: *const u8) !MapEntry { /// pub fn init(mem_profile: *const mem.MemProfile, allocator: *std.mem.Allocator) !void { log.logInfo("Init panic\n", .{}); - defer log.logInfo("Done\n", .{}); + defer log.logInfo("Done panic\n", .{}); + // Exit if we haven't loaded all debug modules if (mem_profile.boot_modules.len < 1) return; @@ -288,7 +289,7 @@ pub fn init(mem_profile: *const mem.MemProfile, allocator: *std.mem.Allocator) ! const mod_start = mem.physToVirt(module.mod_start); const mod_end = mem.physToVirt(module.mod_end) - 1; const mod_str_ptr = mem.physToVirt(@intToPtr([*:0]u8, module.cmdline)); - if (std.mem.eql(u8, std.mem.toSlice(u8, mod_str_ptr), "kernel.map")) { + if (std.mem.eql(u8, std.mem.span(mod_str_ptr), "kernel.map")) { kmap_start = mod_start; kmap_end = mod_end; break; @@ -422,7 +423,7 @@ test "parseMapEntry fails without a name" { } test "SymbolMap" { - var allocator = std.heap.direct_allocator; + var allocator = std.heap.page_allocator; var map = SymbolMap.init(allocator); try map.add("abc"[0..], 123); try map.addEntry(MapEntry{ .func_name = "def"[0..], .addr = 456 }); diff --git a/src/kernel/pmm.zig b/src/kernel/pmm.zig index 02a74dd..9fbaf32 100644 --- a/src/kernel/pmm.zig +++ b/src/kernel/pmm.zig @@ -91,6 +91,8 @@ pub fn free(addr: usize) (PmmBitmap.BitmapError || PmmError)!void { /// pub fn init(mem: *const MemProfile, allocator: *std.mem.Allocator) void { log.logInfo("Init pmm\n", .{}); + defer log.logInfo("Done pmm\n", .{}); + bitmap = PmmBitmap.init(mem.mem_kb * 1024 / BLOCK_SIZE, allocator) catch @panic("Bitmap allocation failed"); // Occupy the regions of memory that the memory map describes as reserved @@ -118,10 +120,8 @@ pub fn init(mem: *const MemProfile, allocator: *std.mem.Allocator) void { else => panic(@errorReturnTrace(), "Failed setting kernel code address 0x{x} as occupied: {}", .{ addr, e }), }; } - log.logInfo("Done\n", .{}); - if (build_options.rt_test) { - runtimeTests(mem); - } + + if (build_options.rt_test) runtimeTests(mem); } /// @@ -154,7 +154,7 @@ fn runtimeTests(mem: *const MemProfile) void { } test "alloc" { - bitmap = try Bitmap(u32).init(32, std.heap.direct_allocator); + bitmap = try Bitmap(u32).init(32, std.heap.page_allocator); comptime var addr = 0; comptime var i = 0; // Allocate all entries, making sure they succeed and return the correct addresses @@ -171,7 +171,7 @@ test "alloc" { } test "free" { - bitmap = try Bitmap(u32).init(32, std.heap.direct_allocator); + bitmap = try Bitmap(u32).init(32, std.heap.page_allocator); comptime var i = 0; // Allocate and free all entries inline while (i < 32) : (i += 1) { @@ -186,7 +186,7 @@ test "free" { test "setAddr and isSet" { const num_entries: u32 = 32; - bitmap = try Bitmap(u32).init(num_entries, std.heap.direct_allocator); + bitmap = try Bitmap(u32).init(num_entries, std.heap.page_allocator); var addr: u32 = 0; var i: u32 = 0; while (i < num_entries) : ({ diff --git a/src/kernel/serial.zig b/src/kernel/serial.zig index bc89f1c..7e0d08c 100644 --- a/src/kernel/serial.zig +++ b/src/kernel/serial.zig @@ -1,7 +1,7 @@ const arch = @import("arch.zig").internals; const panic = @import("panic.zig").panic; const testing = @import("std").testing; -const options = @import("build_options"); +const build_options = @import("build_options"); /// The I/O port numbers associated with each serial port pub const Port = enum(u16) { @@ -147,12 +147,13 @@ pub fn init(baud: u32, port: Port) SerialError!void { // Send the divisor's msb arch.outb(port_int + 1, @truncate(u8, divisor >> 8)); // Send the properties to use - arch.outb(port_int + LCR, lcrValue(CHAR_LEN, SINGLE_STOP_BIT, PARITY_BIT, 0) catch |e| panic(@errorReturnTrace(), "Failed to setup serial properties: {}", .{e})); + arch.outb(port_int + LCR, lcrValue(CHAR_LEN, SINGLE_STOP_BIT, PARITY_BIT, 0) catch |e| { + panic(@errorReturnTrace(), "Failed to setup serial properties: {}", .{e}); + }); // Stop initialisation arch.outb(port_int + 1, 0); - if (options.rt_test) - runtimeTests(); + if (build_options.rt_test) runtimeTests(); } test "lcrValue computes the correct value" { diff --git a/src/kernel/tty.zig b/src/kernel/tty.zig index afd4ae2..2dc6724 100644 --- a/src/kernel/tty.zig +++ b/src/kernel/tty.zig @@ -11,6 +11,9 @@ const vga = if (is_test) @import(mock_path ++ "vga_mock.zig") else @import("vga. const log = if (is_test) @import(mock_path ++ "log_mock.zig") else @import("log.zig"); const panic = if (is_test) @import(mock_path ++ "panic_mock.zig").panic else @import("panic.zig").panic; +/// The OutStream for the format function +const OutStream = std.io.OutStream(void, TtyError, printCallback); + /// The error set for if there is an error whiles printing. const TtyError = error{ /// If the printing tries to print outside the video buffer. @@ -427,8 +430,9 @@ fn printLogo() void { /// Errors: /// TtyError.OutOfBounds - If trying to print beyond the video buffer. /// -fn printCallback(ctx: void, str: []const u8) TtyError!void { +fn printCallback(ctx: void, str: []const u8) TtyError!usize { try writeString(str); + return str.len; } /// @@ -441,7 +445,7 @@ fn printCallback(ctx: void, str: []const u8) TtyError!void { /// pub fn print(comptime format: []const u8, args: var) void { // Printing can't error because of the scrolling, if it does, we have a big problem - fmt.format({}, TtyError, printCallback, format, args) catch |e| { + fmt.format(OutStream{ .context = {} }, format, args) catch |e| { log.logError("TTY: Error printing. Error: {}\n", .{e}); }; } @@ -570,6 +574,7 @@ pub fn getVideoBufferAddress() usize { /// pub fn init() void { log.logInfo("Init tty\n", .{}); + defer log.logInfo("Done tty\n", .{}); // Video buffer in higher half if (is_test) { @@ -631,8 +636,6 @@ pub fn init() void { displayPageNumber(); updateCursor(); - log.logInfo("Done\n", .{}); - if (build_options.rt_test) runtimeTests(); } diff --git a/src/kernel/vga.zig b/src/kernel/vga.zig index 4c31ae8..c0fed7d 100644 --- a/src/kernel/vga.zig +++ b/src/kernel/vga.zig @@ -145,7 +145,6 @@ inline fn sendData(data: u8) void { inline fn getData() u8 { return arch.inb(PORT_DATA); } - /// /// Set the VGA register port to write to and sending data to that VGA register port. /// @@ -287,6 +286,7 @@ pub fn setCursorShape(shape: CursorShape) void { /// pub fn init() void { log.logInfo("Init vga\n", .{}); + defer log.logInfo("Done vga\n", .{}); // Set the maximum scan line to 0x0F sendPortData(REG_MAXIMUM_SCAN_LINE, CURSOR_SCANLINE_END); @@ -294,8 +294,6 @@ pub fn init() void { // Set by default the underline cursor setCursorShape(CursorShape.UNDERLINE); - log.logInfo("Done\n", .{}); - if (build_options.rt_test) runtimeTests(); } diff --git a/test/kernel/arch/x86/rt-test.py b/test/kernel/arch/x86/rt-test.py index 237eda6..f972d6c 100644 --- a/test/kernel/arch/x86/rt-test.py +++ b/test/kernel/arch/x86/rt-test.py @@ -1,23 +1,39 @@ def get_test_cases(TestCase): return [ - TestCase("GDT init", [r"Init gdt", r"Done"]), + TestCase("GDT init", [r"Init gdt"]), TestCase("GDT tests", [r"GDT: Tested loading GDT"]), - TestCase("IDT init", [r"Init idt", r"Done"]), + TestCase("GDT done", [r"Done gdt"]), + + TestCase("IDT init", [r"Init idt"]), TestCase("IDT tests", [r"IDT: Tested loading IDT"]), - TestCase("PIC init", [r"Init pic", r"Done"]), + TestCase("IDT done", [r"Done idt"]), + + TestCase("PIC init", [r"Init pic"]), TestCase("PIC tests", [r"PIC: Tested masking"]), - TestCase("ISR init", [r"Init isr", r"Done"]), + TestCase("PIC done", [r"Done pic"]), + + TestCase("ISR init", [r"Init isr"]), TestCase("ISR tests", [r"ISR: Tested registered handlers", r"ISR: Tested opened IDT entries"]), - TestCase("IRQ init", [r"Init irq", r"Done"]), + TestCase("ISR done", [r"Done isr"]), + + TestCase("IRQ init", [r"Init irq"]), TestCase("IRQ tests", [r"IRQ: Tested registered handlers", r"IRQ: Tested opened IDT entries"]), - TestCase("Paging init", [r"Init paging", r"Done"]), + TestCase("IRQ done", [r"Done irq"]), + + TestCase("Paging init", [r"Init paging"]), TestCase("Paging tests", [r"Paging: Tested accessing unmapped memory", r"Paging: Tested accessing mapped memory"]), + TestCase("Paging done", [r"Done paging"]), + TestCase("PIT init", [r"Init pit"]), TestCase("PIT init", [r".+"], r"\[DEBUG\] "), - TestCase("PIT init", [r"Done"]), TestCase("PIT tests", [r"PIT: Tested init", r"PIT: Tested wait ticks", r"PIT: Tested wait ticks 2"]), - TestCase("RTC init", [r"Init rtc", r"Done"]), + TestCase("PIT done", [r"Done pit"]), + + TestCase("RTC init", [r"Init rtc"]), TestCase("RTC tests", [r"RTC: Tested init", r"RTC: Tested interrupts"]), - TestCase("Syscalls init", [r"Init syscalls", r"Done"]), - TestCase("Syscall tests", [r"Syscalls: Tested no args", r"Syscalls: Tested 1 arg", r"Syscalls: Tested 2 args", r"Syscalls: Tested 3 args", r"Syscalls: Tested 4 args", r"Syscalls: Tested 5 args"]) + TestCase("RTC done", [r"Done rtc"]), + + TestCase("Syscalls init", [r"Init syscalls"]), + TestCase("Syscalls tests", [r"Syscalls: Tested no args", r"Syscalls: Tested 1 arg", r"Syscalls: Tested 2 args", r"Syscalls: Tested 3 args", r"Syscalls: Tested 4 args", r"Syscalls: Tested 5 args"]), + TestCase("Syscalls done", [r"Done syscalls"]), ] diff --git a/test/rt-test.py b/test/rt-test.py index 49d7a54..5e660b8 100644 --- a/test/rt-test.py +++ b/test/rt-test.py @@ -31,26 +31,40 @@ def test_pass(case, exp, expected_idx, found): def get_pre_archinit_cases(): return [ TestCase("Serial tests", [r"c", r"123"], ""), - TestCase("Log info tests", [r"Test INFO level", r"Test INFO level with args a, 1", r"Test INFO function", r"Test INFO function with args a, 1"], "\[INFO\] "), - TestCase("Log debug tests", [r"Test DEBUG level", r"Test DEBUG level with args a, 1", r"Test DEBUG function", r"Test DEBUG function with args a, 1"], "\[DEBUG\] "), - TestCase("Log warning tests", [r"Test WARNING level", r"Test WARNING level with args a, 1", r"Test WARNING function", r"Test WARNING function with args a, 1"], "\[WARNING\] "), - TestCase("Log error tests", [r"Test ERROR level", r"Test ERROR level with args a, 1", r"Test ERROR function", r"Test ERROR function with args a, 1"], "\[ERROR\] "), - TestCase("Mem init", [r"Init mem", r"Done"]), - TestCase("PMM init", [r"Init pmm", r"Done"]), + + TestCase("Log info tests", [r"Test INFO level", r"Test INFO level with args a, 1", r"Test INFO function", r"Test INFO function with args a, 1"], r"\[INFO\] "), + TestCase("Log debug tests", [r"Test DEBUG level", r"Test DEBUG level with args a, 1", r"Test DEBUG function", r"Test DEBUG function with args a, 1"], r"\[DEBUG\] "), + TestCase("Log warning tests", [r"Test WARNING level", r"Test WARNING level with args a, 1", r"Test WARNING function", r"Test WARNING function with args a, 1"], r"\[WARNING\] "), + TestCase("Log error tests", [r"Test ERROR level", r"Test ERROR level with args a, 1", r"Test ERROR function", r"Test ERROR function with args a, 1"], r"\[ERROR\] "), + + TestCase("Mem init", [r"Init mem"]), + TestCase("Mem done", [r"Done mem"]), + + TestCase("PMM init", [r"Init pmm"]), TestCase("PMM tests", [r"PMM: Tested allocation"]), + TestCase("PMM done", [r"Done pmm"]), + TestCase("Arch init starts", [r"Init arch \w+"]) ] def get_post_archinit_cases(): return [ TestCase("Arch init finishes", [r"Arch init done"]), - TestCase("Panic init", [r"Init panic", r"Done"]), - TestCase("VGA init", [r"Init vga", r"Done"]), + + TestCase("Panic init", [r"Init panic"]), + TestCase("Panic done", [r"Done panic"]), + + TestCase("VGA init", [r"Init vga"]), TestCase("VGA tests", [r"VGA: Tested max scan line", r"VGA: Tested cursor shape", r"VGA: Tested updating cursor"]), - TestCase("TTY init", [r"Init tty", r"Done"]), + TestCase("VGA done", [r"Done vga"]), + + TestCase("TTY init", [r"Init tty"]), TestCase("TTY tests", [r"TTY: Tested globals", r"TTY: Tested printing"]), + TestCase("TTY done", [r"Done tty"]), + TestCase("Init finishes", [r"Init done"]), - TestCase("Panic tests", [r"Kernel panic: integer overflow", r"c[a-z\d]+: panic", r"c[a-z\d]+: panic.runtimeTests", r"c[a-z\d]+: kmain", r"c[a-z\d]+: start_higher_half"], "\[ERROR\] ") + + TestCase("Panic tests", [r"Kernel panic: integer overflow", r"c[a-z\d]+: panic", r"c[a-z\d]+: panic.runtimeTests", r"c[a-z\d]+: kmain", r"c[a-z\d]+: start_higher_half"], r"\[ERROR\] ") ] def read_messages(proc):