Building RISC-V Phone's Firmware, where is riscv64-unknown-elf-gcc?

I’m trying to build the firmware for the RISC-V Phone. What I’ve been able to do so far is to write a nix flake and a nix shell that both seem to put together the toolchain needed, either with nix develop or nix-shell. However, when I try to build the Firmware for Freedom E310 SoC, it gives the same error where it complains about not finding the riscv64-unknown-elf-gcc package.

My shell.nix:

{ pkgs ? import <nixpkgs> {} }:
let
  crossPkgs = 
    import <nixpkgs> {
      crossSystem = { config = "riscv64-none-elf"; };
      #crossSystem = {system = "riscv64-unknown-none-elf"; };
    };
in
with import <nixpkgs> {};
#crossPkgs.mkShell {
pkgsCross.riscv64.mkShell {
  buildInputs = with pkgs; [
    openocd
    mkspiffs-presets.esp-idf
  ];
}

And my flake.nix:

{
  outputs = { self, nixpkgs, flake-utils, ... }:
   flake-utils.lib.eachDefaultSystem (system:
     let
       riscv-toolchain =
         import nixpkgs {
           localSystem = "${system}";
           crossSystem = {
             config = "riscv64-none-elf";
             #config = "riscv64-unknown-none-elf";
           };
         };
     in
       with import <nixpkgs> {};
       {
         devShell = pkgs.mkShell {
           buildInputs = with pkgs; [
             riscv-toolchain.buildPackages.gcc
             openocd
             mkspiffs-presets.esp-idf              
           ];
         };
       }
   );
}

The error I get building the toolchain either way, when doing make on <path-to-repository>/rvPhone/fw/fe310:

for i in bsp/drivers bsp/gloss bsp/metal eos eos/i2c eos/eve eos/eve/screen eos/eve/widget /home/nuno/pendente/riscv-phone/rvPhone/ext/fsfat /home/nuno/pendente/riscv-phone/rvPhone/ext/crypto; do \
	(cd $i && make) || exit; \
done
make[1]: a entrar na pasta "/home/nuno/pendente/riscv-phone/rvPhone/fw/fe310/bsp/drivers"
/bin/riscv64-unknown-elf-gcc -march=rv32imac -mabi=ilp32 -mcmodel=medlow -ffunction-sections -fdata-sections --specs=nano.specs -O2 -I/home/nuno/pendente/riscv-phone/rvPhone/fw/fe310/eos -I/home/nuno/pendente/riscv-phone/rvPhone/fw/fe310/bsp/include -include sys/cdefs.h -c plic_driver.c
make[1]: /bin/riscv64-unknown-elf-gcc: No such file or directory
make[1]: *** [Makefile:5: plic_driver.o] Erro 127
make[1]: exiting folder "/home/nuno/riscv-phone/rvPhone/fw/fe310/bsp/drivers"
make: *** [Makefile:16: libeos.a] Erro 2

I wonder what I’m doing wrong. Also, I’m only able to run the flake with nix develop --impure, otherwise it compains with the following error: error: cannot look up '<nixpkgs>' in pure evaluation mode (use '--impure' to override). I wonder why this happens.

I got as far as creating a shell hook with variable RISCV_PATH, pointing it to the gcc package:

{
  inputs.flake-utils.url = "github:numtide/flake-utils";
  outputs = { self, nixpkgs, flake-utils, ... }: {
    devShell.x86_64-linux =
        letbuild
          pkgs = nixpkgs.legacyPackages.x86_64-linux; 
          riscv-toolchain =
            import nixpkgs {            
              localSystem = "x86_64-linux";
              crossSystem = {
                config = "riscv64-none-elf";
                #config = "riscv64-unknown-linux-gnu";
              };
            };
        in
          pkgs.mkShell {
            buildInputs = with pkgs; [
              mkspiffs-presets.esp-idf              
              openocd
            ];
            shellHook = ''
              RISCV_PATH=${riscv-toolchain.buildPackages.gcc}
              RISCV_OPENOCD_PATH=${pkgs.openocd}
            '';
          };
    };
}

On the build environment for the derivation, echo $RISCV_PATH prints /nix/store/kyrmx1bbhr6kivwq3mvf3q90xwhhqi4v-riscv64-none-elf-stage-final-gcc-debug-wrapper-11.3.0 where config = "riscv64-none-elf"; or /nix/store/aaa664hcsgfblg1mmrzrg3x5fmj5y6lx-riscv64-unknown-linux-gnu-stage-final-gcc-debug-wrapper-11.3.0 where config = "riscv64-unknown-linux-gnu";

The problem persists in which I can successfully create environments with two diferent riscv64 kernels (riscv64-unknown-linux-gnu and riscv64-none-elf) but still can’t build any firmware as it will not find the right compiler (riscv64-unknown-elf-gcc).

Tried other configurations such as config = "riscv64-unknown-none-elf"; and config = "riscv64-unknown-elf, but didn’t recognize any kernel with those names: > checking target system type... Invalid configuration 'riscv64-unknown-none-elf': Kernel 'none' not known to work with OS 'elf'.

