diff --git a/.cargo/config.toml b/.cargo/config.toml index 4228b49..b7b016b 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -5,11 +5,18 @@ debug = true incremental = false opt-level = 0 rustflags = [ - "-Cembed-bitcode=no", - "-Crelocation-model=pie", - "-Cdebuginfo=2", - "-Zmacro-backtrace", + "-Cembed-bitcode=no", + "-Crelocation-model=pie", + "-Cdebuginfo=2", + "-Zmacro-backtrace", ] [profile.release.build-override] -opt-level=3 +opt-level = 3 + +[unstable] +build-std-features = ["compiler-builtins-mem"] +build-std = ["core", "compiler_builtins", "alloc"] + +[build] +target = "x86_64-boss-uefi.json" diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..4fee1ee --- /dev/null +++ b/flake.lock @@ -0,0 +1,100 @@ +{ + "nodes": { + "crane": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1721842668, + "narHash": "sha256-k3oiD2z2AAwBFLa4+xfU+7G5fisRXfkvrMTCJrjZzXo=", + "owner": "ipetkov", + "repo": "crane", + "rev": "529c1a0b1f29f0d78fa3086b8f6a134c71ef3aaf", + "type": "github" + }, + "original": { + "owner": "ipetkov", + "repo": "crane", + "type": "github" + } + }, + "flake-parts": { + "inputs": { + "nixpkgs-lib": "nixpkgs-lib" + }, + "locked": { + "lastModified": 1719994518, + "narHash": "sha256-pQMhCCHyQGRzdfAkdJ4cIWiw+JNuWsTX7f0ZYSyz0VY=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "9227223f6d922fee3c7b190b2cc238a99527bbb7", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1722415718, + "narHash": "sha256-5US0/pgxbMksF92k1+eOa8arJTJiPvsdZj9Dl+vJkM4=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "c3392ad349a5227f4a3464dce87bcc5046692fce", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-lib": { + "locked": { + "lastModified": 1719876945, + "narHash": "sha256-Fm2rDDs86sHy0/1jxTOKB1118Q0O3Uc7EC0iXvXKpbI=", + "type": "tarball", + "url": "https://github.com/NixOS/nixpkgs/archive/5daf0514482af3f97abaefc78a6606365c9108e2.tar.gz" + }, + "original": { + "type": "tarball", + "url": "https://github.com/NixOS/nixpkgs/archive/5daf0514482af3f97abaefc78a6606365c9108e2.tar.gz" + } + }, + "root": { + "inputs": { + "crane": "crane", + "flake-parts": "flake-parts", + "nixpkgs": "nixpkgs", + "rust-overlay": "rust-overlay" + } + }, + "rust-overlay": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1722651535, + "narHash": "sha256-2uRmNwxe3CO5h7PfvqXrRe8OplXaEdwhqOUtaF13rpU=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "56d83ca6f3c557647476f3720426a7615c22b860", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..c5f64cd --- /dev/null +++ b/flake.nix @@ -0,0 +1,132 @@ +{ + inputs = { + nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; + flake-parts.url = "github:hercules-ci/flake-parts"; + crane.url = "github:ipetkov/crane"; + crane.inputs.nixpkgs.follows = "nixpkgs"; + rust-overlay.url = "github:oxalica/rust-overlay"; + rust-overlay.inputs = { + nixpkgs.follows = "nixpkgs"; + }; + }; + outputs = + { + nixpkgs, + flake-parts, + crane, + rust-overlay, + ... + }@inputs: + flake-parts.lib.mkFlake { inherit inputs; } { + imports = [ flake-parts.flakeModules.easyOverlay ]; + systems = nixpkgs.lib.platforms.all; + perSystem = + { + pkgs, + system, + lib, + self', + ... + }: + let + platform = lib.systems.elaborate system; + inherit (if platform.isx86_64 -> platform.isDarwin then pkgs.pkgsCross.x86_64-embedded else pkgs) + OVMF + ; + toolchain = p: p.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml; + craneLib = (crane.mkLib pkgs).overrideToolchain toolchain; + buildCargoPackage = import ./nix/build-rust-app.nix { inherit craneLib lib; }; + in + { + packages = + let + extraExclude = [ + ./rust-toolchain.toml + ./nix + ./apps + ./demo + ./.github + ]; + extraInclude = [ ./src/vm/genop.tab ]; + src = lib.cleanSourceWith { + filter = ( + path: type: + (!builtins.elem path (map toString extraExclude)) + && (craneLib.filterCargoSources path type || builtins.elem path (map toString extraInclude)) + ); + src = ./.; + name = "source"; + }; + boss = buildCargoPackage { + doCheck = false; + fixBuildStd = true; + inherit src; + target = ./x86_64-boss-uefi.json; + extraArgs = { + # https://github.com/ipetkov/crane/issues/262 + dummyrs = ./nix/dummy.rs; + }; + }; + inherit (pkgs.callPackage ./nix { }) buildEmulator bosbaima buildIso; + in + { + kernel = boss.package; + inherit (boss) + audit + clippy + rustdoc + rustfmt + deps + ; + emulator = buildEmulator { + src = lib.getExe' self'.packages.kernel "boss.efi"; + magic-offset = "0x141000000"; + reloc-offset = "0x141001000"; + }; + bosbaima = bosbaima.override { + bossApps = + let + apps = self'.legacyPackages.bossApps; + in + [ apps.base ]; + }; + iso = buildIso { + inherit (self'.packages) bosbaima; + boss-emulator = self'.packages.emulator; + }; + qemu = pkgs.writeShellApplication { + name = "qemu-boss"; + runtimeInputs = [ pkgs.qemu ]; + text = '' + qemu-system-x86_64 \ + -drive if=pflash,format=raw,readonly=on,file=${lib.escapeShellArg OVMF.fd}/FV/OVMF.fd \ + -device ahci,id=ahci \ + -device ide-hd,drive=disk,bus=ahci.0 \ + -drive if=none,id=disk,format=raw,snapshot=on,file=${lib.escapeShellArg self'.packages.iso} \ + -m 128 \ + -smp 1,sockets=1,cores=1,threads=1 \ + -boot menu=off,splash-time=0 \ + -serial stdio + ''; + }; + }; + legacyPackages = { + inherit (pkgs.callPackage ./nix/boss-lib { }) buildBossApp; + bossApps = { + base = self'.legacyPackages.buildBossApp { + src = ./apps/base; + pname = "base"; + version = "0.1.0"; + }; + }; + }; + + apps.default.program = self'.packages.qemu; + + _module.args.pkgs = import nixpkgs { + inherit system; + overlays = [ (import rust-overlay) ]; + }; + }; + }; +} diff --git a/justfile b/justfile index 9b6aea2..bcb9670 100644 --- a/justfile +++ b/justfile @@ -16,7 +16,7 @@ bosbaima: profile := "release" # "dev" or "release" profile_dir := "release" # "debug" or "release" features := "," -cargo_flags := "--target x86_64-boss-uefi.json -Zbuild-std=core,compiler_builtins,alloc -Zbuild-std-features=compiler-builtins-mem --profile " + profile + " --features " + features +cargo_flags := "--profile " + profile + " --features " + features magic_section_offset := "0x141000000" reloc_section_offset := "0x141001000" # EFI executable diff --git a/nix/bosbaima.nix b/nix/bosbaima.nix new file mode 100644 index 0000000..34e071f --- /dev/null +++ b/nix/bosbaima.nix @@ -0,0 +1,28 @@ +{ + stdenvNoCC, + lib, + bossApps ? [ ], +}: +stdenvNoCC.mkDerivation { + pname = "bosbaima"; + version = "0.1.0"; + + dontUnpack = true; + dontBuild = true; + + installPhase = + '' + mkdir -p "$out" + '' + + lib.concatLines ( + map ( + app: + # sh + '' + cp ${lib.escapeShellArg app.bop} "$out"/${lib.escapeShellArg app.app-name}.bop + '') bossApps + ); + passthru = { + apps = bossApps; + }; +} diff --git a/nix/boss-lib/build-boss-app.nix b/nix/boss-lib/build-boss-app.nix new file mode 100644 index 0000000..fc25a97 --- /dev/null +++ b/nix/boss-lib/build-boss-app.nix @@ -0,0 +1,54 @@ +{ + erlang_27, + stdenv, + etfify, + lib, +}: +{ + pname, + version, + src, + app-name ? pname, + ... +}@args: +stdenv.mkDerivation ( + { + inherit pname version src; + outputs = [ + "out" + "bop" + ]; + nativeBuildInputs = [ + erlang_27 + etfify + ]; + buildPhase = '' + runHook preBuild + + mkdir build + find src/ -name '*.erl' -exec erlc -b beam -o build/ '{}' + + etfify src/${lib.escapeShellArg app-name}.app.src app + + runHook postBuild + ''; + installPhase = '' + runHook preInstall + + mv build "$out" + mv app "$out"/ + + tar --create --file="$bop" --directory="$out" --transform='s%\.%ebin%' . + + runHook postInstall + ''; + passthru = { + inherit app-name; + }; + } + // builtins.removeAttrs args [ + "pname" + "version" + "src" + "app-name" + ] +) diff --git a/nix/boss-lib/default.nix b/nix/boss-lib/default.nix new file mode 100644 index 0000000..0b509b4 --- /dev/null +++ b/nix/boss-lib/default.nix @@ -0,0 +1,7 @@ +{ callPackage }: +let + etfify = callPackage ./etfify.nix { }; +in +{ + buildBossApp = callPackage ./build-boss-app.nix { inherit etfify; }; +} diff --git a/nix/boss-lib/etfify.nix b/nix/boss-lib/etfify.nix new file mode 100644 index 0000000..1c8097a --- /dev/null +++ b/nix/boss-lib/etfify.nix @@ -0,0 +1,22 @@ +{ erlang_27, stdenvNoCC }: +stdenvNoCC.mkDerivation { + pname = "etfify"; + version = "0.1.0"; + src = ../../apps/etfify; + dontUnpack = true; + dontPatch = true; + dontConfigure = true; + dontBuild = true; + + buildInputs = [ erlang_27 ]; + installPhase = '' + runHook preInstall + + mkdir -p "$out/bin" + install -m 0555 "$src" "$out/bin/etfify" + + runHook postInstall + ''; + + meta.mainProgram = "etfify"; +} diff --git a/nix/build-rust-app.nix b/nix/build-rust-app.nix new file mode 100644 index 0000000..dfb4c8c --- /dev/null +++ b/nix/build-rust-app.nix @@ -0,0 +1,45 @@ +{ craneLib, lib }: +{ + src, + doCheck ? true, + target ? null, + extraArgs ? { }, + fixBuildStd ? false, +}: +let + inherit (builtins) mapAttrs; + commonArgs = + { + inherit src; + inherit doCheck; + env.CARGO_BUILD_TARGET = lib.mapNullable toString target; + passthru = { + inherit craneLib; + }; + } + // lib.optionalAttrs fixBuildStd { + # https://github.com/ipetkov/crane/issues/285 + cargoVendorDir = craneLib.vendorMultipleCargoDeps { + inherit (craneLib.findCargoFiles src) cargoConfigs; + cargoLockList = [ + "${src}/Cargo.lock" + "${craneLib.rustc.passthru.availableComponents.rust-src}/lib/rustlib/src/rust/Cargo.lock" + ]; + }; + } + // extraArgs; + cargoArtifacts = craneLib.buildDepsOnly commonArgs; + totalArgs = commonArgs // { + inherit cargoArtifacts; + }; +in +{ + deps = cargoArtifacts; +} +// mapAttrs (_: f: f totalArgs) { + package = craneLib.buildPackage; + clippy = craneLib.cargoClippy; + rustfmt = craneLib.cargoFmt; + rustdoc = craneLib.cargoDoc; + audit = craneLib.cargoAudit; +} diff --git a/nix/default.nix b/nix/default.nix new file mode 100644 index 0000000..2708e3c --- /dev/null +++ b/nix/default.nix @@ -0,0 +1,7 @@ +{ callPackage }: +{ + boss-lib = callPackage ./boss-lib { }; + bosbaima = callPackage ./bosbaima.nix { }; + buildEmulator = callPackage ./emulator.nix { }; + buildIso = callPackage ./iso.nix; +} diff --git a/nix/dummy.rs b/nix/dummy.rs new file mode 100644 index 0000000..22a8f51 --- /dev/null +++ b/nix/dummy.rs @@ -0,0 +1,10 @@ +#![allow(unused)] +#![cfg_attr(any(target_os = "none", target_os = "uefi"), no_std, no_main)] + +#[cfg_attr(any(target_os = "none", target_os = "uefi"), panic_handler)] +fn panic(_info: &::core::panic::PanicInfo<'_>) -> ! { + loop {} +} + +#[cfg_attr(any(target_os = "none", target_os = "uefi"), export_name = "efi_main")] +fn main() {} diff --git a/nix/emulator.nix b/nix/emulator.nix new file mode 100644 index 0000000..0259b98 --- /dev/null +++ b/nix/emulator.nix @@ -0,0 +1,41 @@ +{ + runCommand, + lib, + writeText, + openssl, + binutils-unwrapped-all-targets, +}: +{ + src, + magic-offset, + reloc-offset, +}: +let + relocMagic = runCommand "boss-reloc-magic.bin" { } '' + ${lib.getExe openssl} shake256 -xoflen 1024 -binary <${lib.escapeShellArg src} > rand + { + cat rand rand + ${lib.getExe' binutils-unwrapped-all-targets "objdump"} -hj.data ${lib.escapeShellArg src} \ + | tail -n+6 | head -n1 + printf '\0' + } > "$out" + ''; +in +runCommand "boss-emulator" + { + passthru = { + inherit + src + magic-offset + reloc-offset + relocMagic + ; + }; + } + '' + ${lib.getExe' binutils-unwrapped-all-targets "objcopy"} ${lib.escapeShellArg src} \ + --add-section .reloc-magic=${lib.escapeShellArg relocMagic} \ + --change-section-address .reloc-magic=${toString magic-offset} \ + --change-section-address .reloc=${toString reloc-offset} \ + "$out" + '' diff --git a/nix/iso.nix b/nix/iso.nix new file mode 100644 index 0000000..99e595f --- /dev/null +++ b/nix/iso.nix @@ -0,0 +1,37 @@ +{ + bosbaima, + boss-emulator, + mtools, + runCommand, + lib, + gnutar, +}: +let + size-mb = 32; + size = 65536; + bosbaima-tar = runCommand "bossbaima.tar" { } '' + find ${lib.escapeShellArg bosbaima} -maxdepth 1 -printf '%P\0' \ + | ${lib.getExe gnutar} \ + --create \ + --file="$out" \ + --directory=${lib.escapeShellArg bosbaima} \ + --null \ + --files-from=- \ + ''; +in +runCommand "boss.iso" + { + nativeBuildInputs = [ mtools ]; + passthru = { + inherit bosbaima-tar; + }; + } + '' + dd if=/dev/zero of="$out" bs=1M count=${toString size-mb} + mformat -i "$out" -T ${toString size} + mmd -i "$out" ::/EFI + mmd -i "$out" ::/EFI/BOOT + mmd -i "$out" ::/BOSS + mcopy -i "$out" ${lib.escapeShellArg boss-emulator} ::/EFI/BOOT/BOOTX64.EFI + mcopy -i "$out" ${lib.escapeShellArg bosbaima-tar} ::/BOSS/BOSBAIMA.TAR + '' diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 010a4c2..b486431 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,4 @@ [toolchain] channel = "nightly-2024-07-25" targets = [ "x86_64-unknown-uefi" ] +components = [ "rust-src" ]