From c1a4b0518a54dd61efe254016c4621b5877a3190 Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Tue, 22 Apr 2025 12:07:43 -0700 Subject: [PATCH 01/18] [zcheri] Initial support for the RISC-V CHERI standard This adds a --riscv-cheri-isa flag to choose the target toolchain. --- pycheribuild/boot_cheribsd/__init__.py | 10 ++++++++-- pycheribuild/config/chericonfig.py | 12 ++++++++++++ pycheribuild/config/compilation_targets.py | 14 +++++++++----- pycheribuild/projects/build_qemu.py | 8 ++++++-- pycheribuild/projects/cross/bbl.py | 4 ++-- pycheribuild/projects/cross/freertos.py | 6 +++--- pycheribuild/projects/cross/littlekernel.py | 2 +- pycheribuild/projects/cross/opensbi.py | 21 ++++++++++++++------- pycheribuild/projects/cross/picolibc.py | 2 +- pycheribuild/projects/run_qemu.py | 8 ++++++-- pycheribuild/projects/syzkaller.py | 2 +- pycheribuild/qemu_utils.py | 21 +++++++++++++++++---- 12 files changed, 80 insertions(+), 30 deletions(-) diff --git a/pycheribuild/boot_cheribsd/__init__.py b/pycheribuild/boot_cheribsd/__init__.py index 76e2ffa8a..dcc313bd7 100755 --- a/pycheribuild/boot_cheribsd/__init__.py +++ b/pycheribuild/boot_cheribsd/__init__.py @@ -53,6 +53,7 @@ from typing import Callable, Optional, Union from ..colour import AnsiColour, coloured +from ..config.chericonfig import RiscvCheriISA from ..config.compilation_targets import CompilationTargets, CrossCompileTarget from ..processutils import commandline_to_str, keep_terminal_sane, run_and_kill_children_on_exit from ..qemu_utils import QemuOptions, riscv_bios_arguments @@ -916,7 +917,7 @@ def boot_cheribsd( if bios_path is not None: bios_args = ["-bios", str(bios_path)] elif qemu_options.xtarget.is_riscv(include_purecap=True): - bios_args = riscv_bios_arguments(qemu_options.xtarget, None) + bios_args = riscv_bios_arguments(qemu_options.xtarget, qemu_options.riscv_cheri_isa) else: bios_args = [] qemu_args = qemu_options.get_commandline( @@ -1516,7 +1517,12 @@ def _main( if argparse_adjust_args_callback: argparse_adjust_args_callback(args) - qemu_options = QemuOptions(xtarget) + riscv_cheri_isa = None + # Slightly ugly hack to avoid having to pass yet another argument for something + # that is a temporary workaround until ISAv9 is gone. + if args.qemu_cmd is not None and str(args.qemu_cmd).endswith("cheristd"): + riscv_cheri_isa = RiscvCheriISA.STD + qemu_options = QemuOptions(xtarget, riscv_cheri_isa=riscv_cheri_isa) if args.qemu_cmd is not None: if not Path(args.qemu_cmd).exists(): failure("ERROR: Cannot find QEMU binary ", args.qemu_cmd, " doesn't exist", exit=True) diff --git a/pycheribuild/config/chericonfig.py b/pycheribuild/config/chericonfig.py index 4948a2438..3825e136c 100644 --- a/pycheribuild/config/chericonfig.py +++ b/pycheribuild/config/chericonfig.py @@ -123,6 +123,11 @@ def clang_march_flag(self) -> str: return self.value[1] +class RiscvCheriISA(Enum): + V9 = "v9" + STD = "std" + + class RiscvFloatAbi(Enum): SOFT = "soft" HARD = "hard" @@ -319,6 +324,13 @@ def __init__(self, loader, action_class: "type[CheribuildActionEnum]") -> None: self.skip_configure: "Optional[bool] " = None self.force_configure: "Optional[bool] " = None self.force_update: "Optional[bool] " = None + self.riscv_cheri_isa = loader.add_option( + "riscv-cheri-isa", + default=RiscvCheriISA.V9, + type=RiscvCheriISA, + group=loader.cross_compile_options_group, + help="The CHERI ISA to target for RISC-V code", + ) self.mips_float_abi = loader.add_option( "mips-float-abi", default=MipsFloatAbi.SOFT, diff --git a/pycheribuild/config/compilation_targets.py b/pycheribuild/config/compilation_targets.py index 3717b256a..1b5737c2d 100644 --- a/pycheribuild/config/compilation_targets.py +++ b/pycheribuild/config/compilation_targets.py @@ -40,7 +40,7 @@ from pathlib import Path from typing import Optional -from .chericonfig import CheriConfig +from .chericonfig import CheriConfig, RiscvCheriISA from .config_loader_base import ConfigLoaderBase, ConfigOptionHandle from .target_info import ( AArch64FloatSimdOptions, @@ -277,7 +277,7 @@ def essential_compiler_and_linker_flags_impl( result.append("-mcpu=beri") elif xtarget.is_riscv(include_purecap=True): # Use the insane RISC-V arch string to enable CHERI - result.append("-march=" + cls.get_riscv_arch_string(xtarget, softfloat=softfloat)) + result.append("-march=" + cls.get_riscv_arch_string(xtarget, config, softfloat=softfloat)) result.append("-mabi=" + cls.get_riscv_abi(xtarget, softfloat=softfloat)) result.append( "-mrelax" if _linker_supports_riscv_relaxations(instance.linker, config, xtarget) else "-mno-relax" @@ -313,7 +313,7 @@ def essential_compiler_and_linker_flags_impl( return result @classmethod - def get_riscv_arch_string(cls, xtarget: CrossCompileTarget, softfloat: bool) -> str: + def get_riscv_arch_string(cls, xtarget: CrossCompileTarget, config: CheriConfig, softfloat: bool) -> str: assert xtarget.is_riscv(include_purecap=True) # Use the insane RISC-V arch string to enable CHERI arch_string = "rv" + str(xtarget.cpu_architecture.word_bits()) + "ima" @@ -321,7 +321,11 @@ def get_riscv_arch_string(cls, xtarget: CrossCompileTarget, softfloat: bool) -> arch_string += "fd" arch_string += "c" if xtarget.is_hybrid_or_purecap_cheri(): - arch_string += "xcheri" + if config.riscv_cheri_isa == RiscvCheriISA.V9: + arch_string += "xcheri" + else: + assert config.riscv_cheri_isa == RiscvCheriISA.STD + arch_string += "zcherihybrid" return arch_string @classmethod @@ -502,7 +506,7 @@ def has_test_extra_arg_override(arg: str): rootfs_xtarget = xtarget.get_rootfs_target() from ..qemu_utils import QemuOptions - qemu_options = QemuOptions(rootfs_xtarget) + qemu_options = QemuOptions(rootfs_xtarget, riscv_cheri_isa=self.config.riscv_cheri_isa) run_instance: LaunchFreeBSDInterface = self._get_run_project(rootfs_xtarget, self.project) if rootfs_xtarget.cpu_architecture not in ( CPUArchitecture.MIPS64, diff --git a/pycheribuild/projects/build_qemu.py b/pycheribuild/projects/build_qemu.py index 1a76311fa..487cb4dc7 100644 --- a/pycheribuild/projects/build_qemu.py +++ b/pycheribuild/projects/build_qemu.py @@ -51,6 +51,7 @@ Project, ) from .simple_project import BoolConfigOption, SimpleProject, _cached_get_homebrew_prefix +from ..config.chericonfig import RiscvCheriISA from ..config.compilation_targets import BaremetalFreestandingTargetInfo, CompilationTargets from ..config.config_loader_base import ConfigOptionHandle from ..processutils import get_program_version @@ -486,10 +487,13 @@ def qemu_binary_for_target(cls, xtarget: CrossCompileTarget, config: CheriConfig # Always use the CHERI qemu even for plain riscv: if xtarget.is_riscv(include_purecap=True): xlen = 32 if xtarget.is_riscv32(include_purecap=True) else 64 - binary_name = f"qemu-system-riscv{xlen}cheri" # Prefer the xcheri-suffixed binary (if it exists) to ensure backwards compatibility. - if (config.qemu_bindir / f"qemu-system-riscv{xlen}xcheri").exists(): + if config.riscv_cheri_isa == RiscvCheriISA.STD: + binary_name = f"qemu-system-riscv{xlen}cheristd" + elif (config.qemu_bindir / f"qemu-system-riscv{xlen}xcheri").exists(): binary_name = f"qemu-system-riscv{xlen}xcheri" + else: + binary_name = f"qemu-system-riscv{xlen}cheri" elif xtarget.is_mips(include_purecap=True): binary_name = "qemu-system-mips64cheri128" elif xtarget.is_aarch64(include_purecap=True): diff --git a/pycheribuild/projects/cross/bbl.py b/pycheribuild/projects/cross/bbl.py index bbd649cba..d50814425 100644 --- a/pycheribuild/projects/cross/bbl.py +++ b/pycheribuild/projects/cross/bbl.py @@ -91,7 +91,7 @@ def setup(self): tinfo = cast(self.target_info, BaremetalClangTargetInfo) # Assume hardfloat architecture and softfloat ABI self.configure_args.append( - "--with-arch=" + tinfo.get_riscv_arch_string(self.crosscompile_target, softfloat=False), + "--with-arch=" + tinfo.get_riscv_arch_string(self.crosscompile_target, self.config, softfloat=False), ) self.configure_args.append("--with-abi=" + tinfo.get_riscv_abi(self.crosscompile_target, softfloat=True)) self.configure_args.append("--with-mem-start=" + self.mem_start) @@ -160,7 +160,7 @@ def setup(self): self.configure_args.append("--enable-print-device-tree") def run_tests(self) -> None: - options = QemuOptions(self.crosscompile_target) + options = QemuOptions(self.crosscompile_target, riscv_cheri_isa=self.config.riscv_cheri_isa) self.run_cmd( options.get_commandline( qemu_command=BuildQEMU.qemu_binary(self), diff --git a/pycheribuild/projects/cross/freertos.py b/pycheribuild/projects/cross/freertos.py index 11cf3c6fa..fe11bc99f 100644 --- a/pycheribuild/projects/cross/freertos.py +++ b/pycheribuild/projects/cross/freertos.py @@ -76,7 +76,7 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.default_demo_app = ( "qemu_virt-" - + self.target_info.get_riscv_arch_string(self.crosscompile_target, softfloat=True) + + self.target_info.get_riscv_arch_string(self.crosscompile_target, self.config, softfloat=True) + self.target_info.get_riscv_abi(self.crosscompile_target, softfloat=True) ) @@ -145,7 +145,7 @@ def setup_config_options(cls, **kwargs): def default_demo_bsp(self): return ( "qemu_virt-" - + self.target_info.get_riscv_arch_string(self.crosscompile_target, softfloat=True) + + self.target_info.get_riscv_arch_string(self.crosscompile_target, self.config, softfloat=True) + "-" + self.target_info.get_riscv_abi(self.crosscompile_target, softfloat=True) ) @@ -252,7 +252,7 @@ def setup_config_options(cls, **kwargs): def default_demo_bsp(self): return ( "qemu_virt-" - + self.target_info.get_riscv_arch_string(self.crosscompile_target, softfloat=True) + + self.target_info.get_riscv_arch_string(self.crosscompile_target, self.config, softfloat=True) + "-" + self.target_info.get_riscv_abi(self.crosscompile_target, softfloat=True) ) diff --git a/pycheribuild/projects/cross/littlekernel.py b/pycheribuild/projects/cross/littlekernel.py index bd0e8a9b3..2eb7f6d5a 100644 --- a/pycheribuild/projects/cross/littlekernel.py +++ b/pycheribuild/projects/cross/littlekernel.py @@ -164,7 +164,7 @@ def run_tests(self): elif self.compiling_for_riscv(include_purecap=True): bios_args = ["-bios", "none"] if self.use_mmu: - bios_args = riscv_bios_arguments(self.crosscompile_target, self) + bios_args = riscv_bios_arguments(self.crosscompile_target, self.config.riscv_cheri_isa) cmd = [ qemu, "-cpu", diff --git a/pycheribuild/projects/cross/opensbi.py b/pycheribuild/projects/cross/opensbi.py index efc45aa64..f3add3d28 100644 --- a/pycheribuild/projects/cross/opensbi.py +++ b/pycheribuild/projects/cross/opensbi.py @@ -42,6 +42,7 @@ Project, ReuseOtherProjectRepository, ) +from ...config.chericonfig import RiscvCheriISA from ...config.compilation_targets import CompilationTargets from ...qemu_utils import QemuOptions from ...utils import OSInfo, classproperty @@ -60,7 +61,7 @@ class BuildOpenSBI(Project): supported_architectures = ( CompilationTargets.FREESTANDING_RISCV64_HYBRID, CompilationTargets.FREESTANDING_RISCV64, - # Won't compile yet: CompilationTargets.FREESTANDING_RISCV64_PURECAP + CompilationTargets.FREESTANDING_RISCV64_PURECAP, ) make_kind = MakeCommandKind.GnuMake _always_add_suffixed_targets = True @@ -98,7 +99,9 @@ def setup(self): # FW_JUMP_ADDR= ## cheribsd start addr # FW_JUMP_FDT_ADDR= ## cheribsd fdt addr PLATFORM_RISCV_ABI=self.target_info.get_riscv_abi(self.crosscompile_target, softfloat=True), - PLATFORM_RISCV_ISA=self.target_info.get_riscv_arch_string(self.crosscompile_target, softfloat=True), + PLATFORM_RISCV_ISA=self.target_info.get_riscv_arch_string( + self.crosscompile_target, self.config, softfloat=True + ), PLATFORM_RISCV_XLEN=64, ) if self.config.verbose: @@ -107,9 +110,9 @@ def setup(self): @property def all_platforms(self): platforms_dir = self.source_dir / "platform" - self.info(list(platforms_dir.glob("**/config.mk"))) + self.info(list(platforms_dir.glob("**/objects.mk"))) all_platforms = [] - for c in platforms_dir.glob("**/config.mk"): + for c in platforms_dir.glob("**/objects.mk"): relpath = str(c.parent.relative_to(platforms_dir)) if relpath != "template": all_platforms.append(relpath) @@ -120,6 +123,8 @@ def all_platforms(self): return ["generic"] def compile(self, **kwargs): + if self.compiling_for_cheri() and self.config.riscv_cheri_isa != RiscvCheriISA.STD: + self.fatal("Purecap openSBI is only supported for the staandard ISA for now.") for platform in self.all_platforms: args = self.make_args.copy() args.set(PLATFORM=platform) @@ -132,17 +137,19 @@ def install(self, **kwargs): args.set(PLATFORM=platform) self.run_make_install(cwd=self.source_dir, options=args) # Only install BuildBBLNoPayload as the QEMU bios and not the GFE version by checking build_dir_suffix - if self.crosscompile_target.is_cheri_hybrid() and not self.build_dir_suffix: + if self.crosscompile_target.is_hybrid_or_purecap_cheri() and not self.build_dir_suffix: # Install into the QEMU firware directory so that `-bios default` works qemu_fw_dir = BuildQEMU.get_install_dir(self, cross_target=CompilationTargets.NATIVE) / "share/qemu/" + suffix = "cheristd" if self.crosscompile_target.is_cheri_purecap() else "cheri" self.makedirs(qemu_fw_dir) + # TODO: looks like newer versions install a .bin that we could just copy instead. self.run_cmd( self.sdk_bindir / "llvm-objcopy", "-S", "-O", "binary", self._fw_jump_path(), - qemu_fw_dir / "opensbi-riscv64cheri-virt-fw_jump.bin", + qemu_fw_dir / f"opensbi-riscv64{suffix}-virt-fw_jump.bin", print_verbose_only=False, ) @@ -190,7 +197,7 @@ class BuildUpstreamOpenSBI(BuildOpenSBI): supported_architectures = (CompilationTargets.FREESTANDING_RISCV64,) def run_tests(self): - options = QemuOptions(self.crosscompile_target) + options = QemuOptions(self.crosscompile_target, riscv_cheri_isa=self.config.riscv_cheri_isa) self.run_cmd( options.get_commandline( qemu_command=BuildQEMU.qemu_binary(self), diff --git a/pycheribuild/projects/cross/picolibc.py b/pycheribuild/projects/cross/picolibc.py index bb9bda4fe..2ebc7d60a 100644 --- a/pycheribuild/projects/cross/picolibc.py +++ b/pycheribuild/projects/cross/picolibc.py @@ -143,7 +143,7 @@ def install(self, **kwargs): softfloat = self.uses_softfloat_by_default() rv_abi = self.target_info.get_riscv_abi(self.crosscompile_target, softfloat=softfloat) rv_arch = self.target_info.get_riscv_arch_string( - self.crosscompile_target.get_non_cheri_target(), softfloat=softfloat + self.crosscompile_target.get_non_cheri_target(), self.config, softfloat=softfloat ) self.makedirs(self.install_dir / rv_arch) self.create_symlink(self.install_dir, self.install_dir / rv_arch / rv_abi, print_verbose_only=False) diff --git a/pycheribuild/projects/run_qemu.py b/pycheribuild/projects/run_qemu.py index 2cbcd6f7b..4fc970142 100644 --- a/pycheribuild/projects/run_qemu.py +++ b/pycheribuild/projects/run_qemu.py @@ -224,14 +224,18 @@ def __init__(self, *args, **kwargs): self.disk_image_format = "raw" self._project_specific_options = [] self.bios_flags = [] - self.qemu_options = QemuOptions(self.crosscompile_target, want_debugger=self.config.wait_for_debugger) + self.qemu_options = QemuOptions( + self.crosscompile_target, + want_debugger=self.config.wait_for_debugger, + riscv_cheri_isa=self.config.riscv_cheri_isa, + ) self.qemu_user_networking = True self.rootfs_path: Optional[Path] = None self._after_disk_options = [] def get_riscv_bios_args(self) -> "list[str]": # Explicit bios args no longer needed now that qemu defaults to a different file name for CHERI - return riscv_bios_arguments(self.crosscompile_target, self) + return riscv_bios_arguments(self.crosscompile_target, self.config.riscv_cheri_isa) @classmethod def targets_reset(cls): diff --git a/pycheribuild/projects/syzkaller.py b/pycheribuild/projects/syzkaller.py index a59492e03..989c8313e 100644 --- a/pycheribuild/projects/syzkaller.py +++ b/pycheribuild/projects/syzkaller.py @@ -214,7 +214,7 @@ def syzkaller_config(self, syzkaller: BuildSyzkaller): # Run in debug mode vm_type = "none" - qemu_opts = QemuOptions(self.crosscompile_target) + qemu_opts = QemuOptions(self.crosscompile_target, riscv_cheri_isa=self.config.riscv_cheri_isa) qemu_args = [*qemu_opts.machine_flags, "-device", "virtio-rng-pci", "-D", "syz-trace.log"] template = { "name": "cheribsd-n64", diff --git a/pycheribuild/qemu_utils.py b/pycheribuild/qemu_utils.py index 90f7ad6f6..d6f8ff8a6 100644 --- a/pycheribuild/qemu_utils.py +++ b/pycheribuild/qemu_utils.py @@ -33,19 +33,23 @@ from pathlib import Path from typing import Optional +from .config.chericonfig import RiscvCheriISA from .config.target_info import CPUArchitecture, CrossCompileTarget from .processutils import run_command from .utils import ConfigBase, OSInfo, warning_message class QemuOptions: - def __init__(self, xtarget: CrossCompileTarget, want_debugger=False) -> None: + def __init__( + self, xtarget: CrossCompileTarget, want_debugger=False, riscv_cheri_isa: Optional[RiscvCheriISA] = None + ) -> None: self.xtarget = xtarget self.virtio_disk = True self.force_virtio_blk_device = False self.can_boot_kernel_directly = False self.memory_size = "2048" self.has_default_nic = False + self.riscv_cheri_isa = riscv_cheri_isa if xtarget.is_hybrid_or_purecap_cheri([CPUArchitecture.AARCH64]): self._qemu_arch_suffix = "morello" self.can_boot_kernel_directly = False # boot from disk @@ -63,8 +67,14 @@ def __init__(self, xtarget: CrossCompileTarget, want_debugger=False) -> None: self.has_default_nic = True # MALTA board has a default pcnet at 0x0b elif xtarget.is_riscv(include_purecap=True): # Note: we always use the CHERI QEMU - self._qemu_arch_suffix = "riscv32cheri" if xtarget.is_riscv32(include_purecap=True) else "riscv64cheri" + xlen = 32 if xtarget.is_riscv32(include_purecap=True) else 64 self.machine_flags = ["-M", "virt"] + if riscv_cheri_isa is RiscvCheriISA.STD: + self._qemu_arch_suffix = self._qemu_arch_suffix = f"riscv{xlen}cheristd" + # cheri_levels=2 enables local/global, cheri_pte enables the UCRG feature + self.machine_flags.extend(["-cpu", "codasip-a730,cheri_pte=on,cheri_levels=2"]) + else: + self._qemu_arch_suffix = f"riscv{xlen}cheri" self.can_boot_kernel_directly = True elif xtarget.is_any_x86(): # We boot i386 FreeBSD in a x86_64 QEMU. This avoids having to build another version of QEMU. @@ -232,10 +242,13 @@ def qemu_supports_9pfs(qemu: Path, *, config: ConfigBase) -> bool: return b"-virtfs ?: Usage: -virtfs" in prog.stderr -def riscv_bios_arguments(xtarget: CrossCompileTarget, _, prefer_bbl=True) -> "list[str]": +def riscv_bios_arguments( + xtarget: CrossCompileTarget, cheri_isa: Optional[RiscvCheriISA], prefer_bbl=True +) -> "list[str]": assert xtarget.is_riscv(include_purecap=True) if xtarget.is_hybrid_or_purecap_cheri([CPUArchitecture.RISCV64]): - # noinspection PyUnreachableCode + if cheri_isa == RiscvCheriISA.STD: + return ["-bios", "opensbi-riscv64cheristd-virt-fw_jump.bin"] if prefer_bbl: # We want a purecap BBL: # from .projects.cross.bbl import BuildBBLNoPayload From 648dda8901e061f28dcc3c691122cd2a4374e095 Mon Sep 17 00:00:00 2001 From: Alfredo Mazzinghi Date: Mon, 26 May 2025 15:09:58 +0100 Subject: [PATCH 02/18] [zcheri] Honor riscv_cheri_isa configuration flag for CheriBSD builds. --- pycheribuild/projects/cross/cheribsd.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/pycheribuild/projects/cross/cheribsd.py b/pycheribuild/projects/cross/cheribsd.py index 705c9264b..eceb8a8a9 100644 --- a/pycheribuild/projects/cross/cheribsd.py +++ b/pycheribuild/projects/cross/cheribsd.py @@ -55,6 +55,7 @@ ReuseOtherProjectRepository, ) from ..simple_project import SimpleProject, TargetAliasWithDependencies, _clear_line_sequence, flush_stdio +from ...config.chericonfig import RiscvCheriISA from ...config.compilation_targets import CompilationTargets, FreeBSDTargetInfo from ...config.loader import ConfigOptionHandle from ...config.target_info import AutoVarInit, CompilerType, CrossCompileTarget @@ -829,7 +830,12 @@ def arch_build_flags(self) -> "dict[str, Union[str, bool]]": # FIXME: still needed? result["WITH_CHERI"] = True else: - result["TARGET_CPUTYPE"] = "cheri" + if self.config.riscv_cheri_isa == RiscvCheriISA.STD: + result["TARGET_CPUTYPE"] = "cheri" + elif self.config.riscv_cheri_isa == RiscvCheriISA.V9: + result["TARGET_CPUTYPE"] = "xcheri" + else: + assert False, "Not reached: unsupported RISC-V Cheri ISA" if self.compiling_for_mips(include_purecap=True): result["CHERI"] = self.config.mips_cheri_bits_str return result From 96049c5447bdc0ce42a030418b44c691dc668fa1 Mon Sep 17 00:00:00 2001 From: Alfredo Mazzinghi Date: Fri, 8 Aug 2025 11:27:21 +0100 Subject: [PATCH 03/18] [zcheri] Add CHERI Alliance SDK (QEMU and LLVM) Imitate morello-llvm to build CHERI Alliance's LLVM and QEMU for --riscv-cheri-isa std. This only applies to CHERI-RISC-V. Co-authored-by: Hesham Almatary --- pycheribuild/projects/cross/opensbi.py | 44 +++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/pycheribuild/projects/cross/opensbi.py b/pycheribuild/projects/cross/opensbi.py index f3add3d28..0eefbd92e 100644 --- a/pycheribuild/projects/cross/opensbi.py +++ b/pycheribuild/projects/cross/opensbi.py @@ -30,7 +30,7 @@ from pathlib import Path -from ..build_qemu import BuildQEMU +from ..build_qemu import BuildCheriAllianceQEMU, BuildQEMU from ..project import ( BuildType, CheriConfig, @@ -83,6 +83,8 @@ def setup(self): super().setup() compflags = " " + self.commandline_to_str(self.essential_compiler_and_linker_flags) compflags += " -Qunused-arguments" # -mstrict-align -no-pie + if self.config.riscv_cheri_isa == RiscvCheriISA.STD: + compflags += " -mno-relax" if OSInfo.IS_MAC: self.make_args.set(READLINK="greadlink") self.make_args.set( @@ -124,7 +126,7 @@ def all_platforms(self): def compile(self, **kwargs): if self.compiling_for_cheri() and self.config.riscv_cheri_isa != RiscvCheriISA.STD: - self.fatal("Purecap openSBI is only supported for the staandard ISA for now.") + self.fatal("Purecap openSBI is only supported for the standard ISA for now.") for platform in self.all_platforms: args = self.make_args.copy() args.set(PLATFORM=platform) @@ -139,8 +141,12 @@ def install(self, **kwargs): # Only install BuildBBLNoPayload as the QEMU bios and not the GFE version by checking build_dir_suffix if self.crosscompile_target.is_hybrid_or_purecap_cheri() and not self.build_dir_suffix: # Install into the QEMU firware directory so that `-bios default` works - qemu_fw_dir = BuildQEMU.get_install_dir(self, cross_target=CompilationTargets.NATIVE) / "share/qemu/" - suffix = "cheristd" if self.crosscompile_target.is_cheri_purecap() else "cheri" + qemu_fw_dir = self._qemu_install_dir() / "share/qemu/" + suffix = "" + if self.crosscompile_target.is_cheri_purecap(): + suffix = "cheri" + if self.config.riscv_cheri_isa == RiscvCheriISA.STD: + suffix += "std" self.makedirs(qemu_fw_dir) # TODO: looks like newer versions install a .bin that we could just copy instead. self.run_cmd( @@ -158,6 +164,9 @@ def _fw_jump_path(self) -> Path: abi = self.target_info.get_riscv_abi(self.crosscompile_target, softfloat=True) return self.install_dir / f"share/opensbi/{abi}/generic/firmware/fw_jump.elf" + def _qemu_install_dir(self) -> Path: + return BuildQEMU.get_install_dir(self, cross_target=CompilationTargets.NATIVE) + @classmethod def get_nocap_instance(cls, caller, cpu_arch=CPUArchitecture.RISCV64) -> "BuildOpenSBI": assert cpu_arch == CPUArchitecture.RISCV64, "RISCV32 not supported yet" @@ -208,3 +217,30 @@ def run_tests(self): give_tty_control=True, cwd="/", ) + + +class BuildAllianceOpenSBI(BuildOpenSBI): + target = "cheri-alliance-opensbi" + _default_install_dir_fn = ComputedDefaultValue( + function=lambda config, p: config.cheri_alliance_sdk_dir / "opensbi/riscv64", + as_string="$SDK_ROOT/opensbi/riscv64", + ) + repository = GitRepository("https://github.com/CHERI-Alliance/opensbi", default_branch="codasip-cheri-riscv") + supported_architectures = ( + CompilationTargets.FREESTANDING_RISCV64, + CompilationTargets.FREESTANDING_RISCV64_PURECAP, + ) + + def _qemu_install_dir(self) -> Path: + return BuildCheriAllianceQEMU.get_install_dir(self, cross_target=CompilationTargets.NATIVE) + + + @property + def all_platforms(self): + return ["generic"] + + def compile(self, **kwargs): + for platform in self.all_platforms: + args = self.make_args.copy() + args.set(PLATFORM=platform) + self.run_make(parallel=False, cwd=self.source_dir, options=args) From 48d415d16592366f0a4da849cbd35e97143df2d9 Mon Sep 17 00:00:00 2001 From: Alfredo Mazzinghi Date: Fri, 8 Aug 2025 11:27:56 +0100 Subject: [PATCH 04/18] [zcheri] Default OpenSBI start to 0x80000000 Otherwise it'll link to 0x0. Co-authored-by: Hesham Almatary --- pycheribuild/projects/cross/opensbi.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pycheribuild/projects/cross/opensbi.py b/pycheribuild/projects/cross/opensbi.py index 0eefbd92e..b53339d01 100644 --- a/pycheribuild/projects/cross/opensbi.py +++ b/pycheribuild/projects/cross/opensbi.py @@ -234,6 +234,9 @@ class BuildAllianceOpenSBI(BuildOpenSBI): def _qemu_install_dir(self) -> Path: return BuildCheriAllianceQEMU.get_install_dir(self, cross_target=CompilationTargets.NATIVE) + def setup(self): + super().setup() + self.make_args.set(FW_TEXT_START=0x80000000) @property def all_platforms(self): From 65e276df78556c83018fb509a624f07b12dfd1be Mon Sep 17 00:00:00 2001 From: Franz Fuchs Date: Thu, 29 May 2025 10:51:13 +0100 Subject: [PATCH 05/18] [zcheri] Added gfe build for cheri alliance opensbi --- pycheribuild/projects/cross/opensbi.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pycheribuild/projects/cross/opensbi.py b/pycheribuild/projects/cross/opensbi.py index b53339d01..12d9c7e3b 100644 --- a/pycheribuild/projects/cross/opensbi.py +++ b/pycheribuild/projects/cross/opensbi.py @@ -247,3 +247,12 @@ def compile(self, **kwargs): args = self.make_args.copy() args.set(PLATFORM=platform) self.run_make(parallel=False, cwd=self.source_dir, options=args) + + +class BuildAllianceOpenSBIGFE(BuildAllianceOpenSBI): + target = "cheri-alliance-opensbi-gfe" + repository = ReuseOtherProjectRepository(BuildAllianceOpenSBI, do_update=True) + + def setup(self): + super().setup() + self.make_args.set(FW_TEXT_START=0xC0000000) From e6936bf06832e1213819801cf2e582274a706281 Mon Sep 17 00:00:00 2001 From: Hesham Almatary Date: Mon, 23 Jun 2025 10:45:36 +0000 Subject: [PATCH 06/18] [zcheri] Add CHERI Alliance SDK (QEMU and LLVM) Imitate morello-llvm to build CHERI Alliance's LLVM and QEMU for --riscv-cheri-isa std. This only applies to CHERI-RISC-V. --- pycheribuild/config/chericonfig.py | 13 ++++++ pycheribuild/config/compilation_targets.py | 28 +++++++++++++ pycheribuild/config/defaultconfig.py | 10 +++++ pycheribuild/config/jenkinsconfig.py | 13 ++++++ pycheribuild/config/target_info.py | 4 ++ pycheribuild/projects/build_qemu.py | 49 ++++++++++++++++++++++ pycheribuild/projects/cross/llvm.py | 47 +++++++++++++++++++-- tests/setup_mock_chericonfig.py | 1 + 8 files changed, 161 insertions(+), 4 deletions(-) diff --git a/pycheribuild/config/chericonfig.py b/pycheribuild/config/chericonfig.py index 3825e136c..372167846 100644 --- a/pycheribuild/config/chericonfig.py +++ b/pycheribuild/config/chericonfig.py @@ -467,6 +467,7 @@ def __init__(self, loader, action_class: "type[CheribuildActionEnum]") -> None: self.cheribsd_image_root: Optional[Path] = None self.cheri_sdk_dir: Optional[Path] = None self.morello_sdk_dir: Optional[Path] = None + self.cheri_alliance_sdk_dir: Optional[Path] = None self.other_tools_dir: Optional[Path] = None self.sysroot_output_root: Optional[Path] = None self.docker = loader.add_bool_option( @@ -749,6 +750,10 @@ def default_cheri_sdk_directory_name(self) -> str: def default_morello_sdk_directory_name(self) -> str: return "morello-sdk" + @property + def default_cheri_alliance_sdk_directory_name(self) -> str: + return "cheri-alliance-sdk" + @property def cheri_sdk_bindir(self): return self.cheri_sdk_dir / "bin" @@ -757,6 +762,14 @@ def cheri_sdk_bindir(self): def morello_sdk_bindir(self): return self.morello_sdk_dir / "bin" + @property + def cheri_alliance_sdk_bindir(self): + return self.cheri_alliance_sdk_dir / "bin" + + @property + def cheri_alliance_qemu_bindir(self): + return self.cheri_alliance_sdk_bindir + @property def qemu_bindir(self): return self.cheri_sdk_bindir diff --git a/pycheribuild/config/compilation_targets.py b/pycheribuild/config/compilation_targets.py index 1b5737c2d..d01530f80 100644 --- a/pycheribuild/config/compilation_targets.py +++ b/pycheribuild/config/compilation_targets.py @@ -1044,6 +1044,34 @@ def sysroot_dir(self) -> Path: return sysroot_dir / "baremetal" / self.target.get_rootfs_target().generic_arch_suffix +class BaremetalFreestandingCheriAllianceTargetInfo(BaremetalClangTargetInfo): + shortname: str = "Baremetal" + os_prefix: str = "baremetal-" + uses_cheri_alliance_llvm: bool = True + + @classmethod + def _get_compiler_project(cls) -> "type[BuildLLVMInterface]": + return typing.cast("type[BuildLLVMInterface]", + SimpleProject.get_class_for_target_name("cheri-alliance-llvm", None)) + + @classmethod + def base_sysroot_targets(cls, target: "CrossCompileTarget", config: "CheriConfig") -> "list[str]": + return [] + + @classmethod + def triple_for_target(cls, target: "CrossCompileTarget", config: "CheriConfig", *, include_version: bool) -> str: + if target.cpu_architecture.value == CPUArchitecture.RISCV32: + return "riscv32-unknown-elf" + if target.is_riscv64(include_purecap=True): + return "riscv64-unknown-elf" + assert False, "Other baremetal cases have not been tested yet!" + + @property + def sysroot_dir(self) -> Path: + sysroot_dir = self.config.sysroot_output_root / self.config.default_cheri_alliance_sdk_directory_name + return sysroot_dir / "baremetal" / self.target.get_rootfs_target().generic_arch_suffix + + class MorelloBaremetalTargetInfo(BaremetalFreestandingTargetInfo): shortname: str = "Morello-Baremetal" os_prefix: str = "baremetal-" diff --git a/pycheribuild/config/defaultconfig.py b/pycheribuild/config/defaultconfig.py index e559b900b..a4be9bd81 100644 --- a/pycheribuild/config/defaultconfig.py +++ b/pycheribuild/config/defaultconfig.py @@ -234,6 +234,16 @@ def __init__(self, loader: ConfigLoaderBase, available_targets: "list[str]") -> group=loader.path_group, help="The directory to find/install the Morello SDK", ) + default_cheri_alliance_sdk = ComputedDefaultValue( + function=lambda p, cls: (p.tools_root / p.default_cheri_alliance_sdk_directory_name), + as_string="'/cheri-alliance-sdk'", + ) + self.cheri_alliance_sdk_dir = loader.add_path_option( + "cheri-alliance-sdk-root", + default=default_cheri_alliance_sdk, + group=loader.path_group, + help="The directory to find/install the CHERI Alliance SDK", + ) self.sysroot_output_root = loader.add_path_option( "sysroot-install-root", shortname="-sysroot-install-dir", diff --git a/pycheribuild/config/jenkinsconfig.py b/pycheribuild/config/jenkinsconfig.py index a6ab2f310..bb361f7a0 100644 --- a/pycheribuild/config/jenkinsconfig.py +++ b/pycheribuild/config/jenkinsconfig.py @@ -179,6 +179,12 @@ def __init__(self, loader: ConfigLoaderBase, available_targets: "list[str]") -> type=Path, help="Override the path to the CHERI SDK (default is $WORKSPACE/cherisdk)", ) + self._cheri_alliance_sdk_dir_override = loader.add_commandline_only_option( + "cheri-alliance-sdk-path", + default=None, + type=Path, + help="Override the path to the CHERI Alliance SDK (default is $WORKSPACE/cheri-alliance-sdk)", + ) self._morello_sdk_dir_override = loader.add_commandline_only_option( "morello-sdk-path", default=None, @@ -293,6 +299,13 @@ def load(self) -> None: else: self.cheri_sdk_dir = self.workspace / self.default_cheri_sdk_directory_name + if self._cheri_alliance_sdk_dir_override is not None: + self.cheri_alliance_sdk_dir = self._cheri_alliance_sdk_dir_override + elif Path("/cheri-alliance-sdk/bin/clang").exists(): # check for docker image + self.cheri_alliance_sdk_dir = Path("/cheri-alliance-sdk") + else: + self.cheri_alliance_sdk_dir = self.workspace / self.default_cheri_alliance_sdk_directory_name + if self._morello_sdk_dir_override is not None: self.morello_sdk_dir = self._morello_sdk_dir_override elif Path("/morello-sdk/bin/clang").exists(): # check for docker image diff --git a/pycheribuild/config/target_info.py b/pycheribuild/config/target_info.py index bbdbeaa37..47c9550de 100644 --- a/pycheribuild/config/target_info.py +++ b/pycheribuild/config/target_info.py @@ -110,6 +110,7 @@ class CompilerType(Enum): DEFAULT_COMPILER = "default-compiler" # Default system compiler (i.e. the argument passed to cheribuild) CHERI_LLVM = "cheri-llvm" # Compile with CHERI LLVM built by cheribuild MORELLO_LLVM = "morello-llvm" # Compile with Morello LLVM built by cheribuild + CHERI_ALLIANCE_LLVM = "cheri-alliance-llvm" # Compile with CHERI Alliance LLVM built by cheribuild UPSTREAM_LLVM = "upstream-llvm" # Compile with upstream LLVM built by cheribuild SYSTEM_LLVM = "system-llvm" # Compile with system installation of LLVM/Clang BOOTSTRAPPED = "bootstrap" # Compiler is included with the project @@ -149,6 +150,7 @@ class DefaultInstallDir(Enum): KDE_PREFIX = "The sysroot for this target (/opt//kde by default)" CHERI_SDK = "The CHERI SDK directory" MORELLO_SDK = "The Morello SDK directory" + CHERI_ALLIANCE_SDK = "The CHERI Alliance SDK directory" BOOTSTRAP_TOOLS = "The bootstap tools directory" CUSTOM_INSTALL_DIR = "Custom install directory" SYSROOT_FOR_BAREMETAL_ROOTFS_OTHERWISE = "Sysroot for baremetal projects, rootfs otherwise" @@ -599,6 +601,8 @@ def default_install_dir(self, install_dir: DefaultInstallDir) -> Path: return config.cheri_sdk_dir elif install_dir == DefaultInstallDir.MORELLO_SDK: return config.morello_sdk_dir + elif install_dir == DefaultInstallDir.CHERI_ALLIANCE_SDK: + return config.cheri_alliance_sdk_dir elif install_dir == DefaultInstallDir.BOOTSTRAP_TOOLS: return config.other_tools_dir return super().default_install_dir(install_dir) diff --git a/pycheribuild/projects/build_qemu.py b/pycheribuild/projects/build_qemu.py index 487cb4dc7..734b56bce 100644 --- a/pycheribuild/projects/build_qemu.py +++ b/pycheribuild/projects/build_qemu.py @@ -574,3 +574,52 @@ def install(self, **kwargs): *self.config.morello_sdk_dir.rglob("share/icons/**/qemu.bmp"), *self.config.morello_sdk_dir.rglob("share/icons/**/qemu.svg"), ) + + +class BuildCheriAllianceQEMU(BuildQEMUBase): + target = "cheri-alliance-qemu" + repository = GitRepository( + "https://github.com/CHERI-Alliance/qemu.git", default_branch="codasip-cheri-riscv_v3", force_branch=True + ) + native_install_dir = DefaultInstallDir.CHERI_ALLIANCE_SDK + default_targets = "riscv64-softmmu,riscv64cheri-softmmu,riscv32-softmmu,riscv32cheri-softmmu," + + # Turn on unaligned loads/stores by default + unaligned = BoolConfigOption("unaligned", show_help=False, help="Permit un-aligned loads/stores", default=False) + statistics = BoolConfigOption( + "statistics", + show_help=True, + help="Collect statistics on out-of-bounds capability creation.", + ) + + @classmethod + def qemu_binary_for_target(cls, xtarget: CrossCompileTarget, config: CheriConfig): + # Always use the CHERI qemu even for plain riscv: + if xtarget.is_riscv64(include_purecap=True): + binary_name = "qemu-system-riscv64cheri" + elif xtarget.is_riscv32(include_purecap=True): + binary_name = "qemu-system-riscv32cheri" + else: + raise ValueError("Invalid xtarget" + str(xtarget)) + return config.cheri_alliance_qemu_bindir / os.getenv("QEMU_CHERI_PATH", binary_name) + + @classmethod + def get_firmware_dir(cls, caller: SimpleProject, cross_target: "Optional[CrossCompileTarget]" = None): + return cls.get_install_dir(caller, cross_target=cross_target) / "share/qemu" + + def setup(self): + super().setup() + if self.unaligned: + self.COMMON_FLAGS.append("-DCHERI_UNALIGNED") + if self.statistics: + self.COMMON_FLAGS.append("-DDO_CHERI_STATISTICS=1") + if self.build_type == BuildType.DEBUG: + self.COMMON_FLAGS.append("-DENABLE_CHERI_SANITIY_CHECKS=1") + # the capstone disassembler doesn't support CHERI instructions: + self.configure_args.append("--disable-capstone") + # Linux/BSD-user is not supported for CHERI (yet) + self.configure_args.append("--disable-bsd-user") + self.configure_args.append("--disable-linux-user") + + def install(self, **kwargs): + super().install(**kwargs) diff --git a/pycheribuild/projects/cross/llvm.py b/pycheribuild/projects/cross/llvm.py index 4a61fbc4f..cc934ad78 100644 --- a/pycheribuild/projects/cross/llvm.py +++ b/pycheribuild/projects/cross/llvm.py @@ -612,6 +612,8 @@ def get_install_dir_for_type(cls, caller: SimpleProject, compiler_type: Compiler return BuildCheriLLVM.get_native_install_path(caller.config) if compiler_type == CompilerType.MORELLO_LLVM: return BuildMorelloLLVM.get_native_install_path(caller.config) + if compiler_type == CompilerType.CHERI_ALLIANCE_LLVM: + return BuildCheriAllianceLLVM.get_native_install_path(caller.config) if compiler_type == CompilerType.UPSTREAM_LLVM: return BuildUpstreamLLVM.get_native_install_path(caller.config) else: @@ -762,17 +764,54 @@ def configure(self, **kwargs): def install(self, **kwargs): super().install(**kwargs) - # FIXME: this appears to break the cheribsd build, so let's remove it for now... - # Seems like this is fixed in CHERI LLVM so it might be caused by Morello LLVM being based on an older version + + @classmethod + def get_native_install_path(cls, config: CheriConfig): + return config.morello_sdk_dir + + +class BuildCheriAllianceLLVM(BuildLLVMMonoRepoBase): + repository = GitRepository( + "https://github.com/CHERI-Alliance/llvm-project.git", default_branch="codasip-cheri-riscv", force_branch=True + ) + default_directory_basename = "cheri-alliance-llvm-project" + target = "cheri-alliance-llvm" + skip_cheri_symlinks = False # add target-specific symlinks + is_sdk_target = True + native_install_dir = DefaultInstallDir.CHERI_ALLIANCE_SDK + cross_install_dir = DefaultInstallDir.ROOTFS_OPTBASE + + supported_architectures = (CompilationTargets.NATIVE_NON_PURECAP,) + + @property + def triple_prefixes_for_binaries(self) -> "Iterable[str]": + triples = [ + CheriBSDTargetInfo.triple_for_target( + CompilationTargets.FREESTANDING_RISCV64_PURECAP, + self.config, + include_version=False, + ), + ] + return [x + "-" for x in triples] + + def configure(self, **kwargs): + self.add_cmake_options(LLVM_TARGETS_TO_BUILD="RISCV;host") + # The current master branch isn't ready yet to switch over to the new pass manager + # CLANG_ROUND_TRIP_CC1_ARGS doesn't work for us yet. See e.g. https://reviews.llvm.org/D97462#2677130 + self.add_cmake_options(CLANG_ROUND_TRIP_CC1_ARGS=False) + super().configure(**kwargs) + + def install(self, **kwargs): + super().install(**kwargs) if OSInfo.IS_MAC and (self.install_dir / "include/c++/v1").is_symlink(): self.delete_file(self.install_dir / "include/c++/v1") if self.compiling_for_host(): - for tgt in CompilationTargets.ALL_CHERIBSD_MORELLO_TARGETS: + for tgt in CompilationTargets.ALL_CHERIBSD_RISCV_TARGETS: self.add_compilers_with_config_files("cheribsd", tgt) @classmethod def get_native_install_path(cls, config: CheriConfig): - return config.morello_sdk_dir + return config.cheri_alliance_sdk_dir class BuildUpstreamLLVM(BuildLLVMMonoRepoBase): diff --git a/tests/setup_mock_chericonfig.py b/tests/setup_mock_chericonfig.py index 5c779d334..cd2c0a75b 100644 --- a/tests/setup_mock_chericonfig.py +++ b/tests/setup_mock_chericonfig.py @@ -57,6 +57,7 @@ def __init__(self, source_root: Path, pretend=True): # allow overriding pretend self.output_root = source_root / "output" self.cheri_sdk_dir = self.output_root / "sdk" self.morello_sdk_dir = self.output_root / "morello-sdk" + self.cheri_alliance_sdk_dir = self.output_root / "cheri-alliance-sdk" self.sysroot_output_root = self.output_root self.other_tools_dir = self.output_root / "other" From e75c6e31cfb6f2339121ba30bb9f3dd24d09f3c1 Mon Sep 17 00:00:00 2001 From: Alfredo Mazzinghi Date: Fri, 27 Jun 2025 10:45:55 +0100 Subject: [PATCH 07/18] [zcheri] Use CHERI Alliance SDK for CheriBSD targets. Depending on ISA switch --riscv-cheri-isa,use the appropriat SDK. --- pycheribuild/config/compilation_targets.py | 38 +++++++++++++--------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/pycheribuild/config/compilation_targets.py b/pycheribuild/config/compilation_targets.py index d01530f80..e3328a275 100644 --- a/pycheribuild/config/compilation_targets.py +++ b/pycheribuild/config/compilation_targets.py @@ -118,15 +118,17 @@ def sdk_root_dir(self) -> Path: return self._sdk_root_dir @classmethod - def _get_compiler_project(cls) -> "type[BuildLLVMInterface]": + def _get_compiler_project(cls, config: CheriConfig) -> "type[BuildLLVMInterface]": raise NotImplementedError() def _get_sdk_root_dir_lazy(self) -> Path: - return self._get_compiler_project().get_native_install_path(self.config) + return self._get_compiler_project(self.config).get_native_install_path(self.config) @classmethod def toolchain_targets(cls, target: "CrossCompileTarget", config: "CheriConfig") -> "list[str]": - return [cls._get_compiler_project().get_class_for_target(BasicCompilationTargets.NATIVE_NON_PURECAP).target] + return [ + cls._get_compiler_project(config).get_class_for_target(BasicCompilationTargets.NATIVE_NON_PURECAP).target + ] def _rootfs_path(self) -> Path: xtarget = self.target.get_rootfs_target() @@ -370,7 +372,7 @@ def _get_sdk_root_dir_lazy(self) -> Path: # If we couldn't find a working system compiler, default to cheribuild-compiled upstream LLVM. assert fbsd.build_toolchain == CompilerType.DEFAULT_COMPILER # noinspection PyUnresolvedReferences - return self._get_compiler_project().get_native_install_path(self.config) + return self._get_compiler_project(self.config).get_native_install_path(self.config) return configured_path @property @@ -468,7 +470,7 @@ def localbase(self) -> Path: return Path("usr/local") @classmethod - def _get_compiler_project(cls) -> "type[BuildLLVMInterface]": + def _get_compiler_project(cls, config: CheriConfig) -> "type[BuildLLVMInterface]": return typing.cast("type[BuildLLVMInterface]", SimpleProject.get_class_for_target_name("upstream-llvm", None)) def _get_rootfs_class(self, xtarget: "CrossCompileTarget") -> "type[SimpleProject]": @@ -639,8 +641,12 @@ class CheriBSDTargetInfo(FreeBSDTargetInfo): FREEBSD_VERSION: int = 13 @classmethod - def _get_compiler_project(cls) -> "type[BuildLLVMInterface]": - return typing.cast("type[BuildLLVMInterface]", SimpleProject.get_class_for_target_name("llvm", None)) + def _get_compiler_project(cls, config: CheriConfig) -> "type[BuildLLVMInterface]": + if config.riscv_cheri_isa == RiscvCheriISA.STD: + llvm_target = SimpleProject.get_class_for_target_name("cheri-alliance-llvm", None) + else: + llvm_target = SimpleProject.get_class_for_target_name("llvm", None) + return typing.cast("type[BuildLLVMInterface]", llvm_target) def _get_run_project(self, xtarget: "CrossCompileTarget", caller: SimpleProject) -> LaunchFreeBSDInterface: result = SimpleProject.get_instance_for_target_name("run", xtarget, caller.config, caller) @@ -707,7 +713,7 @@ class CheriBSDMorelloTargetInfo(CheriBSDTargetInfo): uses_morello_llvm: bool = True @classmethod - def _get_compiler_project(cls) -> "type[BuildLLVMInterface]": + def _get_compiler_project(cls, config: CheriConfig) -> "type[BuildLLVMInterface]": return typing.cast("type[BuildLLVMInterface]", SimpleProject.get_class_for_target_name("morello-llvm", None)) @classmethod @@ -743,10 +749,10 @@ def _get_rootfs_class(self, xtarget: "CrossCompileTarget") -> "type[SimpleProjec raise LookupError("Should not be called") def _get_sdk_root_dir_lazy(self) -> Path: - return self._get_compiler_project().get_native_install_path(self.config) + return self._get_compiler_project(self.config).get_native_install_path(self.config) @classmethod - def _get_compiler_project(cls) -> "type[BuildLLVMInterface]": + def _get_compiler_project(cls, config: CheriConfig) -> "type[BuildLLVMInterface]": return typing.cast("type[BuildLLVMInterface]", SimpleProject.get_class_for_target_name("cherios-llvm", None)) @property @@ -813,7 +819,7 @@ def sysroot_install_prefix_relative(self) -> Path: return Path(self.target_triple) @classmethod - def _get_compiler_project(cls) -> "type[BuildLLVMInterface]": + def _get_compiler_project(cls, config: CheriConfig) -> "type[BuildLLVMInterface]": return typing.cast("type[BuildLLVMInterface]", SimpleProject.get_class_for_target_name("llvm", None)) @property @@ -865,7 +871,7 @@ def sysroot_dir(self) -> Path: return sysroot_dir / "baremetal" / suffix @classmethod - def _get_compiler_project(cls) -> "type[BuildLLVMInterface]": + def _get_compiler_project(cls, config: CheriConfig) -> "type[BuildLLVMInterface]": return typing.cast("type[BuildLLVMInterface]", SimpleProject.get_class_for_target_name("llvm", None)) @classmethod @@ -951,7 +957,7 @@ def sysroot_dir(self) -> Path: return result @classmethod - def _get_compiler_project(cls) -> "type[BuildLLVMInterface]": + def _get_compiler_project(cls, config: CheriConfig) -> "type[BuildLLVMInterface]": return typing.cast("type[BuildLLVMInterface]", SimpleProject.get_class_for_target_name("llvm", None)) @property @@ -1025,7 +1031,7 @@ class BaremetalFreestandingTargetInfo(BaremetalClangTargetInfo): os_prefix: str = "baremetal-" @classmethod - def _get_compiler_project(cls) -> "type[BuildLLVMInterface]": + def _get_compiler_project(cls, config: CheriConfig) -> "type[BuildLLVMInterface]": return typing.cast("type[BuildLLVMInterface]", SimpleProject.get_class_for_target_name("llvm", None)) @classmethod @@ -1050,7 +1056,7 @@ class BaremetalFreestandingCheriAllianceTargetInfo(BaremetalClangTargetInfo): uses_cheri_alliance_llvm: bool = True @classmethod - def _get_compiler_project(cls) -> "type[BuildLLVMInterface]": + def _get_compiler_project(cls, config: CheriConfig) -> "type[BuildLLVMInterface]": return typing.cast("type[BuildLLVMInterface]", SimpleProject.get_class_for_target_name("cheri-alliance-llvm", None)) @@ -1078,7 +1084,7 @@ class MorelloBaremetalTargetInfo(BaremetalFreestandingTargetInfo): uses_morello_llvm: bool = True @classmethod - def _get_compiler_project(cls) -> "type[BuildLLVMInterface]": + def _get_compiler_project(cls, config: CheriConfig) -> "type[BuildLLVMInterface]": return typing.cast("type[BuildLLVMInterface]", SimpleProject.get_class_for_target_name("morello-llvm", None)) @property From 3d22971463ea542fee4d2238ad85873571f7e5d6 Mon Sep 17 00:00:00 2001 From: Hesham Almatary Date: Thu, 26 Jun 2025 11:18:37 +0000 Subject: [PATCH 08/18] [zcheri] Add GDB target off CHERI Alliance --- pycheribuild/projects/cross/gdb.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/pycheribuild/projects/cross/gdb.py b/pycheribuild/projects/cross/gdb.py index ace380cfd..c31df9841 100644 --- a/pycheribuild/projects/cross/gdb.py +++ b/pycheribuild/projects/cross/gdb.py @@ -294,6 +294,19 @@ class BuildGDB(BuildGDBBase): ) +class BuildCheriAllianceGDB(BuildGDBBase): + target = "cheri-alliance-gdb" + native_install_dir = DefaultInstallDir.CHERI_ALLIANCE_SDK + repository = GitRepository( + "https://github.com/CHERI-Alliance/gdb.git", + default_branch="codasip-cheri-riscv", + ) + + supported_architectures = ( + CompilationTargets.NATIVE_NON_PURECAP, + ) + + class BuildKGDB(BuildGDB): default_branch = "cheri-14-kgdb" repository = GitRepository( From 038f88a65944e5515efe59b9e202bef14561af36 Mon Sep 17 00:00:00 2001 From: Alfredo Mazzinghi Date: Mon, 30 Jun 2025 15:48:11 +0100 Subject: [PATCH 09/18] [zcheri] Obey --riscv-cheri-isa in run-riscv64-xxx. --- pycheribuild/projects/run_qemu.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/pycheribuild/projects/run_qemu.py b/pycheribuild/projects/run_qemu.py index 4fc970142..8941eb6ef 100644 --- a/pycheribuild/projects/run_qemu.py +++ b/pycheribuild/projects/run_qemu.py @@ -37,7 +37,7 @@ from pathlib import Path from typing import Optional -from .build_qemu import BuildQEMU, BuildQEMUBase, BuildUpstreamQEMU +from .build_qemu import BuildCheriAllianceQEMU, BuildQEMU, BuildQEMUBase, BuildUpstreamQEMU from .cross.cheribsd import BuildCHERIBSD, BuildCheriBsdMfsKernel, BuildFreeBSD, ConfigPlatform, KernelABI from .cross.gdb import BuildGDB from .cross.u_boot import BuildUBoot @@ -50,6 +50,7 @@ ) from .project import CheriConfig, ComputedDefaultValue, CPUArchitecture, Project from .simple_project import BoolConfigOption, SimpleProject, TargetAliasWithDependencies +from ..config.chericonfig import RiscvCheriISA from ..config.compilation_targets import CompilationTargets, LaunchFreeBSDInterface from ..config.target_info import CrossCompileTarget from ..qemu_utils import QemuOptions, qemu_supports_9pfs, riscv_bios_arguments @@ -252,9 +253,12 @@ def get_chosen_qemu(cls, config: CheriConfig) -> ChosenQEMU: supported_qemu_classes = [] if xtarget.is_mips(include_purecap=True) or xtarget.is_riscv(include_purecap=True): can_provide_src_via_smb = True - supported_qemu_classes += [BuildQEMU] - if not xtarget.is_hybrid_or_purecap_cheri(): - supported_qemu_classes += [BuildUpstreamQEMU, None] + if xtarget.is_riscv(include_purecap=True) and config.riscv_cheri_isa == RiscvCheriISA.STD: + supported_qemu_classes += [BuildCheriAllianceQEMU] + else: + supported_qemu_classes += [BuildQEMU] + if not xtarget.is_hybrid_or_purecap_cheri(): + supported_qemu_classes += [BuildUpstreamQEMU, None] elif xtarget.is_aarch64(include_purecap=True): can_provide_src_via_smb = True # Prefer CHERI QEMU for AArch64 like other architectures. From 79aabeb71f7ec91c5188edf094930b660f37552f Mon Sep 17 00:00:00 2001 From: Alfredo Mazzinghi Date: Tue, 1 Jul 2025 20:02:06 +0100 Subject: [PATCH 10/18] [zcheri] Honor --riscv-cheri-isa for baremetal targets. --- pycheribuild/config/compilation_targets.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pycheribuild/config/compilation_targets.py b/pycheribuild/config/compilation_targets.py index e3328a275..cc930b575 100644 --- a/pycheribuild/config/compilation_targets.py +++ b/pycheribuild/config/compilation_targets.py @@ -1032,7 +1032,11 @@ class BaremetalFreestandingTargetInfo(BaremetalClangTargetInfo): @classmethod def _get_compiler_project(cls, config: CheriConfig) -> "type[BuildLLVMInterface]": - return typing.cast("type[BuildLLVMInterface]", SimpleProject.get_class_for_target_name("llvm", None)) + if config.riscv_cheri_isa == RiscvCheriISA.STD: + llvm_target = SimpleProject.get_class_for_target_name("cheri-alliance-llvm", None) + else: + llvm_target = SimpleProject.get_class_for_target_name("llvm", None) + return typing.cast("type[BuildLLVMInterface]", llvm_target) @classmethod def base_sysroot_targets(cls, target: "CrossCompileTarget", config: "CheriConfig") -> "list[str]": From d89cff5928f3c284795b6d5660a0afc27500603d Mon Sep 17 00:00:00 2001 From: Alfredo Mazzinghi Date: Thu, 3 Jul 2025 10:47:19 +0100 Subject: [PATCH 11/18] [zcheri] Add Cheri Alliance gdb for purecap rootfs target. --- pycheribuild/projects/cross/gdb.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pycheribuild/projects/cross/gdb.py b/pycheribuild/projects/cross/gdb.py index c31df9841..be67c62be 100644 --- a/pycheribuild/projects/cross/gdb.py +++ b/pycheribuild/projects/cross/gdb.py @@ -303,6 +303,7 @@ class BuildCheriAllianceGDB(BuildGDBBase): ) supported_architectures = ( + CompilationTargets.CHERIBSD_RISCV_HYBRID_FOR_PURECAP_ROOTFS, CompilationTargets.NATIVE_NON_PURECAP, ) From bf73ec8a2ef128bff1b5211988dab248e8fb41cf Mon Sep 17 00:00:00 2001 From: Alfredo Mazzinghi Date: Thu, 3 Jul 2025 10:47:43 +0100 Subject: [PATCH 12/18] [zcheri] Disable -mrelax for Zcheri ISA. This is not currently supported by the Cheri Allliance LLVM. --- pycheribuild/config/compilation_targets.py | 6 +++++- pycheribuild/projects/cross/opensbi.py | 2 -- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/pycheribuild/config/compilation_targets.py b/pycheribuild/config/compilation_targets.py index cc930b575..5bfa4b552 100644 --- a/pycheribuild/config/compilation_targets.py +++ b/pycheribuild/config/compilation_targets.py @@ -84,8 +84,12 @@ def get_qemu_mfs_root_kernel(self, use_benchmark_kernel: bool) -> Path: @functools.lru_cache(maxsize=20) def _linker_supports_riscv_relaxations(linker: Path, config: CheriConfig, xtarget: "CrossCompileTarget") -> bool: - if xtarget.is_hybrid_or_purecap_cheri(): + # XXX-AM: Hack: codasip lld does not seem to play nice with -mrelax and cheri + if config.riscv_cheri_isa == RiscvCheriISA.STD: return False + elif xtarget.is_hybrid_or_purecap_cheri(): + return False + try: linker_version = get_version_output(linker, config=config) except subprocess.CalledProcessError as e: diff --git a/pycheribuild/projects/cross/opensbi.py b/pycheribuild/projects/cross/opensbi.py index 12d9c7e3b..1e7643fa2 100644 --- a/pycheribuild/projects/cross/opensbi.py +++ b/pycheribuild/projects/cross/opensbi.py @@ -83,8 +83,6 @@ def setup(self): super().setup() compflags = " " + self.commandline_to_str(self.essential_compiler_and_linker_flags) compflags += " -Qunused-arguments" # -mstrict-align -no-pie - if self.config.riscv_cheri_isa == RiscvCheriISA.STD: - compflags += " -mno-relax" if OSInfo.IS_MAC: self.make_args.set(READLINK="greadlink") self.make_args.set( From 25a5a9406c4eecfe6ce67477a501d93f8242d894 Mon Sep 17 00:00:00 2001 From: Hesham Almatary Date: Fri, 25 Jul 2025 11:04:40 +0000 Subject: [PATCH 13/18] [zcheri] Fix sysroot path to alliance sdk Also delete unused Alliance target class --- pycheribuild/config/compilation_targets.py | 33 +++------------------- 1 file changed, 4 insertions(+), 29 deletions(-) diff --git a/pycheribuild/config/compilation_targets.py b/pycheribuild/config/compilation_targets.py index 5bfa4b552..0c3d86d65 100644 --- a/pycheribuild/config/compilation_targets.py +++ b/pycheribuild/config/compilation_targets.py @@ -1054,35 +1054,10 @@ def triple_for_target(cls, target: "CrossCompileTarget", config: "CheriConfig", @property def sysroot_dir(self) -> Path: - sysroot_dir = self.config.sysroot_output_root / self.config.default_cheri_sdk_directory_name - return sysroot_dir / "baremetal" / self.target.get_rootfs_target().generic_arch_suffix - - -class BaremetalFreestandingCheriAllianceTargetInfo(BaremetalClangTargetInfo): - shortname: str = "Baremetal" - os_prefix: str = "baremetal-" - uses_cheri_alliance_llvm: bool = True - - @classmethod - def _get_compiler_project(cls, config: CheriConfig) -> "type[BuildLLVMInterface]": - return typing.cast("type[BuildLLVMInterface]", - SimpleProject.get_class_for_target_name("cheri-alliance-llvm", None)) - - @classmethod - def base_sysroot_targets(cls, target: "CrossCompileTarget", config: "CheriConfig") -> "list[str]": - return [] - - @classmethod - def triple_for_target(cls, target: "CrossCompileTarget", config: "CheriConfig", *, include_version: bool) -> str: - if target.cpu_architecture.value == CPUArchitecture.RISCV32: - return "riscv32-unknown-elf" - if target.is_riscv64(include_purecap=True): - return "riscv64-unknown-elf" - assert False, "Other baremetal cases have not been tested yet!" - - @property - def sysroot_dir(self) -> Path: - sysroot_dir = self.config.sysroot_output_root / self.config.default_cheri_alliance_sdk_directory_name + if self.config.riscv_cheri_isa == RiscvCheriISA.STD: + sysroot_dir = self.config.sysroot_output_root / self.config.default_cheri_alliance_sdk_directory_name + else: + sysroot_dir = self.config.sysroot_output_root / self.config.default_cheri_sdk_directory_name return sysroot_dir / "baremetal" / self.target.get_rootfs_target().generic_arch_suffix From e2a0df78ca85d840894198694eba6550d39496dd Mon Sep 17 00:00:00 2001 From: Hesham Almatary Date: Fri, 25 Jul 2025 15:14:51 +0000 Subject: [PATCH 14/18] combine-files: Make sure opensbi.py precedes other projects CI fails otherwise with an error: Traceback (most recent call last): File "", line 22514, in File "", line 22851, in BuildCheriseL4Excercises NameError: name 'BuildAllianceOpenSBI' is not defined --- combine-files.py | 1 + 1 file changed, 1 insertion(+) diff --git a/combine-files.py b/combine-files.py index f0af0d9f7..44a23e5e5 100755 --- a/combine-files.py +++ b/combine-files.py @@ -151,6 +151,7 @@ def check_all_files_used(directory: Path): add_filtered_file(script_dir / "projects/cross/crosscompileproject.py") add_filtered_file(script_dir / "projects/cross/benchmark_mixin.py") add_filtered_file(script_dir / "projects/cross/llvm_test_suite.py") +add_filtered_file(script_dir / "projects/cross/opensbi.py") # disk-image, sdk and run_qemu must come after cheribsd as they use CheriBSD.rootfs_dir add_filtered_file(script_dir / "projects/disk_image.py") add_filtered_file(script_dir / "projects/run_qemu.py") From 6ffd4fc171f82796325a1ee26c0797073e857c2d Mon Sep 17 00:00:00 2001 From: Alfredo Mazzinghi Date: Mon, 28 Jul 2025 14:30:01 +0100 Subject: [PATCH 15/18] [zcheri] Fix llvm_test_suite llvm_project dependency resolution. Propagate the current CheriConfig depending whether the llvm_project is queried during early dependency resolution or during Project initialization. --- pycheribuild/projects/cross/llvm_test_suite.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/pycheribuild/projects/cross/llvm_test_suite.py b/pycheribuild/projects/cross/llvm_test_suite.py index 80b60cc90..6595dfed4 100644 --- a/pycheribuild/projects/cross/llvm_test_suite.py +++ b/pycheribuild/projects/cross/llvm_test_suite.py @@ -43,7 +43,7 @@ from ..project import ReuseOtherProjectRepository from ..simple_project import BoolConfigOption from ...config.compilation_targets import FreeBSDTargetInfo -from ...utils import classproperty, is_jenkins_build +from ...utils import is_jenkins_build class BuildLLVMTestSuiteBase(BenchmarkMixin, CrossCompileCMakeProject): @@ -57,18 +57,22 @@ class BuildLLVMTestSuiteBase(BenchmarkMixin, CrossCompileCMakeProject): @classmethod def dependencies(cls, config) -> "tuple[str, ...]": - return (cls.llvm_project.get_class_for_target(CompilationTargets.NATIVE_NON_PURECAP).target,) + return (cls.get_llvm_project(config).get_class_for_target(CompilationTargets.NATIVE_NON_PURECAP).target,) # noinspection PyMethodParameters - @classproperty - def llvm_project(self) -> "type[BuildLLVMBase]": - target_info = self.get_crosscompile_target().target_info_cls + @classmethod + def get_llvm_project(cls, config) -> "type[BuildLLVMBase]": + target_info = cls.get_crosscompile_target().target_info_cls if issubclass(target_info, FreeBSDTargetInfo): # noinspection PyProtectedMember - return target_info._get_compiler_project() + return target_info._get_compiler_project(config) else: return BuildCheriLLVM + @property + def llvm_project(self): + return self.get_llvm_project(self.config) + def __find_in_sdk_or_llvm_build_dir(self, name) -> Path: llvm_project = self.llvm_project.get_instance(self, cross_target=CompilationTargets.NATIVE_NON_PURECAP) if (llvm_project.build_dir / "bin" / name).exists(): From 6c3606d55a587cb92ced24577d3e918ba517c161 Mon Sep 17 00:00:00 2001 From: Alfredo Mazzinghi Date: Wed, 30 Jul 2025 11:49:26 +0100 Subject: [PATCH 16/18] [zcheri] Drop unused `unaligned` option from BuildCheriAllianceQEMU. This is only used for MIPS. --- pycheribuild/projects/build_qemu.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pycheribuild/projects/build_qemu.py b/pycheribuild/projects/build_qemu.py index 734b56bce..204a4b6f4 100644 --- a/pycheribuild/projects/build_qemu.py +++ b/pycheribuild/projects/build_qemu.py @@ -584,8 +584,6 @@ class BuildCheriAllianceQEMU(BuildQEMUBase): native_install_dir = DefaultInstallDir.CHERI_ALLIANCE_SDK default_targets = "riscv64-softmmu,riscv64cheri-softmmu,riscv32-softmmu,riscv32cheri-softmmu," - # Turn on unaligned loads/stores by default - unaligned = BoolConfigOption("unaligned", show_help=False, help="Permit un-aligned loads/stores", default=False) statistics = BoolConfigOption( "statistics", show_help=True, @@ -609,8 +607,6 @@ def get_firmware_dir(cls, caller: SimpleProject, cross_target: "Optional[CrossCo def setup(self): super().setup() - if self.unaligned: - self.COMMON_FLAGS.append("-DCHERI_UNALIGNED") if self.statistics: self.COMMON_FLAGS.append("-DDO_CHERI_STATISTICS=1") if self.build_type == BuildType.DEBUG: From d27b56105728e121c427545aca4dc0374563b216 Mon Sep 17 00:00:00 2001 From: Alfredo Mazzinghi Date: Fri, 1 Aug 2025 17:52:42 +0100 Subject: [PATCH 17/18] [qemu] Bump tracked branch in cheri-alliance-qemu. --- pycheribuild/projects/build_qemu.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pycheribuild/projects/build_qemu.py b/pycheribuild/projects/build_qemu.py index 204a4b6f4..7a1541a1b 100644 --- a/pycheribuild/projects/build_qemu.py +++ b/pycheribuild/projects/build_qemu.py @@ -579,7 +579,7 @@ def install(self, **kwargs): class BuildCheriAllianceQEMU(BuildQEMUBase): target = "cheri-alliance-qemu" repository = GitRepository( - "https://github.com/CHERI-Alliance/qemu.git", default_branch="codasip-cheri-riscv_v3", force_branch=True + "https://github.com/CHERI-Alliance/qemu.git", default_branch="codasip-cheri-riscv.25-03-31", force_branch=True ) native_install_dir = DefaultInstallDir.CHERI_ALLIANCE_SDK default_targets = "riscv64-softmmu,riscv64cheri-softmmu,riscv32-softmmu,riscv32cheri-softmmu," From 691d9c837ed43c9464c59b4a6786506da5b9a0f7 Mon Sep 17 00:00:00 2001 From: Alfredo Mazzinghi Date: Wed, 6 Aug 2025 19:37:25 +0100 Subject: [PATCH 18/18] [WIP] DO NOT MERGE Point the cheri-alliance-llvm target to codasip-rebased. Temporarily point the default branch of the cheri-alliance-llvm to the private repository with the latest rebased branch. This unbreaks cheribsd builds, but should not be used as the official solution. --- pycheribuild/projects/cross/llvm.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pycheribuild/projects/cross/llvm.py b/pycheribuild/projects/cross/llvm.py index cc934ad78..56b636245 100644 --- a/pycheribuild/projects/cross/llvm.py +++ b/pycheribuild/projects/cross/llvm.py @@ -771,8 +771,11 @@ def get_native_install_path(cls, config: CheriConfig): class BuildCheriAllianceLLVM(BuildLLVMMonoRepoBase): + # repository = GitRepository( + # "https://github.com/CHERI-Alliance/llvm-project.git", default_branch="codasip-cheri-riscv", force_branch=True + # ) repository = GitRepository( - "https://github.com/CHERI-Alliance/llvm-project.git", default_branch="codasip-cheri-riscv", force_branch=True + "https://github.com/veselypeta/cherillvm", default_branch="codasip-rebased", force_branch=True ) default_directory_basename = "cheri-alliance-llvm-project" target = "cheri-alliance-llvm"