An idea: can you patch the upstream build system to use $CC instead of a hardcoded compiler name?

@bjornfor not exactly sure what you mean or how could I go about doing what you describe, but this is what I’ve been trying to do in order to build the RISC-V GNU Compiler Toolchain:

{
  inputs.flake-utils.url = "github:numtide/flake-utils";

  outputs = { self, nixpkgs, flake-utils, ... }:
      flake-utils.lib.eachDefaultSystem (system:
        let
          pkgs = nixpkgs.legacyPackages.${system};
          riscvToolchain = pkgs.stdenv.mkDerivation {
            name = "riscv-toolchain";           
            dontPatchELF = true;
            fetchSubmodules = true;            
            src = pkgs.fetchFromGitHub {
              owner = "riscv";
              repo = "riscv-gnu-toolchain";
              rev = "b39e36160aa0649ba0dfb9aa314d375900d610fb";
              sha256 = "0qqp9w6595saw9gzq73n6plhdc1r1mrswjagxmqkzd1fxg7hwjzn";
            };
            configureFlags = ["--with-arch=rv64g"];            
            buildInputs = with pkgs; [ autoconf automake curl python39 libmpc mpfr gmp gawk bison flex texinfo gperf libtool patchutils bc zlib expat git flock ];
          };          
        in
          {
            devShell = pkgs.mkShell {
              buildInputs = with pkgs; [
                riscvToolchain
              ];
            };
          }
      );
}

Unfortunately, I’ve not been able to go past this point:

@nix { "action": "setPhase", "phase": "unpackPhase" }
unpacking sources
unpacking source archive /nix/store/q5fw16am9jjw53w9a8c1lzj23aymf5fr-source
source root is source
@nix { "action": "setPhase", "phase": "patchPhase" }
patching sources
@nix { "action": "setPhase", "phase": "configurePhase" }
configuring
configure flags: --prefix=/nix/store/887zyp0h1d11jzv43j51qnbv1ck63pr9-riscv-toolchain --with-arch=rv64g
checking for gcc... gcc
checking whether the C compiler works... yes
checking for C compiler default output file name... a.out
checking for suffix of executables... 
checking whether we are cross compiling... no
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
checking whether gcc accepts -g... yes
checking for gcc option to accept ISO C89... none needed
checking for grep that handles long lines and -e... /nix/store/adh4n2lv5a558114jc1bra7v4khdnjds-gnugrep-3.7/bin/grep
checking for fgrep... /nix/store/adh4n2lv5a558114jc1bra7v4khdnjds-gnugrep-3.7/bin/grep -F
checking for grep that handles long lines and -e... (cached) /nix/store/adh4n2lv5a558114jc1bra7v4khdnjds-gnugrep-3.7/bin/grep
checking for bash... /nix/store/qm2lv1gpbyn0rsfai40cbvj3h4gz69yc-bash-5.1-p16/bin/bash
checking for __gmpz_init in -lgmp... yes
checking for mpfr_init in -lmpfr... yes
checking for mpc_init2 in -lmpc... yes
checking for curl... /nix/store/08zv5pg7q0ip0js1n0axlnnbs0phf4ff-curl-7.84.0-bin/bin/curl
checking for wget... no
checking for ftp... no
configure: creating ./config.status
config.status: creating Makefile
config.status: creating scripts/wrapper/awk/awk
config.status: creating scripts/wrapper/sed/sed
@nix { "action": "setPhase", "phase": "buildPhase" }
building
build flags: SHELL=/nix/store/qm2lv1gpbyn0rsfai40cbvj3h4gz69yc-bash-5.1-p16/bin/bash
cd /build/source && \
flock `git rev-parse --git-dir`/config git submodule init /build/source/riscv-gcc/ && \
flock `git rev-parse --git-dir`/config git submodule update /build/source/riscv-gcc/
fatal: not a git repository (or any of the parent directories): .git
flock: cannot open lock file /config: Permission denied
flock: invalid input: Permission denied
make: *** [Makefile:247: /build/source/riscv-gcc/.git] Error 66

Sorry, I don’t know.

This article describes how to assemble a cross-compiler gcc toolchain to build RiscV binaries on x86_64, and then running them in qemu. Possibly you can find some clues in there.

1 Like

This articulation seemed to do the trick (I also needed newlib-nano):

{
  inputs.flake-utils.url = "github:numtide/flake-utils";
  inputs.nixpkgs.url = "github:NixOS/nixpkgs";

  outputs = { self, nixpkgs, flake-utils, ... }:
    flake-utils.lib.eachDefaultSystem (system:
      let
        pkgs = nixpkgs.legacyPackages.${system};

        riscv-toolchain =
          import nixpkgs {
            localSystem = "${system}";
            crossSystem = {
              config = "riscv32-none-elf";
              libc = "newlib-nano";
              abi = "ilp32";
            };
          };

      in {

        devShells = {

          fe310Shell = pkgs.mkShell {
            buildInputs = [
              riscv-toolchain.buildPackages.gcc
            ];
          };
        };
      });
2 Likes