Re: git: 96eec29c9aa6 - main - lang/rust: Add riscv64 (riscv64gc-unknown-freebsd) support

From: Piotr Kubaj <pkubaj_at_anongoth.pl>
Date: Thu, 23 Dec 2021 13:20:12 UTC
Regarding OpenSSL - I just upstreamed BSD-riscv64 target in https://github.com/openssl/openssl/commit/c2d1ad0e048dd3bfa60e6aa0b5ee343cc6d97a15 and want to backport that to ports, so we may want to switch to that once openssl-src-rs has it.

On 21-12-23 10:10:41, Tobias Kortkamp wrote:
> The branch main has been updated by tobik:
> 
> URL: https://cgit.FreeBSD.org/ports/commit/?id=96eec29c9aa623f3aef843e238b50329ef386c45
> 
> commit 96eec29c9aa623f3aef843e238b50329ef386c45
> Author:     Tobias Kortkamp <tobik@FreeBSD.org>
> AuthorDate: 2021-11-05 10:25:23 +0000
> Commit:     Tobias Kortkamp <tobik@FreeBSD.org>
> CommitDate: 2021-12-23 10:10:16 +0000
> 
>     lang/rust: Add riscv64 (riscv64gc-unknown-freebsd) support
>     
>     A kernel with COMPAT_FREEBSD11 is required for now like on all
>     other FreeBSD archs. FreeBSD11 never had riscv64 support, so
>     GENERIC does not have it and a kernel rebuild is required. The
>     same issue existed on powerpc64le.
>     
>     The riscv64gc-unknown-freebsd target was upstreamed and will
>     be part of Rust 1.59.0 (2021-02-24).
>     
>     Reviewed by:    jrtc27, pkubaj
>     Differential Revision:  https://reviews.freebsd.org/D32881
> ---
>  Mk/Uses/cargo.mk                                   |   1 +
>  lang/rust-bootstrap/Makefile                       |   9 +-
>  lang/rust/Makefile                                 |   5 +-
>  lang/rust/distinfo                                 |   6 +
>  .../riscv64/patch-compiler_rustc__llvm_build.rs    |  16 +++
>  .../patch-compiler_rustc__target_src_spec_mod.rs   |  10 ++
>  ..._target_src_spec_riscv64gc__unknown__freebsd.rs |  21 +++
>  .../riscv64/patch-library_std_src_os_raw_mod.rs    |  22 +++
>  ...tes_std__detect_src_detect_os_freebsd_auxvec.rs |  12 ++
>  .../files/riscv64/patch-src_bootstrap_bootstrap.py |  11 ++
>  .../files/riscv64/patch-src_bootstrap_native.rs    |  20 +++
>  .../patch-src_doc_rustc_src_platform-support.md    |  10 ++
>  .../riscv64/patch-vendor_cc-1.0.69_src_lib.rs      |  12 ++
>  lang/rust/files/riscv64/patch-vendor_cc_src_lib.rs |  12 ++
>  ...c_unix_bsd_freebsdlike_freebsd_freebsd11_mod.rs |  12 ++
>  ...c_unix_bsd_freebsdlike_freebsd_freebsd12_mod.rs |  12 ++
>  ...c_unix_bsd_freebsdlike_freebsd_freebsd13_mod.rs |  12 ++
>  ...-0.2.98_src_unix_bsd_freebsdlike_freebsd_mod.rs |  12 ++
>  ....98_src_unix_bsd_freebsdlike_freebsd_riscv64.rs | 157 +++++++++++++++++++++
>  ...c_unix_bsd_freebsdlike_freebsd_freebsd11_mod.rs |  12 ++
>  ...c_unix_bsd_freebsdlike_freebsd_freebsd12_mod.rs |  12 ++
>  ...c_unix_bsd_freebsdlike_freebsd_freebsd13_mod.rs |  12 ++
>  ...or_libc_src_unix_bsd_freebsdlike_freebsd_mod.rs |  12 ++
>  ...ibc_src_unix_bsd_freebsdlike_freebsd_riscv64.rs | 157 +++++++++++++++++++++
>  .../riscv64/patch-vendor_openssl-src_src_lib.rs    |  10 ++
>  ...vendor_rustc__ap__rustc__target_src_spec_mod.rs |   9 ++
>  ..._target_src_spec_riscv64gc__unknown__freebsd.rs |  21 +++
>  27 files changed, 614 insertions(+), 3 deletions(-)
> 
> diff --git a/Mk/Uses/cargo.mk b/Mk/Uses/cargo.mk
> index 1636f2da320f..a1508a9831aa 100644
> --- a/Mk/Uses/cargo.mk
> +++ b/Mk/Uses/cargo.mk
> @@ -113,6 +113,7 @@ CARGO_BUILD_TARGET?=	${_CARGO_RUST_ARCH_${ARCH}:U${ARCH}}-unknown-${OPSYS:tl}
>  
>  _CARGO_RUST_ARCH_amd64=		x86_64
>  _CARGO_RUST_ARCH_i386=		i686
> +_CARGO_RUST_ARCH_riscv64=	riscv64gc
>  
>  # Environment for cargo
>  #  - CARGO_HOME: local cache of the registry index
> diff --git a/lang/rust-bootstrap/Makefile b/lang/rust-bootstrap/Makefile
> index 4dae6430264f..115fb7fe206c 100644
> --- a/lang/rust-bootstrap/Makefile
> +++ b/lang/rust-bootstrap/Makefile
> @@ -27,7 +27,7 @@ BUILD_DEPENDS=	${FLAVOR:S/_/-/g}-freebsd-sysroot>=a2021.09.14:devel/freebsd-sysr
>  		rust>=${PORTVERSION}:lang/rust
>  
>  FLAVORS=	aarch64 amd64 armv6 armv7 i386 powerpc64_elfv1 powerpc64_elfv2 \
> -		powerpc64le powerpc
> +		powerpc64le powerpc riscv64
>  FLAVOR?=	${FLAVORS:[1]}
>  
>  USES=		cpe ninja:build perl5 python:3.6+,build tar:xz
> @@ -51,6 +51,7 @@ _RUST_ARCH_amd64=			x86_64
>  _RUST_ARCH_i386=			i686
>  _RUST_ARCH_powerpc64_elfv1=		powerpc64
>  _RUST_ARCH_powerpc64_elfv2=		powerpc64
> +_RUST_ARCH_riscv64=			riscv64gc
>  _RUST_HOST=				${_RUST_ARCH_${ARCH}:U${ARCH}}-unknown-${OPSYS:tl}
>  _RUST_TARGET=				${_RUST_ARCH_${FLAVOR}:U${FLAVOR}}-unknown-${OPSYS:tl}
>  _RUST_LLVM_TARGET=			${_RUST_LLVM_TARGET_${FLAVOR}}
> @@ -63,13 +64,14 @@ _RUST_LLVM_TARGET_powerpc64_elfv1=	PowerPC
>  _RUST_LLVM_TARGET_powerpc64_elfv2=	PowerPC
>  _RUST_LLVM_TARGET_powerpc64le=		PowerPC
>  _RUST_LLVM_TARGET_powerpc=		PowerPC
> +_RUST_LLVM_TARGET_riscv64=		RISCV
>  
>  .include <bsd.port.pre.mk>
>  
>  .if ${OPSYS} != FreeBSD
>  IGNORE=	is only for FreeBSD
>  .endif
> -.if ${FLAVOR} == powerpc64le && ${OSVERSION} < 1300116
> +.if (${FLAVOR} == powerpc64le || ${FLAVOR} == riscv64) && ${OSVERSION} < 1300116
>  IGNORE=	will not build on 12.x due to old system
>  .endif
>  
> @@ -112,6 +114,9 @@ do-configure:
>  	@${ECHO_CMD} '[rust]' >> ${WRKSRC}/config.toml
>  	@${ECHO_CMD} 'channel="stable"' >> ${WRKSRC}/config.toml
>  	@${ECHO_CMD} 'default-linker="${CC}"' >> ${WRKSRC}/config.toml
> +.if ${FLAVOR} == riscv64
> +	@${ECHO_CMD} 'debug=true' >> ${WRKSRC}/config.toml
> +.endif
>  	@${ECHO_CMD} 'deny-warnings=false' >> ${WRKSRC}/config.toml
>  	@${ECHO_CMD} '[llvm]' >> ${WRKSRC}/config.toml
>  	@${ECHO_CMD} 'link-shared=false' >> ${WRKSRC}/config.toml
> diff --git a/lang/rust/Makefile b/lang/rust/Makefile
> index 9b5f0cc0927f..ee8779c2f1e6 100644
> --- a/lang/rust/Makefile
> +++ b/lang/rust/Makefile
> @@ -26,7 +26,7 @@ LICENSE_FILE_MIT=	${WRKSRC}/LICENSE-MIT
>  
>  IGNORE_FreeBSD_12_powerpc=	is missing a bootstrap for FreeBSD 12.x powerpc
>  ONLY_FOR_ARCHS?=	aarch64 amd64 armv6 armv7 i386 powerpc64 powerpc64le \
> -			powerpc
> +			powerpc riscv64
>  ONLY_FOR_ARCHS_REASON?=	requires prebuilt bootstrap compiler
>  
>  BUILD_DEPENDS=	cmake:devel/cmake
> @@ -70,6 +70,8 @@ WASM_VARS_OFF=		_RUST_BUILD_WASM=false
>  # See WRKSRC/src/stage0.json for the date and version values
>  BOOTSTRAPS_DATE?=		2021-10-21
>  RUST_BOOTSTRAP_VERSION?=	1.56.0
> +BOOTSTRAPS_DATE_riscv64=	2021-12-02
> +RUST_BOOTSTRAP_VERSION_riscv64=	1.57.0
>  
>  BOOTSTRAPS_SUFFIX?=		${BOOTSTRAPS_SUFFIX_${ARCH}}
>  BOOTSTRAPS_SUFFIX_powerpc64?=	-${PPC_ABI:tl}
> @@ -79,6 +81,7 @@ CARGO_VENDOR_DIR?=		${WRKSRC}/vendor
>  # Rust's target arch string might be different from *BSD arch strings
>  _RUST_ARCH_amd64=	x86_64
>  _RUST_ARCH_i386=	i686
> +_RUST_ARCH_riscv64=	riscv64gc
>  _RUST_TARGET=		${_RUST_ARCH_${ARCH}:U${ARCH}}-unknown-${OPSYS:tl}
>  _RUST_TARGETS=		${_RUST_TARGET}
>  _RUST_TOOLS=		analysis cargo clippy rustfmt
> diff --git a/lang/rust/distinfo b/lang/rust/distinfo
> index ec6a829367ad..c698f325589e 100644
> --- a/lang/rust/distinfo
> +++ b/lang/rust/distinfo
> @@ -49,6 +49,12 @@ SHA256 (rust/2021-10-21/rust-std-1.56.0-powerpc64le-unknown-freebsd.tar.xz) = d7
>  SIZE (rust/2021-10-21/rust-std-1.56.0-powerpc64le-unknown-freebsd.tar.xz) = 18805860
>  SHA256 (rust/2021-10-21/cargo-1.56.0-powerpc64le-unknown-freebsd.tar.xz) = c29c558c07d09e56c0288d2c9528b63311072ca491a047b9588ea3320d1699bb
>  SIZE (rust/2021-10-21/cargo-1.56.0-powerpc64le-unknown-freebsd.tar.xz) = 5046108
> +SHA256 (rust/2021-12-02/rustc-1.57.0-riscv64gc-unknown-freebsd.tar.xz) = 7831ebf7d9b9c579d3e16e1b7b556a793d63a62f36636fba3b63ef2ed13c6872
> +SIZE (rust/2021-12-02/rustc-1.57.0-riscv64gc-unknown-freebsd.tar.xz) = 141961976
> +SHA256 (rust/2021-12-02/rust-std-1.57.0-riscv64gc-unknown-freebsd.tar.xz) = 3068b2f74537e5efcd293ebae7ce0e16bff92603cbc3ac5201ba3bb8e9ebe4ef
> +SIZE (rust/2021-12-02/rust-std-1.57.0-riscv64gc-unknown-freebsd.tar.xz) = 27221940
> +SHA256 (rust/2021-12-02/cargo-1.57.0-riscv64gc-unknown-freebsd.tar.xz) = c88fb84cd53349fcac5516f79b88f8b23ebdcbac40408719a112ef095068a95d
> +SIZE (rust/2021-12-02/cargo-1.57.0-riscv64gc-unknown-freebsd.tar.xz) = 24413628
>  SHA256 (rust/2021-10-21/rustc-1.56.0-powerpc64-unknown-freebsd-elfv2.tar.xz) = b5f715c8b66e53ae3ef4a0dcd6fd70b033595316ded47c5b733c34408e8bf1e5
>  SIZE (rust/2021-10-21/rustc-1.56.0-powerpc64-unknown-freebsd-elfv2.tar.xz) = 48308540
>  SHA256 (rust/2021-10-21/rust-std-1.56.0-powerpc64-unknown-freebsd-elfv2.tar.xz) = 012200453f449bd1a5b7b43ccafe11fa6169b6bf3c009f5de689740a43bd39ec
> diff --git a/lang/rust/files/riscv64/patch-compiler_rustc__llvm_build.rs b/lang/rust/files/riscv64/patch-compiler_rustc__llvm_build.rs
> new file mode 100644
> index 000000000000..1786f3e285df
> --- /dev/null
> +++ b/lang/rust/files/riscv64/patch-compiler_rustc__llvm_build.rs
> @@ -0,0 +1,16 @@
> +--- compiler/rustc_llvm/build.rs.orig	2021-11-29 19:27:11 UTC
> ++++ compiler/rustc_llvm/build.rs
> +@@ -276,8 +276,11 @@ fn main() {
> +         "stdc++"
> +     };
> + 
> +-    // RISC-V requires libatomic for sub-word atomic operations
> +-    if target.starts_with("riscv") {
> ++    // RISC-V GCC erroneously requires libatomic for sub-word
> ++    // atomic operations. FreeBSD uses Clang as its system
> ++    // compiler and provides no libatomic in its base system so
> ++    // does not want this.
> ++    if !target.contains("freebsd") && target.starts_with("riscv") {
> +         println!("cargo:rustc-link-lib=atomic");
> +     }
> + 
> diff --git a/lang/rust/files/riscv64/patch-compiler_rustc__target_src_spec_mod.rs b/lang/rust/files/riscv64/patch-compiler_rustc__target_src_spec_mod.rs
> new file mode 100644
> index 000000000000..f08735462131
> --- /dev/null
> +++ b/lang/rust/files/riscv64/patch-compiler_rustc__target_src_spec_mod.rs
> @@ -0,0 +1,10 @@
> +--- compiler/rustc_target/src/spec/mod.rs.orig	2021-11-04 11:23:50 UTC
> ++++ compiler/rustc_target/src/spec/mod.rs
> +@@ -805,6 +805,7 @@ supported_targets! {
> +     ("powerpc-unknown-freebsd", powerpc_unknown_freebsd),
> +     ("powerpc64-unknown-freebsd", powerpc64_unknown_freebsd),
> +     ("powerpc64le-unknown-freebsd", powerpc64le_unknown_freebsd),
> ++    ("riscv64gc-unknown-freebsd", riscv64gc_unknown_freebsd),
> +     ("x86_64-unknown-freebsd", x86_64_unknown_freebsd),
> + 
> +     ("x86_64-unknown-dragonfly", x86_64_unknown_dragonfly),
> diff --git a/lang/rust/files/riscv64/patch-compiler_rustc__target_src_spec_riscv64gc__unknown__freebsd.rs b/lang/rust/files/riscv64/patch-compiler_rustc__target_src_spec_riscv64gc__unknown__freebsd.rs
> new file mode 100644
> index 000000000000..9dcbb17ab3c0
> --- /dev/null
> +++ b/lang/rust/files/riscv64/patch-compiler_rustc__target_src_spec_riscv64gc__unknown__freebsd.rs
> @@ -0,0 +1,21 @@
> +--- compiler/rustc_target/src/spec/riscv64gc_unknown_freebsd.rs.orig	2021-11-04 11:22:10 UTC
> ++++ compiler/rustc_target/src/spec/riscv64gc_unknown_freebsd.rs
> +@@ -0,0 +1,18 @@
> ++use crate::spec::{CodeModel, Target, TargetOptions};
> ++
> ++pub fn target() -> Target {
> ++    Target {
> ++        llvm_target: "riscv64-unknown-freebsd".to_string(),
> ++        pointer_width: 64,
> ++        data_layout: "e-m:e-p:64:64-i64:64-i128:128-n64-S128".to_string(),
> ++        arch: "riscv64".to_string(),
> ++        options: TargetOptions {
> ++            code_model: Some(CodeModel::Medium),
> ++            cpu: "generic-rv64".to_string(),
> ++            features: "+m,+a,+f,+d,+c".to_string(),
> ++            llvm_abiname: "lp64d".to_string(),
> ++            max_atomic_width: Some(64),
> ++            ..super::freebsd_base::opts()
> ++        },
> ++    }
> ++}
> diff --git a/lang/rust/files/riscv64/patch-library_std_src_os_raw_mod.rs b/lang/rust/files/riscv64/patch-library_std_src_os_raw_mod.rs
> new file mode 100644
> index 000000000000..e880f73fd205
> --- /dev/null
> +++ b/lang/rust/files/riscv64/patch-library_std_src_os_raw_mod.rs
> @@ -0,0 +1,22 @@
> +--- library/std/src/os/raw/mod.rs.orig	2021-11-05 15:16:50 UTC
> ++++ library/std/src/os/raw/mod.rs
> +@@ -68,7 +68,8 @@ type_alias! { "char.md", c_char = u8, NonZero_c_char =
> +             target_arch = "aarch64",
> +             target_arch = "arm",
> +             target_arch = "powerpc",
> +-            target_arch = "powerpc64"
> ++            target_arch = "powerpc64",
> ++            target_arch = "riscv64"
> +         )
> +     ),
> +     all(
> +@@ -110,7 +111,8 @@ type_alias! { "char.md", c_char = i8, NonZero_c_char =
> +             target_arch = "aarch64",
> +             target_arch = "arm",
> +             target_arch = "powerpc",
> +-            target_arch = "powerpc64"
> ++            target_arch = "powerpc64",
> ++            target_arch = "riscv64"
> +         )
> +     ),
> +     all(
> diff --git a/lang/rust/files/riscv64/patch-library_stdarch_crates_std__detect_src_detect_os_freebsd_auxvec.rs b/lang/rust/files/riscv64/patch-library_stdarch_crates_std__detect_src_detect_os_freebsd_auxvec.rs
> new file mode 100644
> index 000000000000..d2df5bd0056f
> --- /dev/null
> +++ b/lang/rust/files/riscv64/patch-library_stdarch_crates_std__detect_src_detect_os_freebsd_auxvec.rs
> @@ -0,0 +1,12 @@
> +--- library/stdarch/crates/std_detect/src/detect/os/freebsd/auxvec.rs.orig	2021-10-18 09:52:55 UTC
> ++++ library/stdarch/crates/std_detect/src/detect/os/freebsd/auxvec.rs
> +@@ -3,7 +3,8 @@
> +     any(
> +         target_arch = "aarch64",
> +         target_arch = "arm",
> +-        target_arch = "powerpc64"
> ++        target_arch = "powerpc64",
> ++        target_arch = "riscv64"
> +     ),
> +     allow(dead_code)
> + )]
> diff --git a/lang/rust/files/riscv64/patch-src_bootstrap_bootstrap.py b/lang/rust/files/riscv64/patch-src_bootstrap_bootstrap.py
> new file mode 100644
> index 000000000000..d384c0990ca5
> --- /dev/null
> +++ b/lang/rust/files/riscv64/patch-src_bootstrap_bootstrap.py
> @@ -0,0 +1,11 @@
> +--- src/bootstrap/bootstrap.py.orig	2021-11-11 14:21:03 UTC
> ++++ src/bootstrap/bootstrap.py
> +@@ -283,7 +283,7 @@ def default_build_triple(verbose):
> +         err = "unknown OS type: {}".format(ostype)
> +         sys.exit(err)
> + 
> +-    if cputype == 'powerpc' and ostype == 'unknown-freebsd':
> ++    if cputype in ['powerpc', 'riscv'] and ostype == 'unknown-freebsd':
> +         cputype = subprocess.check_output(
> +               ['uname', '-p']).strip().decode(default_encoding)
> +     cputype_mapper = {
> diff --git a/lang/rust/files/riscv64/patch-src_bootstrap_native.rs b/lang/rust/files/riscv64/patch-src_bootstrap_native.rs
> new file mode 100644
> index 000000000000..df56a7f09589
> --- /dev/null
> +++ b/lang/rust/files/riscv64/patch-src_bootstrap_native.rs
> @@ -0,0 +1,20 @@
> +--- src/bootstrap/native.rs.orig	2021-11-29 19:27:11 UTC
> ++++ src/bootstrap/native.rs
> +@@ -248,9 +248,14 @@ impl Step for Llvm {
> +             }
> +         }
> + 
> +-        if target.starts_with("riscv") {
> +-            // In RISC-V, using C++ atomics require linking to `libatomic` but the LLVM build
> +-            // system check cannot detect this. Therefore it is set manually here.
> ++        if !target.contains("freebsd") && target.starts_with("riscv") {
> ++            // RISC-V GCC erroneously requires linking against
> ++            // `libatomic` when using 1-byte and 2-byte C++
> ++            // atomics but the LLVM build system check cannot
> ++            // detect this. Therefore it is set manually here.
> ++            // FreeBSD uses Clang as its system compiler and
> ++            // provides no libatomic in its base system so does
> ++            // not want this.
> +             if !builder.config.llvm_tools_enabled {
> +                 cfg.define("CMAKE_EXE_LINKER_FLAGS", "-latomic");
> +             } else {
> diff --git a/lang/rust/files/riscv64/patch-src_doc_rustc_src_platform-support.md b/lang/rust/files/riscv64/patch-src_doc_rustc_src_platform-support.md
> new file mode 100644
> index 000000000000..9f82379f9187
> --- /dev/null
> +++ b/lang/rust/files/riscv64/patch-src_doc_rustc_src_platform-support.md
> @@ -0,0 +1,10 @@
> +--- src/doc/rustc/src/platform-support.md.orig	2021-11-04 11:32:01 UTC
> ++++ src/doc/rustc/src/platform-support.md
> +@@ -261,6 +261,7 @@ target | std | host | notes
> + `riscv32gc-unknown-linux-gnu` |   |   | RISC-V Linux (kernel 5.4, glibc 2.33)
> + `riscv32gc-unknown-linux-musl` |   |   | RISC-V Linux (kernel 5.4, musl + RISCV32 support patches)
> + `riscv32imc-esp-espidf` | ✓ |  | RISC-V ESP-IDF
> ++`riscv64gc-unknown-freebsd` |   |   | RISC-V FreeBSD
> + `riscv64gc-unknown-linux-musl` |   |   | RISC-V Linux (kernel 4.20, musl 1.2.0)
> + `s390x-unknown-linux-musl` |  |  | S390x Linux (kernel 2.6.32, MUSL)
> + `sparc-unknown-linux-gnu` | ✓ |  | 32-bit SPARC Linux
> diff --git a/lang/rust/files/riscv64/patch-vendor_cc-1.0.69_src_lib.rs b/lang/rust/files/riscv64/patch-vendor_cc-1.0.69_src_lib.rs
> new file mode 100644
> index 000000000000..be6399810851
> --- /dev/null
> +++ b/lang/rust/files/riscv64/patch-vendor_cc-1.0.69_src_lib.rs
> @@ -0,0 +1,12 @@
> +--- vendor/cc-1.0.69/src/lib.rs.orig	2021-10-18 11:05:53 UTC
> ++++ vendor/cc-1.0.69/src/lib.rs
> +@@ -1700,6 +1700,9 @@ impl Build {
> +                         if target.contains("linux") && arch.starts_with("64") {
> +                             cmd.args.push(("-march=rv64gc").into());
> +                             cmd.args.push("-mabi=lp64d".into());
> ++                        } else if target.contains("freebsd") && arch.starts_with("64") {
> ++                            cmd.args.push(("-march=rv64gc").into());
> ++                            cmd.args.push("-mabi=lp64d".into());
> +                         } else if target.contains("linux") && arch.starts_with("32") {
> +                             cmd.args.push(("-march=rv32gc").into());
> +                             cmd.args.push("-mabi=ilp32d".into());
> diff --git a/lang/rust/files/riscv64/patch-vendor_cc_src_lib.rs b/lang/rust/files/riscv64/patch-vendor_cc_src_lib.rs
> new file mode 100644
> index 000000000000..1c2974574031
> --- /dev/null
> +++ b/lang/rust/files/riscv64/patch-vendor_cc_src_lib.rs
> @@ -0,0 +1,12 @@
> +--- vendor/cc/src/lib.rs.orig	2021-10-18 11:05:53 UTC
> ++++ vendor/cc/src/lib.rs
> +@@ -1700,6 +1700,9 @@ impl Build {
> +                         if target.contains("linux") && arch.starts_with("64") {
> +                             cmd.args.push(("-march=rv64gc").into());
> +                             cmd.args.push("-mabi=lp64d".into());
> ++                        } else if target.contains("freebsd") && arch.starts_with("64") {
> ++                            cmd.args.push(("-march=rv64gc").into());
> ++                            cmd.args.push("-mabi=lp64d".into());
> +                         } else if target.contains("linux") && arch.starts_with("32") {
> +                             cmd.args.push(("-march=rv32gc").into());
> +                             cmd.args.push("-mabi=ilp32d".into());
> diff --git a/lang/rust/files/riscv64/patch-vendor_libc-0.2.98_src_unix_bsd_freebsdlike_freebsd_freebsd11_mod.rs b/lang/rust/files/riscv64/patch-vendor_libc-0.2.98_src_unix_bsd_freebsdlike_freebsd_freebsd11_mod.rs
> new file mode 100644
> index 000000000000..04aef529ce69
> --- /dev/null
> +++ b/lang/rust/files/riscv64/patch-vendor_libc-0.2.98_src_unix_bsd_freebsdlike_freebsd_freebsd11_mod.rs
> @@ -0,0 +1,12 @@
> +--- vendor/libc-0.2.98/src/unix/bsd/freebsdlike/freebsd/freebsd11/mod.rs.orig	2021-11-29 20:27:33 UTC
> ++++ vendor/libc-0.2.98/src/unix/bsd/freebsdlike/freebsd/freebsd11/mod.rs
> +@@ -217,7 +217,8 @@ extern "C" {
> + 
> + cfg_if! {
> +     if #[cfg(any(target_arch = "x86_64",
> +-                 target_arch = "aarch64"))] {
> ++                 target_arch = "aarch64",
> ++                 target_arch = "riscv64"))] {
> +         mod b64;
> +         pub use self::b64::*;
> +     }
> diff --git a/lang/rust/files/riscv64/patch-vendor_libc-0.2.98_src_unix_bsd_freebsdlike_freebsd_freebsd12_mod.rs b/lang/rust/files/riscv64/patch-vendor_libc-0.2.98_src_unix_bsd_freebsdlike_freebsd_freebsd12_mod.rs
> new file mode 100644
> index 000000000000..e9a428f19c59
> --- /dev/null
> +++ b/lang/rust/files/riscv64/patch-vendor_libc-0.2.98_src_unix_bsd_freebsdlike_freebsd_freebsd12_mod.rs
> @@ -0,0 +1,12 @@
> +--- vendor/libc-0.2.98/src/unix/bsd/freebsdlike/freebsd/freebsd12/mod.rs.orig	2021-11-29 20:27:33 UTC
> ++++ vendor/libc-0.2.98/src/unix/bsd/freebsdlike/freebsd/freebsd12/mod.rs
> +@@ -235,7 +235,8 @@ extern "C" {
> + 
> + cfg_if! {
> +     if #[cfg(any(target_arch = "x86_64",
> +-                 target_arch = "aarch64"))] {
> ++                 target_arch = "aarch64",
> ++                 target_arch = "riscv64"))] {
> +         mod b64;
> +         pub use self::b64::*;
> +     }
> diff --git a/lang/rust/files/riscv64/patch-vendor_libc-0.2.98_src_unix_bsd_freebsdlike_freebsd_freebsd13_mod.rs b/lang/rust/files/riscv64/patch-vendor_libc-0.2.98_src_unix_bsd_freebsdlike_freebsd_freebsd13_mod.rs
> new file mode 100644
> index 000000000000..fbfa6662aabb
> --- /dev/null
> +++ b/lang/rust/files/riscv64/patch-vendor_libc-0.2.98_src_unix_bsd_freebsdlike_freebsd_freebsd13_mod.rs
> @@ -0,0 +1,12 @@
> +--- vendor/libc-0.2.98/src/unix/bsd/freebsdlike/freebsd/freebsd13/mod.rs.orig	2021-11-29 20:27:33 UTC
> ++++ vendor/libc-0.2.98/src/unix/bsd/freebsdlike/freebsd/freebsd13/mod.rs
> +@@ -240,7 +240,8 @@ extern "C" {
> + 
> + cfg_if! {
> +     if #[cfg(any(target_arch = "x86_64",
> +-                 target_arch = "aarch64"))] {
> ++                 target_arch = "aarch64",
> ++                 target_arch = "riscv64"))] {
> +         mod b64;
> +         pub use self::b64::*;
> +     }
> diff --git a/lang/rust/files/riscv64/patch-vendor_libc-0.2.98_src_unix_bsd_freebsdlike_freebsd_mod.rs b/lang/rust/files/riscv64/patch-vendor_libc-0.2.98_src_unix_bsd_freebsdlike_freebsd_mod.rs
> new file mode 100644
> index 000000000000..864d0669534c
> --- /dev/null
> +++ b/lang/rust/files/riscv64/patch-vendor_libc-0.2.98_src_unix_bsd_freebsdlike_freebsd_mod.rs
> @@ -0,0 +1,12 @@
> +--- vendor/libc-0.2.98/src/unix/bsd/freebsdlike/freebsd/mod.rs.orig	2021-11-29 20:27:33 UTC
> ++++ vendor/libc-0.2.98/src/unix/bsd/freebsdlike/freebsd/mod.rs
> +@@ -1749,6 +1749,9 @@ cfg_if! {
> +     } else if #[cfg(target_arch = "powerpc")] {
> +         mod powerpc;
> +         pub use self::powerpc::*;
> ++    } else if #[cfg(target_arch = "riscv64")] {
> ++        mod riscv64;
> ++        pub use self::riscv64::*;
> +     } else {
> +         // Unknown target_arch
> +     }
> diff --git a/lang/rust/files/riscv64/patch-vendor_libc-0.2.98_src_unix_bsd_freebsdlike_freebsd_riscv64.rs b/lang/rust/files/riscv64/patch-vendor_libc-0.2.98_src_unix_bsd_freebsdlike_freebsd_riscv64.rs
> new file mode 100644
> index 000000000000..d4fddf2844a2
> --- /dev/null
> +++ b/lang/rust/files/riscv64/patch-vendor_libc-0.2.98_src_unix_bsd_freebsdlike_freebsd_riscv64.rs
> @@ -0,0 +1,157 @@
> +--- vendor/libc-0.2.98/src/unix/bsd/freebsdlike/freebsd/riscv64.rs.orig	2021-11-05 13:41:21 UTC
> ++++ vendor/libc-0.2.98/src/unix/bsd/freebsdlike/freebsd/riscv64.rs
> +@@ -0,0 +1,154 @@
> ++pub type c_char = u8;
> ++pub type c_long = i64;
> ++pub type c_ulong = u64;
> ++pub type wchar_t = ::c_int;
> ++pub type time_t = i64;
> ++pub type suseconds_t = ::c_long;
> ++pub type register_t = i64;
> ++
> ++// should be pub(crate), but that requires Rust 1.18.0
> ++cfg_if! {
> ++    if #[cfg(libc_const_size_of)] {
> ++        #[doc(hidden)]
> ++        pub const _ALIGNBYTES: usize = ::mem::size_of::<::c_longlong>() - 1;
> ++    } else {
> ++        #[doc(hidden)]
> ++        pub const _ALIGNBYTES: usize = 8 - 1;
> ++    }
> ++}
> ++
> ++s_no_extra_traits! {
> ++    pub struct gpregs {
> ++        pub gp_ra: ::register_t,
> ++        pub gp_sp: ::register_t,
> ++        pub gp_gp: ::register_t,
> ++        pub gp_tp: ::register_t,
> ++        pub gp_t: [::register_t; 7],
> ++        pub gp_s: [::register_t; 12],
> ++        pub gp_a: [::register_t; 8],
> ++        pub gp_sepc: ::register_t,
> ++        pub gp_sstatus: ::register_t,
> ++    }
> ++
> ++    pub struct fpregs {
> ++        pub fp_x: [[::register_t; 2]; 32],
> ++        pub fp_fcsr: ::register_t,
> ++        pub fp_flags: ::c_int,
> ++        pub fp_pad: ::c_int,
> ++    }
> ++
> ++    pub struct mcontext_t {
> ++        pub mc_gpregs: gpregs,
> ++        pub mc_fpregs: fpregs,
> ++        pub mc_flags: ::c_int,
> ++        pub mc_pad: ::c_int,
> ++        pub mc_spare: [u64; 8],
> ++    }
> ++}
> ++
> ++cfg_if! {
> ++    if #[cfg(feature = "extra_traits")] {
> ++        impl PartialEq for gpregs {
> ++            fn eq(&self, other: &gpregs) -> bool {
> ++                self.gp_ra == other.gp_ra &&
> ++                self.gp_sp == other.gp_sp &&
> ++                self.gp_gp == other.gp_gp &&
> ++                self.gp_tp == other.gp_tp &&
> ++                self.gp_t.iter().zip(other.gp_t.iter()).all(|(a, b)| a == b) &&
> ++                self.gp_s.iter().zip(other.gp_s.iter()).all(|(a, b)| a == b) &&
> ++                self.gp_a.iter().zip(other.gp_a.iter()).all(|(a, b)| a == b) &&
> ++                self.gp_sepc == other.gp_sepc &&
> ++                self.gp_sstatus == other.gp_sstatus
> ++            }
> ++        }
> ++        impl Eq for gpregs {}
> ++        impl ::fmt::Debug for gpregs {
> ++            fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
> ++                f.debug_struct("gpregs")
> ++                    .field("gp_ra", &self.gp_ra)
> ++                    .field("gp_sp", &self.gp_sp)
> ++                    .field("gp_gp", &self.gp_gp)
> ++                    .field("gp_tp", &self.gp_tp)
> ++                    .field("gp_t", &self.gp_t)
> ++                    .field("gp_s", &self.gp_s)
> ++                    .field("gp_a", &self.gp_a)
> ++                    .field("gp_sepc", &self.gp_sepc)
> ++                    .field("gp_sstatus", &self.gp_sstatus)
> ++                    .finish()
> ++            }
> ++        }
> ++        impl ::hash::Hash for gpregs {
> ++            fn hash<H: ::hash::Hasher>(&self, state: &mut H) {
> ++                self.gp_ra.hash(state);
> ++                self.gp_sp.hash(state);
> ++                self.gp_gp.hash(state);
> ++                self.gp_tp.hash(state);
> ++                self.gp_t.hash(state);
> ++                self.gp_s.hash(state);
> ++                self.gp_a.hash(state);
> ++                self.gp_sepc.hash(state);
> ++                self.gp_sstatus.hash(state);
> ++            }
> ++        }
> ++        impl PartialEq for fpregs {
> ++            fn eq(&self, other: &fpregs) -> bool {
> ++                self.fp_x == other.fp_x &&
> ++                self.fp_fcsr == other.fp_fcsr &&
> ++                self.fp_flags == other.fp_flags &&
> ++                self.fp_pad == other.fp_pad
> ++            }
> ++        }
> ++        impl Eq for fpregs {}
> ++        impl ::fmt::Debug for fpregs {
> ++            fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
> ++                f.debug_struct("fpregs")
> ++                    .field("fp_x", &self.fp_x)
> ++                    .field("fp_fcsr", &self.fp_fcsr)
> ++                    .field("fp_flags", &self.fp_flags)
> ++                    .field("fp_pad", &self.fp_pad)
> ++                    .finish()
> ++            }
> ++        }
> ++        impl ::hash::Hash for fpregs {
> ++            fn hash<H: ::hash::Hasher>(&self, state: &mut H) {
> ++                self.fp_x.hash(state);
> ++                self.fp_fcsr.hash(state);
> ++                self.fp_flags.hash(state);
> ++                self.fp_pad.hash(state);
> ++            }
> ++        }
> ++        impl PartialEq for mcontext_t {
> ++            fn eq(&self, other: &mcontext_t) -> bool {
> ++                self.mc_gpregs == other.mc_gpregs &&
> ++                self.mc_fpregs == other.mc_fpregs &&
> ++                self.mc_flags == other.mc_flags &&
> ++                self.mc_pad == other.mc_pad &&
> ++                self.mc_spare.iter().zip(other.mc_spare.iter()).all(|(a, b)| a == b)
> ++            }
> ++        }
> ++        impl Eq for mcontext_t {}
> ++        impl ::fmt::Debug for mcontext_t {
> ++            fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
> ++                f.debug_struct("mcontext_t")
> ++                    .field("mc_gpregs", &self.mc_gpregs)
> ++                    .field("mc_fpregs", &self.mc_fpregs)
> ++                    .field("mc_flags", &self.mc_flags)
> ++                    .field("mc_pad", &self.mc_pad)
> ++                    .field("mc_spare", &self.mc_spare)
> ++                    .finish()
> ++            }
> ++        }
> ++        impl ::hash::Hash for mcontext_t {
> ++            fn hash<H: ::hash::Hasher>(&self, state: &mut H) {
> ++                self.mc_gpregs.hash(state);
> ++                self.mc_fpregs.hash(state);
> ++                self.mc_flags.hash(state);
> ++                self.mc_pad.hash(state);
> ++                self.mc_spare.hash(state);
> ++            }
> ++        }
> ++    }
> ++}
> ++
> ++pub const MAP_32BIT: ::c_int = 0x00080000;
> ++pub const MINSIGSTKSZ: ::size_t = 4096; // 1024 * 4
> diff --git a/lang/rust/files/riscv64/patch-vendor_libc_src_unix_bsd_freebsdlike_freebsd_freebsd11_mod.rs b/lang/rust/files/riscv64/patch-vendor_libc_src_unix_bsd_freebsdlike_freebsd_freebsd11_mod.rs
> new file mode 100644
> index 000000000000..017c18db6f9c
> --- /dev/null
> +++ b/lang/rust/files/riscv64/patch-vendor_libc_src_unix_bsd_freebsdlike_freebsd_freebsd11_mod.rs
> @@ -0,0 +1,12 @@
> +--- vendor/libc/src/unix/bsd/freebsdlike/freebsd/freebsd11/mod.rs.orig	2021-11-29 20:27:33 UTC
> ++++ vendor/libc/src/unix/bsd/freebsdlike/freebsd/freebsd11/mod.rs
> +@@ -217,7 +217,8 @@ extern "C" {
> + 
> + cfg_if! {
> +     if #[cfg(any(target_arch = "x86_64",
> +-                 target_arch = "aarch64"))] {
> ++                 target_arch = "aarch64",
> ++                 target_arch = "riscv64"))] {
> +         mod b64;
> +         pub use self::b64::*;
> +     }
> diff --git a/lang/rust/files/riscv64/patch-vendor_libc_src_unix_bsd_freebsdlike_freebsd_freebsd12_mod.rs b/lang/rust/files/riscv64/patch-vendor_libc_src_unix_bsd_freebsdlike_freebsd_freebsd12_mod.rs
> new file mode 100644
> index 000000000000..599ba3d18247
> --- /dev/null
> +++ b/lang/rust/files/riscv64/patch-vendor_libc_src_unix_bsd_freebsdlike_freebsd_freebsd12_mod.rs
> @@ -0,0 +1,12 @@
> +--- vendor/libc/src/unix/bsd/freebsdlike/freebsd/freebsd12/mod.rs.orig	2021-11-29 20:27:33 UTC
> ++++ vendor/libc/src/unix/bsd/freebsdlike/freebsd/freebsd12/mod.rs
> +@@ -241,7 +241,8 @@ extern "C" {
> + 
> + cfg_if! {
> +     if #[cfg(any(target_arch = "x86_64",
> +-                 target_arch = "aarch64"))] {
> ++                 target_arch = "aarch64",
> ++                 target_arch = "riscv64"))] {
> +         mod b64;
> +         pub use self::b64::*;
> +     }
> diff --git a/lang/rust/files/riscv64/patch-vendor_libc_src_unix_bsd_freebsdlike_freebsd_freebsd13_mod.rs b/lang/rust/files/riscv64/patch-vendor_libc_src_unix_bsd_freebsdlike_freebsd_freebsd13_mod.rs
> new file mode 100644
> index 000000000000..4098c94249cc
> --- /dev/null
> +++ b/lang/rust/files/riscv64/patch-vendor_libc_src_unix_bsd_freebsdlike_freebsd_freebsd13_mod.rs
> @@ -0,0 +1,12 @@
> +--- vendor/libc/src/unix/bsd/freebsdlike/freebsd/freebsd13/mod.rs.orig	2021-11-29 20:27:33 UTC
> ++++ vendor/libc/src/unix/bsd/freebsdlike/freebsd/freebsd13/mod.rs
> +@@ -271,7 +271,8 @@ extern "C" {
> + 
> + cfg_if! {
> +     if #[cfg(any(target_arch = "x86_64",
> +-                 target_arch = "aarch64"))] {
> ++                 target_arch = "aarch64",
> ++                 target_arch = "riscv64"))] {
> +         mod b64;
> +         pub use self::b64::*;
> +     }
> diff --git a/lang/rust/files/riscv64/patch-vendor_libc_src_unix_bsd_freebsdlike_freebsd_mod.rs b/lang/rust/files/riscv64/patch-vendor_libc_src_unix_bsd_freebsdlike_freebsd_mod.rs
> new file mode 100644
> index 000000000000..a99c851e9422
> --- /dev/null
> +++ b/lang/rust/files/riscv64/patch-vendor_libc_src_unix_bsd_freebsdlike_freebsd_mod.rs
> @@ -0,0 +1,12 @@
> +--- vendor/libc/src/unix/bsd/freebsdlike/freebsd/mod.rs.orig	2021-11-29 20:27:33 UTC
> ++++ vendor/libc/src/unix/bsd/freebsdlike/freebsd/mod.rs
> +@@ -2021,6 +2021,9 @@ cfg_if! {
> +     } else if #[cfg(target_arch = "powerpc")] {
> +         mod powerpc;
> +         pub use self::powerpc::*;
> ++    } else if #[cfg(target_arch = "riscv64")] {
> ++        mod riscv64;
> ++        pub use self::riscv64::*;
> +     } else {
> +         // Unknown target_arch
> +     }
> diff --git a/lang/rust/files/riscv64/patch-vendor_libc_src_unix_bsd_freebsdlike_freebsd_riscv64.rs b/lang/rust/files/riscv64/patch-vendor_libc_src_unix_bsd_freebsdlike_freebsd_riscv64.rs
> new file mode 100644
> index 000000000000..103a066a39af
> --- /dev/null
> +++ b/lang/rust/files/riscv64/patch-vendor_libc_src_unix_bsd_freebsdlike_freebsd_riscv64.rs
> @@ -0,0 +1,157 @@
> +--- vendor/libc/src/unix/bsd/freebsdlike/freebsd/riscv64.rs.orig	2021-11-05 13:41:21 UTC
> ++++ vendor/libc/src/unix/bsd/freebsdlike/freebsd/riscv64.rs
> +@@ -0,0 +1,154 @@
> ++pub type c_char = u8;
> ++pub type c_long = i64;
> ++pub type c_ulong = u64;
> ++pub type wchar_t = ::c_int;
> ++pub type time_t = i64;
> ++pub type suseconds_t = ::c_long;
> ++pub type register_t = i64;
> ++
> ++// should be pub(crate), but that requires Rust 1.18.0
> ++cfg_if! {
> ++    if #[cfg(libc_const_size_of)] {
> ++        #[doc(hidden)]
> ++        pub const _ALIGNBYTES: usize = ::mem::size_of::<::c_longlong>() - 1;
> ++    } else {
> ++        #[doc(hidden)]
> ++        pub const _ALIGNBYTES: usize = 8 - 1;
> ++    }
> ++}
> ++
> ++s_no_extra_traits! {
> ++    pub struct gpregs {
> ++        pub gp_ra: ::register_t,
> ++        pub gp_sp: ::register_t,
> ++        pub gp_gp: ::register_t,
> ++        pub gp_tp: ::register_t,
> ++        pub gp_t: [::register_t; 7],
> ++        pub gp_s: [::register_t; 12],
> ++        pub gp_a: [::register_t; 8],
> ++        pub gp_sepc: ::register_t,
> ++        pub gp_sstatus: ::register_t,
> ++    }
> ++
> ++    pub struct fpregs {
> ++        pub fp_x: [[::register_t; 2]; 32],
> ++        pub fp_fcsr: ::register_t,
> ++        pub fp_flags: ::c_int,
> ++        pub fp_pad: ::c_int,
> ++    }
> ++
> ++    pub struct mcontext_t {
> ++        pub mc_gpregs: gpregs,
> ++        pub mc_fpregs: fpregs,
> ++        pub mc_flags: ::c_int,
> ++        pub mc_pad: ::c_int,
> ++        pub mc_spare: [u64; 8],
> ++    }
> ++}
> ++
> ++cfg_if! {
> ++    if #[cfg(feature = "extra_traits")] {
> ++        impl PartialEq for gpregs {
> ++            fn eq(&self, other: &gpregs) -> bool {
> ++                self.gp_ra == other.gp_ra &&
> ++                self.gp_sp == other.gp_sp &&
> ++                self.gp_gp == other.gp_gp &&
> ++                self.gp_tp == other.gp_tp &&
> ++                self.gp_t.iter().zip(other.gp_t.iter()).all(|(a, b)| a == b) &&
> ++                self.gp_s.iter().zip(other.gp_s.iter()).all(|(a, b)| a == b) &&
> ++                self.gp_a.iter().zip(other.gp_a.iter()).all(|(a, b)| a == b) &&
> ++                self.gp_sepc == other.gp_sepc &&
> ++                self.gp_sstatus == other.gp_sstatus
> ++            }
> ++        }
> ++        impl Eq for gpregs {}
> ++        impl ::fmt::Debug for gpregs {
> ++            fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
> ++                f.debug_struct("gpregs")
> ++                    .field("gp_ra", &self.gp_ra)
> ++                    .field("gp_sp", &self.gp_sp)
> ++                    .field("gp_gp", &self.gp_gp)
> ++                    .field("gp_tp", &self.gp_tp)
> ++                    .field("gp_t", &self.gp_t)
> ++                    .field("gp_s", &self.gp_s)
> ++                    .field("gp_a", &self.gp_a)
> ++                    .field("gp_sepc", &self.gp_sepc)
> ++                    .field("gp_sstatus", &self.gp_sstatus)
> ++                    .finish()
> ++            }
> ++        }
> ++        impl ::hash::Hash for gpregs {
> ++            fn hash<H: ::hash::Hasher>(&self, state: &mut H) {
> ++                self.gp_ra.hash(state);
> ++                self.gp_sp.hash(state);
> ++                self.gp_gp.hash(state);
> ++                self.gp_tp.hash(state);
> ++                self.gp_t.hash(state);
> ++                self.gp_s.hash(state);
> ++                self.gp_a.hash(state);
> ++                self.gp_sepc.hash(state);
> ++                self.gp_sstatus.hash(state);
> ++            }
> ++        }
> ++        impl PartialEq for fpregs {
> ++            fn eq(&self, other: &fpregs) -> bool {
> ++                self.fp_x == other.fp_x &&
> ++                self.fp_fcsr == other.fp_fcsr &&
> ++                self.fp_flags == other.fp_flags &&
> ++                self.fp_pad == other.fp_pad
> ++            }
> ++        }
> ++        impl Eq for fpregs {}
> ++        impl ::fmt::Debug for fpregs {
> ++            fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
> ++                f.debug_struct("fpregs")
> ++                    .field("fp_x", &self.fp_x)
> ++                    .field("fp_fcsr", &self.fp_fcsr)
> ++                    .field("fp_flags", &self.fp_flags)
> ++                    .field("fp_pad", &self.fp_pad)
> ++                    .finish()
> ++            }
> ++        }
> ++        impl ::hash::Hash for fpregs {
> ++            fn hash<H: ::hash::Hasher>(&self, state: &mut H) {
> ++                self.fp_x.hash(state);
> ++                self.fp_fcsr.hash(state);
> ++                self.fp_flags.hash(state);
> ++                self.fp_pad.hash(state);
> ++            }
> ++        }
> ++        impl PartialEq for mcontext_t {
> ++            fn eq(&self, other: &mcontext_t) -> bool {
> ++                self.mc_gpregs == other.mc_gpregs &&
> ++                self.mc_fpregs == other.mc_fpregs &&
> ++                self.mc_flags == other.mc_flags &&
> ++                self.mc_pad == other.mc_pad &&
> ++                self.mc_spare.iter().zip(other.mc_spare.iter()).all(|(a, b)| a == b)
> ++            }
> ++        }
> ++        impl Eq for mcontext_t {}
> ++        impl ::fmt::Debug for mcontext_t {
> ++            fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
> ++                f.debug_struct("mcontext_t")
> ++                    .field("mc_gpregs", &self.mc_gpregs)
> ++                    .field("mc_fpregs", &self.mc_fpregs)
> ++                    .field("mc_flags", &self.mc_flags)
> ++                    .field("mc_pad", &self.mc_pad)
> ++                    .field("mc_spare", &self.mc_spare)
> ++                    .finish()
> ++            }
> ++        }
> ++        impl ::hash::Hash for mcontext_t {
> ++            fn hash<H: ::hash::Hasher>(&self, state: &mut H) {
> ++                self.mc_gpregs.hash(state);
> ++                self.mc_fpregs.hash(state);
> ++                self.mc_flags.hash(state);
> ++                self.mc_pad.hash(state);
> ++                self.mc_spare.hash(state);
> ++            }
> ++        }
> ++    }
> ++}
> ++
> ++pub const MAP_32BIT: ::c_int = 0x00080000;
> ++pub const MINSIGSTKSZ: ::size_t = 4096; // 1024 * 4
> diff --git a/lang/rust/files/riscv64/patch-vendor_openssl-src_src_lib.rs b/lang/rust/files/riscv64/patch-vendor_openssl-src_src_lib.rs
> new file mode 100644
> index 000000000000..3171b5769f1a
> --- /dev/null
> +++ b/lang/rust/files/riscv64/patch-vendor_openssl-src_src_lib.rs
> @@ -0,0 +1,10 @@
> +--- vendor/openssl-src/src/lib.rs.orig	2021-11-04 11:27:54 UTC
> ++++ vendor/openssl-src/src/lib.rs
> +@@ -260,6 +260,7 @@ impl Build {
> +             "powerpc64le-unknown-freebsd" => "BSD-generic64",
> +             "powerpc64le-unknown-linux-gnu" => "linux-ppc64le",
> +             "powerpc64le-unknown-linux-musl" => "linux-ppc64le",
> ++            "riscv64gc-unknown-freebsd" => "BSD-generic64",
> +             "riscv64gc-unknown-linux-gnu" => "linux-generic64",
> +             "s390x-unknown-linux-gnu" => "linux64-s390x",
> +             "s390x-unknown-linux-musl" => "linux64-s390x",
> diff --git a/lang/rust/files/riscv64/patch-vendor_rustc__ap__rustc__target_src_spec_mod.rs b/lang/rust/files/riscv64/patch-vendor_rustc__ap__rustc__target_src_spec_mod.rs
> new file mode 100644
> index 000000000000..9e0858752a7f
> --- /dev/null
> +++ b/lang/rust/files/riscv64/patch-vendor_rustc__ap__rustc__target_src_spec_mod.rs
> @@ -0,0 +1,9 @@
> +--- vendor/rustc-ap-rustc_target/src/spec/mod.rs.orig	2021-11-04 11:23:50 UTC
> ++++ vendor/rustc-ap-rustc_target/src/spec/mod.rs
> +@@ -805,6 +805,7 @@ supported_targets! {
> +     ("powerpc-unknown-freebsd", powerpc_unknown_freebsd),
> +     ("powerpc64-unknown-freebsd", powerpc64_unknown_freebsd),
> ++    ("riscv64gc-unknown-freebsd", riscv64gc_unknown_freebsd),
> +     ("x86_64-unknown-freebsd", x86_64_unknown_freebsd),
> + 
> +     ("x86_64-unknown-dragonfly", x86_64_unknown_dragonfly),
> diff --git a/lang/rust/files/riscv64/patch-vendor_rustc__ap__rustc__target_src_spec_riscv64gc__unknown__freebsd.rs b/lang/rust/files/riscv64/patch-vendor_rustc__ap__rustc__target_src_spec_riscv64gc__unknown__freebsd.rs
> new file mode 100644
> index 000000000000..5faf5e2aacf8
> --- /dev/null
> +++ b/lang/rust/files/riscv64/patch-vendor_rustc__ap__rustc__target_src_spec_riscv64gc__unknown__freebsd.rs
> @@ -0,0 +1,21 @@
> +--- vendor/rustc-ap-rustc_target/src/spec/riscv64gc_unknown_freebsd.rs.orig	2021-11-04 11:22:10 UTC
> ++++ vendor/rustc-ap-rustc_target/src/spec/riscv64gc_unknown_freebsd.rs
> +@@ -0,0 +1,18 @@
> ++use crate::spec::{CodeModel, Target, TargetOptions};
> ++
> ++pub fn target() -> Target {
> ++    Target {
> ++        llvm_target: "riscv64-unknown-freebsd".to_string(),
> ++        pointer_width: 64,
> ++        data_layout: "e-m:e-p:64:64-i64:64-i128:128-n64-S128".to_string(),
> ++        arch: "riscv64".to_string(),
> ++        options: TargetOptions {
> ++            code_model: Some(CodeModel::Medium),
> ++            cpu: "generic-rv64".to_string(),
> ++            features: "+m,+a,+f,+d,+c".to_string(),
> ++            llvm_abiname: "lp64d".to_string(),
> ++            max_atomic_width: Some(64),
> ++            ..super::freebsd_base::opts()
> ++        },
> ++    }
> ++}