From b23da30c46eaec4afede5116920a178d2ad36682 Mon Sep 17 00:00:00 2001 From: Konrad Witaszczyk Date: Mon, 22 Nov 2021 22:46:41 +0000 Subject: [PATCH 01/19] Introduce the bsd-user-qemu target. The target builds the QEMU CheriABI user mode targets from the qemu-cheri-bsd-user branch in CTSRD-CHERI/QEMU and installs it in a separate SDK directory. This target doesn't use SMB and hence doesn't require SMB support. --- pycheribuild/config/chericonfig.py | 13 +++++++++++ pycheribuild/config/defaultconfig.py | 1 + pycheribuild/config/target_info.py | 3 +++ pycheribuild/projects/build_qemu.py | 33 +++++++++++++++++++++++++++- 4 files changed, 49 insertions(+), 1 deletion(-) diff --git a/pycheribuild/config/chericonfig.py b/pycheribuild/config/chericonfig.py index 0e1507764..e7f604177 100644 --- a/pycheribuild/config/chericonfig.py +++ b/pycheribuild/config/chericonfig.py @@ -325,6 +325,7 @@ def __init__(self, loader, action_class) -> None: self.build_root = None # type: Optional[Path] # Path to kernel/disk images (this is the same as output_root by default but different in Jenkins) self.cheribsd_image_root = None # type: Optional[Path] + self.bsd_user_sdk_dir = None # type: Optional[Path] self.cheri_sdk_dir = None # type: Optional[Path] self.morello_sdk_dir = None # type: Optional[Path] self.other_tools_dir = None # type: Optional[Path] @@ -529,6 +530,10 @@ def make_j_flag(self): def mips_cheri_bits_str(self): return str(self.mips_cheri_bits) + @property + def default_bsd_user_sdk_directory_name(self) -> str: + return "bsd-user-sdk" + @property def default_cheri_sdk_directory_name(self) -> str: return "sdk" @@ -537,6 +542,10 @@ def default_cheri_sdk_directory_name(self) -> str: def default_morello_sdk_directory_name(self) -> str: return "morello-sdk" + @property + def bsd_user_sdk_bindir(self): + return self.bsd_user_sdk_dir / "bin" + @property def cheri_sdk_bindir(self): return self.cheri_sdk_dir / "bin" @@ -549,6 +558,10 @@ def morello_sdk_bindir(self): def qemu_bindir(self): return self.cheri_sdk_bindir + @property + def bsd_user_qemu_bindir(self): + return self.bsd_user_sdk_bindir + @property def test_ssh_key(self) -> Path: if self._test_ssh_key is not None: diff --git a/pycheribuild/config/defaultconfig.py b/pycheribuild/config/defaultconfig.py index e28da62f0..600e92535 100644 --- a/pycheribuild/config/defaultconfig.py +++ b/pycheribuild/config/defaultconfig.py @@ -193,6 +193,7 @@ def load(self) -> None: super().load() # now set some generic derived config options self.cheri_sdk_dir = self.tools_root / self.default_cheri_sdk_directory_name + self.bsd_user_sdk_dir = self.tools_root / self.default_bsd_user_sdk_directory_name self.other_tools_dir = self.tools_root / "bootstrap" self.cheribsd_image_root = self.output_root # TODO: allow this to be different? diff --git a/pycheribuild/config/target_info.py b/pycheribuild/config/target_info.py index 1125c6800..78577d58c 100644 --- a/pycheribuild/config/target_info.py +++ b/pycheribuild/config/target_info.py @@ -131,6 +131,7 @@ class DefaultInstallDir(Enum): ROOTFS_LOCALBASE = "The sysroot for this target (/usr/local/ by default)" KDE_PREFIX = "The sysroot for this target (/opt//kde by default)" CHERI_SDK = "The CHERI SDK directory" + BSD_USER_SDK = "The QEMU BSD user mode SDK directory" MORELLO_SDK = "The Morello SDK directory" BOOTSTRAP_TOOLS = "The bootstap tools directory" CUSTOM_INSTALL_DIR = "Custom install directory" @@ -541,6 +542,8 @@ def default_install_dir(self, install_dir: DefaultInstallDir) -> Path: if self._is_libcompat_target: return config.output_root / ("local" + self._compat_abi_suffix) return config.output_root / "local" + elif install_dir == DefaultInstallDir.BSD_USER_SDK: + return config.bsd_user_sdk_dir elif install_dir == DefaultInstallDir.CHERI_SDK: return config.cheri_sdk_dir elif install_dir == DefaultInstallDir.MORELLO_SDK: diff --git a/pycheribuild/projects/build_qemu.py b/pycheribuild/projects/build_qemu.py index fda74ac5a..460de5638 100644 --- a/pycheribuild/projects/build_qemu.py +++ b/pycheribuild/projects/build_qemu.py @@ -60,6 +60,7 @@ class BuildQEMUBase(AutotoolsProject): can_build_with_asan = True default_targets: str = "some-invalid-target" default_build_type = BuildType.RELEASE + default_use_smbd = True lto_by_default = True use_smbd: bool smbd_path: Optional[Path] @@ -78,7 +79,7 @@ def _build_type_basic_compiler_flags(self): @classmethod def setup_config_options(cls, **kwargs): super().setup_config_options(**kwargs) - cls.use_smbd = cls.add_bool_option("use-smbd", show_help=False, default=True, + cls.use_smbd = cls.add_bool_option("use-smbd", show_help=False, default=cls.default_use_smbd, help="Don't require SMB support when building QEMU (warning: most --test " "targets will fail without smbd support)") @@ -394,3 +395,33 @@ def install(self, **kwargs): *self.config.morello_sdk_dir.rglob("share/icons/**/qemu.png"), *self.config.morello_sdk_dir.rglob("share/icons/**/qemu.bmp"), *self.config.morello_sdk_dir.rglob("share/icons/**/qemu.svg")) + + +class BuildBsdUserQEMU(BuildQEMU): + repository = GitRepository("https://github.com/CTSRD-CHERI/qemu.git", + default_branch="qemu-cheri-bsd-user", + force_branch=True) + native_install_dir = DefaultInstallDir.BSD_USER_SDK + default_targets = "riscv64cheri-bsd-user" + default_use_smbd = False + target = "bsd-user-qemu" + hide_options_from_help = True + + @classmethod + def qemu_cheri_binary(cls, caller: SimpleProject, xtarget: CrossCompileTarget = None): + if xtarget is None: + xtarget = caller.get_crosscompile_target() + if xtarget.is_riscv(include_purecap=True): + binary_name = "qemu-riscv64cheri" + else: + raise ValueError("Invalid xtarget" + str(xtarget)) + return caller.config.bsd_user_qemu_bindir / os.getenv("QEMU_BSD_USER_PATH", binary_name) + + def setup(self): + super().setup() + # Disable RVFI-DDI unsupported in the user mode. + self.configure_args.append("--disable-rvfi-dii") + # Enable to build BSD user mode targets. + self.configure_args.append("--enable-bsd-user") + # Build a static binary that can be easily included in a guest jail. + self.configure_args.append("--static") From 6ef2b0802a5922d70d310ef5baa9eb3bf761a678 Mon Sep 17 00:00:00 2001 From: Konrad Witaszczyk Date: Tue, 23 Nov 2021 21:19:51 +0000 Subject: [PATCH 02/19] Introduce the run--shell targets. A run--shell target launches a shell with the QEMU user mode in a CheriBSD sysroot. * Since the run--shell targets run a QEMU user mode binary, different QEMU flags are required, as opposed to the run- targets. Modify the QemuOptions class to provide separate methods to construct argument lists for a system or a user mode binary; * Instead of using the LaunchQEMUBase class, introduce the LaunchBsdUserQEMUBase class that runs a user mode binary; * Instead of using the LaunchCheriBSD class, introduce the LaunchCheriBSDShell class that creates run- targets with the "-shell" suffix; * Describe the run--shell targets in README. --- README.md | 1 + pycheribuild/boot_cheribsd/__init__.py | 2 +- pycheribuild/projects/run_qemu.py | 63 ++++++++++++++++++++++++-- pycheribuild/qemu_utils.py | 22 +++++++-- 4 files changed, 79 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 730c5cd06..24cde2fe0 100644 --- a/README.md +++ b/README.md @@ -184,6 +184,7 @@ For the `cheribsd`, `disk-image` and `run` targets the hybrid vs purecap distinc #### Other targets - `freebsd-` builds and installs [freebsd/freebsd](https://github.com/freebsd/freebsd). - `disk-image-freebsd-` creates a FreeBSD disk-image. +- `run--shell` launches a shell with the QEMU user mode in a CheriBSD sysroot. - `run-freebsd-` launches QEMU with the FreeBSD disk image. - `cmake` builds and installs latest [CMake](https://github.com/Kitware/CMake) - `cherios` builds and installs [CTSRD-CHERI/cherios](https://github.com/CTSRD-CHERI/cherios) diff --git a/pycheribuild/boot_cheribsd/__init__.py b/pycheribuild/boot_cheribsd/__init__.py index 0c6294013..6f413ff89 100755 --- a/pycheribuild/boot_cheribsd/__init__.py +++ b/pycheribuild/boot_cheribsd/__init__.py @@ -772,7 +772,7 @@ def boot_cheribsd(qemu_options: QemuOptions, qemu_command: Optional[Path], kerne bios_args = riscv_bios_arguments(qemu_options.xtarget, None) else: bios_args = [] - qemu_args = qemu_options.get_commandline(qemu_command=qemu_command, kernel_file=kernel_image, disk_image=disk_image, + qemu_args = qemu_options.get_system_commandline(qemu_command=qemu_command, kernel_file=kernel_image, disk_image=disk_image, bios_args=bios_args, user_network_args=user_network_args, write_disk_image_changes=write_disk_image_changes, add_network_device=True, diff --git a/pycheribuild/projects/run_qemu.py b/pycheribuild/projects/run_qemu.py index 42213de76..01f7ebce6 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 BuildBsdUserQEMU, BuildQEMU, BuildQEMUBase, BuildUpstreamQEMU from .cherios import BuildCheriOS from .cross.cheribsd import BuildCHERIBSD, BuildCheriBsdMfsKernel, BuildFreeBSD, ConfigPlatform, KernelABI from .cross.gdb import BuildGDB @@ -51,7 +51,7 @@ ) from .project import CheriConfig, ComputedDefaultValue, CPUArchitecture, Project from .simple_project import SimpleProject, TargetAliasWithDependencies -from ..config.compilation_targets import CompilationTargets +from ..config.compilation_targets import CompilationTargets, CrossCompileTarget from ..qemu_utils import QemuOptions, qemu_supports_9pfs, riscv_bios_arguments from ..utils import AnsiColour, OSInfo, classproperty, coloured, fatal_error, find_free_port @@ -447,7 +447,7 @@ def add_smb_or_9p_dir(directory, target, share_name=None, readonly=False): self._after_disk_options += ["-snapshot"] # input("Press enter to continue") - qemu_command = self.qemu_options.get_commandline(qemu_command=self.chosen_qemu.binary, + qemu_command = self.qemu_options.get_system_commandline(qemu_command=self.chosen_qemu.binary, kernel_file=qemu_loader_or_kernel, disk_image=self.disk_image, disk_image_format=self.disk_image_format, @@ -585,6 +585,41 @@ def is_port_available(port: int): return False +class LaunchBsdUserQEMUBase(SimpleProject): + do_not_add_to_targets = True + + @classmethod + def setup_config_options(cls, default_ssh_port: int = None, **kwargs): + super().setup_config_options(**kwargs) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.qemu_binary = None # type: typing.Optional[Path] + self.qemu_options = QemuOptions(self.crosscompile_target, is_system_mode=False) + self.rootfs_path = None # type:typing.Optional[Path] + + def setup(self): + super().setup() + xtarget = self.crosscompile_target + if xtarget.is_riscv(include_purecap=True): + self.qemu_binary = BuildBsdUserQEMU.qemu_cheri_binary(self) + else: + assert False, "Unknown target " + str(xtarget) + + def process(self): + assert self.qemu_binary is not None + if not self.qemu_binary.exists(): + self.dependency_error("QEMU is missing:", self.qemu_binary, cheribuild_target="qemu") + + program = "{}{}".format(self.rootfs_path, "/bin/sh") + qemu_command = self.qemu_options.get_user_commandline(qemu_command=self.qemu_binary, + rootfs_path=self.rootfs_path, program=program) + + self.info("About to run '{}' with the QEMU user mode".format(program)) + + self.run_cmd(qemu_command, stdout=sys.stdout, stderr=sys.stderr, give_tty_control=True) + + class AbstractLaunchFreeBSD(LaunchQEMUBase): do_not_add_to_targets = True kernel_project: Optional[BuildFreeBSD] @@ -757,6 +792,28 @@ def dependencies(cls, config: CheriConfig) -> "list[str]": return result +class LaunchCheriBSDShell(LaunchBsdUserQEMUBase): + target = "run" + _source_class = BuildCHERIBSD + _freebsd_class = BuildCHERIBSD + _always_add_suffixed_targets = True + supported_architectures = [CompilationTargets.CHERIBSD_RISCV_PURECAP] + + def __init__(self, config): + super().__init__(config) + self.rootfs_path = self._source_class.get_rootfs_dir(self, config=config) + + @staticmethod + def custom_target_name(base_target: str, xtarget: CrossCompileTarget) -> str: + return base_target + '-' + xtarget.generic_target_suffix + '-shell' + + @classmethod + def dependencies(cls: "typing.Type[_RunMultiArchFreeBSDImage]", config: CheriConfig) -> "list[str]": + xtarget = cls.get_crosscompile_target(config) + result = ["bsd-user-qemu", cls._source_class.get_class_for_target(xtarget).target] + return result + + class LaunchCheriOSQEMU(LaunchQEMUBase): target = "run-cherios" dependencies = ["qemu", "cherios"] diff --git a/pycheribuild/qemu_utils.py b/pycheribuild/qemu_utils.py index 42f0d30c0..3966ff41a 100644 --- a/pycheribuild/qemu_utils.py +++ b/pycheribuild/qemu_utils.py @@ -39,7 +39,8 @@ class QemuOptions: - def __init__(self, xtarget: CrossCompileTarget, want_debugger=False) -> None: + def __init__(self, xtarget: CrossCompileTarget, want_debugger=False, + is_system_mode=True) -> None: self.xtarget = xtarget self.virtio_disk = True self.force_virtio_blk_device = False @@ -152,16 +153,19 @@ 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_commandline(self, *, qemu_command=None, kernel_file: "Optional[Path]" = None, + def get_common_commandline(self, *, qemu_command=None): + if qemu_command is None: + qemu_command = self.get_qemu_binary() + return [str(qemu_command)] + + def get_system_commandline(self, *, qemu_command=None, kernel_file: "Optional[Path]" = None, disk_image: "Optional[Path]" = None, disk_image_format: str = "raw", user_network_args: str = "", add_network_device=True, bios_args: "Optional[list[str]]" = None, trap_on_unrepresentable=False, debugger_on_cheri_trap=False, add_virtio_rng=False, write_disk_image_changes=True, gui_options: "Optional[list[str]]" = None) -> "list[str]": if kernel_file is None and disk_image is None: raise ValueError("Must pass kernel and/or disk image path when launching QEMU") - if qemu_command is None: - qemu_command = self.get_qemu_binary() - result = [str(qemu_command)] + result = self.get_common_commandline() result.extend(self.machine_flags) result.extend(["-m", self.memory_size]) if gui_options is None: @@ -189,6 +193,14 @@ def get_commandline(self, *, qemu_command=None, kernel_file: "Optional[Path]" = result.extend(["-device", "virtio-rng-pci"]) return result + def get_user_commandline(self, *, qemu_command=None, rootfs_path: Path = None, program: Path =None): + result = self.get_common_commandline(qemu_command=qemu_command) + if rootfs_path: + result.extend(["-L", rootfs_path]) + if program: + result.append(program) + return result + @functools.lru_cache(maxsize=20) def qemu_supports_9pfs(qemu: Path) -> bool: From 94ff254334ec1fb768006a737a40f65325acc41a Mon Sep 17 00:00:00 2001 From: Konrad Witaszczyk Date: Wed, 24 Nov 2021 17:04:47 +0000 Subject: [PATCH 03/19] Introduce run--exec targets. A run--exec target executes a command passed with an option --exec/command. Additionally, one of the following options can be used: * --exec/chroot tells cheribuild to change a root directory to a sysroot before executing the command; * --exec/jail tells cheribuild to enter a jail with a sysroot before executing the command. The flags --exec/{chroot,jail} require cheribuild to be run as root. At the moment, --allow-running-as-root can be used to run cheribuild with sudo but this option shouldn't be used without the flags --exec/{chroot,jail}. Additionally, --skip-update is recommended when carefully using --allow-running-as-root. --- pycheribuild/projects/build_qemu.py | 7 ++- pycheribuild/projects/run_qemu.py | 68 ++++++++++++++++++++++++----- pycheribuild/qemu_utils.py | 6 +-- 3 files changed, 65 insertions(+), 16 deletions(-) diff --git a/pycheribuild/projects/build_qemu.py b/pycheribuild/projects/build_qemu.py index 460de5638..5f2508a05 100644 --- a/pycheribuild/projects/build_qemu.py +++ b/pycheribuild/projects/build_qemu.py @@ -408,14 +408,17 @@ class BuildBsdUserQEMU(BuildQEMU): hide_options_from_help = True @classmethod - def qemu_cheri_binary(cls, caller: SimpleProject, xtarget: CrossCompileTarget = None): + def qemu_cheri_binary(cls, caller: SimpleProject, xtarget: CrossCompileTarget = None, absolute_path=True): if xtarget is None: xtarget = caller.get_crosscompile_target() if xtarget.is_riscv(include_purecap=True): binary_name = "qemu-riscv64cheri" else: raise ValueError("Invalid xtarget" + str(xtarget)) - return caller.config.bsd_user_qemu_bindir / os.getenv("QEMU_BSD_USER_PATH", binary_name) + if absolute_path: + return caller.config.bsd_user_qemu_bindir / os.getenv("QEMU_BSD_USER_PATH", binary_name) + else: + return binary_name def setup(self): super().setup() diff --git a/pycheribuild/projects/run_qemu.py b/pycheribuild/projects/run_qemu.py index 01f7ebce6..fb415ce4e 100644 --- a/pycheribuild/projects/run_qemu.py +++ b/pycheribuild/projects/run_qemu.py @@ -600,24 +600,45 @@ def __init__(self, *args, **kwargs): def setup(self): super().setup() + absolute_path = not self.chroot and not self.jail xtarget = self.crosscompile_target if xtarget.is_riscv(include_purecap=True): - self.qemu_binary = BuildBsdUserQEMU.qemu_cheri_binary(self) + self.qemu_binary = BuildBsdUserQEMU.qemu_cheri_binary(self, absolute_path=absolute_path) else: assert False, "Unknown target " + str(xtarget) def process(self): assert self.qemu_binary is not None - if not self.qemu_binary.exists(): - self.dependency_error("QEMU is missing:", self.qemu_binary, cheribuild_target="qemu") + assert self.rootfs_path is not None + + if self.chroot and self.jail: + self.fatal("Chroot and jail options are mutually exclusive.") + elif self.chroot: + command = ["chroot", self.rootfs_path] + qemu_command = self.qemu_binary + rootfs_path = None + elif self.jail: + command = ["jail", "-c", "path={}".format(self.rootfs_path)] + qemu_command = "command={}".format(self.qemu_binary) + rootfs_path = None + else: + command = [] + qemu_command = self.qemu_binary + rootfs_path = self.rootfs_path + + if self.command: + user_command = self.command + elif rootfs_path: + user_command = ["{}{}".format(rootfs_path, "/bin/sh")] + else: + user_command = ["sh"] - program = "{}{}".format(self.rootfs_path, "/bin/sh") - qemu_command = self.qemu_options.get_user_commandline(qemu_command=self.qemu_binary, - rootfs_path=self.rootfs_path, program=program) + command.extend(self.qemu_options.get_user_commandline(qemu_command=qemu_command, + rootfs_path=rootfs_path, user_command=user_command)) - self.info("About to run '{}' with the QEMU user mode".format(program)) + self.info("About to run '{}' with the QEMU user mode".format(" ".join(user_command))) - self.run_cmd(qemu_command, stdout=sys.stdout, stderr=sys.stderr, give_tty_control=True) + self.run_cmd(command, stdout=sys.stdout, stderr=sys.stderr, give_tty_control=True) class AbstractLaunchFreeBSD(LaunchQEMUBase): @@ -792,8 +813,8 @@ def dependencies(cls, config: CheriConfig) -> "list[str]": return result -class LaunchCheriBSDShell(LaunchBsdUserQEMUBase): - target = "run" +class AbstractLaunchFreeBSDProgram(LaunchBsdUserQEMUBase): + do_not_add_to_targets = True _source_class = BuildCHERIBSD _freebsd_class = BuildCHERIBSD _always_add_suffixed_targets = True @@ -803,9 +824,17 @@ def __init__(self, config): super().__init__(config) self.rootfs_path = self._source_class.get_rootfs_dir(self, config=config) + @classmethod + def setup_config_options(cls, **kwargs): + super().setup_config_options(**kwargs) + cls.chroot = cls.add_bool_option("chroot", default=False, show_help=True, + help="Change the root directory to a sysroot before executing a command.") + cls.jail = cls.add_bool_option("jail", default=False, show_help=True, + help="Enter a jail with a sysroot before executing a command.") + @staticmethod def custom_target_name(base_target: str, xtarget: CrossCompileTarget) -> str: - return base_target + '-' + xtarget.generic_target_suffix + '-shell' + return "run-{}-{}".format(xtarget.generic_target_suffix, base_target) @classmethod def dependencies(cls: "typing.Type[_RunMultiArchFreeBSDImage]", config: CheriConfig) -> "list[str]": @@ -814,6 +843,23 @@ def dependencies(cls: "typing.Type[_RunMultiArchFreeBSDImage]", config: CheriCon return result +class LaunchCheriBSDShell(AbstractLaunchFreeBSDProgram): + target = "shell" + + def __init__(self, config): + super().__init__(config) + self.command = None + + +class LaunchCheriBSDExec(AbstractLaunchFreeBSDProgram): + target = "exec" + + @classmethod + def setup_config_options(cls, **kwargs): + super().setup_config_options(**kwargs) + cls.command = cls.add_config_option("command", metavar="COMMAND", show_help=True, kind=list, + help="Command to execute.") + class LaunchCheriOSQEMU(LaunchQEMUBase): target = "run-cherios" dependencies = ["qemu", "cherios"] diff --git a/pycheribuild/qemu_utils.py b/pycheribuild/qemu_utils.py index 3966ff41a..169ec8a79 100644 --- a/pycheribuild/qemu_utils.py +++ b/pycheribuild/qemu_utils.py @@ -193,12 +193,12 @@ def get_system_commandline(self, *, qemu_command=None, kernel_file: "Optional[Pa result.extend(["-device", "virtio-rng-pci"]) return result - def get_user_commandline(self, *, qemu_command=None, rootfs_path: Path = None, program: Path =None): + def get_user_commandline(self, *, qemu_command=None, rootfs_path: Path = None, user_command: Path = None): result = self.get_common_commandline(qemu_command=qemu_command) if rootfs_path: result.extend(["-L", rootfs_path]) - if program: - result.append(program) + if user_command: + result.extend(user_command) return result From 8c67455d9a781fdf545fe33d49e3d5ecaee79fe4 Mon Sep 17 00:00:00 2001 From: Konrad Witaszczyk Date: Wed, 24 Nov 2021 18:11:14 +0000 Subject: [PATCH 04/19] Rename run--{shell,exec} targets. * Rename the targets to run-{shell,user}- for consistency with other targets; * Describe the run-user- in README. Pointed out by: @jrtc27 --- README.md | 3 ++- pycheribuild/projects/run_qemu.py | 8 ++------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 24cde2fe0..eb203c921 100644 --- a/README.md +++ b/README.md @@ -184,8 +184,9 @@ For the `cheribsd`, `disk-image` and `run` targets the hybrid vs purecap distinc #### Other targets - `freebsd-` builds and installs [freebsd/freebsd](https://github.com/freebsd/freebsd). - `disk-image-freebsd-` creates a FreeBSD disk-image. -- `run--shell` launches a shell with the QEMU user mode in a CheriBSD sysroot. - `run-freebsd-` launches QEMU with the FreeBSD disk image. +- `run-shell-` launches a shell with the QEMU user mode in a CheriBSD sysroot. +- `run-user-` launches a command with the QEMU user mode in a CheriBSD sysroot. - `cmake` builds and installs latest [CMake](https://github.com/Kitware/CMake) - `cherios` builds and installs [CTSRD-CHERI/cherios](https://github.com/CTSRD-CHERI/cherios) - `cheritrace` builds and installs [CTSRD-CHERI/cheritrace](https://github.com/CTSRD-CHERI/cheritrace) diff --git a/pycheribuild/projects/run_qemu.py b/pycheribuild/projects/run_qemu.py index fb415ce4e..4018b1b0b 100644 --- a/pycheribuild/projects/run_qemu.py +++ b/pycheribuild/projects/run_qemu.py @@ -832,10 +832,6 @@ def setup_config_options(cls, **kwargs): cls.jail = cls.add_bool_option("jail", default=False, show_help=True, help="Enter a jail with a sysroot before executing a command.") - @staticmethod - def custom_target_name(base_target: str, xtarget: CrossCompileTarget) -> str: - return "run-{}-{}".format(xtarget.generic_target_suffix, base_target) - @classmethod def dependencies(cls: "typing.Type[_RunMultiArchFreeBSDImage]", config: CheriConfig) -> "list[str]": xtarget = cls.get_crosscompile_target(config) @@ -844,7 +840,7 @@ def dependencies(cls: "typing.Type[_RunMultiArchFreeBSDImage]", config: CheriCon class LaunchCheriBSDShell(AbstractLaunchFreeBSDProgram): - target = "shell" + target = "run-shell" def __init__(self, config): super().__init__(config) @@ -852,7 +848,7 @@ def __init__(self, config): class LaunchCheriBSDExec(AbstractLaunchFreeBSDProgram): - target = "exec" + target = "run-user" @classmethod def setup_config_options(cls, **kwargs): From 3bb34a6a25083d8a67e508937880c379d9552df9 Mon Sep 17 00:00:00 2001 From: Konrad Witaszczyk Date: Fri, 26 Nov 2021 14:29:53 +0000 Subject: [PATCH 05/19] Introduce --run-{shell,user}/jail-extra-args. The jail-extra-args options allow to pass extra jail parameters to jail(8), e.g. to mount devfs(8). --- pycheribuild/projects/run_qemu.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pycheribuild/projects/run_qemu.py b/pycheribuild/projects/run_qemu.py index 4018b1b0b..8482325c7 100644 --- a/pycheribuild/projects/run_qemu.py +++ b/pycheribuild/projects/run_qemu.py @@ -619,6 +619,8 @@ def process(self): rootfs_path = None elif self.jail: command = ["jail", "-c", "path={}".format(self.rootfs_path)] + if self.jail_extra_args: + command.extend(self.jail_extra_args) qemu_command = "command={}".format(self.qemu_binary) rootfs_path = None else: @@ -831,6 +833,8 @@ def setup_config_options(cls, **kwargs): help="Change the root directory to a sysroot before executing a command.") cls.jail = cls.add_bool_option("jail", default=False, show_help=True, help="Enter a jail with a sysroot before executing a command.") + cls.jail_extra_args = cls.add_config_option("jail-extra-args", metavar="ARGS", kind=list, show_help=True, + help="Extra jail parameters to pass to jail(8).") @classmethod def dependencies(cls: "typing.Type[_RunMultiArchFreeBSDImage]", config: CheriConfig) -> "list[str]": From efe407576e12783f4902f7a3b2a561937adbb66d Mon Sep 17 00:00:00 2001 From: Konrad Witaszczyk Date: Sat, 4 Dec 2021 16:01:45 +0000 Subject: [PATCH 06/19] Add QEMU BSD user mode options for Jenkins. --- pycheribuild/config/jenkinsconfig.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/pycheribuild/config/jenkinsconfig.py b/pycheribuild/config/jenkinsconfig.py index a969e2271..9a5e3a513 100644 --- a/pycheribuild/config/jenkinsconfig.py +++ b/pycheribuild/config/jenkinsconfig.py @@ -141,6 +141,9 @@ def __init__(self, loader: ConfigLoaderBase, available_targets: list) -> None: help="Don't use the CHERI SDK -> only /usr (for native builds)") self.strip_elf_files = loader.add_commandline_only_bool_option( "strip-elf-files", help="Strip ELF files before creating the tarball", default=True, negatable=True) + self._bsd_user_sdk_dir_override = loader.add_commandline_only_option( + "bsd-user-sdk-path", default=None, type=Path, + help="Override the path to the BSD user mode SDK (default is $WORKSPACE/bsd-user-sdk)") # type: Path self._cheri_sdk_dir_override = loader.add_commandline_only_option( "cheri-sdk-path", default=None, type=Path, help="Override the path to the CHERI SDK (default is $WORKSPACE/cherisdk)") @@ -207,6 +210,23 @@ def qemu_bindir(self): os_suffix = "unknown-os" return self.workspace / ("qemu-" + os_suffix) / "bin" + @property + def bsd_user_qemu_bindir(self): + for i in self.bsd_user_sdk_bindir.glob("qemu-*"): + if self.verbose: + print("Found QEMU binary", i, "in BSD user-mode SDK dir -> using that for BSD user-mode QEMU binaries") + # If one qemu-foo exists in the bsd_user_sdk_bindir use that instead of $WORKSPACE/qemu- + return self.bsd_user_sdk_bindir + if OSInfo.IS_LINUX: + os_suffix = "linux" + elif OSInfo.IS_FREEBSD: + os_suffix = "freebsd" + elif OSInfo.IS_MAC: + os_suffix = "mac" + else: + os_suffix = "unknown-os" + return self.workspace / ("qemu-" + os_suffix) / "bin" + def load(self) -> None: super().load() @@ -230,6 +250,11 @@ def load(self) -> None: self.other_tools_dir = self.workspace / "bootstrap" + if self._bsd_user_sdk_dir_override is not None: + self.bsd_user_sdk_dir = self._bsd_user_sdk_dir_override + else: + self.bsd_user_sdk_dir = self.workspace / self.default_bsd_user_sdk_directory_name + if self._cheri_sdk_dir_override is not None: self.cheri_sdk_dir = self._cheri_sdk_dir_override elif Path("/cheri-sdk/bin/clang").exists(): # check for ctsrd/cheri-sdk docker image @@ -280,6 +305,8 @@ def load(self) -> None: self.clang_plusplus_path = compiler_dir_override / "clang++" self.clang_cpp_path = compiler_dir_override / "clang-cpp" + if self._bsd_user_sdk_dir_override is not None: + assert self.bsd_user_sdk_bindir == self._bsd_user_sdk_dir_override / "bin" if self._cheri_sdk_dir_override is not None: assert self.cheri_sdk_bindir == self._cheri_sdk_dir_override / "bin" if self._morello_sdk_dir_override is not None: From 6a3da25f880ec358b3ab605f408ed3b29a96702f Mon Sep 17 00:00:00 2001 From: Konrad Witaszczyk Date: Sat, 4 Dec 2021 16:34:40 +0000 Subject: [PATCH 07/19] Mock the BSD user-mode SDK directory path. --- tests/setup_mock_chericonfig.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/setup_mock_chericonfig.py b/tests/setup_mock_chericonfig.py index ac45e1d21..530e9e1fa 100644 --- a/tests/setup_mock_chericonfig.py +++ b/tests/setup_mock_chericonfig.py @@ -55,6 +55,7 @@ def __init__(self, source_root: Path, pretend=True): # allow overriding pretend self.source_root = source_root self.build_root = source_root / "build" self.output_root = source_root / "output" + self.bsd_user_sdk_dir = self.output_root / "bsd-user-sdk" self.cheri_sdk_dir = self.output_root / "sdk" self.morello_sdk_dir = self.output_root / "morello-sdk" self.sysroot_output_root = self.output_root From b664350433df10e162f6e708c2979ce021135ab9 Mon Sep 17 00:00:00 2001 From: Konrad Witaszczyk Date: Sat, 4 Dec 2021 18:00:57 +0000 Subject: [PATCH 08/19] Make Flake8 happy. --- pycheribuild/boot_cheribsd/__init__.py | 15 ++++++++------- pycheribuild/projects/run_qemu.py | 21 +++++++++------------ pycheribuild/qemu_utils.py | 11 +++++------ 3 files changed, 22 insertions(+), 25 deletions(-) diff --git a/pycheribuild/boot_cheribsd/__init__.py b/pycheribuild/boot_cheribsd/__init__.py index 6f413ff89..2ff223e7c 100755 --- a/pycheribuild/boot_cheribsd/__init__.py +++ b/pycheribuild/boot_cheribsd/__init__.py @@ -772,13 +772,14 @@ def boot_cheribsd(qemu_options: QemuOptions, qemu_command: Optional[Path], kerne bios_args = riscv_bios_arguments(qemu_options.xtarget, None) else: bios_args = [] - qemu_args = qemu_options.get_system_commandline(qemu_command=qemu_command, kernel_file=kernel_image, disk_image=disk_image, - bios_args=bios_args, user_network_args=user_network_args, - write_disk_image_changes=write_disk_image_changes, - add_network_device=True, - trap_on_unrepresentable=trap_on_unrepresentable, # For debugging - add_virtio_rng=True # faster entropy gathering - ) + qemu_args = qemu_options.get_system_commandline(qemu_command=qemu_command, kernel_file=kernel_image, + disk_image=disk_image, bios_args=bios_args, + user_network_args=user_network_args, + write_disk_image_changes=write_disk_image_changes, + add_network_device=True, + trap_on_unrepresentable=trap_on_unrepresentable, # For debugging + add_virtio_rng=True # faster entropy gathering + ) qemu_args.extend(smp_args) kernel_commandline = [] if kernel_init_only: diff --git a/pycheribuild/projects/run_qemu.py b/pycheribuild/projects/run_qemu.py index 8482325c7..069289f7d 100644 --- a/pycheribuild/projects/run_qemu.py +++ b/pycheribuild/projects/run_qemu.py @@ -51,7 +51,7 @@ ) from .project import CheriConfig, ComputedDefaultValue, CPUArchitecture, Project from .simple_project import SimpleProject, TargetAliasWithDependencies -from ..config.compilation_targets import CompilationTargets, CrossCompileTarget +from ..config.compilation_targets import CompilationTargets from ..qemu_utils import QemuOptions, qemu_supports_9pfs, riscv_bios_arguments from ..utils import AnsiColour, OSInfo, classproperty, coloured, fatal_error, find_free_port @@ -447,16 +447,12 @@ def add_smb_or_9p_dir(directory, target, share_name=None, readonly=False): self._after_disk_options += ["-snapshot"] # input("Press enter to continue") - qemu_command = self.qemu_options.get_system_commandline(qemu_command=self.chosen_qemu.binary, - kernel_file=qemu_loader_or_kernel, - disk_image=self.disk_image, - disk_image_format=self.disk_image_format, - add_network_device=self.qemu_user_networking, - bios_args=self.bios_flags, - user_network_args=user_network_options, - trap_on_unrepresentable=self.config.trap_on_unrepresentable, - debugger_on_cheri_trap=self.config.debugger_on_cheri_trap, - add_virtio_rng=self._add_virtio_rng) + qemu_command = self.qemu_options.get_system_commandline( + qemu_command=self.chosen_qemu.binary, kernel_file=qemu_loader_or_kernel, disk_image=self.disk_image, + disk_image_format=self.disk_image_format, add_network_device=self.qemu_user_networking, + bios_args=self.bios_flags, user_network_args=user_network_options, + trap_on_unrepresentable=self.config.trap_on_unrepresentable, + debugger_on_cheri_trap=self.config.debugger_on_cheri_trap, add_virtio_rng=self._add_virtio_rng) qemu_command += self._project_specific_options + self._after_disk_options + monitor_options qemu_command += logfile_options + self.extra_qemu_options + virtfs_args if self.disk_image is None: @@ -636,7 +632,7 @@ def process(self): user_command = ["sh"] command.extend(self.qemu_options.get_user_commandline(qemu_command=qemu_command, - rootfs_path=rootfs_path, user_command=user_command)) + rootfs_path=rootfs_path, user_command=user_command)) self.info("About to run '{}' with the QEMU user mode".format(" ".join(user_command))) @@ -860,6 +856,7 @@ def setup_config_options(cls, **kwargs): cls.command = cls.add_config_option("command", metavar="COMMAND", show_help=True, kind=list, help="Command to execute.") + class LaunchCheriOSQEMU(LaunchQEMUBase): target = "run-cherios" dependencies = ["qemu", "cherios"] diff --git a/pycheribuild/qemu_utils.py b/pycheribuild/qemu_utils.py index 169ec8a79..7c5bf5b1e 100644 --- a/pycheribuild/qemu_utils.py +++ b/pycheribuild/qemu_utils.py @@ -39,8 +39,7 @@ class QemuOptions: - def __init__(self, xtarget: CrossCompileTarget, want_debugger=False, - is_system_mode=True) -> None: + def __init__(self, xtarget: CrossCompileTarget, want_debugger=False, is_system_mode=True) -> None: self.xtarget = xtarget self.virtio_disk = True self.force_virtio_blk_device = False @@ -159,10 +158,10 @@ def get_common_commandline(self, *, qemu_command=None): return [str(qemu_command)] def get_system_commandline(self, *, qemu_command=None, kernel_file: "Optional[Path]" = None, - disk_image: "Optional[Path]" = None, disk_image_format: str = "raw", - user_network_args: str = "", add_network_device=True, bios_args: "Optional[list[str]]" = None, - trap_on_unrepresentable=False, debugger_on_cheri_trap=False, add_virtio_rng=False, - write_disk_image_changes=True, gui_options: "Optional[list[str]]" = None) -> "list[str]": + disk_image: "Optional[Path]" = None, disk_image_format: str = "raw", + user_network_args: str = "", add_network_device=True, bios_args: "Optional[list[str]]" = None, + trap_on_unrepresentable=False, debugger_on_cheri_trap=False, add_virtio_rng=False, + write_disk_image_changes=True, gui_options: "Optional[list[str]]" = None) -> "list[str]": if kernel_file is None and disk_image is None: raise ValueError("Must pass kernel and/or disk image path when launching QEMU") result = self.get_common_commandline() From 8505ecb11fccf91f7d84b2b92554bc70e6a7392b Mon Sep 17 00:00:00 2001 From: Konrad Witaszczyk Date: Mon, 6 Dec 2021 14:20:56 +0000 Subject: [PATCH 09/19] Introduce the BuildSystemQEMU class. BuildSystemQEMU is a parent class for all classes for system-mode targets. Thanks to this class, two issues are resolved: * BuildQEMUBase was adding --disable-bsd-user to configure flags also for user-mode targets; * BuildQEMU was adding morello-softmmu to the default targets if a QEMU branch includes Morello support. BuildBsdUserQEMU can manage its own list of targets and not use configuration flags only related to the system mode now. --- pycheribuild/projects/build_qemu.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/pycheribuild/projects/build_qemu.py b/pycheribuild/projects/build_qemu.py index 5f2508a05..dc08e0cbc 100644 --- a/pycheribuild/projects/build_qemu.py +++ b/pycheribuild/projects/build_qemu.py @@ -223,7 +223,6 @@ def setup(self): self.configure_args.extend([ "--target-list=" + self.qemu_targets, "--disable-linux-user", - "--disable-bsd-user", "--disable-xen", "--disable-docs", "--disable-rdma", @@ -278,8 +277,17 @@ def process(self) -> None: super().process() +class BuildSystemQEMU(BuildQEMUBase): + do_not_add_to_targets = True + + def setup(self): + super().setup() + # Don't build BSD user mode targets as we only want system mode binaries. + self.configure_args.append("--disable-bsd-user") + + # noinspection PyAbstractClass -class BuildUpstreamQEMU(BuildQEMUBase): +class BuildUpstreamQEMU(BuildSystemQEMU): repository = GitRepository("https://github.com/qemu/qemu.git") target = "upstream-qemu" _default_install_dir_fn = ComputedDefaultValue( @@ -309,7 +317,7 @@ def qemu_binary_for_target(cls, xtarget: CrossCompileTarget, config: CheriConfig return config.output_root / "upstream-qemu/bin" / binary_name -class BuildQEMU(BuildQEMUBase): +class BuildQEMU(BuildSystemQEMU): target = "qemu" repository = GitRepository("https://github.com/CTSRD-CHERI/qemu.git", default_branch="qemu-cheri") default_targets = "aarch64-softmmu,morello-softmmu," \ @@ -397,7 +405,7 @@ def install(self, **kwargs): *self.config.morello_sdk_dir.rglob("share/icons/**/qemu.svg")) -class BuildBsdUserQEMU(BuildQEMU): +class BuildBsdUserQEMU(BuildQEMUBase): repository = GitRepository("https://github.com/CTSRD-CHERI/qemu.git", default_branch="qemu-cheri-bsd-user", force_branch=True) @@ -422,6 +430,8 @@ def qemu_cheri_binary(cls, caller: SimpleProject, xtarget: CrossCompileTarget = def setup(self): super().setup() + # Disable capstone disassembler unsupporting CHERI instructions. + self.configure_args.append("--disable-capstone") # Disable RVFI-DDI unsupported in the user mode. self.configure_args.append("--disable-rvfi-dii") # Enable to build BSD user mode targets. From be4fd63e42aa673b2b6aac3d130370859a4eab66 Mon Sep 17 00:00:00 2001 From: Konrad Witaszczyk Date: Mon, 10 Jan 2022 13:51:55 +0000 Subject: [PATCH 10/19] Build BSD user modes for aarch64 and riscv64. Extend the bsd-user-qemu target to build BSD user modes for all targets we're interested in: aarch64, riscv64, riscv64c. Morello will be added to the above list once it's working. --- 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 dc08e0cbc..f9f641f38 100644 --- a/pycheribuild/projects/build_qemu.py +++ b/pycheribuild/projects/build_qemu.py @@ -410,7 +410,7 @@ class BuildBsdUserQEMU(BuildQEMUBase): default_branch="qemu-cheri-bsd-user", force_branch=True) native_install_dir = DefaultInstallDir.BSD_USER_SDK - default_targets = "riscv64cheri-bsd-user" + default_targets = "aarch64-bsd-user,riscv64-bsd-user,riscv64cheri-bsd-user" default_use_smbd = False target = "bsd-user-qemu" hide_options_from_help = True From ddfd6005f75814b65e25866aefc4ab199f78f68b Mon Sep 17 00:00:00 2001 From: Konrad Witaszczyk Date: Mon, 17 Jan 2022 20:22:44 +0000 Subject: [PATCH 11/19] Build the Morello user mode by default. --- 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 f9f641f38..404dd56bf 100644 --- a/pycheribuild/projects/build_qemu.py +++ b/pycheribuild/projects/build_qemu.py @@ -410,7 +410,7 @@ class BuildBsdUserQEMU(BuildQEMUBase): default_branch="qemu-cheri-bsd-user", force_branch=True) native_install_dir = DefaultInstallDir.BSD_USER_SDK - default_targets = "aarch64-bsd-user,riscv64-bsd-user,riscv64cheri-bsd-user" + default_targets = "aarch64-bsd-user,morello-bsd-user,riscv64-bsd-user,riscv64cheri-bsd-user" default_use_smbd = False target = "bsd-user-qemu" hide_options_from_help = True From d466115c1ad7ba717e6ea3e12c561a7d70442dec Mon Sep 17 00:00:00 2001 From: Konrad Witaszczyk Date: Tue, 22 Feb 2022 13:56:42 +0000 Subject: [PATCH 12/19] Rename the run-shell target to run-user-shell. * Rename the target to indiciate with a 'user' subword it's related to the BSD user mode (built with the bsd-user-qemu cheribuild target); * Update class names to match target names better. Pointed out by: jrtc27 --- README.md | 2 +- pycheribuild/projects/run_qemu.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index eb203c921..ce2a38f98 100644 --- a/README.md +++ b/README.md @@ -185,8 +185,8 @@ For the `cheribsd`, `disk-image` and `run` targets the hybrid vs purecap distinc - `freebsd-` builds and installs [freebsd/freebsd](https://github.com/freebsd/freebsd). - `disk-image-freebsd-` creates a FreeBSD disk-image. - `run-freebsd-` launches QEMU with the FreeBSD disk image. -- `run-shell-` launches a shell with the QEMU user mode in a CheriBSD sysroot. - `run-user-` launches a command with the QEMU user mode in a CheriBSD sysroot. +- `run-user-shell-` launches a shell with the QEMU user mode in a CheriBSD sysroot. - `cmake` builds and installs latest [CMake](https://github.com/Kitware/CMake) - `cherios` builds and installs [CTSRD-CHERI/cherios](https://github.com/CTSRD-CHERI/cherios) - `cheritrace` builds and installs [CTSRD-CHERI/cheritrace](https://github.com/CTSRD-CHERI/cheritrace) diff --git a/pycheribuild/projects/run_qemu.py b/pycheribuild/projects/run_qemu.py index 069289f7d..d94cc38a7 100644 --- a/pycheribuild/projects/run_qemu.py +++ b/pycheribuild/projects/run_qemu.py @@ -839,15 +839,15 @@ def dependencies(cls: "typing.Type[_RunMultiArchFreeBSDImage]", config: CheriCon return result -class LaunchCheriBSDShell(AbstractLaunchFreeBSDProgram): - target = "run-shell" +class LaunchUserShell(AbstractLaunchFreeBSDProgram): + target = "run-user-shell" def __init__(self, config): super().__init__(config) self.command = None -class LaunchCheriBSDExec(AbstractLaunchFreeBSDProgram): +class LaunchUser(AbstractLaunchFreeBSDProgram): target = "run-user" @classmethod From 553bf451cfccd5b23ed8ead686bb9faa2f466b17 Mon Sep 17 00:00:00 2001 From: Konrad Witaszczyk Date: Tue, 22 Feb 2022 14:02:41 +0000 Subject: [PATCH 13/19] Add an interpreter path option. Allow to specify an ELF interpreter path for the run-user and run-user-shell targets. The interpreter path can be different than an encoded one in an ELF binary in multi-ABI environments, e.g. a Poudriere jail. --- pycheribuild/projects/run_qemu.py | 6 +++++- pycheribuild/qemu_utils.py | 5 ++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/pycheribuild/projects/run_qemu.py b/pycheribuild/projects/run_qemu.py index d94cc38a7..808a997e1 100644 --- a/pycheribuild/projects/run_qemu.py +++ b/pycheribuild/projects/run_qemu.py @@ -606,6 +606,7 @@ def setup(self): def process(self): assert self.qemu_binary is not None assert self.rootfs_path is not None + assert self.interpreter_path is not None if self.chroot and self.jail: self.fatal("Chroot and jail options are mutually exclusive.") @@ -632,7 +633,8 @@ def process(self): user_command = ["sh"] command.extend(self.qemu_options.get_user_commandline(qemu_command=qemu_command, - rootfs_path=rootfs_path, user_command=user_command)) + rootfs_path=rootfs_path, interpreter_path=self.interpreter_path, + user_command=user_command)) self.info("About to run '{}' with the QEMU user mode".format(" ".join(user_command))) @@ -827,6 +829,8 @@ def setup_config_options(cls, **kwargs): super().setup_config_options(**kwargs) cls.chroot = cls.add_bool_option("chroot", default=False, show_help=True, help="Change the root directory to a sysroot before executing a command.") + cls.interpreter_path = cls.add_path_option("interpreter", metavar="PATH", default="/libexec/ld-elf.so.1", + show_help=True, help="ELF interpreter path relative to a sysroot") cls.jail = cls.add_bool_option("jail", default=False, show_help=True, help="Enter a jail with a sysroot before executing a command.") cls.jail_extra_args = cls.add_config_option("jail-extra-args", metavar="ARGS", kind=list, show_help=True, diff --git a/pycheribuild/qemu_utils.py b/pycheribuild/qemu_utils.py index 7c5bf5b1e..560451d8f 100644 --- a/pycheribuild/qemu_utils.py +++ b/pycheribuild/qemu_utils.py @@ -192,10 +192,13 @@ def get_system_commandline(self, *, qemu_command=None, kernel_file: "Optional[Pa result.extend(["-device", "virtio-rng-pci"]) return result - def get_user_commandline(self, *, qemu_command=None, rootfs_path: Path = None, user_command: Path = None): + def get_user_commandline(self, *, qemu_command=None, rootfs_path: Path = None, + interpreter_path: Path = None, user_command: Path = None): result = self.get_common_commandline(qemu_command=qemu_command) if rootfs_path: result.extend(["-L", rootfs_path]) + if interpreter_path: + result.extend(["-interpreter", interpreter_path]) if user_command: result.extend(user_command) return result From c6d823e206e39d59a815bf43e79883a745db3673 Mon Sep 17 00:00:00 2001 From: Konrad Witaszczyk Date: Tue, 22 Feb 2022 14:04:30 +0000 Subject: [PATCH 14/19] Map a guest address space at 0x100000000. Map the guest address space not to overlap with a host address space. --- pycheribuild/qemu_utils.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pycheribuild/qemu_utils.py b/pycheribuild/qemu_utils.py index 560451d8f..5d79beebd 100644 --- a/pycheribuild/qemu_utils.py +++ b/pycheribuild/qemu_utils.py @@ -199,6 +199,9 @@ def get_user_commandline(self, *, qemu_command=None, rootfs_path: Path = None, result.extend(["-L", rootfs_path]) if interpreter_path: result.extend(["-interpreter", interpreter_path]) + # Map a guest address space at 0x100000000 not to overlap with a host + # address space. + result.extend(["-B", "4294967296"]) if user_command: result.extend(user_command) return result From cd8b16e3563a9c246bfc9bf202445b1cff1e24b0 Mon Sep 17 00:00:00 2001 From: Konrad Witaszczyk Date: Tue, 22 Feb 2022 14:06:01 +0000 Subject: [PATCH 15/19] Remove an unused argument. Pointed out by: jrtc27 --- pycheribuild/projects/run_qemu.py | 2 +- pycheribuild/qemu_utils.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pycheribuild/projects/run_qemu.py b/pycheribuild/projects/run_qemu.py index 808a997e1..c446b9314 100644 --- a/pycheribuild/projects/run_qemu.py +++ b/pycheribuild/projects/run_qemu.py @@ -591,7 +591,7 @@ def setup_config_options(cls, default_ssh_port: int = None, **kwargs): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.qemu_binary = None # type: typing.Optional[Path] - self.qemu_options = QemuOptions(self.crosscompile_target, is_system_mode=False) + self.qemu_options = QemuOptions(self.crosscompile_target) self.rootfs_path = None # type:typing.Optional[Path] def setup(self): diff --git a/pycheribuild/qemu_utils.py b/pycheribuild/qemu_utils.py index 5d79beebd..0af1110ef 100644 --- a/pycheribuild/qemu_utils.py +++ b/pycheribuild/qemu_utils.py @@ -39,7 +39,7 @@ class QemuOptions: - def __init__(self, xtarget: CrossCompileTarget, want_debugger=False, is_system_mode=True) -> None: + def __init__(self, xtarget: CrossCompileTarget, want_debugger=False) -> None: self.xtarget = xtarget self.virtio_disk = True self.force_virtio_blk_device = False From 74274780b1dd71ecd7493d5bf89bac1b19b3d537 Mon Sep 17 00:00:00 2001 From: Konrad Witaszczyk Date: Tue, 22 Feb 2022 15:18:50 +0000 Subject: [PATCH 16/19] Remove AbstractLaunchFreeBSDProgram. AbstractLaunchFreeBSDProgram was the only child class of the LaunchBsdUserQEMUBase class. Instead of introducing another abstraction, move AbstractLaunchFreeBSDProgram login into LaunchBsdUserQEMUBase. Pointed out by: jrtc27 --- pycheribuild/projects/run_qemu.py | 56 ++++++++++++------------------- 1 file changed, 22 insertions(+), 34 deletions(-) diff --git a/pycheribuild/projects/run_qemu.py b/pycheribuild/projects/run_qemu.py index c446b9314..20c18725d 100644 --- a/pycheribuild/projects/run_qemu.py +++ b/pycheribuild/projects/run_qemu.py @@ -583,16 +583,34 @@ def is_port_available(port: int): class LaunchBsdUserQEMUBase(SimpleProject): do_not_add_to_targets = True + _source_class = BuildCHERIBSD + _freebsd_class = BuildCHERIBSD + _always_add_suffixed_targets = True + supported_architectures = [CompilationTargets.CHERIBSD_RISCV_PURECAP] @classmethod - def setup_config_options(cls, default_ssh_port: int = None, **kwargs): + def setup_config_options(cls, **kwargs): super().setup_config_options(**kwargs) + cls.chroot = cls.add_bool_option("chroot", default=False, show_help=True, + help="Change the root directory to a sysroot before executing a command.") + cls.interpreter_path = cls.add_path_option("interpreter", metavar="PATH", default="/libexec/ld-elf.so.1", + show_help=True, help="ELF interpreter path relative to a sysroot") + cls.jail = cls.add_bool_option("jail", default=False, show_help=True, + help="Enter a jail with a sysroot before executing a command.") + cls.jail_extra_args = cls.add_config_option("jail-extra-args", metavar="ARGS", kind=list, show_help=True, + help="Extra jail parameters to pass to jail(8).") + + @classmethod + def dependencies(cls: "typing.Type[_RunMultiArchFreeBSDImage]", config: CheriConfig) -> "list[str]": + xtarget = cls.get_crosscompile_target() + result = ["bsd-user-qemu", cls._source_class.get_class_for_target(xtarget).target] + return result def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.qemu_binary = None # type: typing.Optional[Path] self.qemu_options = QemuOptions(self.crosscompile_target) - self.rootfs_path = None # type:typing.Optional[Path] + self.rootfs_path = self._source_class.get_rootfs_dir(self) def setup(self): super().setup() @@ -813,37 +831,7 @@ def dependencies(cls, config: CheriConfig) -> "list[str]": return result -class AbstractLaunchFreeBSDProgram(LaunchBsdUserQEMUBase): - do_not_add_to_targets = True - _source_class = BuildCHERIBSD - _freebsd_class = BuildCHERIBSD - _always_add_suffixed_targets = True - supported_architectures = [CompilationTargets.CHERIBSD_RISCV_PURECAP] - - def __init__(self, config): - super().__init__(config) - self.rootfs_path = self._source_class.get_rootfs_dir(self, config=config) - - @classmethod - def setup_config_options(cls, **kwargs): - super().setup_config_options(**kwargs) - cls.chroot = cls.add_bool_option("chroot", default=False, show_help=True, - help="Change the root directory to a sysroot before executing a command.") - cls.interpreter_path = cls.add_path_option("interpreter", metavar="PATH", default="/libexec/ld-elf.so.1", - show_help=True, help="ELF interpreter path relative to a sysroot") - cls.jail = cls.add_bool_option("jail", default=False, show_help=True, - help="Enter a jail with a sysroot before executing a command.") - cls.jail_extra_args = cls.add_config_option("jail-extra-args", metavar="ARGS", kind=list, show_help=True, - help="Extra jail parameters to pass to jail(8).") - - @classmethod - def dependencies(cls: "typing.Type[_RunMultiArchFreeBSDImage]", config: CheriConfig) -> "list[str]": - xtarget = cls.get_crosscompile_target(config) - result = ["bsd-user-qemu", cls._source_class.get_class_for_target(xtarget).target] - return result - - -class LaunchUserShell(AbstractLaunchFreeBSDProgram): +class LaunchUserShell(LaunchBsdUserQEMUBase): target = "run-user-shell" def __init__(self, config): @@ -851,7 +839,7 @@ def __init__(self, config): self.command = None -class LaunchUser(AbstractLaunchFreeBSDProgram): +class LaunchUser(LaunchBsdUserQEMUBase): target = "run-user" @classmethod From 48dc5288c6ef3365d27acb3344cd012258576480 Mon Sep 17 00:00:00 2001 From: Konrad Witaszczyk Date: Tue, 22 Feb 2022 16:31:38 +0000 Subject: [PATCH 17/19] Set a default value for --run-user/command. Set the default value of a command to execute with the user mode to /bin/sh within a rootfs. --- pycheribuild/projects/run_qemu.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pycheribuild/projects/run_qemu.py b/pycheribuild/projects/run_qemu.py index 20c18725d..57e140d12 100644 --- a/pycheribuild/projects/run_qemu.py +++ b/pycheribuild/projects/run_qemu.py @@ -846,7 +846,8 @@ class LaunchUser(LaunchBsdUserQEMUBase): def setup_config_options(cls, **kwargs): super().setup_config_options(**kwargs) cls.command = cls.add_config_option("command", metavar="COMMAND", show_help=True, kind=list, - help="Command to execute.") + help="Command to execute (default: '/bin/sh').", + default=lambda _, p: str(p.rootfs_path) + "/bin/sh") class LaunchCheriOSQEMU(LaunchQEMUBase): From d4c322e6ec3064dd10ec6f53db8538351b813970 Mon Sep 17 00:00:00 2001 From: Konrad Witaszczyk Date: Tue, 22 Feb 2022 16:33:08 +0000 Subject: [PATCH 18/19] Compute a command within a target context. The command should be computed depending on a target context. In case of run-user-shell, we'd like to append a rootfs path if the shell is not executed with chroot nor jail. Pointed out by: jrtc27 --- pycheribuild/projects/run_qemu.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/pycheribuild/projects/run_qemu.py b/pycheribuild/projects/run_qemu.py index 57e140d12..400a65277 100644 --- a/pycheribuild/projects/run_qemu.py +++ b/pycheribuild/projects/run_qemu.py @@ -625,6 +625,7 @@ def process(self): assert self.qemu_binary is not None assert self.rootfs_path is not None assert self.interpreter_path is not None + assert self.command is not None if self.chroot and self.jail: self.fatal("Chroot and jail options are mutually exclusive.") @@ -643,18 +644,11 @@ def process(self): qemu_command = self.qemu_binary rootfs_path = self.rootfs_path - if self.command: - user_command = self.command - elif rootfs_path: - user_command = ["{}{}".format(rootfs_path, "/bin/sh")] - else: - user_command = ["sh"] - command.extend(self.qemu_options.get_user_commandline(qemu_command=qemu_command, rootfs_path=rootfs_path, interpreter_path=self.interpreter_path, - user_command=user_command)) + user_command=self.command)) - self.info("About to run '{}' with the QEMU user mode".format(" ".join(user_command))) + self.info("About to run '{}' with the QEMU user mode".format(" ".join(self.command))) self.run_cmd(command, stdout=sys.stdout, stderr=sys.stderr, give_tty_control=True) @@ -834,9 +828,15 @@ def dependencies(cls, config: CheriConfig) -> "list[str]": class LaunchUserShell(LaunchBsdUserQEMUBase): target = "run-user-shell" - def __init__(self, config): - super().__init__(config) - self.command = None + def process(self): + assert self.rootfs_path is not None + + command = "/bin/sh" + if self.chroot or self.jail: + self.command = [command] + else: + self.command = [str(self.rootfs_path) + command] + super().process() class LaunchUser(LaunchBsdUserQEMUBase): From 1590f857cad44f38eb6cd3bfef74282e69ff1392 Mon Sep 17 00:00:00 2001 From: Konrad Witaszczyk Date: Tue, 22 Feb 2022 16:57:22 +0000 Subject: [PATCH 19/19] Remove BuildSystemQEMU. Reduce a number of additional abstractions required for the user mode support that should be eventually removed once the user mode is merged into the qemu-cheri branch. This change uses a hack to always pass --disabled-bsd-user to configure and later pass --enable-bsd-user to overwrite it. Pointed out by: jrtc27 --- pycheribuild/projects/build_qemu.py | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/pycheribuild/projects/build_qemu.py b/pycheribuild/projects/build_qemu.py index 404dd56bf..234a167a1 100644 --- a/pycheribuild/projects/build_qemu.py +++ b/pycheribuild/projects/build_qemu.py @@ -223,6 +223,7 @@ def setup(self): self.configure_args.extend([ "--target-list=" + self.qemu_targets, "--disable-linux-user", + "--disable-bsd-user", "--disable-xen", "--disable-docs", "--disable-rdma", @@ -277,17 +278,8 @@ def process(self) -> None: super().process() -class BuildSystemQEMU(BuildQEMUBase): - do_not_add_to_targets = True - - def setup(self): - super().setup() - # Don't build BSD user mode targets as we only want system mode binaries. - self.configure_args.append("--disable-bsd-user") - - # noinspection PyAbstractClass -class BuildUpstreamQEMU(BuildSystemQEMU): +class BuildUpstreamQEMU(BuildQEMUBase): repository = GitRepository("https://github.com/qemu/qemu.git") target = "upstream-qemu" _default_install_dir_fn = ComputedDefaultValue( @@ -317,7 +309,7 @@ def qemu_binary_for_target(cls, xtarget: CrossCompileTarget, config: CheriConfig return config.output_root / "upstream-qemu/bin" / binary_name -class BuildQEMU(BuildSystemQEMU): +class BuildQEMU(BuildQEMUBase): target = "qemu" repository = GitRepository("https://github.com/CTSRD-CHERI/qemu.git", default_branch="qemu-cheri") default_targets = "aarch64-softmmu,morello-softmmu," \