Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pycheribuild/boot_cheribsd/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1524,7 +1524,7 @@ def _main(
else:
args.qemu_cmd = qemu_options.get_qemu_binary()
if args.qemu_cmd is None:
failure("ERROR: Cannot find QEMU binary for target ", qemu_options.qemu_arch_sufffix, exit=True)
failure("ERROR: Cannot find QEMU binary for target ", qemu_options.xtarget, exit=True)

global INTERACT_ON_KERNEL_PANIC # noqa: PLW0603
if args.interact_on_kernel_panic:
Expand Down
25 changes: 19 additions & 6 deletions pycheribuild/projects/build_qemu.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
import inspect
import os
import re
import shutil
Expand All @@ -51,6 +52,7 @@
)
from .simple_project import BoolConfigOption, SimpleProject, _cached_get_homebrew_prefix
from ..config.compilation_targets import BaremetalFreestandingTargetInfo, CompilationTargets
from ..config.config_loader_base import ConfigOptionHandle
from ..processutils import get_program_version
from ..utils import OSInfo

Expand Down Expand Up @@ -298,10 +300,8 @@ def setup(self):
"If you really don't need QEMU host shares you can disable the samba dependency "
"by setting --" + self.target + "/no-use-smbd",
)

self.configure_args.extend(
[
"--target-list=" + self.qemu_targets,
"--disable-xen",
"--disable-docs",
"--disable-rdma",
Expand Down Expand Up @@ -338,6 +338,17 @@ def configure(self, **kwargs):
self.configure_args.append("--enable-slirp")
else:
self.configure_args.append("--enable-slirp=git")

chosen_targets = self.qemu_targets
qemu_targets_option = typing.cast(ConfigOptionHandle, inspect.getattr_static(self, "qemu_targets"))
if qemu_targets_option.is_default_value:
if (self.source_dir / "configs/targets/riscv32cheristd-softmmu.mak").exists():
chosen_targets += ",riscv32cheristd-softmmu,riscv64cheristd-softmmu"
# Use the new xcheri targets if available:
if (self.source_dir / "configs/targets/riscv32xcheri-softmmu.mak").exists():
chosen_targets = chosen_targets.replace("riscv32cheri-softmmu", "riscv32xcheri-softmmu")
chosen_targets = chosen_targets.replace("riscv64cheri-softmmu", "riscv64xcheri-softmmu")
self.configure_args.append("--target-list=" + chosen_targets)
super().configure(**kwargs)

def run_tests(self):
Expand Down Expand Up @@ -455,10 +466,12 @@ class BuildQEMU(BuildQEMUBase):
@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"
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():
binary_name = f"qemu-system-riscv{xlen}xcheri"
elif xtarget.is_mips(include_purecap=True):
binary_name = "qemu-system-mips64cheri128"
elif xtarget.is_aarch64(include_purecap=True):
Expand Down
25 changes: 10 additions & 15 deletions pycheribuild/projects/run_qemu.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,21 +110,17 @@ def setup(self, launch):
assert launch.use_qemu == QEMUType.SYSTEM or launch.use_qemu == QEMUType.DEFAULT, (
"Unexpected use_qemu for lazy binary location: " + str(launch.use_qemu)
)
binary_name = "qemu-system-" + launch.qemu_options.qemu_arch_sufffix
if (launch.config.qemu_bindir / binary_name).is_file() and launch.use_qemu != QEMUType.SYSTEM:
qemu_binary = launch.qemu_options.get_qemu_binary(search_dirs=[launch.config.qemu_bindir])
if qemu_binary is not None and qemu_binary.is_file() and launch.use_qemu != QEMUType.SYSTEM:
# Only CHERI QEMU supports more than one SMB share
self._can_provide_src_via_smb = True
self._binary = launch.config.qemu_bindir / binary_name
else:
# Only CHERI QEMU supports more than one SMB share; conservatively
# guess what kind of QEMU this is
# Only CHERI QEMU supports more than one SMB share; conservatively guess what kind of QEMU this is
self._can_provide_src_via_smb = launch.crosscompile_target.is_hybrid_or_purecap_cheri()
launch.check_required_system_tool(binary_name)
binary_path = shutil.which(binary_name)
if not binary_path:
launch.fatal("Could not find system QEMU", binary_name)
binary_path = "/could/not/find/qemu"
self._binary = Path(binary_path)
if qemu_binary is None:
launch.fatal("Could not find system QEMU for target:", launch.qemu_options.xtarget)
qemu_binary = Path("/could/not/find/qemu")
self._binary = qemu_binary


class LaunchQEMUBase(SimpleProject):
Expand Down Expand Up @@ -243,8 +239,8 @@ def targets_reset(cls):
cls._cached_chosen_qemu = None

@classmethod
def get_chosen_qemu(cls, config: CheriConfig):
if cls._cached_chosen_qemu:
def get_chosen_qemu(cls, config: CheriConfig) -> ChosenQEMU:
if cls._cached_chosen_qemu is not None:
return cls._cached_chosen_qemu

xtarget = cls.get_crosscompile_target()
Expand Down Expand Up @@ -273,8 +269,7 @@ def get_chosen_qemu(cls, config: CheriConfig):
assert False, "Unknown target " + str(xtarget)

if cls.use_qemu == QEMUType.CUSTOM:
# Only CHERI QEMU supports more than one SMB share; conservatively
# guess what kind of QEMU this is
# Only CHERI QEMU supports more than one SMB share; conservatively guess what kind of QEMU this is
can_provide_src_via_smb = xtarget.is_hybrid_or_purecap_cheri()
if not cls.custom_qemu_path:
fatal_error(
Expand Down
24 changes: 15 additions & 9 deletions pycheribuild/qemu_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def __init__(self, xtarget: CrossCompileTarget, want_debugger=False) -> None:
self.memory_size = "2048"
self.has_default_nic = False
if xtarget.is_hybrid_or_purecap_cheri([CPUArchitecture.AARCH64]):
self.qemu_arch_sufffix = "morello"
self._qemu_arch_suffix = "morello"
self.can_boot_kernel_directly = False # boot from disk
# XXX: Use a CHERI-aware firmware. EL3 is disabled by default for
# virt, so CPTR_EL3 doesn't exist and CheriBSD can enable
Expand All @@ -56,19 +56,19 @@ def __init__(self, xtarget: CrossCompileTarget, want_debugger=False) -> None:
self.machine_flags = ["-M", "virt,gic-version=3", "-cpu", "morello", "-bios", "edk2-aarch64-code.fd"]
elif xtarget.is_mips(include_purecap=True):
# Note: we always use the CHERI QEMU
self.qemu_arch_sufffix = "mips64cheri128"
self._qemu_arch_suffix = "mips64cheri128"
self.machine_flags = ["-M", "malta"]
self.virtio_disk = False # broken for MIPS?
self.can_boot_kernel_directly = True
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_sufffix = "riscv32cheri" if xtarget.is_riscv32(include_purecap=True) else "riscv64cheri"
self._qemu_arch_suffix = "riscv32cheri" if xtarget.is_riscv32(include_purecap=True) else "riscv64cheri"
self.machine_flags = ["-M", "virt"]
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.
self.qemu_arch_sufffix = "x86_64"
self._qemu_arch_suffix = "x86_64"
self.can_boot_kernel_directly = False # boot from disk
# Try to use KVM instead of TCG if possible to speed up emulation
if not want_debugger:
Expand All @@ -83,11 +83,11 @@ def __init__(self, xtarget: CrossCompileTarget, want_debugger=False) -> None:
# We have to use the ancient default instead to avoid kernel panics.
# See https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=253617 for details.
elif xtarget.is_aarch64(include_purecap=False):
self.qemu_arch_sufffix = "aarch64"
self._qemu_arch_suffix = "aarch64"
self.can_boot_kernel_directly = False # boot from disk
self.machine_flags = ["-M", "virt,gic-version=3", "-cpu", "cortex-a72", "-bios", "edk2-aarch64-code.fd"]
elif xtarget.is_arm32(include_purecap=False):
self.qemu_arch_sufffix = "arm"
self._qemu_arch_suffix = "arm"
self.can_boot_kernel_directly = False # boot from disk
self.machine_flags = ["-M", "virt", "-cpu", "cortex-15"]
else:
Expand Down Expand Up @@ -156,9 +156,15 @@ def user_network_args(self, extra_options) -> "list[str]":
network_device_kind = self._qemu_network_config()[0]
return ["-device", network_device_kind + ",netdev=net0", "-netdev", "user,id=net0" + extra_options]

def get_qemu_binary(self) -> "Optional[Path]":
found_in_path = shutil.which("qemu-system-" + self.qemu_arch_sufffix)
return Path(found_in_path) if found_in_path is not None else None
def get_qemu_binary(self, search_dirs: "Optional[list[Path]]" = None) -> "Optional[Path]":
if search_dirs is None:
found_in_path = shutil.which("qemu-system-" + self._qemu_arch_suffix)
return Path(found_in_path) if found_in_path is not None else None
for d in search_dirs:
candidate = d / f"qemu-system-{self._qemu_arch_suffix}"
if candidate.exists():
return candidate
return None

def get_commandline(
self,
Expand Down