Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
vinymeuh committed Jan 24, 2025
0 parents commit 7d62868
Show file tree
Hide file tree
Showing 10 changed files with 402 additions and 0 deletions.
32 changes: 32 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
name: mooOS

on:
push:
paths:
- ".github/workflows/ci.yml"
- "**.zig"
- "**.s"
- "**.ld"
schedule:
- cron: "0 2 * * 1"
workflow_dispatch:

jobs:
build:
strategy:
matrix:
os: [ubuntu-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install Zig compiler
uses: korandoru/setup-zig@v1
with:
zig-version: master
- name: Print Zig version
run: zig version
- name: Build
run: zig build --summary all
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
zig-out
.zig-cache
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# mooOS 🐮

A toy Unix-like operating system written in Zig.

[![Static Badge](https://img.shields.io/badge/nightly-orange?logo=Zig&logoColor=Orange&label=Zig&labelColor=Orange)](https://ziglang.org/download/)
[![](https://tokei.rs/b1/github/vinymeuh/mooOS)](https://github.com/vinymeuh/mooOS)

## 🎯 Current goal

**mooOS** is a learning project aimed at creating a simple operating systems that runs on **QEMU**, targeting a **32-bit RISC-V** architecture.

To keep things simple:

* It is designed for **single processor**.
* It assumes **128 MB** of RAM.

My first milestone is to reach **user mode** and launch a basic shell.

## 💪 Features implemented so far

* [x] Boot and switch to Zig
* [x] Write messages to consoles with OpenSBI
* [x] Kernel panic handler

## 📚 References and inspirations

* [xv6 RISC-V](https://github.com/mit-pdos/xv6-riscv)
* [zesty-core](https://github.com/eastonman/zesty-core)
* [Operating System in 1000 Lines of Code](https://operating-system-in-1000-lines.vercel.app/en/)
33 changes: 33 additions & 0 deletions build.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
const std = @import("std");

pub fn build(b: *std.Build) !void {
const kernel = b.addExecutable(.{
.name = "kernel.elf",
.root_source_file = b.path("kernel/main.zig"),
.optimize = .Debug, // can not change because of boot.s ?
.target = b.resolveTargetQuery(.{
.cpu_arch = .riscv32,
.os_tag = .freestanding,
.abi = .none,
.cpu_features_add = std.Target.riscv.featureSet(&.{.zihintpause}),
}),
.strip = false,
});
kernel.addAssemblyFile(b.path("kernel/boot.s"));
kernel.setLinkerScript(b.path("kernel/linker_rv32.ld"));
b.installArtifact(kernel);

const qemu_cmd = b.addSystemCommand(&.{
// zig fmt: off
"qemu-system-riscv32", "-machine", "virt",
"-kernel", "zig-out/bin/kernel.elf",
"-m", "size=128M",
"-nographic",
"-no-shutdown", "-no-reboot",
// zig fmt: on
});
qemu_cmd.step.dependOn(b.getInstallStep());

const run_step = b.step("run", "Run the kernel in qemu");
run_step.dependOn(&qemu_cmd.step);
}
21 changes: 21 additions & 0 deletions kernel/boot.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
.global _start

.section .text.boot
_start:
li a7, 0x4442434E
li a6, 0x00
li a0, 11
lla a1, boot_msg
li a2, 0
ecall
la sp, boot_stack_top // set up stack pointer (the stack grows downwards)
j kmain // jump to Zig

.section .rodata
boot_msg:
.string "Booting...\n"

.section .bss.stack
boot_stack:
.space 1 * 1024
boot_stack_top:
75 changes: 75 additions & 0 deletions kernel/console.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
const std = @import("std");
const sbi = @import("sbi.zig");

pub const Console = struct {
pub fn init() Console {
return .{};
}

pub fn write(con: *Console, comptime fmt: []const u8, args: anytype) void {
const ArgsType = @TypeOf(args);
const args_type_info = @typeInfo(ArgsType);
if (args_type_info != .@"struct") {
@compileError("expected tuple or struct argument, found " ++ @typeName(ArgsType));
}

const args_fields = args_type_info.@"struct".fields.len;
comptime var args_index = 0;

comptime var i = 0;
inline while (i < fmt.len) : (i += 1) {
switch (fmt[i]) {
'{' => {
if (i >= fmt.len - 2 or fmt[i + 2] != '}') {
@compileError("missing closing }");
}
if (args_index == args_fields) {
@compileError("too few arguments for format '" ++ fmt ++ "'");
}
const arg_field = args_type_info.@"struct".fields[args_index];
const arg_value = @field(args, arg_field.name);
switch (fmt[i + 1]) {
's' => {
con.write_bytes(arg_value);
},
'd' => {
var b: [32]u8 = undefined;
const arg_value_d = std.fmt.bufPrint(&b, "{d}", .{arg_value}) catch {
unreachable;
};
con.write_bytes(arg_value_d);
},
else => @compileError("unsupported format specifier"),
}
i += 2;
args_index += 1;
},
else => con.write_byte(fmt[i]),
}
}

if (args_index != args_fields) {
@compileError("unused argument in '" ++ fmt ++ "'");
}
}

pub inline fn write_bytes(con: *Console, bytes: []const u8) void {
_ = con;
var n: usize = bytes.len;
var s: usize = 0;
while (n > 0) {
const w = sbi.sbi_debug_console_write(bytes[s..]) catch {
return;
};
s += w;
n -= w;
}
}

pub inline fn write_byte(con: *Console, byte: u8) void {
_ = con;
_ = sbi.sbi_debug_console_write_byte(byte) catch {
return;
};
}
};
35 changes: 35 additions & 0 deletions kernel/linker_rv32.ld
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/* OUTPUT_ARCH(riscv) */
ENTRY(_start)

/* OpenSBI transfer control to this address */
BASE_ADDRESS = 0x80200000;

SECTIONS
{
. = BASE_ADDRESS;

.text : {
PROVIDE(__kernel_text_start = .);
KEEP(*(.text.boot));
*(.text .text.*);
PROVIDE(__kernel_text_end = .);
}

.rodata : ALIGN(4) {
*(.rodata .rodata.*);
}

.data : ALIGN(4) {
*(.data .data.*);
}

.bss : ALIGN(4) {
*(.bss .bss.* .sbss .sbss.*);
}

. = ALIGN(4);
. += 128 * 1024; /* 128KB */
__stack_top = .;

PROVIDE(__kernel_size_of_text = SIZEOF(.text));
}
27 changes: 27 additions & 0 deletions kernel/main.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
const std = @import("std");

const riscv = @import("riscv.zig");
const Console = @import("console.zig").Console;

var console: Console = undefined;

// we jump here in supervisor mode
export fn kmain(boot_hartid: usize, dtb_addr: usize) noreturn {
_ = boot_hartid;
_ = dtb_addr;

console = Console.init();
console.write("mooOS version {s}\n", .{"0.0.0"});

while (true) {
riscv.wfi();
}
}

pub fn panic(msg: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn {
@branchHint(.cold);
console.write("KERNEL PANIC: {s}\n", .{msg});
while (true) {
riscv.wfi();
}
}
5 changes: 5 additions & 0 deletions kernel/riscv.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// RISC-V ISA related code

pub inline fn wfi() void {
asm volatile ("wfi");
}
Loading

0 comments on commit 7d62868

Please sign in to comment.