diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..8392d15 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake \ No newline at end of file diff --git a/.gitignore b/.gitignore index 30eaa82..9d4506d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,9 @@ -.zig-cache/ -zig-out/ +# Zig +zig-* +.zig-* -.envrc -.direnv/ +# Nix +result* +# Misc +.direnv diff --git a/build.zig b/build.zig index 3a4f63b..e256efa 100644 --- a/build.zig +++ b/build.zig @@ -1,31 +1,32 @@ const std = @import("std"); -pub fn build(b: *std.Build) void { +pub fn build(b: *std.Build) !void { + var disabled_features = std.Target.Cpu.Feature.Set.empty; + var enabled_features = std.Target.Cpu.Feature.Set.empty; + + disabled_features.addFeature(@intFromEnum(std.Target.x86.Feature.mmx)); + disabled_features.addFeature(@intFromEnum(std.Target.x86.Feature.sse)); + disabled_features.addFeature(@intFromEnum(std.Target.x86.Feature.sse2)); + disabled_features.addFeature(@intFromEnum(std.Target.x86.Feature.avx)); + disabled_features.addFeature(@intFromEnum(std.Target.x86.Feature.avx2)); + + enabled_features.addFeature(@intFromEnum(std.Target.x86.Feature.soft_float)); + const target = b.resolveTargetQuery(.{ .cpu_arch = std.Target.Cpu.Arch.x86, - .ofmt = std.Target.ObjectFormat.elf, .abi = std.Target.Abi.none, .os_tag = std.Target.Os.Tag.freestanding, - .cpu_features_sub = std.Target.x86.featureSet(&.{ - .mmx, - .sse, - .sse2, - .avx, - .avx2, - }), - .cpu_features_add = std.Target.x86.featureSet(&.{ - .soft_float, - }), + .cpu_features_sub = disabled_features, + .cpu_features_add = enabled_features, }); - const optimize = b.standardOptimizeOption(.{}); - const kernel = b.addExecutable(.{ - .name = "kernel", + .name = "kernel.elf", .root_module = b.createModule(.{ - .target = target, - .optimize = optimize, .root_source_file = b.path("src/main.zig"), + .target = target, + .optimize = .ReleaseFast, + .code_model = .kernel, }), }); kernel.setLinkerScript(b.path("kernel.ld")); @@ -41,4 +42,3 @@ pub fn build(b: *std.Build) void { const run = b.step("run", "Run QEMU"); run.dependOn(&qemu.step); } - diff --git a/flake.lock b/flake.lock index d680c26..bbb64ca 100644 --- a/flake.lock +++ b/flake.lock @@ -20,11 +20,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1757745802, - "narHash": "sha256-hLEO2TPj55KcUFUU1vgtHE9UEIOjRcH/4QbmfHNF820=", + "lastModified": 1762363567, + "narHash": "sha256-YRqMDEtSMbitIMj+JLpheSz0pwEr0Rmy5mC7myl17xs=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", + "rev": "ae814fd3904b621d8ab97418f1d0f2eb0d3716f4", "type": "github" }, "original": { diff --git a/src/Console.zig b/src/Console.zig index 0825e73..6b75378 100644 --- a/src/Console.zig +++ b/src/Console.zig @@ -119,22 +119,29 @@ const Writer = struct { console: *Self, interface: std.Io.Writer, - fn drain(w: *std.Io.Writer, data: []const []const u8, splat: usize) std.Io.Writer.Error!usize { - _ = splat; + fn drain(io_w: *std.Io.Writer, data: []const []const u8, splat: usize) std.Io.Writer.Error!usize { + const self: *@This() = @fieldParentPtr("interface", io_w); - const self: *@This() = @alignCast(@fieldParentPtr("interface", w)); + try self.puts(io_w.buffered()); + io_w.end = 0; - const buffered = w.buffered(); - if (buffered.len != 0) { - self.console.puts(buffered); - return w.consume(buffered.len); + for (data[0..data.len - 1]) |bytes| { + try self.puts(bytes); } - self.console.puts(data[0]); - return data[0].len; + const pattern = data[data.len - 1]; + for (0..splat) |_| { + try self.puts(pattern); + } + + return std.Io.Writer.countSplat(data, splat); + } + + fn puts(self: *@This(), data: []const u8) std.Io.Writer.Error!void { + self.console.puts(data); } }; -fn writer(self: *Self, buffer: []u8) Writer { +pub fn writer(self: *Self, buffer: []u8) Writer { return .{ .console = self, .interface = .{ @@ -147,7 +154,10 @@ fn writer(self: *Self, buffer: []u8) Writer { } pub fn printf(self: *Self, comptime format: []const u8, args: anytype) void { - var w = self.writer(&.{}); - w.interface.print(format, args) catch unreachable; + var buffer: [1024]u8 = undefined; + var w = self.writer(&buffer); + const io_w = &w.interface; + io_w.print(format, args) catch unreachable; + io_w.flush() catch unreachable; } diff --git a/src/main.zig b/src/main.zig index 727bbc9..dd4f020 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1,21 +1,23 @@ const lazy = @import("utils/Lazy.zig").lazy; const Console = @import("Console.zig"); +const MultibootInfo = @import("multiboot.zig").Info; + +const MultibootHeader = packed struct { + magic: i32, + flags: i32, + checksum: i32, + padding: u32, +}; const ALIGN = 1 << 0; const MEMINFO = 1 << 1; const MAGIC = 0x1BADB002; const FLAGS = ALIGN | MEMINFO; - -const MultibootHeader = packed struct { - magic: i32 = MAGIC, - flags: i32, - checksum: i32, - padding: u32 = 0, -}; - export var mutliboot: MultibootHeader align(4) linksection(".multiboot") = .{ + .magic = MAGIC, .flags = FLAGS, .checksum = -(MAGIC + FLAGS), + .padding = 0, }; var stack_bytes: [16 * 1024]u8 align(16) linksection(".bss") = undefined; @@ -24,6 +26,8 @@ export fn _start() callconv(.naked) noreturn { asm volatile ( \\ movl %[stack_top], %%esp \\ movl %%esp, %%ebp + \\ push %%ebx + \\ push %%eax \\ call %[kmain:P] : : [stack_top] "i" (@as([*]align(16) u8, @ptrCast(&stack_bytes)) + @sizeOf(@TypeOf(stack_bytes))), @@ -33,13 +37,23 @@ export fn _start() callconv(.naked) noreturn { var console = lazy(Console, .init); -fn kmain() callconv(.c) void { - std.log.info("This is an info message", .{}); - std.log.debug("This is a debug message!", .{}); - std.log.warn("This is a warning message!", .{}); - std.log.err("This is an error message!", .{}); +fn kmain(magic: u32, info: *const MultibootInfo) callconv(.c) void { + std.debug.assert(magic == MAGIC); - @panic("Uh oh"); + std.log.info("{any}", .{info}); + + if (info.isValid(.boot_loader_name)) { + std.log.info("Booted by {s}", .{info.boot_loader_name}); + } + if (info.isValid(.cmdline)) { + std.log.info("Booted with cmdline \"{s}\"", .{info.cmdline}); + } + + hang(); +} + +fn hang() noreturn { + while (true) asm volatile ("hlt"); } const std = @import("std"); @@ -51,7 +65,7 @@ fn kpanic(msg: []const u8, first_trace_addr: ?usize) noreturn { std.log.err("PANIC: {s}", .{msg}); - while (true) {} + hang(); } pub const std_options = std.Options{ @@ -73,13 +87,11 @@ fn klog( .info => Console.ConsoleColor.light_blue, .debug => Console.ConsoleColor.light_green, }; - c.putChar('['); - { - c.setColor(color, Console.ConsoleColor.black); - defer c.resetColor(); - c.puts(level.asText()); - } + c.putChar('['); + c.setColor(color, Console.ConsoleColor.black); + c.puts(level.asText()); + c.resetColor(); c.putChar(']'); c.putChar(' '); @@ -90,4 +102,3 @@ fn klog( c.printf(format ++ "\n", args); } - diff --git a/src/multiboot.zig b/src/multiboot.zig index d30a255..9863d22 100644 --- a/src/multiboot.zig +++ b/src/multiboot.zig @@ -1,56 +1,96 @@ -pub const Info = extern struct { - flags: c_uint, - mem_lower: c_uint, - mem_upper: c_uint, - boot_device: c_uint, - cmdline: c_uint, - mods_count: c_uint, - mods_addr: c_uint, - u: extern union { - aout_sym: extern struct { - tabsize: c_uint, - strsize: c_uint, - addr: c_uint, - reserved: c_uint, - }, - elf_sec: extern struct { - num: c_uint, - size: c_uint, - addr: c_uint, - shndx: c_uint, - }, - }, - mmap_length: c_uint, - mmap_addr: c_uint, - drives_length: c_uint, - drives_addr: c_uint, - config_table: c_uint, - boot_loader_name: c_uint, - apm_table: c_uint, - vbe_control_info: c_uint, - vbe_move_info: c_uint, - vbe_mode: c_ushort, - vbe_interface_seg: c_ushort, - vbe_interface_off: c_ushort, - vbe_interface_len: c_ushort, - framebuffer_addr: c_ulonglong, - framebuffer_pitch: c_uint, - framebuffer_width: c_uint, - framebuffer_height: c_uint, - framebuffer_bpp: u8, - framebuffer_type: u8, - unnamed_0: extern union { - unnamed_0: extern struct { - framebuffer_palette_addr: c_uint, - framebuffer_palette_num_colors: c_ushort, - }, - unnamed_1: extern struct { - framebuffer_red_field_position: u8, - framebuffer_red_mask_size: u8, - framebuffer_green_field_position: u8, - framebuffer_green_mask_size: u8, - framebuffer_blue_field_position: u8, - framebuffer_blue_mask_size: u8, - }, - }, +const std = @import("std"); + +const BootModule = packed struct { + start: u32, + end: u32, + string: ?[*:0]u8, + reserved: u32, }; + +pub const Info = packed struct { + flags: std.bit_set.IntegerBitSet(32), + mem_lower: u32, + mem_upper: u32, + boot_device: packed struct { + part3: u8, + part2: u8, + part1: u8, + drive: u8, + }, + cmdline: [*:0]u8, + mods_count: u32, + mods_addr: [*]BootModule, + u: packed union { + aout_sym: packed struct { + tabsize: u32, + strsize: u32, + addr: u32, + reserved: u32, + }, + elf_sec: packed struct { + num: u32, + size: u32, + addr: u32, + shndx: u32, + }, + }, + mmap_length: u32, + mmap_addr: u32, + drives_length: u32, + drives_addr: u32, + config_table: u32, + boot_loader_name: [*:0]u8, + apm_table: u32, + vbe: packed struct { + control_info: u32, + move_info: u32, + mode: u16, + interface_seg: u16, + interface_off: u16, + interface_len: u16, + }, + framebuffer: packed struct { + addr: u64, + pitch: u32, + width: u32, + height: u32, + bpp: u8, + type: u8, + color_info: packed union { + indexed_color: packed struct { + framebuffer_palette_addr: u32, + framebuffer_palette_num_colors: u16, + }, + rgb_color: packed struct { + framebuffer_red_field_position: u8, + framebuffer_red_mask_size: u8, + framebuffer_green_field_position: u8, + framebuffer_green_mask_size: u8, + framebuffer_blue_field_position: u8, + framebuffer_blue_mask_size: u8, + }, + }, + }, + + const Self = @This(); + + pub fn isValid(self: *const Self, comptime field: std.meta.FieldEnum(Self)) bool { + return switch (field) { + .flags => true, + .mem_lower, .mem_upper => self.flags.isSet(0), + .boot_device => self.flags.isSet(1), + .cmdline => self.flags.isSet(2), + .mods_count, .mods_addr => self.flags.isSet(3), + // TODO: .u => either 4 or 5 + .mmap_length, .mmap_addr => self.flags.isSet(6), + .drives_length, .drives_addr => self.flags.isSet(7), + .config_table => self.flags.isSet(8), + .boot_loader_name => self.flags.isSet(9), + .apm_table => self.flags.isSet(10), + .vbe => self.flags.isSet(11), + .framebuffer => self.flags.isSet(12), + else => false, + }; + } +}; +