diff options
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | build.zig | 76 | ||||
| -rw-r--r-- | src/console.zig | 84 | ||||
| -rw-r--r-- | src/grub.cfg | 3 | ||||
| -rw-r--r-- | src/linker.ld | 26 | ||||
| -rw-r--r-- | src/main.zig | 31 |
6 files changed, 221 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..93d6756 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/zig-cache diff --git a/build.zig b/build.zig new file mode 100644 index 0000000..6aef258 --- /dev/null +++ b/build.zig @@ -0,0 +1,76 @@ +const std = @import("std"); +const Builder = @import("std").build.Builder; +const Target = @import("std").Target; +const CrossTarget = @import("std").zig.CrossTarget; +const Feature = @import("std").Target.Cpu.Feature; + +pub fn build(b: *Builder) void { + const features = Target.x86.Feature; + + var disabled_features = Feature.Set.empty; + var enabled_features = Feature.Set.empty; + + disabled_features.addFeature(@enumToInt(features.mmx)); + disabled_features.addFeature(@enumToInt(features.sse)); + disabled_features.addFeature(@enumToInt(features.sse2)); + disabled_features.addFeature(@enumToInt(features.avx)); + disabled_features.addFeature(@enumToInt(features.avx2)); + enabled_features.addFeature(@enumToInt(features.soft_float)); + + const target = CrossTarget{ + .cpu_arch = Target.Cpu.Arch.i386, + .os_tag = Target.Os.Tag.freestanding, + .abi = Target.Abi.none, + .cpu_features_sub = disabled_features, + .cpu_features_add = enabled_features + }; + + const mode = b.standardReleaseOptions(); + + const kernel = b.addExecutable("kernel.elf", "src/main.zig"); + kernel.setTarget(target); + kernel.setBuildMode(mode); + kernel.setLinkerScriptPath(.{ .path = "src/linker.ld" }); + kernel.code_model = .kernel; + kernel.install(); + + const kernel_step = b.step("kernel", "Build the kernel"); + kernel_step.dependOn(&kernel.install_step.?.step); + + const iso_dir = b.fmt("{s}/iso_root", .{b.cache_root}); + const kernel_path = b.getInstallPath(kernel.install_step.?.dest_dir, kernel.out_filename); + const iso_path = b.fmt("{s}/disk.iso", .{b.exe_dir}); + + const iso_cmd_str = &[_][]const u8{ + "/bin/sh", "-c", + std.mem.concat(b.allocator, u8, &[_][]const u8{ + "mkdir -p ", iso_dir, " && ", + "cp ", kernel_path, " ", iso_dir, " && ", + "cp src/grub.cfg ", iso_dir, " && ", + "grub-mkrescue -o ", iso_path, " ", iso_dir + }) catch unreachable + }; + + const iso_cmd = b.addSystemCommand(iso_cmd_str); + iso_cmd.step.dependOn(kernel_step); + + const iso_step = b.step("iso", "Build an ISO image"); + iso_step.dependOn(&iso_cmd.step); + b.default_step.dependOn(iso_step); + + const run_cmd_str = &[_][]const u8{ + "qemu-system-x86_64", + "-cdrom", iso_path, + "-debugcon", "stdio", + "-vga", "virtio", + "-m", "4G", + "-machine", "q35,accel=kvm:whpx:tcg", + "-no-reboot", "-no-shutdown" + }; + + const run_cmd = b.addSystemCommand(run_cmd_str); + run_cmd.step.dependOn(b.getInstallStep()); + + const run_step = b.step("run", "Run the kernel"); + run_step.dependOn(&run_cmd.step); +} diff --git a/src/console.zig b/src/console.zig new file mode 100644 index 0000000..6fc5043 --- /dev/null +++ b/src/console.zig @@ -0,0 +1,84 @@ +const fmt = @import("std").fmt; +const Writer = @import("std").io.Writer; + +const VGA_WIDTH = 80; +const VGA_HEIGHT = 25; +const VGA_SIZE = VGA_WIDTH * VGA_HEIGHT; + +pub const ConsoleColors = enum(u8) { + Black = 0, + Blue = 1, + Green = 2, + Cyan = 3, + Red = 4, + Magenta = 5, + Brown = 6, + LightGray = 7, + DarkGray = 8, + LightBlue = 9, + LightGreen = 10, + LightCyan = 11, + LightRed = 12, + LightMagenta = 13, + LightBrown = 14, + White = 15, +}; + +var row: usize = 0; +var column: usize = 0; +var color = vgaEntryColor(ConsoleColors.LightGray, ConsoleColors.Black); +var buffer = @as([*]volatile u16, @ptrFromInt(0xB8000)); + +fn vgaEntryColor(fg: ConsoleColors, bg: ConsoleColors) u8 { + return @enumToInt(fg) | (@enumToInt(bg) << 4); +} + +fn vgaEntry(uc: u8, new_color: u8) u16 { + var c: u16 = new_color; + + return uc | (c << 8); +} + +pub fn initialize() void { + clear(); +} + +pub fn setColor(new_color: u8) void { + color = new_color; +} + +pub fn clear() void { + @memset(u16, buffer[0..VGA_SIZE], vgaEntry(' ', color)); +} + +pub fn putCharAt(c: u8, new_color: u8, x: usize, y: usize) void { + const index = y * VGA_WIDTH + x; + buffer[index] = vgaEntry(c, new_color); +} + +pub fn putChar(c: u8) void { + putCharAt(c, color, column, row); + column += 1; + if (column == VGA_WIDTH) { + column = 0; + row += 1; + if (row == VGA_HEIGHT) + row = 0; + } +} + +pub fn puts(data: []const u8) void { + for (data) |c| + putChar(c); +} + +pub const writer = Writer(void, error{}, callback){ .context = {} }; + +fn callback(_: void, string: []const u8) error{}!usize { + puts(string); + return string.len; +} + +pub fn printf(comptime format: []const u8, args: anytype) void { + fmt.format(writer, format, args) catch unreachable; +} diff --git a/src/grub.cfg b/src/grub.cfg new file mode 100644 index 0000000..7904bf7 --- /dev/null +++ b/src/grub.cfg @@ -0,0 +1,3 @@ +menuentry "Zig Bare Bones" { + multiboot /boot/kernel.elf +} diff --git a/src/linker.ld b/src/linker.ld new file mode 100644 index 0000000..429da33 --- /dev/null +++ b/src/linker.ld @@ -0,0 +1,26 @@ +ENTRY(_start) + +SECTIONS { + . = 1M; + + .multiboot { + KEEP(*(.multiboot)) + } + + .text : ALIGN(4K) { + *(.text) + } + + .rodata : ALIGN(4K) { + *(.rodata) + } + + .data : ALIGN(4K) { + *(.data) + } + + .bss : ALIGN(4K) { + *(COMMON) + *(.bss) + } +} diff --git a/src/main.zig b/src/main.zig new file mode 100644 index 0000000..298e2c2 --- /dev/null +++ b/src/main.zig @@ -0,0 +1,31 @@ +const console = @import("console.zig"); + +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, +}; + +export var multiboot align(4) linksection(".multiboot") = MultibootHeader{ + .flags = FLAGS, + .checksum = -(MAGIC + FLAGS), +}; + +export var stack_bytes: [16 * 1024]u8 align(16) linksection(".bss") = undefined; +const stack_bytes_slice = stack_bytes[0..]; + +export fn _start() callconv(.Naked) noreturn { + @call(.{ .stack = stack_bytes_slice }, kmain, .{}); + + while (true) {} +} + +fn kmain() void { + console.initialize(); + console.puts("Hello world!"); +} |
