aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarin Ivanov <[email protected]>2024-04-01 01:50:23 +0300
committerMarin Ivanov <[email protected]>2024-04-01 01:50:23 +0300
commite4005e37848fe396dba45eacdaa5df948bec9fb8 (patch)
tree4c06e0dd6ffc20dbd184401d7a5667f4719ff8c7
parent4676edf5d99a0c1ff0b50c0db0932ec1b163235c (diff)
import Zig Bare Bones project
ref: https://wiki.osdev.org/Zig_Bare_Bones
-rw-r--r--.gitignore1
-rw-r--r--build.zig76
-rw-r--r--src/console.zig84
-rw-r--r--src/grub.cfg3
-rw-r--r--src/linker.ld26
-rw-r--r--src/main.zig31
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!");
+}