Skip to content

Commit f005e2f

Browse files
committed
WIP: CHERI Standard support
1 parent 6d623fc commit f005e2f

File tree

11 files changed

+77
-29
lines changed

11 files changed

+77
-29
lines changed

pycheribuild/boot_cheribsd/__init__.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
from typing import Callable, Optional, Union
5454

5555
from ..colour import AnsiColour, coloured
56+
from ..config.chericonfig import RiscvCheriISA
5657
from ..config.compilation_targets import CompilationTargets, CrossCompileTarget
5758
from ..processutils import commandline_to_str, keep_terminal_sane, run_and_kill_children_on_exit
5859
from ..qemu_utils import QemuOptions, riscv_bios_arguments
@@ -916,7 +917,7 @@ def boot_cheribsd(
916917
if bios_path is not None:
917918
bios_args = ["-bios", str(bios_path)]
918919
elif qemu_options.xtarget.is_riscv(include_purecap=True):
919-
bios_args = riscv_bios_arguments(qemu_options.xtarget, None)
920+
bios_args = riscv_bios_arguments(qemu_options.xtarget, qemu_options.riscv_cheri_isa)
920921
else:
921922
bios_args = []
922923
qemu_args = qemu_options.get_commandline(
@@ -1516,7 +1517,12 @@ def _main(
15161517
if argparse_adjust_args_callback:
15171518
argparse_adjust_args_callback(args)
15181519

1519-
qemu_options = QemuOptions(xtarget)
1520+
riscv_cheri_isa = None
1521+
# Slightly ugly hack to avoid having to pass yet another argument for something
1522+
# that is a temporary workaround until ISAv9 is gone.
1523+
if args.qemu_cmd is not None and str(args.qemu_cmd).endswith("cheristd"):
1524+
riscv_cheri_isa = RiscvCheriISA.STD
1525+
qemu_options = QemuOptions(xtarget, riscv_cheri_isa=riscv_cheri_isa)
15201526
if args.qemu_cmd is not None:
15211527
if not Path(args.qemu_cmd).exists():
15221528
failure("ERROR: Cannot find QEMU binary ", args.qemu_cmd, " doesn't exist", exit=True)

pycheribuild/config/chericonfig.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,11 @@ def clang_march_flag(self) -> str:
123123
return self.value[1]
124124

125125

126+
class RiscvCheriISA(Enum):
127+
V9 = "v9"
128+
STD = "std"
129+
130+
126131
def _default_arm_none_eabi_prefix(c: "CheriConfig", _):
127132
# see if the local install exists:
128133
default_path = c.output_root / c.local_arm_none_eabi_toolchain_relpath
@@ -314,6 +319,13 @@ def __init__(self, loader, action_class: "type[CheribuildActionEnum]") -> None:
314319
self.skip_configure: "Optional[bool] " = None
315320
self.force_configure: "Optional[bool] " = None
316321
self.force_update: "Optional[bool] " = None
322+
self.riscv_cheri_isa = loader.add_option(
323+
"riscv-cheri-isa",
324+
default=RiscvCheriISA.V9,
325+
type=RiscvCheriISA,
326+
group=loader.cross_compile_options_group,
327+
help="The CHERI ISA to target for RISC-V code",
328+
)
317329
self.mips_float_abi = loader.add_option(
318330
"mips-float-abi",
319331
default=MipsFloatAbi.SOFT,

pycheribuild/config/compilation_targets.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
from pathlib import Path
4141
from typing import Optional
4242

43-
from .chericonfig import CheriConfig
43+
from .chericonfig import CheriConfig, RiscvCheriISA
4444
from .config_loader_base import ConfigLoaderBase, ConfigOptionHandle
4545
from .target_info import (
4646
AArch64FloatSimdOptions,
@@ -273,7 +273,7 @@ def essential_compiler_and_linker_flags_impl(
273273
result.append("-mcpu=beri")
274274
elif xtarget.is_riscv(include_purecap=True):
275275
# Use the insane RISC-V arch string to enable CHERI
276-
result.append("-march=" + cls.get_riscv_arch_string(xtarget, softfloat=softfloat))
276+
result.append("-march=" + cls.get_riscv_arch_string(xtarget, config, softfloat=softfloat))
277277
result.append("-mabi=" + cls.get_riscv_abi(xtarget, softfloat=softfloat))
278278
result.append("-mrelax" if _linker_supports_riscv_relaxations(instance.linker, config) else "-mno-relax")
279279

@@ -307,15 +307,19 @@ def essential_compiler_and_linker_flags_impl(
307307
return result
308308

309309
@classmethod
310-
def get_riscv_arch_string(cls, xtarget: CrossCompileTarget, softfloat: bool) -> str:
310+
def get_riscv_arch_string(cls, xtarget: CrossCompileTarget, config: CheriConfig, softfloat: bool) -> str:
311311
assert xtarget.is_riscv(include_purecap=True)
312312
# Use the insane RISC-V arch string to enable CHERI
313313
arch_string = "rv" + str(xtarget.cpu_architecture.word_bits()) + "ima"
314314
if not softfloat:
315315
arch_string += "fd"
316316
arch_string += "c"
317317
if xtarget.is_hybrid_or_purecap_cheri():
318-
arch_string += "xcheri"
318+
if config.riscv_cheri_isa == RiscvCheriISA.V9:
319+
arch_string += "xcheri"
320+
else:
321+
assert config.riscv_cheri_isa == RiscvCheriISA.STD
322+
arch_string += "zcherihybrid"
319323
return arch_string
320324

321325
@classmethod
@@ -500,7 +504,7 @@ def has_test_extra_arg_override(arg: str):
500504
rootfs_xtarget = xtarget.get_rootfs_target()
501505
from ..qemu_utils import QemuOptions
502506

503-
qemu_options = QemuOptions(rootfs_xtarget)
507+
qemu_options = QemuOptions(rootfs_xtarget, riscv_cheri_isa=self.config.riscv_cheri_isa)
504508
run_instance: LaunchFreeBSDInterface = self._get_run_project(rootfs_xtarget, self.project)
505509
if rootfs_xtarget.cpu_architecture not in (
506510
CPUArchitecture.MIPS64,

pycheribuild/projects/build_qemu.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
Project,
5252
)
5353
from .simple_project import BoolConfigOption, SimpleProject, _cached_get_homebrew_prefix
54+
from ..config.chericonfig import RiscvCheriISA
5455
from ..config.compilation_targets import BaremetalFreestandingTargetInfo, CompilationTargets
5556
from ..config.config_loader_base import ConfigOptionHandle
5657
from ..processutils import get_program_version
@@ -468,10 +469,13 @@ def qemu_binary_for_target(cls, xtarget: CrossCompileTarget, config: CheriConfig
468469
# Always use the CHERI qemu even for plain riscv:
469470
if xtarget.is_riscv(include_purecap=True):
470471
xlen = 32 if xtarget.is_riscv32(include_purecap=True) else 64
471-
binary_name = f"qemu-system-riscv{xlen}cheri"
472472
# Prefer the xcheri-suffixed binary (if it exists) to ensure backwards compatibility.
473-
if (config.qemu_bindir / f"qemu-system-riscv{xlen}xcheri").exists():
473+
if config.riscv_cheri_isa == RiscvCheriISA.STD:
474+
binary_name = f"qemu-system-riscv{xlen}cheristd"
475+
elif (config.qemu_bindir / f"qemu-system-riscv{xlen}xcheri").exists():
474476
binary_name = f"qemu-system-riscv{xlen}xcheri"
477+
else:
478+
binary_name = f"qemu-system-riscv{xlen}cheri"
475479
elif xtarget.is_mips(include_purecap=True):
476480
binary_name = "qemu-system-mips64cheri128"
477481
elif xtarget.is_aarch64(include_purecap=True):

pycheribuild/projects/cross/bbl.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ def setup(self):
9191
tinfo = cast(self.target_info, BaremetalClangTargetInfo)
9292
# Assume hardfloat architecture and softfloat ABI
9393
self.configure_args.append(
94-
"--with-arch=" + tinfo.get_riscv_arch_string(self.crosscompile_target, softfloat=False),
94+
"--with-arch=" + tinfo.get_riscv_arch_string(self.crosscompile_target, self.config, softfloat=False),
9595
)
9696
self.configure_args.append("--with-abi=" + tinfo.get_riscv_abi(self.crosscompile_target, softfloat=True))
9797
self.configure_args.append("--with-mem-start=" + self.mem_start)
@@ -160,7 +160,7 @@ def setup(self):
160160
self.configure_args.append("--enable-print-device-tree")
161161

162162
def run_tests(self) -> None:
163-
options = QemuOptions(self.crosscompile_target)
163+
options = QemuOptions(self.crosscompile_target, riscv_cheri_isa=self.config.riscv_cheri_isa)
164164
self.run_cmd(
165165
options.get_commandline(
166166
qemu_command=BuildQEMU.qemu_binary(self),

pycheribuild/projects/cross/freertos.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ def __init__(self, *args, **kwargs):
7373
super().__init__(*args, **kwargs)
7474
self.default_demo_app = (
7575
"qemu_virt-"
76-
+ self.target_info.get_riscv_arch_string(self.crosscompile_target, softfloat=True)
76+
+ self.target_info.get_riscv_arch_string(self.crosscompile_target, self.config, softfloat=True)
7777
+ self.target_info.get_riscv_abi(self.crosscompile_target, softfloat=True)
7878
)
7979

@@ -142,7 +142,7 @@ def setup_config_options(cls, **kwargs):
142142
def default_demo_bsp(self):
143143
return (
144144
"qemu_virt-"
145-
+ self.target_info.get_riscv_arch_string(self.crosscompile_target, softfloat=True)
145+
+ self.target_info.get_riscv_arch_string(self.crosscompile_target, self.config, softfloat=True)
146146
+ "-"
147147
+ self.target_info.get_riscv_abi(self.crosscompile_target, softfloat=True)
148148
)
@@ -249,7 +249,7 @@ def setup_config_options(cls, **kwargs):
249249
def default_demo_bsp(self):
250250
return (
251251
"qemu_virt-"
252-
+ self.target_info.get_riscv_arch_string(self.crosscompile_target, softfloat=True)
252+
+ self.target_info.get_riscv_arch_string(self.crosscompile_target, self.config, softfloat=True)
253253
+ "-"
254254
+ self.target_info.get_riscv_abi(self.crosscompile_target, softfloat=True)
255255
)

pycheribuild/projects/cross/littlekernel.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ def run_tests(self):
164164
elif self.compiling_for_riscv(include_purecap=True):
165165
bios_args = ["-bios", "none"]
166166
if self.use_mmu:
167-
bios_args = riscv_bios_arguments(self.crosscompile_target, self)
167+
bios_args = riscv_bios_arguments(self.crosscompile_target, self.config.riscv_cheri_isa)
168168
cmd = [
169169
qemu,
170170
"-cpu",

pycheribuild/projects/cross/opensbi.py

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
Project,
4343
ReuseOtherProjectRepository,
4444
)
45+
from ...config.chericonfig import RiscvCheriISA
4546
from ...config.compilation_targets import CompilationTargets
4647
from ...qemu_utils import QemuOptions
4748
from ...utils import OSInfo, classproperty
@@ -60,7 +61,7 @@ class BuildOpenSBI(Project):
6061
supported_architectures = (
6162
CompilationTargets.FREESTANDING_RISCV64_HYBRID,
6263
CompilationTargets.FREESTANDING_RISCV64,
63-
# Won't compile yet: CompilationTargets.FREESTANDING_RISCV64_PURECAP
64+
CompilationTargets.FREESTANDING_RISCV64_PURECAP,
6465
)
6566
make_kind = MakeCommandKind.GnuMake
6667
_always_add_suffixed_targets = True
@@ -98,7 +99,9 @@ def setup(self):
9899
# FW_JUMP_ADDR= ## cheribsd start addr
99100
# FW_JUMP_FDT_ADDR= ## cheribsd fdt addr
100101
PLATFORM_RISCV_ABI=self.target_info.get_riscv_abi(self.crosscompile_target, softfloat=True),
101-
PLATFORM_RISCV_ISA=self.target_info.get_riscv_arch_string(self.crosscompile_target, softfloat=True),
102+
PLATFORM_RISCV_ISA=self.target_info.get_riscv_arch_string(
103+
self.crosscompile_target, self.config, softfloat=True
104+
),
102105
PLATFORM_RISCV_XLEN=64,
103106
)
104107
if self.config.verbose:
@@ -107,9 +110,9 @@ def setup(self):
107110
@property
108111
def all_platforms(self):
109112
platforms_dir = self.source_dir / "platform"
110-
self.info(list(platforms_dir.glob("**/config.mk")))
113+
self.info(list(platforms_dir.glob("**/objects.mk")))
111114
all_platforms = []
112-
for c in platforms_dir.glob("**/config.mk"):
115+
for c in platforms_dir.glob("**/objects.mk"):
113116
relpath = str(c.parent.relative_to(platforms_dir))
114117
if relpath != "template":
115118
all_platforms.append(relpath)
@@ -120,6 +123,8 @@ def all_platforms(self):
120123
return ["generic"]
121124

122125
def compile(self, **kwargs):
126+
if self.compiling_for_cheri() and self.config.riscv_cheri_isa != RiscvCheriISA.STD:
127+
self.fatal("Purecap openSBI is only supported for the staandard ISA for now.")
123128
for platform in self.all_platforms:
124129
args = self.make_args.copy()
125130
args.set(PLATFORM=platform)
@@ -132,17 +137,19 @@ def install(self, **kwargs):
132137
args.set(PLATFORM=platform)
133138
self.run_make_install(cwd=self.source_dir, options=args)
134139
# Only install BuildBBLNoPayload as the QEMU bios and not the GFE version by checking build_dir_suffix
135-
if self.crosscompile_target.is_cheri_hybrid() and not self.build_dir_suffix:
140+
if self.crosscompile_target.is_hybrid_or_purecap_cheri() and not self.build_dir_suffix:
136141
# Install into the QEMU firware directory so that `-bios default` works
137142
qemu_fw_dir = BuildQEMU.get_install_dir(self, cross_target=CompilationTargets.NATIVE) / "share/qemu/"
143+
suffix = "cheristd" if self.crosscompile_target.is_cheri_purecap() else "cheri"
138144
self.makedirs(qemu_fw_dir)
145+
# TODO: looks like newer versions install a .bin that we could just copy instead.
139146
self.run_cmd(
140147
self.sdk_bindir / "llvm-objcopy",
141148
"-S",
142149
"-O",
143150
"binary",
144151
self._fw_jump_path(),
145-
qemu_fw_dir / "opensbi-riscv64cheri-virt-fw_jump.bin",
152+
qemu_fw_dir / f"opensbi-riscv64{suffix}-virt-fw_jump.bin",
146153
print_verbose_only=False,
147154
)
148155

@@ -190,7 +197,7 @@ class BuildUpstreamOpenSBI(BuildOpenSBI):
190197
supported_architectures = (CompilationTargets.FREESTANDING_RISCV64,)
191198

192199
def run_tests(self):
193-
options = QemuOptions(self.crosscompile_target)
200+
options = QemuOptions(self.crosscompile_target, riscv_cheri_isa=self.config.riscv_cheri_isa)
194201
self.run_cmd(
195202
options.get_commandline(
196203
qemu_command=BuildQEMU.qemu_binary(self),

pycheribuild/projects/run_qemu.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -224,14 +224,18 @@ def __init__(self, *args, **kwargs):
224224
self.disk_image_format = "raw"
225225
self._project_specific_options = []
226226
self.bios_flags = []
227-
self.qemu_options = QemuOptions(self.crosscompile_target, want_debugger=self.config.wait_for_debugger)
227+
self.qemu_options = QemuOptions(
228+
self.crosscompile_target,
229+
want_debugger=self.config.wait_for_debugger,
230+
riscv_cheri_isa=self.config.riscv_cheri_isa,
231+
)
228232
self.qemu_user_networking = True
229233
self.rootfs_path: Optional[Path] = None
230234
self._after_disk_options = []
231235

232236
def get_riscv_bios_args(self) -> "list[str]":
233237
# Explicit bios args no longer needed now that qemu defaults to a different file name for CHERI
234-
return riscv_bios_arguments(self.crosscompile_target, self)
238+
return riscv_bios_arguments(self.crosscompile_target, self.config.riscv_cheri_isa)
235239

236240
@classmethod
237241
def targets_reset(cls):

pycheribuild/projects/syzkaller.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ def syzkaller_config(self, syzkaller: BuildSyzkaller):
214214
# Run in debug mode
215215
vm_type = "none"
216216

217-
qemu_opts = QemuOptions(self.crosscompile_target)
217+
qemu_opts = QemuOptions(self.crosscompile_target, riscv_cheri_isa=self.config.riscv_cheri_isa)
218218
qemu_args = [*qemu_opts.machine_flags, "-device", "virtio-rng-pci", "-D", "syz-trace.log"]
219219
template = {
220220
"name": "cheribsd-n64",

0 commit comments

Comments
 (0)