diff --git a/build.zig b/build.zig index 71b1c94..7e82a04 100644 --- a/build.zig +++ b/build.zig @@ -77,7 +77,7 @@ pub fn build(b: *std.Build) void { const run_step = b.step("run", "Run the image with qemu"); const run_cmd = b.addSystemCommand(&.{ - "qemu-system-x86_64", "-M", "q35", "-m", "2G", "-cdrom", image_name, "-boot", "d" + "qemu-system-x86_64", "-serial", "stdio", "-M", "q35", "-m", "2G", "-cdrom", image_name, "-boot", "d" }); run_cmd.step.dependOn(image_step); run_step.dependOn(&run_cmd.step); diff --git a/kernel/debug.zig b/kernel/debug.zig index f125c14..266de9c 100644 --- a/kernel/debug.zig +++ b/kernel/debug.zig @@ -1,7 +1,11 @@ const std = @import("std"); const root = @import("root"); +const SpinLock = @import("lock.zig").SpinLock; +const serial = @import("serial.zig"); const tty = @import("tty.zig"); +var log_lock: SpinLock = .{}; + var fba_buffer: [16 * 1024 * 1024]u8 = undefined; // 16MB var debug_fba = std.heap.FixedBufferAllocator.init(&fba_buffer); const debug_allocator = debug_fba.allocator(); @@ -122,3 +126,23 @@ fn getSectionSlice(elf: [*]const u8, section_name: []const u8) ![]const u8 { return error.SectionNotFound; } + +pub fn log( + comptime level: std.log.Level, + comptime scope: @TypeOf(.EnumLiteral), + comptime format: []const u8, + args: anytype, +) void { + const level_txt = comptime switch (level) { + .err => "\x1b[31merror\x1b[m", + .warn => "\x1b[33mwarning\x1b[m", + .info => "\x1b[32minfo\x1b[m", + .debug => "\x1b[34mdebug\x1b[m", + }; + const prefix2 = (if (scope != .default) "@" ++ @tagName(scope)) ++ ": "; + log_lock.lock(); + defer log_lock.unlock(); + const fmt = level_txt ++ prefix2 ++ format ++ "\n"; + nosuspend tty.print(fmt, args); + nosuspend serial.print(fmt, args); +} diff --git a/kernel/fs.zig b/kernel/fs.zig new file mode 100644 index 0000000..ea16960 --- /dev/null +++ b/kernel/fs.zig @@ -0,0 +1,13 @@ +// TODO + +// fn loadFile(name: []const u8) !*limine.File { +// const module_response = module_request.response.?; +// for (module_response.modules()) |file| { +// const path: []u8 = file.path[0..std.mem.len(file.path)]; +// if (std.mem.endsWith(u8, path, name)) { +// return file; +// } +// } + +// return error.FileNotFound; +// } diff --git a/kernel/main.zig b/kernel/main.zig index 60406ab..ee7204e 100644 --- a/kernel/main.zig +++ b/kernel/main.zig @@ -1,14 +1,17 @@ const std = @import("std"); const limine = @import("limine"); +const debug = @import("debug.zig"); const serial = @import("serial.zig"); const tty = @import("tty.zig"); const gdt = @import("gdt.zig"); const idt = @import("idt.zig"); const pmm = @import("pmm.zig"); const vmm = @import("vmm.zig"); -const debug = @import("debug.zig"); +const mem = @import("mem.zig"); -// pub const page_allocator = mem.page_allocator; +pub const std_options = struct { + pub const logFn = debug.log; +}; export var boot_info_request: limine.BootloaderInfoRequest = .{}; pub export var hhdm_request: limine.HhdmRequest = .{}; @@ -19,18 +22,6 @@ pub export var kernel_file_request: limine.KernelFileRequest = .{}; // export var rsdp_request: limine.RsdpRequest = .{}; pub export var kernel_address_request: limine.KernelAddressRequest = .{}; -// fn loadFile(name: []const u8) !*limine.File { -// const module_response = module_request.response.?; -// for (module_response.modules()) |file| { -// const path: []u8 = file.path[0..std.mem.len(file.path)]; -// if (std.mem.endsWith(u8, path, name)) { -// return file; -// } -// } - -// return error.FileNotFound; -// } - inline fn halt() noreturn { while (true) asm volatile ("hlt"); } @@ -69,17 +60,19 @@ fn main() !void { // const module = module_request.response.?; // const rsdp = rsdp_request.response.?; - // TODO: log when init is successful + // TODO: log when init is successful (with serial or tty idk) tty.init(); - tty.drawSquares(); + tty.drawSquares(); // TODO: draw logo instead tty.print("Booting Ubik with {s} {s}\n", .{ boot_info.name, boot_info.version }); + /////////////////////////////////////////////////////////////////////////// tty.print("Hello, World!\n", .{}); tty.foreground = @enumFromInt(0xBD93F9); tty.print("new color of value {X}\n", .{@intFromEnum(tty.foreground)}); tty.foreground = tty.Color.white; + /////////////////////////////////////////////////////////////////////////// serial.init(); debug.init() catch |err| { @@ -88,14 +81,34 @@ fn main() !void { gdt.init(); idt.init(); // TODO: init events <-- for interrupts + // TODO: interrupt controller (pic or apic) + // TODO: PS/2 -> handle keyboard/mouse <-- extern + try pmm.init(); + try vmm.init(); // TODO + // try mem.init(); // TODO: heap allocator -> use gpa + // TODO: apic + // TODO: acpi + // TODO: pci + // TODO: timers (pit ?) + + // TODO: proc + // TODO: scheduler + // TODO: cpu + // TODO: threads <-- with priority level ? <- have a list of thread based + // on priority level and state (accoriding to https://wiki.osdev.org/Going_further_on_x86 + + // TODO: filesystem <-- extern + + // TODO: start /bin/init <- load elf with std.elf + + /////////////////////////////////////////////////////////////////////////// const buf = try pmm.alloc(1, false); defer pmm.free(buf); tty.print("{*} {}\n", .{ buf.ptr, buf.len }); - try vmm.init(); - asm volatile ("sti"); @breakpoint(); + /////////////////////////////////////////////////////////////////////////// } diff --git a/kernel/serial.zig b/kernel/serial.zig index 52aa57a..3e5c095 100644 --- a/kernel/serial.zig +++ b/kernel/serial.zig @@ -1,15 +1,19 @@ -// TODO: mostly useless - +const std = @import("std"); const SpinLock = @import("lock.zig").SpinLock; -const com1_port = 0x3f8; -const com_ports = [_]u16{ com1_port, 0x2f8, 0x3e8, 0x2e8 }; +pub const Port = enum(u16) { + com1 = 0x3f8, + com2 = 0x2f8, + com3 = 0x3e8, + com4 = 0x2e8, +}; -var lock: SpinLock = .{}; +var com1_lock: SpinLock = .{}; +const com1_writer = std.io.Writer(void, error{}, com1Write){ .context = {} }; pub fn init() void { - for (com_ports) |port| { - _ = initPort(port); + for (std.enums.values(Port)) |port| { + _ = initPort(@intFromEnum(port)); } } @@ -86,35 +90,28 @@ pub inline fn in(comptime T: type, port: u16) T { }; } -inline fn isTransmitterEmpty(port: u16) bool { - return (in(u8, port + 5) & 0b01000000) != 0; +inline fn transmitterIsEmpty(port: Port) bool { + return in(u8, @intFromEnum(port) + 5) & 0b01000000 != 0; } -inline fn transmitData(port: u16, value: u8) void { - while (!isTransmitterEmpty(port)) { +inline fn transmitData(port: Port, value: u8) void { + while (!transmitterIsEmpty(port)) { asm volatile ("pause"); } - out(u8, port, value); + out(u8, @intFromEnum(port), value); } -pub fn outChar(char: u8) void { - lock.lock(); - defer lock.unlock(); +fn com1Write(_: void, str: []const u8) error{}!usize { + com1_lock.lock(); + defer com1_lock.unlock(); - if (char == '\n') { - transmitData(com1_port, '\r'); + for (str) |char| { + transmitData(Port.com1, char); } - transmitData(com1_port, char); -} -pub fn outStr(str: []const u8) void { - lock.lock(); - defer lock.unlock(); + return str.len; +} - for (str) |char| { - if (char == '\n') { - transmitData(com1_port, '\r'); - } - transmitData(com1_port, char); - } +pub fn print(comptime fmt: []const u8, args: anytype) void { + std.fmt.format(com1_writer, fmt, args) catch unreachable; }