From 30d28c323e1e75fd62e1081d1734180a81f4de75 Mon Sep 17 00:00:00 2001 From: Douglas Reis Date: Tue, 2 Jun 2026 10:57:41 +0100 Subject: [PATCH 1/2] nix: Add stdenv with the toolchain to build cheriLinux Signed-off-by: Douglas Reis --- flake.lock | 6 +- flake.nix | 30 ++++-- nix/CrossToolchain.cmake.in | 67 ++++++++++++ nix/cheri_toolchain.nix | 209 ++++++++++++++++++++++++++++++++++++ sw/cmake/uboot.cmake | 35 +++++- 5 files changed, 335 insertions(+), 12 deletions(-) create mode 100644 nix/CrossToolchain.cmake.in create mode 100644 nix/cheri_toolchain.nix diff --git a/flake.lock b/flake.lock index d57a66a94..29934e80a 100644 --- a/flake.lock +++ b/flake.lock @@ -88,11 +88,11 @@ "nixpkgs": "nixpkgs_2" }, "locked": { - "lastModified": 1780410653, - "narHash": "sha256-GgjcPoL9ZDuasunwIP0I9JTkP2oGvoZ93Vzwbwz1ldI=", + "lastModified": 1780500542, + "narHash": "sha256-XKbtr82IfB5RXhBzWgsTnuZcS230Lq9NdFE13IM/Zi8=", "owner": "lowRISC", "repo": "lowrisc-nix", - "rev": "560d419c61cb216001f05db14ac64a310b64e4af", + "rev": "c134ded39dab6c6dc15ad4675a446269c12756ff", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 4c5f4e43f..556284dd0 100644 --- a/flake.nix +++ b/flake.nix @@ -71,13 +71,12 @@ llvm = lrPkgs.llvm_cheri; }; ftditool-cli = inputs.ftditool.packages.${system}.default; - + cheri-toolchain = pkgs.callPackage ./nix/cheri_toolchain.nix {inherit (lrPkgs) llvm_cheri;}; commonPackages = with pkgs; [ bison cmake flex gnumake - screen picocom gtkwave openfpgaloader @@ -89,17 +88,30 @@ srecord d2 dtc + autoconf + automake + bc + bmake + byacc + libarchive + libarchive.dev + libelf + libtool + pkg-config + zlib + zlib.dev ]; in { formatter = pkgs.alejandra; devShells = rec { - default = cheri; - cheri = pkgs.mkShell { - name = "mocha-cheri"; + default = baremetal; + baremetal = pkgs.mkShell.override {stdenv = cheri-toolchain.cheriStdenv;} { + name = "baremetal"; + strictDeps = true; + hardeningDisable = [ "all" ]; nativeBuildInputs = commonPackages ++ (with lrPkgs; [ - llvm_cheri verilator_5_040 ]); buildInputs = with pkgs; [libelf zlib]; @@ -108,6 +120,12 @@ UV_PYTHON_DOWNLOADS = "never"; # Force uv to use nixpkgs Python interpreter UV_PYTHON = pythonSet.python.interpreter; + + HOSTCC = "${pkgs.llvmPackages_21.clang}/bin/clang"; + HOSTCXX = "${pkgs.llvmPackages_21.clang}/bin/clang++"; + HOSTLD = "${pkgs.llvmPackages_21.lld}/bin/ld.lld"; + LLVM = "1"; + ARCH = "riscv"; }; }; }; diff --git a/nix/CrossToolchain.cmake.in b/nix/CrossToolchain.cmake.in new file mode 100644 index 000000000..19a981357 --- /dev/null +++ b/nix/CrossToolchain.cmake.in @@ -0,0 +1,67 @@ +# Copyright lowRISC contributors. +# +# SPDX-License-Identifier: MIT + +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR riscv64) + +set(CMAKE_C_COMPILER "@llvmCheri@/bin/clang") +set(CMAKE_C_COMPILER_TARGET "riscv64-linux-musl") +set(CMAKE_CXX_COMPILER "@llvmCheri@/bin/clang++") +set(CMAKE_CXX_COMPILER_TARGET "riscv64-linux-musl") +set(CMAKE_ASM_COMPILER "@llvmCheri@/bin/clang") +set(CMAKE_ASM_COMPILER_TARGET "riscv64-linux-musl") + +set(CMAKE_AR + "@llvmCheri@/bin/llvm-ar" + CACHE FILEPATH "ar") +set(CMAKE_RANLIB + "@llvmCheri@/bin/llvm-ranlib" + CACHE FILEPATH "ranlib") +set(CMAKE_NM + "@llvmCheri@/bin/llvm-nm" + CACHE FILEPATH "nm") +set(CMAKE_STRIP + "@llvmCheri@/bin/llvm-strip" + CACHE FILEPATH "strip") +set(CMAKE_LINKER + "@llvmCheri@/bin/ld.lld" + CACHE FILEPATH "linker") + +set(CHERI_COMMON_FLAGS + "-target riscv64-linux-musl \ + -B@llvmCheri@/bin \ + -march=rv64imaczcherihybrid_zcherilevels \ + -mabi=l64pc128 \ + -mno-relax \ + -Xclang -target-feature -Xclang +cheri-bounded-vararg \ + -Xclang -target-feature -Xclang +cheri-bounded-memarg-caller \ + -Xclang -target-feature -Xclang +cheri-bounded-memarg-callee \ + -isystem @linuxHeadersPurecap@/usr/include \ + -ggdb \ + -gz \ + -Wno-error=unused-command-line-argument \ + -ffreestanding \ + -Werror=implicit-function-declaration \ + -Werror=format \ + -Werror=incompatible-pointer-types \ + -Werror=cheri-capability-misuse \ + -Werror=cheri-bitwise-operations \ + -Werror=pass-failed \ + -Werror=cheri-prototypes \ + -Werror=undefined-internal" +) + +set(CHERI_LINKER_FLAGS "${CHERI_COMMON_FLAGS} -fuse-ld=lld") + +set(CMAKE_C_FLAGS_INIT "${CHERI_COMMON_FLAGS}") +set(CMAKE_CXX_FLAGS_INIT "${CHERI_COMMON_FLAGS}") +set(CMAKE_ASM_FLAGS_INIT "${CHERI_COMMON_FLAGS}") +set(CMAKE_EXE_LINKER_FLAGS_INIT "${CHERI_LINKER_FLAGS}") +set(CMAKE_SHARED_LINKER_FLAGS_INIT "${CHERI_LINKER_FLAGS}") +set(CMAKE_MODULE_LINKER_FLAGS_INIT "${CHERI_LINKER_FLAGS}") + +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) diff --git a/nix/cheri_toolchain.nix b/nix/cheri_toolchain.nix new file mode 100644 index 000000000..ce602b832 --- /dev/null +++ b/nix/cheri_toolchain.nix @@ -0,0 +1,209 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +{ + lib, + stdenv, + gnumake, + cmake, + rsync, + fetchFromGitHub, + llvm_cheri, + pkgsCross, +}: let + CHERI_FLAGS = "rv64imaczcherihybrid_zcherilevels"; + MABI = "l64pc128"; +in rec { + linux-headers-purecap = stdenv.mkDerivation { + pname = "linux-headers-purecap"; + version = "6.18"; + + src = fetchFromGitHub { + owner = "CHERI-Alliance"; + repo = "linux"; + rev = "af04d488044fa684760d6480f3623e51b46568ca"; + fetchSubmodules = true; + hash = "sha256-Gjjs+vV0meFHOAt9i88WMzpFEq8IZ1oXDFVXb7ZuLI8="; + }; + + nativeBuildInputs = [ + gnumake + rsync + ]; + + dontConfigure = true; + dontBuild = true; + + installPhase = '' + runHook preInstall + + make -j$NIX_BUILD_CORES headers_install \ + ARCH=riscv \ + INSTALL_HDR_PATH=$out/usr + + runHook postInstall + ''; + + meta = { + description = "CHERI RISC-V 64 purecap Linux kernel (codasip-cheri-riscv-6.18)"; + platforms = ["x86_64-linux"]; + }; + }; + + muslc-linux-riscv64-purecap = stdenv.mkDerivation { + pname = "muslc-linux-riscv64-purecap"; + version = "std093"; + + src = fetchFromGitHub { + owner = "CHERI-Alliance"; + repo = "musl"; + rev = "12d15cddabcfb3f4f0612730f7147e7cf8c5579f"; + fetchSubmodules = true; + hash = "sha256-8cEUnBQSsWEUoe5gLR/3jFO3KwTddJOhDTDnNZgUIXQ="; + }; + + nativeBuildInputs = [ + gnumake + llvm_cheri + ]; + + dontConfigure = false; + + configurePhase = '' + runHook preConfigure + + # Dynamically fetch the resource dir + RESOURCE_DIR=$(${llvm_cheri}/bin/clang -print-resource-dir) + + ./configure \ + --prefix= \ + --disable-shared \ + CC="clang \ + -target riscv64-linux-musl \ + -march=${CHERI_FLAGS} \ + -mabi=${MABI} \ + -mno-relax \ + -Xclang -target-feature -Xclang +cheri-bounded-vararg \ + -Xclang -target-feature -Xclang +cheri-bounded-memarg-caller \ + -Xclang -target-feature -Xclang +cheri-bounded-memarg-callee \ + -idirafter $RESOURCE_DIR/include" + + runHook postConfigure + ''; + + installPhase = '' + runHook preInstall + + make install-headers DESTDIR=$out + make install-libs DESTDIR=$out + + runHook postInstall + ''; + + dontFixup = true; + }; + + compiler-rt-builtins-purecap = stdenv.mkDerivation { + pname = "compiler-rt-builtins-purecap"; + version = "std093"; + + src = llvm_cheri.src; + sourceRoot = "source/compiler-rt/lib/builtins"; + + nativeBuildInputs = [ + cmake + llvm_cheri + ]; + + llvmCheri = llvm_cheri; + linuxHeadersPurecap = linux-headers-purecap; + + preConfigure = '' + substituteAll ${./CrossToolchain.cmake.in} CrossToolchain.cmake + ''; + + configurePhase = '' + runHook preConfigure + + cmake -S . -B build \ + --toolchain=../CrossToolchain.cmake \ + -DCMAKE_BUILD_TYPE=RelWithDebInfo \ + -DLLVM_CONFIG_PATH=NOTFOUND \ + -DCMAKE_DISABLE_FIND_PACKAGE_LLVM=true \ + -DCOMPILER_RT_EXCLUDE_ATOMIC_BUILTIN=false \ + -DCOMPILER_RT_BAREMETAL_BUILD=false \ + -DCOMPILER_RT_DEFAULT_TARGET_ONLY=true \ + -DTARGET_TRIPLE="riscv64-linux-musl" \ + -DCMAKE_SYSROOT="${muslc-linux-riscv64-purecap}" \ + -DCOMPILER_RT_DEBUG=true \ + -DCMAKE_C_COMPILER=${llvm_cheri}/bin/clang \ + -DCMAKE_CXX_COMPILER=${llvm_cheri}/bin/clang++ \ + -DCMAKE_ASM_COMPILER=${llvm_cheri}/bin/clang \ + -DCMAKE_C_FLAGS="-march=${CHERI_FLAGS} -mabi=${MABI} -isystem ${linux-headers-purecap}/usr/include" \ + -DCMAKE_CXX_FLAGS="-march=${CHERI_FLAGS} -mabi=${MABI} -isystem ${linux-headers-purecap}/usr/include" \ + -DCMAKE_ASM_FLAGS="-march=${CHERI_FLAGS} -mabi=${MABI} -isystem ${linux-headers-purecap}/usr/include" \ + -DCMAKE_INSTALL_PREFIX="$out" + ''; + + buildPhase = '' + cmake --build build + ''; + + installPhase = '' + cmake --build build --target install + runHook postInstall + ''; + + postInstall = '' + mkdir -p $out/lib + + ln -fsn $out/lib/linux/libclang_rt.builtins-riscv64.a $out/lib/libclang_rt.builtins-riscv64.a + ln -fsn $out/lib/linux/libclang_rt.builtins-riscv64.a $out/lib/libgcc.a + + ln -fsn $out/lib/linux/clang_rt.crtbegin-riscv64.o $out/lib/crtbeginT.o + ln -fsn $out/lib/linux/clang_rt.crtbegin-riscv64.o $out/lib/crtbeginS.o + ln -fsn $out/lib/linux/clang_rt.crtend-riscv64.o $out/lib/crtend.o + ln -fsn $out/lib/linux/clang_rt.crtend-riscv64.o $out/lib/crtendS.o + ''; + + dontFixup = true; + }; + + cheriBintools = pkgsCross.riscv64.wrapBintoolsWith { + bintools = llvm_cheri; + libc = muslc-linux-riscv64-purecap; + coreutils = pkgsCross.riscv64.buildPackages.coreutils; + extraBuildCommands = '' + for tool in ar as nm objcopy objdump ranlib readelf size strings strip; do + # Link bare names: llvm-nm -> nm + if [ -x "$out/bin/$tool" ]; then + ln -s "$tool" "$out/bin/llvm-$tool" + fi + done + ''; + }; + + cheriCC = pkgsCross.riscv64.wrapCCWith { + cc = llvm_cheri; + bintools = cheriBintools; + libc = muslc-linux-riscv64-purecap; + coreutils = pkgsCross.riscv64.buildPackages.coreutils; + extraBuildCommands = '' + echo "-isystem ${linux-headers-purecap}/usr/include" >> $out/nix-support/cc-cflags + echo "-B${compiler-rt-builtins-purecap}/lib" >> $out/nix-support/cc-cflags + echo "-L${compiler-rt-builtins-purecap}/lib" >> $out/nix-support/cc-ldflags + ''; + }; + + cheriStdenv = pkgsCross.riscv64.stdenv.override { + cc = cheriCC; + allowedRequisites = null; + + targetPlatform = + stdenv.targetPlatform + // { + config = "riscv64-linux-musl"; + libc = "musl"; + }; + }; +} diff --git a/sw/cmake/uboot.cmake b/sw/cmake/uboot.cmake index 52459894d..ec69ab2bb 100644 --- a/sw/cmake/uboot.cmake +++ b/sw/cmake/uboot.cmake @@ -9,9 +9,34 @@ function(mocha_uboot OUTPUT_NAME) set(UBOOT_REPOSITORY https://github.com/lowrisc/u-boot) set(UBOOT_TAG mocha-devel) - # configure command - load Mocha defconfig file. + if(NOT DEFINED ENV{HOSTCC}) + message(FATAL_ERROR "HOSTCC environment variable is not set") + endif() + + # Resolve ld.lld through the compiler so the build doesn't depend on PATH. + execute_process( + COMMAND ${CMAKE_C_COMPILER} -target riscv64-unknown-elf -print-prog-name=ld.lld + OUTPUT_VARIABLE UBOOT_LD + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + + # Resolve sysroot through the compiler so the build doesn't depend on PATH. + execute_process( + COMMAND sh -c "$ENV{HOSTCC} -v -E -x c /dev/null -o /dev/null 2>&1 | grep -E '^ /.*/include.*$'" + OUTPUT_VARIABLE _compiler_includes + ) + string(STRIP "${_compiler_includes}" _compiler_includes) + string(REPLACE "\n" ";" UBOOT_HOSTCFLAGS ${_compiler_includes}) + list(TRANSFORM UBOOT_HOSTCFLAGS PREPEND "-isystem ") + list(JOIN UBOOT_HOSTCFLAGS " " UBOOT_HOSTCFLAGS) + set(CONFIGURE_COMMAND make + # override CC and LD, as U-boot defaults to using the GNU toolchain. + "CC=${CMAKE_C_COMPILER} -target riscv64-unknown-elf" + "LD=${UBOOT_LD}" + "HOSTCC=$ENV{HOSTCC}" + "HOSTLD=$ENV{HOSTLD}" lowrisc_mocha_cheri_smode_defconfig ) @@ -19,8 +44,11 @@ function(mocha_uboot OUTPUT_NAME) set(BUILD_COMMAND make # override CC and LD, as U-boot defaults to using the GNU toolchain. - "CC=clang -target riscv64-unknown-elf" - "LD=ld.lld" + "CC=${CMAKE_C_COMPILER} -target riscv64-unknown-elf" + "LD=${UBOOT_LD}" + "HOSTCC=$ENV{HOSTCC}" + "HOSTLD=$ENV{HOSTLD}" + "HOSTCFLAGS=${UBOOT_HOSTCFLAGS}" ) ExternalProject_Add( @@ -29,6 +57,7 @@ function(mocha_uboot OUTPUT_NAME) GIT_REPOSITORY ${UBOOT_REPOSITORY} GIT_TAG ${UBOOT_TAG} GIT_SHALLOW true + UPDATE_COMMAND "" # U-boot builds in it's own source tree. BUILD_IN_SOURCE true # make is job server aware. From d9d3f1ca35755fd99ffe7ada648d7e899217d724 Mon Sep 17 00:00:00 2001 From: Douglas Reis Date: Thu, 18 Jun 2026 17:31:19 +0000 Subject: [PATCH 2/2] fixup Signed-off-by: Douglas Reis --- flake.nix | 3 ++- sw/cmake/uboot.cmake | 9 +++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 556284dd0..d5f340a2d 100644 --- a/flake.nix +++ b/flake.nix @@ -100,12 +100,13 @@ pkg-config zlib zlib.dev + cheri-toolchain.cheriStdenv.cc ]; in { formatter = pkgs.alejandra; devShells = rec { default = baremetal; - baremetal = pkgs.mkShell.override {stdenv = cheri-toolchain.cheriStdenv;} { + baremetal = pkgs.mkShell { name = "baremetal"; strictDeps = true; hardeningDisable = [ "all" ]; diff --git a/sw/cmake/uboot.cmake b/sw/cmake/uboot.cmake index ec69ab2bb..87f2d3b91 100644 --- a/sw/cmake/uboot.cmake +++ b/sw/cmake/uboot.cmake @@ -20,6 +20,13 @@ function(mocha_uboot OUTPUT_NAME) OUTPUT_STRIP_TRAILING_WHITESPACE ) + # Resolve llvm-objcopy through the compiler so the build doesn't depend on PATH. + execute_process( + COMMAND ${CMAKE_C_COMPILER} -target riscv64-unknown-elf -print-prog-name=llvm-objcopy + OUTPUT_VARIABLE UBOOT_OBJCOPY + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + # Resolve sysroot through the compiler so the build doesn't depend on PATH. execute_process( COMMAND sh -c "$ENV{HOSTCC} -v -E -x c /dev/null -o /dev/null 2>&1 | grep -E '^ /.*/include.*$'" @@ -35,6 +42,7 @@ function(mocha_uboot OUTPUT_NAME) # override CC and LD, as U-boot defaults to using the GNU toolchain. "CC=${CMAKE_C_COMPILER} -target riscv64-unknown-elf" "LD=${UBOOT_LD}" + "OBJCOPY=${UBOOT_OBJCOPY}" "HOSTCC=$ENV{HOSTCC}" "HOSTLD=$ENV{HOSTLD}" lowrisc_mocha_cheri_smode_defconfig @@ -46,6 +54,7 @@ function(mocha_uboot OUTPUT_NAME) # override CC and LD, as U-boot defaults to using the GNU toolchain. "CC=${CMAKE_C_COMPILER} -target riscv64-unknown-elf" "LD=${UBOOT_LD}" + "OBJCOPY=${UBOOT_OBJCOPY}" "HOSTCC=$ENV{HOSTCC}" "HOSTLD=$ENV{HOSTLD}" "HOSTCFLAGS=${UBOOT_HOSTCFLAGS}"