Updating to zig master

Added cpu model


Moved logging to defer done log

Moved mem.init to bottom

Updated again to new zig master
This commit is contained in:
DrDeano 2020-04-12 22:26:34 +01:00
parent d17381c267
commit 1f97a5c6c8
No known key found for this signature in database
GPG key ID: 96188600582B9ED7
21 changed files with 157 additions and 135 deletions

View file

@ -3,30 +3,19 @@ const builtin = @import("builtin");
const Builder = std.build.Builder; const Builder = std.build.Builder;
const LibExeObjStep = std.build.LibExeObjStep; const LibExeObjStep = std.build.LibExeObjStep;
const Step = std.build.Step; const Step = std.build.Step;
const Target = std.build.Target; const Target = std.Target;
const CrossTarget = std.zig.CrossTarget;
const fs = std.fs; const fs = std.fs;
const Mode = builtin.Mode; const Mode = builtin.Mode;
pub fn build(b: *Builder) !void { pub fn build(b: *Builder) !void {
const target = Target{ const target = CrossTarget{
.Cross = Target.Cross{ .cpu_arch = .i386,
.arch = .i386, .os_tag = .freestanding,
.os = .freestanding, .cpu_model = .{ .explicit = &Target.x86.cpu._i686 },
.abi = .gnu,
.cpu_features = Target.CpuFeatures.initFromCpu(.i386, &builtin.Target.x86.cpu._i686),
},
}; };
const test_target = Target{ const target_str = switch (target.getCpuArch()) {
.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()) {
.i386 => "x86", .i386 => "x86",
else => unreachable, else => unreachable,
}; };
@ -50,7 +39,7 @@ pub fn build(b: *Builder) !void {
exec.addBuildOption(bool, "rt_test", rt_test); exec.addBuildOption(bool, "rt_test", rt_test);
exec.setBuildMode(build_mode); exec.setBuildMode(build_mode);
exec.setLinkerScriptPath("link.ld"); 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 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" }); 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, "mock_path", mock_path);
unit_tests.addBuildOption([]const u8, "arch_mock_path", arch_mock_path); unit_tests.addBuildOption([]const u8, "arch_mock_path", arch_mock_path);
const qemu_bin = switch (test_target.getArch()) { if (builtin.os.tag != .windows) unit_tests.enable_qemu = true;
.i386 => "qemu-i386",
else => unreachable,
};
// We need this as the build as the make() doesn't handle it properly unit_tests.setTarget(.{ .cpu_arch = .i386 });
unit_tests.setExecCmd(&[_]?[]const u8{ qemu_bin, null });
unit_tests.setTheTarget(test_target);
test_step.dependOn(&unit_tests.step); 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_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 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", .i386 => "qemu-system-i386",
else => unreachable, else => unreachable,
}; };

View file

@ -425,6 +425,7 @@ pub fn setTssStack(esp0: u32) void {
/// ///
pub fn init() void { pub fn init() void {
log.logInfo("Init gdt\n", .{}); log.logInfo("Init gdt\n", .{});
defer log.logInfo("Done gdt\n", .{});
// Initiate TSS // Initiate TSS
gdt_entries[TSS_INDEX] = makeEntry(@ptrToInt(&tss), @sizeOf(TtsEntry) - 1, TSS_SEGMENT, NULL_FLAGS); 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 // Load the TSS
arch.ltr(TSS_OFFSET); arch.ltr(TSS_OFFSET);
log.logInfo("Done\n", .{});
if (build_options.rt_test) runtimeTests(); if (build_options.rt_test) runtimeTests();
} }

View file

@ -180,11 +180,11 @@ pub fn openInterruptGate(index: u8, handler: InterruptHandler) IdtError!void {
/// ///
pub fn init() void { pub fn init() void {
log.logInfo("Init idt\n", .{}); log.logInfo("Init idt\n", .{});
defer log.logInfo("Done idt\n", .{});
idt_ptr.base = @ptrToInt(&idt_entries); idt_ptr.base = @ptrToInt(&idt_entries);
arch.lidt(&idt_ptr); arch.lidt(&idt_ptr);
log.logInfo("Done\n", .{});
if (build_options.rt_test) runtimeTests(); if (build_options.rt_test) runtimeTests();
} }

View file

@ -129,14 +129,13 @@ pub fn registerIrq(irq_num: u8, handler: IrqHandler) IrqError!void {
/// ///
pub fn init() void { pub fn init() void {
log.logInfo("Init irq\n", .{}); log.logInfo("Init irq\n", .{});
defer log.logInfo("Done irq\n", .{});
comptime var i = IRQ_OFFSET; comptime var i = IRQ_OFFSET;
inline while (i < IRQ_OFFSET + 16) : (i += 1) { inline while (i < IRQ_OFFSET + 16) : (i += 1) {
openIrq(i, interrupts.getInterruptStub(i)); openIrq(i, interrupts.getInterruptStub(i));
} }
log.logInfo("Done\n", .{});
if (build_options.rt_test) runtimeTests(); if (build_options.rt_test) runtimeTests();
} }

View file

@ -235,6 +235,7 @@ pub fn registerIsr(isr_num: u16, handler: IsrHandler) IsrError!void {
/// ///
pub fn init() void { pub fn init() void {
log.logInfo("Init isr\n", .{}); log.logInfo("Init isr\n", .{});
defer log.logInfo("Done isr\n", .{});
comptime var i = 0; comptime var i = 0;
inline while (i < 32) : (i += 1) { inline while (i < 32) : (i += 1) {
@ -243,8 +244,6 @@ pub fn init() void {
openIsr(syscalls.INTERRUPT, interrupts.getInterruptStub(syscalls.INTERRUPT)); openIsr(syscalls.INTERRUPT, interrupts.getInterruptStub(syscalls.INTERRUPT));
log.logInfo("Done\n", .{});
if (build_options.rt_test) runtimeTests(); if (build_options.rt_test) runtimeTests();
} }

View file

@ -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 { pub fn init(mb_info: *multiboot.multiboot_info_t, mem_profile: *const MemProfile, allocator: *std.mem.Allocator) void {
log.logInfo("Init paging\n", .{}); log.logInfo("Init paging\n", .{});
defer log.logInfo("Done paging\n", .{});
// Calculate start and end of mapping // Calculate start and end of mapping
const v_start = std.mem.alignBackward(@ptrToInt(mem_profile.vaddr_start), PAGE_SIZE_4KB); 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); 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| { 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}); panic(@errorReturnTrace(), "Failed to register page fault ISR: {}\n", .{e});
}; };
log.logInfo("Done\n", .{});
if (options.rt_test) runtimeTests(v_end); if (options.rt_test) runtimeTests(v_end);
} }
@ -410,7 +411,7 @@ test "virtToTableEntryIdx" {
} }
test "mapDirEntry" { 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 dir: Directory = Directory{ .entries = [_]DirectoryEntry{0} ** ENTRIES_PER_DIRECTORY, .tables = [_]?*Table{null} ** ENTRIES_PER_DIRECTORY };
var phys: usize = 0 * PAGE_SIZE_4MB; var phys: usize = 0 * PAGE_SIZE_4MB;
const phys_end: usize = phys + PAGE_SIZE_4MB; const phys_end: usize = phys + PAGE_SIZE_4MB;
@ -425,7 +426,7 @@ test "mapDirEntry" {
} }
test "mapDirEntry returns errors correctly" { 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 }; 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.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)); 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" { 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 }; var dir = Directory{ .entries = [_]DirectoryEntry{0} ** ENTRIES_PER_DIRECTORY, .tables = [_]?*Table{null} ** ENTRIES_PER_DIRECTORY };
const phys_start: usize = PAGE_SIZE_4MB * 2; const phys_start: usize = PAGE_SIZE_4MB * 2;
const virt_start: usize = PAGE_SIZE_4MB * 4; const virt_start: usize = PAGE_SIZE_4MB * 4;

View file

@ -433,6 +433,7 @@ pub fn clearMask(irq_num: u8) void {
/// ///
pub fn init() void { pub fn init() void {
log.logInfo("Init pic\n", .{}); log.logInfo("Init pic\n", .{});
defer log.logInfo("Done pic\n", .{});
// Initiate // Initiate
sendCommandMaster(ICW1_INITIALISATION | ICW1_EXPECT_ICW4); sendCommandMaster(ICW1_INITIALISATION | ICW1_EXPECT_ICW4);
@ -467,8 +468,6 @@ pub fn init() void {
// Clear the IRQ for the slave // Clear the IRQ for the slave
clearMask(IRQ_CASCADE_FOR_SLAVE); clearMask(IRQ_CASCADE_FOR_SLAVE);
log.logInfo("Done\n", .{});
if (build_options.rt_test) runtimeTests(); if (build_options.rt_test) runtimeTests();
} }

View file

@ -371,6 +371,8 @@ pub fn getFrequency() u32 {
/// ///
pub fn init() void { pub fn init() void {
log.logInfo("Init pit\n", .{}); 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 // Set up counter 0 at 10000hz in a square wave mode counting in binary
const freq: u32 = 10000; const freq: u32 = 10000;
setupCounter(CounterSelect.Counter0, freq, OCW_MODE_SQUARE_WAVE_GENERATOR | OCW_BINARY_COUNT_BINARY) catch |e| { 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(); if (build_options.rt_test) runtimeTests();
} }

View file

@ -252,6 +252,7 @@ fn enableInterrupts() void {
/// ///
pub fn init() void { pub fn init() void {
log.logInfo("Init rtc\n", .{}); log.logInfo("Init rtc\n", .{});
defer log.logInfo("Done rtc\n", .{});
// Register the interrupt handler // Register the interrupt handler
irq.registerIrq(pic.IRQ_REAL_TIME_CLOCK, rtcHandler) catch |err| switch (err) { irq.registerIrq(pic.IRQ_REAL_TIME_CLOCK, rtcHandler) catch |err| switch (err) {
@ -276,16 +277,12 @@ pub fn init() void {
// Enable RTC interrupts // Enable RTC interrupts
enableInterrupts(); 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 // Can now enable interrupts
arch.enableInterrupts(); 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); const reg_c = cmos.readStatusRegister(cmos.StatusRegister.C, false);
log.logInfo("Done\n", .{});
if (build_options.rt_test) runtimeTests(); if (build_options.rt_test) runtimeTests();
} }

View file

@ -238,8 +238,9 @@ inline fn syscallArg(ctx: *arch.InterruptContext, comptime arg_idx: u32) u32 {
/// ///
pub fn init() void { pub fn init() void {
log.logInfo("Init syscalls\n", .{}); log.logInfo("Init syscalls\n", .{});
defer log.logInfo("Done syscalls\n", .{});
isr.registerIsr(INTERRUPT, handle) catch unreachable; isr.registerIsr(INTERRUPT, handle) catch unreachable;
log.logInfo("Done\n", .{});
if (options.rt_test) runtimeTests(); if (options.rt_test) runtimeTests();
} }

View file

@ -157,7 +157,7 @@ pub fn Bitmap(comptime BitmapType: type) type {
} }
test "setEntry" { 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); testing.expectEqual(@as(u32, 31), bmp.num_free_entries);
try bmp.setEntry(0); try bmp.setEntry(0);
@ -178,7 +178,7 @@ test "setEntry" {
} }
test "clearEntry" { 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); testing.expectEqual(@as(u32, 32), bmp.num_free_entries);
try bmp.setEntry(0); try bmp.setEntry(0);
@ -204,7 +204,7 @@ test "clearEntry" {
} }
test "setFirstFree multiple bitmaps" { 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 // Allocate the first entry
testing.expectEqual(bmp.setFirstFree() orelse unreachable, 0); testing.expectEqual(bmp.setFirstFree() orelse unreachable, 0);
@ -239,7 +239,7 @@ test "setFirstFree multiple bitmaps" {
testing.expectEqual(bmp.bitmaps[1], 1); testing.expectEqual(bmp.bitmaps[1], 1);
} }
test "setFirstFree" { 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 // Allocate the first entry
testing.expectEqual(bmp.setFirstFree() orelse unreachable, 0); testing.expectEqual(bmp.setFirstFree() orelse unreachable, 0);
@ -260,7 +260,7 @@ test "setFirstFree" {
} }
test "isSet" { 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; bmp.bitmaps[0] = 1;
// Make sure that only the set entry is considered set // Make sure that only the set entry is considered set
@ -292,7 +292,7 @@ test "isSet" {
} }
test "indexToBit" { 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(0), 1);
testing.expectEqual(bmp.indexToBit(1), 2); testing.expectEqual(bmp.indexToBit(1), 2);
testing.expectEqual(bmp.indexToBit(2), 4); testing.expectEqual(bmp.indexToBit(2), 4);

View file

@ -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| { serial.init(serial.DEFAULT_BAUDRATE, serial.Port.COM1) catch |e| {
panic_root.panic(@errorReturnTrace(), "Failed to initialise serial: {}", .{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); const mem_profile = mem.init(mb_info);
var buffer = mem_profile.vaddr_end[0..mem_profile.fixed_alloc_size]; var buffer = mem_profile.vaddr_end[0..mem_profile.fixed_alloc_size];
var fixed_allocator = std.heap.FixedBufferAllocator.init(buffer); 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(); tty.init();
log.logInfo("Init done\n", .{}); log.logInfo("Init done\n", .{});
tty.print("Hello Pluto from kernel :)\n", .{}); tty.print("Hello Pluto from kernel :)\n", .{});
// The panic runtime tests must run last as they never return // The panic runtime tests must run last as they never return
if (options.rt_test) panic_root.runtimeTests(); if (options.rt_test) panic_root.runtimeTests();

View file

@ -1,5 +1,12 @@
const serial = @import("serial.zig"); 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 { pub const Level = enum {
INFO, INFO,
@ -8,8 +15,9 @@ pub const Level = enum {
ERROR, 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); 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. /// 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 { 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;
} }
/// ///

View file

@ -53,36 +53,6 @@ const FIXED_ALLOC_SIZE: usize = 1024 * 1024;
/// release-safe. This is a workaround until that is fixed. /// release-safe. This is a workaround until that is fixed.
var ADDR_OFFSET: usize = undefined; 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. /// 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) { pub inline fn virtToPhys(virt: var) @TypeOf(virt) {
const T = @TypeOf(virt); const T = @TypeOf(virt);
return switch (@typeId(T)) { return switch (@typeInfo(T)) {
.Pointer => @intToPtr(T, @ptrToInt(virt) - ADDR_OFFSET), .Pointer => @intToPtr(T, @ptrToInt(virt) - ADDR_OFFSET),
.Int => virt - ADDR_OFFSET, .Int => virt - ADDR_OFFSET,
else => @compileError("Only pointers and integers are supported"), 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) { pub inline fn physToVirt(phys: var) @TypeOf(phys) {
const T = @TypeOf(phys); const T = @TypeOf(phys);
return switch (@typeId(T)) { return switch (@typeInfo(T)) {
.Pointer => @intToPtr(T, @ptrToInt(phys) + ADDR_OFFSET), .Pointer => @intToPtr(T, @ptrToInt(phys) + ADDR_OFFSET),
.Int => phys + ADDR_OFFSET, .Int => phys + ADDR_OFFSET,
else => @compileError("Only pointers and integers are supported"), 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" { test "physToVirt" {
ADDR_OFFSET = 0xC0000000; ADDR_OFFSET = 0xC0000000;
const offset: usize = ADDR_OFFSET; const offset: usize = ADDR_OFFSET;

View file

@ -77,11 +77,11 @@ const SymbolMap = struct {
/// The function name associated with that program address, or null if one wasn't found. /// 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 { pub fn search(self: *const SymbolMap, addr: usize) ?[]const u8 {
if (self.symbols.len == 0) if (self.symbols.items.len == 0)
return null; return null;
// Find the first element whose address is greater than addr // Find the first element whose address is greater than addr
var previous_name: ?[]const u8 = null; var previous_name: ?[]const u8 = null;
for (self.symbols.toSliceConst()) |entry| { for (self.symbols.items) |entry| {
if (entry.addr > addr) if (entry.addr > addr)
return previous_name; return previous_name;
previous_name = entry.func_name; previous_name = entry.func_name;
@ -116,7 +116,7 @@ pub fn panic(trace: ?*builtin.StackTrace, comptime format: []const u8, args: var
} else { } else {
const first_ret_addr = @returnAddress(); const first_ret_addr = @returnAddress();
var last_addr: u64 = 0; 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| { while (it.next()) |ret_addr| {
if (ret_addr != last_addr) logTraceAddress(ret_addr); if (ret_addr != last_addr) logTraceAddress(ret_addr);
last_addr = 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 { pub fn init(mem_profile: *const mem.MemProfile, allocator: *std.mem.Allocator) !void {
log.logInfo("Init panic\n", .{}); 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 // Exit if we haven't loaded all debug modules
if (mem_profile.boot_modules.len < 1) if (mem_profile.boot_modules.len < 1)
return; 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_start = mem.physToVirt(module.mod_start);
const mod_end = mem.physToVirt(module.mod_end) - 1; const mod_end = mem.physToVirt(module.mod_end) - 1;
const mod_str_ptr = mem.physToVirt(@intToPtr([*:0]u8, module.cmdline)); 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_start = mod_start;
kmap_end = mod_end; kmap_end = mod_end;
break; break;
@ -422,7 +423,7 @@ test "parseMapEntry fails without a name" {
} }
test "SymbolMap" { test "SymbolMap" {
var allocator = std.heap.direct_allocator; var allocator = std.heap.page_allocator;
var map = SymbolMap.init(allocator); var map = SymbolMap.init(allocator);
try map.add("abc"[0..], 123); try map.add("abc"[0..], 123);
try map.addEntry(MapEntry{ .func_name = "def"[0..], .addr = 456 }); try map.addEntry(MapEntry{ .func_name = "def"[0..], .addr = 456 });

View file

@ -91,6 +91,8 @@ pub fn free(addr: usize) (PmmBitmap.BitmapError || PmmError)!void {
/// ///
pub fn init(mem: *const MemProfile, allocator: *std.mem.Allocator) void { pub fn init(mem: *const MemProfile, allocator: *std.mem.Allocator) void {
log.logInfo("Init pmm\n", .{}); 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"); 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 // 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 }), else => panic(@errorReturnTrace(), "Failed setting kernel code address 0x{x} as occupied: {}", .{ addr, e }),
}; };
} }
log.logInfo("Done\n", .{});
if (build_options.rt_test) { if (build_options.rt_test) runtimeTests(mem);
runtimeTests(mem);
}
} }
/// ///
@ -154,7 +154,7 @@ fn runtimeTests(mem: *const MemProfile) void {
} }
test "alloc" { 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 addr = 0;
comptime var i = 0; comptime var i = 0;
// Allocate all entries, making sure they succeed and return the correct addresses // Allocate all entries, making sure they succeed and return the correct addresses
@ -171,7 +171,7 @@ test "alloc" {
} }
test "free" { 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; comptime var i = 0;
// Allocate and free all entries // Allocate and free all entries
inline while (i < 32) : (i += 1) { inline while (i < 32) : (i += 1) {
@ -186,7 +186,7 @@ test "free" {
test "setAddr and isSet" { test "setAddr and isSet" {
const num_entries: u32 = 32; 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 addr: u32 = 0;
var i: u32 = 0; var i: u32 = 0;
while (i < num_entries) : ({ while (i < num_entries) : ({

View file

@ -1,7 +1,7 @@
const arch = @import("arch.zig").internals; const arch = @import("arch.zig").internals;
const panic = @import("panic.zig").panic; const panic = @import("panic.zig").panic;
const testing = @import("std").testing; 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 /// The I/O port numbers associated with each serial port
pub const Port = enum(u16) { pub const Port = enum(u16) {
@ -147,12 +147,13 @@ pub fn init(baud: u32, port: Port) SerialError!void {
// Send the divisor's msb // Send the divisor's msb
arch.outb(port_int + 1, @truncate(u8, divisor >> 8)); arch.outb(port_int + 1, @truncate(u8, divisor >> 8));
// Send the properties to use // 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 // Stop initialisation
arch.outb(port_int + 1, 0); arch.outb(port_int + 1, 0);
if (options.rt_test) if (build_options.rt_test) runtimeTests();
runtimeTests();
} }
test "lcrValue computes the correct value" { test "lcrValue computes the correct value" {

View file

@ -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 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; 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. /// The error set for if there is an error whiles printing.
const TtyError = error{ const TtyError = error{
/// If the printing tries to print outside the video buffer. /// If the printing tries to print outside the video buffer.
@ -427,8 +430,9 @@ fn printLogo() void {
/// Errors: /// Errors:
/// TtyError.OutOfBounds - If trying to print beyond the video buffer. /// 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); 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 { 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 // 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}); log.logError("TTY: Error printing. Error: {}\n", .{e});
}; };
} }
@ -570,6 +574,7 @@ pub fn getVideoBufferAddress() usize {
/// ///
pub fn init() void { pub fn init() void {
log.logInfo("Init tty\n", .{}); log.logInfo("Init tty\n", .{});
defer log.logInfo("Done tty\n", .{});
// Video buffer in higher half // Video buffer in higher half
if (is_test) { if (is_test) {
@ -631,8 +636,6 @@ pub fn init() void {
displayPageNumber(); displayPageNumber();
updateCursor(); updateCursor();
log.logInfo("Done\n", .{});
if (build_options.rt_test) runtimeTests(); if (build_options.rt_test) runtimeTests();
} }

View file

@ -145,7 +145,6 @@ inline fn sendData(data: u8) void {
inline fn getData() u8 { inline fn getData() u8 {
return arch.inb(PORT_DATA); return arch.inb(PORT_DATA);
} }
/// ///
/// Set the VGA register port to write to and sending data to that VGA register port. /// 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 { pub fn init() void {
log.logInfo("Init vga\n", .{}); log.logInfo("Init vga\n", .{});
defer log.logInfo("Done vga\n", .{});
// Set the maximum scan line to 0x0F // Set the maximum scan line to 0x0F
sendPortData(REG_MAXIMUM_SCAN_LINE, CURSOR_SCANLINE_END); sendPortData(REG_MAXIMUM_SCAN_LINE, CURSOR_SCANLINE_END);
@ -294,8 +294,6 @@ pub fn init() void {
// Set by default the underline cursor // Set by default the underline cursor
setCursorShape(CursorShape.UNDERLINE); setCursorShape(CursorShape.UNDERLINE);
log.logInfo("Done\n", .{});
if (build_options.rt_test) runtimeTests(); if (build_options.rt_test) runtimeTests();
} }

View file

@ -1,23 +1,39 @@
def get_test_cases(TestCase): def get_test_cases(TestCase):
return [ return [
TestCase("GDT init", [r"Init gdt", r"Done"]), TestCase("GDT init", [r"Init gdt"]),
TestCase("GDT tests", [r"GDT: Tested loading 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("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("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("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("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 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"Init pit"]),
TestCase("PIT init", [r".+"], r"\[DEBUG\] "), 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("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("RTC tests", [r"RTC: Tested init", r"RTC: Tested interrupts"]),
TestCase("Syscalls init", [r"Init syscalls", r"Done"]), TestCase("RTC done", [r"Done rtc"]),
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("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"]),
] ]

View file

@ -31,26 +31,40 @@ def test_pass(case, exp, expected_idx, found):
def get_pre_archinit_cases(): def get_pre_archinit_cases():
return [ return [
TestCase("Serial tests", [r"c", r"123"], ""), 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 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 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 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 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("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("Mem init", [r"Init mem", r"Done"]), 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("PMM init", [r"Init pmm", r"Done"]),
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 tests", [r"PMM: Tested allocation"]),
TestCase("PMM done", [r"Done pmm"]),
TestCase("Arch init starts", [r"Init arch \w+"]) TestCase("Arch init starts", [r"Init arch \w+"])
] ]
def get_post_archinit_cases(): def get_post_archinit_cases():
return [ return [
TestCase("Arch init finishes", [r"Arch init done"]), 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("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 tests", [r"TTY: Tested globals", r"TTY: Tested printing"]),
TestCase("TTY done", [r"Done tty"]),
TestCase("Init finishes", [r"Init done"]), 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): def read_messages(proc):