summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathan Ringo <nathan@remexre.com>2024-02-24 22:03:49 -0600
committerNathan Ringo <nathan@remexre.com>2024-02-24 22:03:49 -0600
commitc8de43bf43242c4ebac3d0ecb8e7951fe2371506 (patch)
treeb438bb1b47b41241702f5783fb7ec3326a4e8ab7
Initial commit
-rw-r--r--.envrc1
-rw-r--r--.gitignore7
-rw-r--r--boards/default.nix33
-rw-r--r--boards/qemu-virt/default.nix7
-rw-r--r--boards/qemu-virt/qemu-virt.ld29
-rw-r--r--boards/qemu-virt/qemu-virt.s23
-rw-r--r--flake.lock97
-rw-r--r--flake.nix103
-rw-r--r--kernel/Cargo.lock7
-rw-r--r--kernel/Cargo.toml12
-rw-r--r--kernel/default.nix9
-rw-r--r--kernel/src/lib.rs16
-rw-r--r--kernel/src/panic.rs12
13 files changed, 356 insertions, 0 deletions
diff --git a/.envrc b/.envrc
new file mode 100644
index 0000000..3550a30
--- /dev/null
+++ b/.envrc
@@ -0,0 +1 @@
+use flake
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..808c7a0
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,7 @@
+*~
+
+target/
+
+.direnv/
+result
+result-*
diff --git a/boards/default.nix b/boards/default.nix
new file mode 100644
index 0000000..dd09255
--- /dev/null
+++ b/boards/default.nix
@@ -0,0 +1,33 @@
+{ libkernel, pkgs }:
+
+let
+ mkKernel = { name, asmFile, linkerScript }:
+ pkgs.stdenvNoCC.mkDerivation {
+ pname = "${libkernel.pname}-${name}";
+ version = libkernel.version;
+ inherit asmFile linkerScript;
+
+ nativeBuildInputs = [ pkgs.stdenv.cc.bintools.bintools ];
+
+ dontUnpack = true;
+ buildPhase = ''
+ runHook preBuild
+
+ riscv64-unknown-none-elf-as -g -march=rv64gc -mabi=lp64d -o asm.o \
+ $asmFile
+
+ riscv64-unknown-none-elf-ld --gc-sections -T$linkerScript -o kernel.elf \
+ asm.o ${libkernel}/lib/libkernel.a
+
+ runHook postBuild
+ '';
+ installPhase = ''
+ runHook preInstall
+ install -Dt $out kernel.elf
+ runHook postInstall
+ '';
+ };
+
+in pkgs.lib.recurseIntoAttrs {
+ qemu-virt = pkgs.callPackage ./qemu-virt { inherit mkKernel; };
+}
diff --git a/boards/qemu-virt/default.nix b/boards/qemu-virt/default.nix
new file mode 100644
index 0000000..e41d924
--- /dev/null
+++ b/boards/qemu-virt/default.nix
@@ -0,0 +1,7 @@
+{ mkKernel }:
+
+mkKernel {
+ name = "qemu-virt";
+ asmFile = ./qemu-virt.s;
+ linkerScript = ./qemu-virt.ld;
+}
diff --git a/boards/qemu-virt/qemu-virt.ld b/boards/qemu-virt/qemu-virt.ld
new file mode 100644
index 0000000..9673637
--- /dev/null
+++ b/boards/qemu-virt/qemu-virt.ld
@@ -0,0 +1,29 @@
+OUTPUT("elf64-littleriscv")
+ENTRY(_start)
+
+SECTIONS {
+ . = 0x80000000;
+ .text : {
+ *(.text.start)
+ *(.text .text.*)
+ . = ALIGN(0x1000);
+ }
+
+ .rodata : {
+ *(.rodata)
+ . = ALIGN(0x1000);
+ }
+
+ .data : {
+ *(.data)
+ }
+ .bss : {
+ *(.bss)
+ . = ALIGN(0x1000);
+ }
+
+ .hart0_initial_stack : {
+ . += 0x1000;
+ PROVIDE(hart0_initial_stack_top = .);
+ }
+}
diff --git a/boards/qemu-virt/qemu-virt.s b/boards/qemu-virt/qemu-virt.s
new file mode 100644
index 0000000..4813b57
--- /dev/null
+++ b/boards/qemu-virt/qemu-virt.s
@@ -0,0 +1,23 @@
+.section .text.start
+
+.extern main
+
+.global _start
+_start:
+ # Have harts other than 0 spin until hart0 wakes them up.
+ csrr a0, mhartid
+ c.bnez a0, wait_for_hart0
+
+ # Set up hart0's stack.
+ la sp, hart0_initial_stack_top
+ call hart0_boot
+
+ # Fall through to a spin loop.
+halt:
+ j halt
+
+.section .text
+
+wait_for_hart0:
+ # TODO
+ j halt
diff --git a/flake.lock b/flake.lock
new file mode 100644
index 0000000..25658c0
--- /dev/null
+++ b/flake.lock
@@ -0,0 +1,97 @@
+{
+ "nodes": {
+ "fenix-flake": {
+ "inputs": {
+ "nixpkgs": [
+ "nixpkgs"
+ ],
+ "rust-analyzer-src": "rust-analyzer-src"
+ },
+ "locked": {
+ "lastModified": 1708755599,
+ "narHash": "sha256-4++tH/nYmYXRjUOA2hKSAWLenWc4vc6GhARrZJ+uPNA=",
+ "owner": "nix-community",
+ "repo": "fenix",
+ "rev": "a941fe943bd7c4c683d8aa8e1a3a1d0595516051",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nix-community",
+ "repo": "fenix",
+ "type": "github"
+ }
+ },
+ "flake-utils": {
+ "inputs": {
+ "systems": "systems"
+ },
+ "locked": {
+ "lastModified": 1705309234,
+ "narHash": "sha256-uNRRNRKmJyCRC/8y1RqBkqWBLM034y4qN7EprSdmgyA=",
+ "owner": "numtide",
+ "repo": "flake-utils",
+ "rev": "1ef2e671c3b0c19053962c07dbda38332dcebf26",
+ "type": "github"
+ },
+ "original": {
+ "id": "flake-utils",
+ "type": "indirect"
+ }
+ },
+ "nixpkgs": {
+ "locked": {
+ "lastModified": 1701539137,
+ "narHash": "sha256-nVO/5QYpf1GwjvtpXhyxx5M3U/WN0MwBro4Lsk+9mL0=",
+ "owner": "NixOS",
+ "repo": "nixpkgs",
+ "rev": "933d7dc155096e7575d207be6fb7792bc9f34f6d",
+ "type": "github"
+ },
+ "original": {
+ "id": "nixpkgs",
+ "type": "indirect"
+ }
+ },
+ "root": {
+ "inputs": {
+ "fenix-flake": "fenix-flake",
+ "flake-utils": "flake-utils",
+ "nixpkgs": "nixpkgs"
+ }
+ },
+ "rust-analyzer-src": {
+ "flake": false,
+ "locked": {
+ "lastModified": 1708720753,
+ "narHash": "sha256-yBKJlyR4rYE+8/9pMSqF1vAn33YHAquL2XK0gqbRq40=",
+ "owner": "rust-lang",
+ "repo": "rust-analyzer",
+ "rev": "03b3cb6be9f21c082f4206b35c7fe7f291c94eaa",
+ "type": "github"
+ },
+ "original": {
+ "owner": "rust-lang",
+ "ref": "nightly",
+ "repo": "rust-analyzer",
+ "type": "github"
+ }
+ },
+ "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
+}
diff --git a/flake.nix b/flake.nix
new file mode 100644
index 0000000..9e812b8
--- /dev/null
+++ b/flake.nix
@@ -0,0 +1,103 @@
+{
+ inputs = {
+ fenix-flake = {
+ url = "github:nix-community/fenix";
+ inputs.nixpkgs.follows = "nixpkgs";
+ };
+ };
+ outputs = { self, fenix-flake, flake-utils, nixpkgs }:
+ flake-utils.lib.eachSystem [ "aarch64-linux" "x86_64-linux" ] (system:
+ let
+ pkgsBuild = nixpkgs.legacyPackages.${system};
+ pkgsHost = import nixpkgs {
+ inherit system;
+ crossSystem.config = "riscv64-unknown-none-elf";
+ };
+ fenix = fenix-flake.packages.${system};
+
+ toolchain = fenix.combine [
+ fenix.stable.cargo
+ fenix.stable.rustc
+ fenix.stable.clippy
+ fenix.targets.riscv64gc-unknown-none-elf.stable.rust-std
+ ];
+ rust = pkgsHost.makeRustPlatform {
+ cargo = toolchain;
+ rustc = toolchain;
+ };
+
+ packages = rec {
+ boards = import ./boards {
+ inherit libkernel;
+ pkgs = pkgsHost;
+ };
+ libkernel = pkgsBuild.callPackage ./kernel { inherit rust; };
+ };
+ run-vm = pkgsBuild.writeShellApplication {
+ name = "run-vm";
+
+ runtimeInputs = [ pkgsBuild.qemu ];
+
+ text = ''
+ set -x
+ qemu-system-riscv64 \
+ -machine virt \
+ -m 1G \
+ -nographic \
+ -bios none \
+ -kernel ${packages.boards.qemu-virt}/kernel.elf \
+ "$@"
+ '';
+ };
+ in {
+ apps = {
+ default = {
+ type = "app";
+ program = pkgsBuild.lib.getExe run-vm;
+ };
+
+ debug = {
+ type = "app";
+ program = pkgsBuild.lib.getExe (pkgsBuild.writeShellApplication {
+ name = "run-vm-debug";
+ runtimeInputs = [ run-vm ];
+ text = ''
+ port=$(( 1000 * ("$(id -u)" - 990) ))
+ run-vm -gdb tcp::$port -S "$@"
+ '';
+ });
+ };
+
+ gdb = {
+ type = "app";
+ program = pkgsBuild.lib.getExe (pkgsBuild.writeShellApplication {
+ name = "gdb";
+ runtimeInputs = [ toolchain ];
+ text = ''
+ port=$(( 1000 * ("$(id -u)" - 990) ))
+ rust-gdb ${packages.boards.qemu-virt}/kernel.elf \
+ -ex "target remote 127.0.0.1:$port" \
+ -ex "set riscv use-compressed-breakpoints yes" \
+ -ex "layout src" \
+ -ex "focus cmd" \
+ -ex "tbreak hart0_boot" \
+ -ex "c"
+ '';
+ });
+ };
+ };
+
+ devShells.default = pkgsBuild.mkShell {
+ inputsFrom =
+ builtins.attrValues (flake-utils.lib.flattenTree packages);
+ nativeBuildInputs = [
+ pkgsBuild.cargo-watch
+ pkgsBuild.qemu
+ pkgsHost.stdenv.cc.bintools.bintools
+ ];
+ CARGO_BUILD_TARGET = "riscv64gc-unknown-none-elf";
+ };
+
+ packages = flake-utils.lib.flattenTree packages;
+ });
+}
diff --git a/kernel/Cargo.lock b/kernel/Cargo.lock
new file mode 100644
index 0000000..0dd1539
--- /dev/null
+++ b/kernel/Cargo.lock
@@ -0,0 +1,7 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "kernel"
+version = "0.1.0"
diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml
new file mode 100644
index 0000000..cef382e
--- /dev/null
+++ b/kernel/Cargo.toml
@@ -0,0 +1,12 @@
+[package]
+name = "kernel"
+version = "0.1.0"
+edition = "2021"
+
+[lib]
+crate-type = ["staticlib"]
+
+[dependencies]
+
+[profile.release]
+debug = true
diff --git a/kernel/default.nix b/kernel/default.nix
new file mode 100644
index 0000000..46352fb
--- /dev/null
+++ b/kernel/default.nix
@@ -0,0 +1,9 @@
+{ rust }:
+
+let toml = builtins.fromTOML (builtins.readFile ./Cargo.toml);
+in rust.buildRustPackage {
+ pname = toml.package.name;
+ version = toml.package.version;
+ src = ./.;
+ cargoLock.lockFile = ./Cargo.lock;
+}
diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs
new file mode 100644
index 0000000..bd5a19f
--- /dev/null
+++ b/kernel/src/lib.rs
@@ -0,0 +1,16 @@
+#![no_std]
+
+mod panic;
+
+/// The entrypoint to the kernel. This should be executed by hart0 alone. It performs some early
+/// boot tasks, then wakes up any other harts.
+#[no_mangle]
+pub extern "C" fn hart0_boot() {
+ for byte in "Hello, world!\n".bytes() {
+ unsafe {
+ core::ptr::write_volatile(0x10000000 as *mut u8, byte);
+ }
+ }
+
+ todo!()
+}
diff --git a/kernel/src/panic.rs b/kernel/src/panic.rs
new file mode 100644
index 0000000..ed6e5d4
--- /dev/null
+++ b/kernel/src/panic.rs
@@ -0,0 +1,12 @@
+use core::panic::PanicInfo;
+
+#[panic_handler]
+fn panic(_info: &PanicInfo) -> ! {
+ loop {
+ for byte in "panic\n".bytes() {
+ unsafe {
+ core::ptr::write_volatile(0x10000000 as *mut u8, byte);
+ }
+ }
+ }
+}