Initial commit
This commit is contained in:
commit
dc6f7e486f
9 changed files with 427 additions and 0 deletions
1
.envrc
Normal file
1
.envrc
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
use flake
|
||||||
9
.gitignore
vendored
Normal file
9
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
# Zig
|
||||||
|
zig-*
|
||||||
|
.zig-*
|
||||||
|
|
||||||
|
# Nix
|
||||||
|
result*
|
||||||
|
|
||||||
|
# Misc
|
||||||
|
.direnv
|
||||||
42
build.zig
Normal file
42
build.zig
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
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,
|
||||||
|
.abi = std.Target.Abi.none,
|
||||||
|
.os_tag = std.Target.Os.Tag.freestanding,
|
||||||
|
.cpu_features_sub = disabled_features,
|
||||||
|
.cpu_features_add = enabled_features,
|
||||||
|
});
|
||||||
|
|
||||||
|
const kernel = b.addExecutable(.{
|
||||||
|
.name = "kernel.elf",
|
||||||
|
.root_source_file = b.path("src/main.zig"),
|
||||||
|
.target = target,
|
||||||
|
.optimize = .ReleaseFast,
|
||||||
|
.code_model = .kernel,
|
||||||
|
});
|
||||||
|
kernel.setLinkerScript(b.path("kernel.ld"));
|
||||||
|
|
||||||
|
b.installArtifact(kernel);
|
||||||
|
|
||||||
|
const qemu = b.addSystemCommand(&[_][]const u8{
|
||||||
|
"qemu-system-x86_64",
|
||||||
|
});
|
||||||
|
qemu.addArg("-kernel");
|
||||||
|
qemu.addFileArg(kernel.getEmittedBin());
|
||||||
|
|
||||||
|
const run = b.step("run", "Run QEMU");
|
||||||
|
run.dependOn(&qemu.step);
|
||||||
|
}
|
||||||
61
flake.lock
generated
Normal file
61
flake.lock
generated
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"flake-utils": {
|
||||||
|
"inputs": {
|
||||||
|
"systems": "systems"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1731533236,
|
||||||
|
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1742669843,
|
||||||
|
"narHash": "sha256-G5n+FOXLXcRx+3hCJ6Rt6ZQyF1zqQ0DL0sWAMn2Nk0w=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "1e5b653dff12029333a6546c11e108ede13052eb",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixos-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-utils": "flake-utils",
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"systems": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
||||||
43
flake.nix
Normal file
43
flake.nix
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
{
|
||||||
|
description = "Zig Template";
|
||||||
|
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||||
|
flake-utils.url = "github:numtide/flake-utils";
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs = {
|
||||||
|
nixpkgs,
|
||||||
|
flake-utils,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
flake-utils.lib.eachDefaultSystem (
|
||||||
|
system: let
|
||||||
|
pkgs = nixpkgs.legacyPackages.${system};
|
||||||
|
nativeBuildInputs = with pkgs; [
|
||||||
|
zig
|
||||||
|
zls
|
||||||
|
];
|
||||||
|
|
||||||
|
buildInputs = with pkgs; [
|
||||||
|
qemu
|
||||||
|
grub2
|
||||||
|
];
|
||||||
|
in {
|
||||||
|
devShells.default = pkgs.mkShell {inherit nativeBuildInputs buildInputs;};
|
||||||
|
|
||||||
|
packages.default = pkgs.stdenv.mkDerivation {
|
||||||
|
pname = "template";
|
||||||
|
version = "0.0.0";
|
||||||
|
src = ./.;
|
||||||
|
|
||||||
|
nativeBuildInputs =
|
||||||
|
nativeBuildInputs
|
||||||
|
++ [
|
||||||
|
pkgs.zig.hook
|
||||||
|
];
|
||||||
|
inherit buildInputs;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
27
kernel.ld
Normal file
27
kernel.ld
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
ENTRY(_start)
|
||||||
|
|
||||||
|
SECTIONS {
|
||||||
|
. = 1M;
|
||||||
|
|
||||||
|
.multiboot : ALIGN(4K) {
|
||||||
|
KEEP(*(.multiboot))
|
||||||
|
}
|
||||||
|
|
||||||
|
.text : ALIGN(4K) {
|
||||||
|
*(.text)
|
||||||
|
}
|
||||||
|
|
||||||
|
.rodata : ALIGN(4K) {
|
||||||
|
*(.rodata)
|
||||||
|
}
|
||||||
|
|
||||||
|
.data : ALIGN(4K) {
|
||||||
|
*(.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bss : ALIGN(4K) {
|
||||||
|
*(COMMON)
|
||||||
|
*(.bss)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
135
src/Console.zig
Normal file
135
src/Console.zig
Normal file
|
|
@ -0,0 +1,135 @@
|
||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
pub fn init() Self {
|
||||||
|
var self = Self{};
|
||||||
|
self.clear();
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
const vga_width = 80;
|
||||||
|
const vga_height = 25;
|
||||||
|
const vga_size = vga_width * vga_height;
|
||||||
|
|
||||||
|
pub const ConsoleColor = 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,
|
||||||
|
};
|
||||||
|
|
||||||
|
const default_color = vgaEntryColor(ConsoleColor.lightGray, ConsoleColor.black);
|
||||||
|
|
||||||
|
column: usize = 0,
|
||||||
|
color: u8 = default_color,
|
||||||
|
buffer: [*]volatile u16 = @ptrFromInt(0xb8000),
|
||||||
|
|
||||||
|
fn vgaEntryColor(fg: ConsoleColor, bg: ConsoleColor) u8 {
|
||||||
|
return @intFromEnum(fg) | (@intFromEnum(bg) << 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vgaEntry(uc: u8, new_color: u8) u16 {
|
||||||
|
const c: u16 = new_color;
|
||||||
|
return uc | (c << 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn index(x: usize, y: usize) usize {
|
||||||
|
return y * vga_width + x;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setColor(self: *Self, fg: ConsoleColor, bg: ConsoleColor) void {
|
||||||
|
self.color = vgaEntryColor(fg, bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn resetColor(self: *Self) void {
|
||||||
|
self.color = default_color;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear(self: *Self) void {
|
||||||
|
@memset(self.buffer[0..vga_size], vgaEntry(' ', self.color));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clearRow(self: *Self, y: usize) void {
|
||||||
|
for (0..vga_width) |x| {
|
||||||
|
const i = index(x, y);
|
||||||
|
self.buffer[i] = vgaEntry(' ', self.color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn newLine(self: *Self) void {
|
||||||
|
for (1..vga_height) |y| {
|
||||||
|
for (0..vga_width) |x| {
|
||||||
|
const entry = self.getEntryAt(x, y);
|
||||||
|
self.putEntryAt(entry, x, y - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.clearRow(vga_height - 1);
|
||||||
|
self.column = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn putCharAt(self: *Self, c: u8, new_color: u8, x: usize, y: usize) void {
|
||||||
|
self.putEntryAt(vgaEntry(c, new_color), x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn putEntryAt(self: *Self, entry: u16, x: usize, y: usize) void {
|
||||||
|
const i = index(x, y);
|
||||||
|
self.buffer[i] = entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn getEntryAt(self: *Self, x: usize, y: usize) u16 {
|
||||||
|
const i = index(x, y);
|
||||||
|
return self.buffer[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn putChar(self: *Self, c: u8) void {
|
||||||
|
switch (c) {
|
||||||
|
'\n' => self.newLine(),
|
||||||
|
else => {
|
||||||
|
if (self.column >= vga_width) {
|
||||||
|
self.newLine();
|
||||||
|
}
|
||||||
|
const y = vga_height - 1;
|
||||||
|
const x = self.column;
|
||||||
|
self.putCharAt(c, self.color, x, y);
|
||||||
|
self.column += 1;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn puts(self: *Self, data: []const u8) void {
|
||||||
|
for (data) |c| {
|
||||||
|
self.putChar(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const Writer = std.io.Writer(
|
||||||
|
*Self,
|
||||||
|
error{},
|
||||||
|
callback,
|
||||||
|
);
|
||||||
|
|
||||||
|
pub fn writer(self: *Self) Writer {
|
||||||
|
return .{ .context = self };
|
||||||
|
}
|
||||||
|
|
||||||
|
fn callback(self: *Self, string: []const u8) error{}!usize {
|
||||||
|
self.puts(string);
|
||||||
|
return string.len;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn printf(self: *Self, comptime format: []const u8, args: anytype) void {
|
||||||
|
std.fmt.format(self.writer(), format, args) catch unreachable;
|
||||||
|
}
|
||||||
89
src/main.zig
Normal file
89
src/main.zig
Normal file
|
|
@ -0,0 +1,89 @@
|
||||||
|
const lazy = @import("utils/Lazy.zig").lazy;
|
||||||
|
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,
|
||||||
|
padding: u32 = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
export var mutliboot: MultibootHeader align(4) linksection(".multiboot") = .{
|
||||||
|
.flags = FLAGS,
|
||||||
|
.checksum = -(MAGIC + FLAGS),
|
||||||
|
};
|
||||||
|
|
||||||
|
var stack_bytes: [16 * 1024]u8 align(16) linksection(".bss") = undefined;
|
||||||
|
|
||||||
|
export fn _start() callconv(.Naked) noreturn {
|
||||||
|
asm volatile (
|
||||||
|
\\ movl %[stack_top], %%esp
|
||||||
|
\\ movl %%esp, %%ebp
|
||||||
|
\\ call %[kmain:P]
|
||||||
|
:
|
||||||
|
: [stack_top] "i" (@as([*]align(16) u8, @ptrCast(&stack_bytes)) + @sizeOf(@TypeOf(stack_bytes))),
|
||||||
|
[kmain] "X" (&kmain),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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!", .{});
|
||||||
|
|
||||||
|
@panic("Uh oh");
|
||||||
|
}
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
pub const panic = std.debug.FullPanic(kpanic);
|
||||||
|
|
||||||
|
fn kpanic(msg: []const u8, first_trace_addr: ?usize) noreturn {
|
||||||
|
_ = first_trace_addr;
|
||||||
|
|
||||||
|
std.log.err("PANIC: {s}", .{msg});
|
||||||
|
|
||||||
|
while (true) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const std_options = std.Options{
|
||||||
|
.log_level = .debug,
|
||||||
|
.logFn = klog,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn klog(
|
||||||
|
comptime level: std.log.Level,
|
||||||
|
comptime scope: @Type(.enum_literal),
|
||||||
|
comptime format: []const u8,
|
||||||
|
args: anytype,
|
||||||
|
) void {
|
||||||
|
const c = console.get();
|
||||||
|
|
||||||
|
const color = switch (level) {
|
||||||
|
.err => Console.ConsoleColor.lightRed,
|
||||||
|
.warn => Console.ConsoleColor.lightBrown,
|
||||||
|
.info => Console.ConsoleColor.lightBlue,
|
||||||
|
.debug => Console.ConsoleColor.lightGreen,
|
||||||
|
};
|
||||||
|
c.putChar('[');
|
||||||
|
c.setColor(color, Console.ConsoleColor.black);
|
||||||
|
c.puts(level.asText());
|
||||||
|
c.resetColor();
|
||||||
|
c.putChar(']');
|
||||||
|
|
||||||
|
c.putChar(' ');
|
||||||
|
|
||||||
|
c.puts("(" ++ @tagName(scope) ++ ")");
|
||||||
|
|
||||||
|
c.putChar(' ');
|
||||||
|
|
||||||
|
c.printf(format ++ "\n", args);
|
||||||
|
}
|
||||||
20
src/utils/Lazy.zig
Normal file
20
src/utils/Lazy.zig
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
pub fn Lazy(comptime T: type, comptime init_fn: std.meta.DeclEnum(T)) type {
|
||||||
|
return struct {
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
value: ?T = null,
|
||||||
|
|
||||||
|
pub fn get(self: *Self) *T {
|
||||||
|
return if (self.value) |*v| v else blk: {
|
||||||
|
self.value = @field(T, @tagName(init_fn))();
|
||||||
|
break :blk &self.value.?;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn lazy(comptime T: type, comptime init_fn: std.meta.DeclEnum(T)) Lazy(T, init_fn) {
|
||||||
|
return .{};
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue