summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arches.nix (renamed from crates/arches.nix)0
-rw-r--r--boards/configure.py45
-rw-r--r--boards/default.nix72
-rw-r--r--boards/qemu-virt/default.nix11
-rw-r--r--boards/qemu-virt/qemu-virt.s21
-rw-r--r--crates/default.nix3
-rw-r--r--flake.nix35
-rw-r--r--kernel/Cargo.toml24
-rw-r--r--kernel/default.nix10
-rw-r--r--kernel/src/console.rs211
-rw-r--r--nix/miri.nix5
11 files changed, 126 insertions, 311 deletions
diff --git a/crates/arches.nix b/arches.nix
index 257ad7d..257ad7d 100644
--- a/crates/arches.nix
+++ b/arches.nix
diff --git a/boards/configure.py b/boards/configure.py
new file mode 100644
index 0000000..5b01652
--- /dev/null
+++ b/boards/configure.py
@@ -0,0 +1,45 @@
+#!/usr/bin/env python3
+from argparse import ArgumentParser
+from ninja.ninja_syntax import Writer as Ninja
+from os import getenv
+from pathlib import Path
+
+
+def main():
+ arg_parser = ArgumentParser()
+ arg_parser.add_argument("arch_name")
+ arg_parser.add_argument("board_name")
+ arg_parser.add_argument("libkernel")
+ arg_parser.add_argument("srcdir")
+ args = arg_parser.parse_args()
+
+ libkernel = Path(args.libkernel).resolve() / "lib/libvernos_kernel.a"
+ srcdir = Path(args.srcdir).resolve()
+ objdir = Path("obj")
+ objdir.mkdir()
+
+ linker_script = str(srcdir / f"{args.board_name}.ld")
+
+ objs: list[str] = []
+ with open("build.ninja", "w") as f:
+ ninja = Ninja(f)
+
+ # Inherit some environment variables.
+ for var in ["AS", "ASFLAGS", "LD", "LDFLAGS"]:
+ ninja.variable(var, getenv(var))
+
+ # Add rules to assemble and link.
+ ninja.rule("as", "$AS $ASFLAGS -g -o $out $in")
+ ninja.rule("ld", f"$LD $LDFLAGS -T{linker_script} -o $out $in")
+
+ for path in srcdir.iterdir():
+ if path.suffix != ".s":
+ continue
+ obj = str(objdir / f"{path.stem}.o")
+ ninja.build(obj, "as", str(path))
+ objs.append(obj)
+ ninja.build("kernel.elf", "ld", objs + [str(libkernel)])
+
+
+if __name__ == "__main__":
+ main()
diff --git a/boards/default.nix b/boards/default.nix
index dd09255..6c8c8a9 100644
--- a/boards/default.nix
+++ b/boards/default.nix
@@ -1,33 +1,55 @@
-{ libkernel, pkgs }:
+{
+ arches,
+ libkernel,
+ nixpkgs,
+ pkgs,
+ python,
+ system,
+}:
let
- mkKernel = { name, asmFile, linkerScript }:
- pkgs.stdenvNoCC.mkDerivation {
- pname = "${libkernel.pname}-${name}";
- version = libkernel.version;
- inherit asmFile linkerScript;
+ mkKernel =
+ path:
+ let
+ args = import path;
+ arch = arches.${args.vernos-arch};
+ libkernel-arch = libkernel.${args.vernos-arch};
+ pkgs-arch = import nixpkgs {
+ inherit system;
+ crossSystem.config = arch.crossSystem;
+ };
+ in
- nativeBuildInputs = [ pkgs.stdenv.cc.bintools.bintools ];
+ pkgs-arch.stdenvNoCC.mkDerivation (
+ {
+ pname = "vernos-kernel-${args.vernos-board}";
+ version = libkernel-arch.version;
- dontUnpack = true;
- buildPhase = ''
- runHook preBuild
+ nativeBuildInputs = [
+ pkgs.ninja
+ pkgs-arch.stdenv.cc.bintools.bintools
+ python
+ ];
- riscv64-unknown-none-elf-as -g -march=rv64gc -mabi=lp64d -o asm.o \
- $asmFile
+ dontUnpack = true;
+ configurePhase = ''
+ runHook preConfigure
+ python3 ${./configure.py} ${args.vernos-arch} ${args.vernos-board} \
+ ${libkernel-arch} $src
+ runHook postConfigure
+ '';
+ installPhase = ''
+ runHook preInstall
+ install -Dt $out kernel.elf
+ runHook postInstall
+ '';
- riscv64-unknown-none-elf-ld --gc-sections -T$linkerScript -o kernel.elf \
- asm.o ${libkernel}/lib/libkernel.a
+ AS = "${arch.crossSystem}-as";
+ LD = "${arch.crossSystem}-ld";
+ }
+ // args
+ );
- runHook postBuild
- '';
- installPhase = ''
- runHook preInstall
- install -Dt $out kernel.elf
- runHook postInstall
- '';
- };
+in
-in pkgs.lib.recurseIntoAttrs {
- qemu-virt = pkgs.callPackage ./qemu-virt { inherit mkKernel; };
-}
+nixpkgs.lib.recurseIntoAttrs { qemu-virt = mkKernel ./qemu-virt; }
diff --git a/boards/qemu-virt/default.nix b/boards/qemu-virt/default.nix
index e41d924..d80d5d4 100644
--- a/boards/qemu-virt/default.nix
+++ b/boards/qemu-virt/default.nix
@@ -1,7 +1,8 @@
-{ mkKernel }:
+{
+ vernos-arch = "riscv64";
+ vernos-board = "qemu-virt";
+ src = ./.;
-mkKernel {
- name = "qemu-virt";
- asmFile = ./qemu-virt.s;
- linkerScript = ./qemu-virt.ld;
+ ASFLAGS = "-march=rv64gc -mabi=lp64d";
+ LDFLAGS = "--gc-sections";
}
diff --git a/boards/qemu-virt/qemu-virt.s b/boards/qemu-virt/qemu-virt.s
index c7e7642..0d69d4d 100644
--- a/boards/qemu-virt/qemu-virt.s
+++ b/boards/qemu-virt/qemu-virt.s
@@ -11,11 +11,6 @@ _start:
csrr tp, mhartid
bnez tp, wait_for_hart0
- ## Set up console_strict_flush.
- la t0, console_strict_flush
- la t1, CONSOLE_STRICT_FLUSH
- sd t0, (t1)
-
## Set up hart0's stack.
la sp, hart0_initial_stack_top
@@ -89,19 +84,3 @@ wait_for_hart0:
wfi
j wait_for_hart0
.size wait_for_hart0, . - wait_for_hart0
-
-.section .text
-
-.type console_strict_flush, STT_FUNC
-console_strict_flush:
- li t0, 0x10000000
-1:
- c.beqz a1, 2f
- lb t1, (a0)
- sb t1, (t0)
- addi a0, a0, 1
- addi a1, a1, -1
- j 1b
-2:
- ret
-.size console_strict_flush, . - console_strict_flush
diff --git a/crates/default.nix b/crates/default.nix
index d615e29..7204dae 100644
--- a/crates/default.nix
+++ b/crates/default.nix
@@ -1,12 +1,11 @@
{
+ arches,
fenix,
nixpkgs,
system,
}:
let
- arches = import ./arches.nix;
-
toml = builtins.fromTOML (builtins.readFile ./kernel/Cargo.toml);
mkLibKernel =
diff --git a/flake.nix b/flake.nix
index aecb62c..5990c23 100644
--- a/flake.nix
+++ b/flake.nix
@@ -23,6 +23,9 @@
pkgs = nixpkgs.legacyPackages.${system};
fenix = fenix-flake.packages.${system};
+ arches = import ./arches.nix;
+
+ python = pkgs.python3.withPackages (ps: [ ps.ninja ]);
rust-toolchain = fenix.combine (
[
fenix.stable.cargo
@@ -30,9 +33,30 @@
fenix.stable.clippy
]
++ (builtins.map ({ rust-target, ... }: fenix.targets.${rust-target}.stable.rust-std) (
- builtins.attrValues (import ./crates/arches.nix)
+ builtins.attrValues arches
))
);
+
+ packages = rec {
+ kernel = import ./boards {
+ inherit
+ arches
+ libkernel
+ nixpkgs
+ pkgs
+ python
+ system
+ ;
+ };
+ libkernel = import ./crates {
+ inherit
+ arches
+ fenix
+ nixpkgs
+ system
+ ;
+ };
+ };
in
/*
pkgsHost = import nixpkgs {
@@ -115,21 +139,16 @@
*/
devShells.default = pkgs.mkShell {
- # inputsFrom = builtins.attrValues (flake-utils.lib.flattenTree packages);
nativeBuildInputs = [
(pkgs.callPackage ./nix/miri.nix { inherit fenix; })
pkgs.cargo-watch
pkgs.qemu
+ python
rust-toolchain
- # pkgsHost.stdenv.cc.bintools.bintools
];
- # CARGO_BUILD_TARGET = "riscv64gc-unknown-none-elf";
};
- lib = import ./crates { inherit fenix nixpkgs system; };
- packages = flake-utils.lib.flattenTree {
- libkernel = import ./crates { inherit fenix nixpkgs system; };
- };
+ packages = flake-utils.lib.flattenTree packages;
}
);
}
diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml
deleted file mode 100644
index f2bb9ff..0000000
--- a/kernel/Cargo.toml
+++ /dev/null
@@ -1,24 +0,0 @@
-[package]
-name = "kernel"
-version = "0.1.0"
-edition = "2021"
-
-[lib]
-crate-type = ["staticlib"]
-
-[dependencies]
-allocator-api2 = { version = "0.2.18", default-features = false }
-bstr = { version = "1.10.0", default-features = false }
-cfg-if = { version = "1.0.0", default-features = false }
-contracts = { version = "0.6.3", default-features = false }
-either = { version = "1.13.0", default-features = false }
-log = { version = "0.4.20", default-features = false }
-spin = { version = "0.9.8", default-features = false, features = ["mutex", "use_ticket_mutex"] }
-static_assertions = { version = "1.1.0", default-features = false }
-void = { version = "1.0.2", default-features = false }
-
-[profile.release]
-codegen-units = 1
-debug = true
-lto = true
-overflow-checks = true
diff --git a/kernel/default.nix b/kernel/default.nix
deleted file mode 100644
index 0949b58..0000000
--- a/kernel/default.nix
+++ /dev/null
@@ -1,10 +0,0 @@
-{ 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;
- dontFixup = true;
-}
diff --git a/kernel/src/console.rs b/kernel/src/console.rs
deleted file mode 100644
index 1c0fe78..0000000
--- a/kernel/src/console.rs
+++ /dev/null
@@ -1,211 +0,0 @@
-//! The console subsystem, used for the kernel to log things.
-
-use crate::util::likely;
-use contracts::{ensures, invariant};
-use core::fmt::Write;
-use log::Log;
-use spin::Mutex;
-
-/// The console singleton.
-static CONSOLE: Console = Console(Mutex::new(ConsoleInner::new()));
-
-/// A function pointer that may be set by the platform-specific initialization
-/// code **before** hart0_boot is called. It must never be modified after that
-/// point.
-///
-/// If present, this function is called after every write to the console with
-/// the buffer contents, after which the console buffer is cleared.
-#[no_mangle]
-static mut CONSOLE_STRICT_FLUSH: Option<unsafe extern "C" fn(*const u8, usize)> = None;
-
-/// Initializes the console subsystem. This must be done before any logging is
-/// performed, and must
-/// only be called once.
-pub fn init() {
- log::set_logger(&CONSOLE).expect("failed to set logger");
- log::set_max_level(log::LevelFilter::Trace);
-}
-
-/// The point of interaction with the console. This is a singleton; see
-/// `CONSOLE`.
-struct Console(Mutex<ConsoleInner<4096>>);
-
-impl Log for Console {
- fn enabled(&self, _metadata: &log::Metadata) -> bool {
- true
- }
-
- fn log(&self, record: &log::Record) {
- if !self.enabled(record.metadata()) {
- return;
- }
-
- let mut inner = self.0.lock();
- let mut body = |line| {
- let level = match record.level() {
- log::Level::Error => "\x1b[1;31mERR\x1b[0m",
- log::Level::Warn => "\x1b[1;33mWRN\x1b[0m",
- log::Level::Info => "\x1b[1;36mINF\x1b[0m",
- log::Level::Debug => "\x1b[1;35mDBG\x1b[0m",
- log::Level::Trace => "TRC",
- };
- let file = record.file().unwrap_or("???");
- let args = record.args();
-
- let result = if args.as_str() == Some("") {
- // A silly convenience, but don't write the extra space if we're
- // not going to write anything anyways.
- writeln!(inner, "[{level}][{file}:{line}]")
- } else {
- writeln!(inner, "[{level}][{file}:{line}] {args}")
- };
-
- // UNWRAP: Since the fmt::Write impl for ConsoleInner has a
- // contract promising that it won't ever return an error, this
- // should be unreachable.
- result.unwrap();
- };
-
- // Some contortions to avoid running afoul of the lifetime requirements
- // of format_args...
- match record.line() {
- Some(line) => body(format_args!("{line}")),
- None => body(format_args!("???")),
- }
-
- // Check for a strict flush handler.
- //
- // SAFETY: We document the function that should be called, as well as
- // the requirement that the function pointer cannot be concurrently
- // modified.
- unsafe {
- if let Some(console_strict_flush) = CONSOLE_STRICT_FLUSH {
- let buffer = inner.buffer();
- console_strict_flush(buffer.as_ptr(), buffer.len());
- inner.clear_buffer();
- }
- }
- }
-
- fn flush(&self) {}
-}
-
-/// The internals of the console. This is put behind a lock.
-struct ConsoleInner<const BUFFER_SIZE: usize> {
- /// The buffer that gets written to. Wraps on overflow.
- buffer: [u8; BUFFER_SIZE],
-
- /// The number of bytes that have actually been written to.
- len: usize,
-
- /// A flag for whether the log buffer has overflowed since the last time it
- /// was cleared.
- has_overflowed: bool,
-}
-
-#[invariant(self.len <= BUFFER_SIZE)]
-impl<const BUFFER_SIZE: usize> ConsoleInner<BUFFER_SIZE> {
- const fn new() -> ConsoleInner<BUFFER_SIZE> {
- ConsoleInner {
- buffer: [0; BUFFER_SIZE],
- len: 0,
- has_overflowed: false,
- }
- }
-
- /// Returns a reference to the filled portion of the buffer.
- fn buffer<'a>(&'a self) -> &'a [u8] {
- &self.buffer[..self.len]
- }
-
- /// Marks the buffer as cleared.
- fn clear_buffer(&mut self) {
- self.len = 0;
- if self.has_overflowed {
- self.has_overflowed = false;
- log::warn!("console buffer overflowed");
- }
- }
-
- /// Writes bytes to the buffer, wrapping and setting the flag on overflow.
- fn write(&mut self, bytes: &[u8]) {
- // Check if there's enough room for the contents of the buffer.
- let remaining = &mut self.buffer[self.len..];
- if likely(bytes.len() <= remaining.len()) {
- // If there is, copy the whole buffer in.
- remaining[..bytes.len()].copy_from_slice(bytes);
- self.len += bytes.len();
- } else if bytes.len() >= BUFFER_SIZE {
- // If not, and the bytes to write would fill up the entire buffer,
- // just write over the whole thing. (This frees us from handling
- // this case below.)
- self.buffer
- .copy_from_slice(&bytes[bytes.len() - BUFFER_SIZE..]);
- self.len = BUFFER_SIZE;
- self.has_overflowed = true;
- } else {
- // If there wasn't enough space, but there still will be enough
- // space for some of the current contents, calculate how many bytes
- // will be kept.
- //
- // This won't overflow (or even be zero), because we tested for
- // that above.
- let bytes_to_keep = BUFFER_SIZE - bytes.len();
-
- // Copy those bytes down to the start of the buffer.
- self.buffer
- .copy_within(self.len - bytes_to_keep..self.len, 0);
-
- // Copy the new bytes to the end of the buffer.
- self.buffer[bytes_to_keep..].copy_from_slice(bytes);
-
- // Update the length and mark the buffer as having overflowed.
- self.len = BUFFER_SIZE;
- self.has_overflowed = true;
- }
- }
-}
-
-impl<const BUFFER_SIZE: usize> Write for ConsoleInner<BUFFER_SIZE> {
- #[ensures(ret.is_ok())]
- fn write_str(&mut self, s: &str) -> core::fmt::Result {
- self.write(s.as_bytes());
- Ok(())
- }
-}
-
-#[test]
-fn console_handles_overflow() {
- let mut console = ConsoleInner::<8>::new();
- assert_eq!(&console.buffer, b"\0\0\0\0\0\0\0\0");
- assert_eq!(console.len, 0);
- assert_eq!(console.has_overflowed, false);
-
- console.write(b"Hello");
- assert_eq!(&console.buffer, b"Hello\0\0\0");
- assert_eq!(console.len, 5);
- assert_eq!(console.has_overflowed, false);
-
- console.write(b", ");
- assert_eq!(&console.buffer, b"Hello, \0");
- assert_eq!(console.len, 7);
- assert_eq!(console.has_overflowed, false);
-
- console.write(b"world!");
- assert_eq!(&console.buffer, b", world!");
- assert_eq!(console.len, 8);
- assert_eq!(console.has_overflowed, true);
-}
-
-#[test]
-fn console_handles_overflow_larger_than_buffer() {
- let mut console = ConsoleInner::<8>::new();
- assert_eq!(&console.buffer, b"\0\0\0\0\0\0\0\0");
- assert_eq!(console.len, 0);
- assert_eq!(console.has_overflowed, false);
-
- console.write("Hello, world!".as_bytes());
- assert_eq!(&console.buffer, b", world!");
- assert_eq!(console.len, 8);
- assert_eq!(console.has_overflowed, true);
-}
diff --git a/nix/miri.nix b/nix/miri.nix
index 5a8c39d..73a7e81 100644
--- a/nix/miri.nix
+++ b/nix/miri.nix
@@ -12,11 +12,6 @@ pkgs.writeShellApplication {
name = "cargo-miri";
runtimeInputs = [ rust-nightly-toolchain ];
text = ''
- set -x
- # https://github.com/proptest-rs/proptest/issues/253#issuecomment-1850534278
- : "''${PROPTEST_DISABLE_FAILURE_PERSISTENCE:=true}"
- : "''${MIRIFLAGS:=-Zmiri-env-forward=PROPTEST_DISABLE_FAILURE_PERSISTENCE}"
- export PROPTEST_DISABLE_FAILURE_PERSISTENCE MIRIFLAGS
exec cargo "$@"
'';
}