hachem.wtf
aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.dockerignore10
-rw-r--r--.gitignore15
-rw-r--r--.gitmodules6
-rw-r--r--Dockerfile29
-rw-r--r--Makefile56
-rw-r--r--README.md6
-rw-r--r--boot/boot.zig22
-rw-r--r--boot/limine.conf5
-rw-r--r--boot/limine.zig27
-rw-r--r--boot/linker.ld52
-rw-r--r--build.zig46
-rw-r--r--kernel/.gitkeep0
m---------limine0
m---------revo0
14 files changed, 273 insertions, 1 deletions
diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..5c42f8f
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,10 @@
+.git
+revo
+limine
+iso_root
+zig-out
+.zig-cache
+*.iso
+*.ppm
+*.png
+*.log
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..f770585
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,15 @@
+# zig build output
+/zig-out/
+/.zig-cache/
+
+# ISO staging + image
+/iso_root/
+/*.iso
+
+# local boot scratch (screendumps, qemu logs)
+/*.ppm
+/*.png
+/*.log
+
+# clang + sanitization stuff
+/*.dSYM
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..a2e24b3
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,6 @@
+[submodule "revo"]
+ path = revo
+ url = https://github.com/hachem-wtf/revo.git
+[submodule "limine"]
+ path = limine
+ url = https://github.com/limine-bootloader/limine.git
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..7a633d3
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,29 @@
+# This is so that if something breaks, lung doesn't tell at me
+#
+# docker build -t revel .
+# docker run --rm -v "$PWD":/revel revel make run
+FROM debian:bookworm-slim
+
+ARG ZIG_VERSION=0.16.0
+ARG TARGETARCH
+ENV DEBIAN_FRONTEND=noninteractive
+
+RUN apt-get update && apt-get install -y --no-install-recommends \
+ ca-certificates curl xz-utils git make gcc \
+ xorriso qemu-system-x86 \
+ && rm -rf /var/lib/apt/lists/*
+
+RUN case "${TARGETARCH}" in \
+ amd64) ZARCH=x86_64 ;; \
+ arm64) ZARCH=aarch64 ;; \
+ *) echo "unsupported TARGETARCH: ${TARGETARCH}" >&2; exit 1 ;; \
+ esac; \
+ curl -fsSL "https://ziglang.org/download/${ZIG_VERSION}/zig-${ZARCH}-linux-${ZIG_VERSION}.tar.xz" \
+ -o /tmp/zig.tar.xz \
+ && mkdir -p /opt/zig \
+ && tar -xJf /tmp/zig.tar.xz -C /opt/zig --strip-components=1 \
+ && ln -s /opt/zig/zig /usr/local/bin/zig \
+ && rm /tmp/zig.tar.xz
+
+WORKDIR /revel
+CMD ["make", "run"]
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..6252139
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,56 @@
+# Revel — build the kernel, assemble a Limine ISO, boot it in QEMU.
+#
+# make build the ISO (default)
+# make run build and boot it headless (serial on stdout)
+# make kernel just compile the kernel ELF
+# make clean remove build output (kernel, ISO, caches)
+# make distclean also remove Limine's built host tool
+
+ZIG ?= zig
+QEMU ?= qemu-system-x86_64
+
+KERNEL := zig-out/bin/revel
+ISO := revel.iso
+
+.PHONY: all kernel iso run clean distclean
+
+all: iso
+
+kernel:
+ $(ZIG) build
+
+limine/limine:
+ $(MAKE) -C limine
+
+iso: kernel limine/limine
+ rm -rf iso_root
+ mkdir -p iso_root/boot/limine iso_root/EFI/BOOT
+ cp $(KERNEL) iso_root/boot/revel
+ cp boot/limine.conf iso_root/boot/limine/
+ cp limine/limine-bios.sys \
+ limine/limine-bios-cd.bin \
+ limine/limine-uefi-cd.bin iso_root/boot/limine/
+ cp limine/BOOTX64.EFI \
+ limine/BOOTIA32.EFI iso_root/EFI/BOOT/
+ xorriso -as mkisofs -R -r -J \
+ -b boot/limine/limine-bios-cd.bin \
+ -no-emul-boot -boot-load-size 4 -boot-info-table \
+ -hfsplus -apm-block-size 2048 \
+ --efi-boot boot/limine/limine-uefi-cd.bin \
+ -efi-boot-part --efi-boot-image --protective-msdos-label \
+ iso_root -o $(ISO)
+ ./limine/limine bios-install $(ISO)
+
+# for now this is just going to be a headless run
+# all I need this for is to check for kernel panics
+# and limine related failures.
+run: iso
+ $(QEMU) -M q35 -m 256M -cdrom $(ISO) -boot d \
+ -display none -serial stdio -no-reboot \
+ -no-shutdown
+
+clean:
+ rm -rf iso_root zig-out .zig-cache $(ISO)
+
+distclean: clean
+ rm -f limine/limine
diff --git a/README.md b/README.md
index 18d5ca9..ec7ca33 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,6 @@
# revel
-kernel made in revo
+A Unix-like kernel, written in revo!
+
+## License
+
+MIT, see [LICENSE](LICENSE).
diff --git a/boot/boot.zig b/boot/boot.zig
new file mode 100644
index 0000000..0f6c92c
--- /dev/null
+++ b/boot/boot.zig
@@ -0,0 +1,22 @@
+const std = @import("std");
+const limine = @import("limine.zig");
+
+// We need a panic handler otherwise zig won't be happy,
+// std usually formats a message through std.Io.Writer which
+// emits SSE instructions which I haven't enabled. For now
+// we just halt.
+pub const panic = std.debug.FullPanic(struct {
+ fn halt(_: []const u8, _: ?usize) noreturn {
+ while (true) asm volatile ("hlt");
+ }
+}.halt);
+
+// Check `linker.ld`
+export var base_revision: limine.BaseRevision linksection(".limine_requests") = limine.BaseRevision.init(3);
+export var requests_start: limine.RequestsStartMarker linksection(".limine_requests_start") = .{};
+export var requests_end: limine.RequestsEndMarker linksection(".limine_requests_end") = .{};
+
+// ENTRY(_start)
+export fn _start() callconv(.c) noreturn {
+ while (true) asm volatile ("hlt");
+}
diff --git a/boot/limine.conf b/boot/limine.conf
new file mode 100644
index 0000000..7398dca
--- /dev/null
+++ b/boot/limine.conf
@@ -0,0 +1,5 @@
+timeout: 0
+
+/Revel
+ protocol: limine
+ path: boot():/boot/revel
diff --git a/boot/limine.zig b/boot/limine.zig
new file mode 100644
index 0000000..e9aac9c
--- /dev/null
+++ b/boot/limine.zig
@@ -0,0 +1,27 @@
+// Limine scans the loaded image for these magic numbers,
+// BaseRevision is a handshake, essentially we ask limine
+// for rev 3, and if it supports it, limine zeros it out
+pub const BaseRevision = extern struct {
+ magic0: u64 = 0xf9562b2d5c95a6c8,
+ magic1: u64 = 0x6a7b384944536bdc,
+ revision: u64,
+
+ pub fn init(revision: u64) BaseRevision {
+ return .{ .revision = revision };
+ }
+};
+
+// Bracketing markers, they are pretty optional but when
+// we add proper limine requests, having these here comes
+// handy
+pub const RequestsStartMarker = extern struct {
+ m0: u64 = 0xf6b8f4b39de7d1ae,
+ m1: u64 = 0xfab91a6940fcb9cf,
+ m2: u64 = 0x785c6ed015d3e316,
+ m3: u64 = 0x181e920a7852b9d9,
+};
+
+pub const RequestsEndMarker = extern struct {
+ m0: u64 = 0xadc0e0531bb10d03,
+ m1: u64 = 0x9572709f31764c62,
+};
diff --git a/boot/linker.ld b/boot/linker.ld
new file mode 100644
index 0000000..e15ed10
--- /dev/null
+++ b/boot/linker.ld
@@ -0,0 +1,52 @@
+/* the higher half of the kernel link maps
+ * at the top 2 GiB is where Limine maps us. */
+
+OUTPUT_FORMAT(elf64-x86-64)
+ENTRY(_start)
+
+PHDRS
+{
+ limine_requests PT_LOAD;
+ text PT_LOAD;
+ rodata PT_LOAD;
+ data PT_LOAD;
+}
+
+SECTIONS
+{
+ . = 0xffffffff80000000;
+
+ /* The loader hunts for the magic numbers here
+ * these are referenced in `boot/` */
+ .limine_requests : {
+ KEEP(*(.limine_requests_start))
+ KEEP(*(.limine_requests))
+ KEEP(*(.limine_requests_end))
+ } :limine_requests
+
+ . = ALIGN(CONSTANT(MAXPAGESIZE));
+ .text : {
+ *(.text .text.*)
+ } :text
+
+ . = ALIGN(CONSTANT(MAXPAGESIZE));
+ .rodata : {
+ *(.rodata .rodata.*)
+ } :rodata
+
+ . = ALIGN(CONSTANT(MAXPAGESIZE));
+ .data : {
+ *(.data .data.*)
+ } :data
+
+ .bss : {
+ *(.bss .bss.*)
+ *(COMMON)
+ } :data
+
+ /* no unwind tables or note sections. */
+ /DISCARD/ : {
+ *(.eh_frame*)
+ *(.note .note.*)
+ }
+}
diff --git a/build.zig b/build.zig
new file mode 100644
index 0000000..f49eb58
--- /dev/null
+++ b/build.zig
@@ -0,0 +1,46 @@
+const std = @import("std");
+
+pub fn build(b: *std.Build) void {
+ // Default to ReleaseSafe because Debug pulls Zig's
+ // UBSan runtime and other sanitization, which needs
+ // f128/SSE ops, which i don't provide.
+ const optimize = b.option(std.builtin.OptimizeMode, "optimize", "optimize mode") orelse .ReleaseSafe;
+
+ // The kernel must NOT touch SSE/MMX/AVX until it has
+ // enabled them itself, so I strip those features and
+ // let the compiler use a soft-float ABI.
+ // `code_model = .kernel` keeps relocations valid for
+ // the higher-half load address in boot/linker.ld.
+ //
+ // In other words. Going raw baby
+ var query: std.Target.Query = .{
+ .cpu_arch = .x86_64,
+ .os_tag = .freestanding,
+ .abi = .none,
+ };
+ const Feature = std.Target.x86.Feature;
+ query.cpu_features_sub.addFeature(@intFromEnum(Feature.mmx));
+ query.cpu_features_sub.addFeature(@intFromEnum(Feature.sse));
+ query.cpu_features_sub.addFeature(@intFromEnum(Feature.sse2));
+ query.cpu_features_sub.addFeature(@intFromEnum(Feature.avx));
+ query.cpu_features_sub.addFeature(@intFromEnum(Feature.avx2));
+ query.cpu_features_add.addFeature(@intFromEnum(Feature.soft_float));
+
+ const kernel = b.addExecutable(.{
+ .name = "revel",
+ .root_module = b.createModule(.{
+ .root_source_file = b.path("boot/boot.zig"),
+ .target = b.resolveTargetQuery(query),
+ .optimize = optimize,
+ .code_model = .kernel,
+ .red_zone = false,
+ .single_threaded = true,
+ .link_libc = false,
+ }),
+ });
+ kernel.entry = .{ .symbol_name = "_start" };
+ kernel.pie = false;
+ kernel.setLinkerScript(b.path("boot/linker.ld"));
+
+ b.installArtifact(kernel);
+}
diff --git a/kernel/.gitkeep b/kernel/.gitkeep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/kernel/.gitkeep
diff --git a/limine b/limine
new file mode 160000
+Subproject 5be26a73d7b7b4d4477d18be94e1d16e615adf5
diff --git a/revo b/revo
new file mode 160000
+Subproject de1a5c8bdca6c0cc7bb60378dfd7c9e64f12dcf