diff --git a/pycheribuild/config/chericonfig.py b/pycheribuild/config/chericonfig.py index a49e991f9..1248ca8a8 100644 --- a/pycheribuild/config/chericonfig.py +++ b/pycheribuild/config/chericonfig.py @@ -328,6 +328,14 @@ def __init__(self, loader, action_class: "type[CheribuildActionEnum]") -> None: group=loader.cross_compile_options_group, help="The floating point/SIMD mode to use for building AArch64 programs", ) + + self.riscv_baremetal_hardfloat = loader.add_bool_option("riscv-baremetal-hardfloat", default=False, + group=loader.cross_compile_options_group, + help="Use hard floating point ABI for building CHERI-RISC-V programs") + self.riscv_cheri_gprel = loader.add_bool_option("riscv-cheri-gprel", default=False, + group=loader.cross_compile_options_group, + help="Build CHERI-RISC-V libs with gprel ABI for CheriFreeRTOS compartmentalization") + self.crosscompile_linkage = loader.add_option( "cross-compile-linkage", default=Linkage.DEFAULT, diff --git a/pycheribuild/config/compilation_targets.py b/pycheribuild/config/compilation_targets.py index cedd2d732..b623f4e1f 100644 --- a/pycheribuild/config/compilation_targets.py +++ b/pycheribuild/config/compilation_targets.py @@ -277,9 +277,16 @@ def essential_compiler_and_linker_flags_impl( result.append("-mabi=" + cls.get_riscv_abi(xtarget, softfloat=softfloat)) result.append("-mrelax" if _linker_supports_riscv_relaxations(instance.linker, config) else "-mno-relax") + softfloat = not config.riscv_baremetal_hardfloat + if cls.is_baremetal() or cls.is_rtems(): # Both RTEMS and baremetal FreeRTOS are linked above 0x80000000 - result.append("-mcmodel=medany") + result.append("-mcmodel=medium") + + if config.riscv_cheri_gprel: + if xtarget.is_cheri_purecap(): + result.append("-cheri-cap-table-abi=gprel") + elif xtarget.is_aarch64(include_purecap=True): fp_simd_option = AArch64FloatSimdOptions.SOFT if softfloat else config.aarch64_fp_and_simd_options march_suffix = fp_simd_option.clang_march_flag() diff --git a/pycheribuild/projects/cross/compiler_rt.py b/pycheribuild/projects/cross/compiler_rt.py index 69de3d590..e0eb027d8 100644 --- a/pycheribuild/projects/cross/compiler_rt.py +++ b/pycheribuild/projects/cross/compiler_rt.py @@ -184,10 +184,14 @@ def install(self, **kwargs): if self.target_info.is_rtems(): self.move_file(self.install_dir / "lib/rtems5" / libname, self.install_dir / "lib" / libname) elif self.target_info.is_baremetal(): - self.move_file(self.install_dir / "lib/baremetal" / libname, self.real_install_root_dir / "lib" / libname) - self.create_symlink( - self.install_dir / "lib" / libname, self.install_dir / "lib/libgcc.a", print_verbose_only=False - ) + if self.config.riscv_cheri_gprel: + gprel_libname = "libclang_rt.builtins-" + self.triple_arch + "-gprel.a" + self.move_file(self.install_dir / "lib/baremetal" / libname, self.real_install_root_dir / "lib" / gprel_libname) + else: + self.move_file(self.install_dir / "lib/baremetal" / libname, self.real_install_root_dir / "lib" / libname) + self.create_symlink( + self.install_dir / "lib" / libname, self.install_dir / "lib/libgcc.a", print_verbose_only=False + ) class BuildUpstreamCompilerRtBuiltins(BuildCompilerRtBuiltins): diff --git a/pycheribuild/projects/cross/freertos.py b/pycheribuild/projects/cross/freertos.py index 7c88d115d..f2bcf0a28 100644 --- a/pycheribuild/projects/cross/freertos.py +++ b/pycheribuild/projects/cross/freertos.py @@ -36,21 +36,20 @@ from .compiler_rt import BuildCompilerRtBuiltins from .crosscompileproject import CompilationTargets, CrossCompileAutotoolsProject, DefaultInstallDir, GitRepository from ..project import ComputedDefaultValue -from ..run_qemu import LaunchQEMUBase class BuildFreeRTOS(CrossCompileAutotoolsProject): - repository = GitRepository( - "https://github.com/CTSRD-CHERI/FreeRTOS-mirror", force_branch=True, default_branch="cheri" - ) + repository = GitRepository("https://github.com/CTSRD-CHERI/FreeRTOS", + force_branch=True, default_branch="hmka2") target = "freertos" dependencies = ("newlib", "compiler-rt-builtins") is_sdk_target = True needs_sysroot = False # We don't need a complete sysroot supported_architectures = ( CompilationTargets.BAREMETAL_NEWLIB_RISCV64_PURECAP, - CompilationTargets.BAREMETAL_NEWLIB_RISCV64, - ) + CompilationTargets.BAREMETAL_NEWLIB_RISCV32, + CompilationTargets.BAREMETAL_NEWLIB_RISCV32_PURECAP, + CompilationTargets.BAREMETAL_NEWLIB_RISCV64) default_install_dir = DefaultInstallDir.ROOTFS_LOCALBASE # FreeRTOS Demos to build @@ -61,56 +60,78 @@ class BuildFreeRTOS(CrossCompileAutotoolsProject): ] # Map Demos and the FreeRTOS apps we support building/running for - supported_demo_apps = {"RISC-V-Generic": ["main_blinky"]} + supported_demo_apps = {"RISC-V-Generic": [ + "aws_ota", + "coremark", + "main_blinky", + "main_peekpoke", + "main_servers", + "mibench", + "modbus", + ]} default_demo = "RISC-V-Generic" default_demo_app = "main_blinky" - demo: "ClassVar[str]" - demo_app: "ClassVar[str]" - demo_bsp: "ClassVar[str]" + default_build_system = "waf" + + def _run_waf(self, *args, **kwargs): + cmdline = ["./waf", "-t", self.source_dir / str("FreeRTOS/Demo/" + self.demo), "-o", self.build_dir] + list(args) + if self.config.verbose: + cmdline.append("-v") + return self.run_cmd(cmdline, cwd=self.source_dir / str("FreeRTOS/Demo/" + self.demo), **kwargs) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) + self.compiler_resource = self.get_compiler_info(self.CC).get_resource_dir() + self.xlen = 64 + self.default_demo_app = ( "qemu_virt-" + self.target_info.get_riscv_arch_string(self.crosscompile_target, softfloat=True) + self.target_info.get_riscv_abi(self.crosscompile_target, softfloat=True) ) - def setup(self): - super().setup() - # We only support building FreeRTOS with llvm from cheribuild - self.make_args.set(TOOLCHAIN="llvm") + if "rv32" in self.target_info.get_riscv_arch_string(self.crosscompile_target, softfloat=True): + self.xlen = 32 + + # Galois uses make build sysetm + if self.demo == "RISC-V_Galois_demo": - # For backward compatibility. CheriFreeRTOS used to be built within a NIX env. - # Override that with no and set the appopriate flags here. - self.make_args.set(NIX_ENV="no") + if self.toolchain == "llvm": + self.make_args.set(USE_CLANG="yes") - # Only build 64-bit FreeRTOS as cheribuild currently only supports building - # for RV64 - self.make_args.set(RISCV_XLEN="64") + # Galois demo only runs on VCU118/GFE + self.make_args.set(BSP="vcu118") - # Set sysroot Makefile arg to pick up libc - self.make_args.set(SYSROOT=str(self.sdk_sysroot)) + if "rv32" in self.target_info.get_riscv_arch_string(self.crosscompile_target, softfloat=True): + self.make_args.set(XLEN="32") + else: + self.make_args.set(XLEN="64") - if self.target_info.target.is_cheri_purecap(): - # CHERI-RISC-V sophisticated Demo with more advanced device drivers - # and currently only runs on FPGA-GFE, purecap - self.supported_freertos_demos.append("RISC-V_Galois_P1") - self.supported_demo_apps["RISC-V_Galois_P1"] = ["main_blinky", "main_netboot"] + # Set sysroot Makefile arg to pick up libc + self.make_args.set(SYSROOT_DIR=str(self.sdk_sysroot)) - self.make_args.set(EXTENSION="cheri") + if self.target_info.target.is_cheri_purecap(): + self.make_args.set(CHERI="1") @classmethod def setup_config_options(cls, **kwargs): super().setup_config_options(**kwargs) - cls.demo: str = typing.cast( - str, - cls.add_config_option( - "demo", metavar="DEMO", show_help=True, default=cls.default_demo, help="The FreeRTOS Demo build." - ), - ) + cls.build_system = cls.add_config_option( + "build_system", metavar="BUILD", show_help=True, + default=cls.default_build_system, + help="The FreeRTOS Demo Build System.") # type: str + + cls.toolchain = cls.add_config_option( + "toolchain", metavar="TOOLCHAIN", show_help=True, + default="llvm", + help="The toolchain to build FreeRTOS with.") # type: str + + cls.demo = cls.add_config_option( + "demo", metavar="DEMO", show_help=True, + default=cls.default_demo, + help="The FreeRTOS Demo build.") # type: str cls.demo_app: str = typing.cast( str, @@ -123,21 +144,80 @@ def setup_config_options(cls, **kwargs): ), ) - cls.demo_bsp: str = typing.cast( - str, - cls.add_config_option( - "bsp", - metavar="BSP", - show_help=True, - default=ComputedDefaultValue( - function=lambda _, p: p.default_demo_bsp(), as_string="target-dependent default" - ), - help="The FreeRTOS BSP to build. This is only valid for the " - "paramterized RISC-V-Generic. The BSP option chooses " - "platform, RISC-V arch and RISC-V abi in the " - "$platform-$arch-$abi format. See RISC-V-Generic/README for more details", - ), - ) + cls.platform = cls.add_config_option( + "platform", metavar="PLATFORM", show_help=True, + default="qemu_virt", + help="The FreeRTOS platform to build for.") # type: str + + cls.mem_start = cls.add_config_option( + "memstart", metavar="MEMSTART", show_help=True, + default=0x80000000, + help="The DRAM start address") + + # Default to QEMU addresses + cls.ipaddr = cls.add_config_option( + "ipaddr", metavar="IPADDR", show_help=True, + default="10.0.2.15/24", + help="The static IP to assign to FreeRTOS.") # type: str + + cls.gateway = cls.add_config_option( + "gateway", metavar="GATEWAY", show_help=True, + default="10.0.2.2", + help="The static gateway IP for FreeRTOS.") # type: str + + cls.compartmentalize= cls.add_bool_option("compartmentalize", show_help=True, + default=False, + help="Compartmentalize FreeRTOS") + + cls.compartmentalize_stdlibs = cls.add_bool_option("compartmentalize_stdlibs", show_help=True, + default=False, + help="Compartmentalize libc, libm and builtins") + + cls.plot_compartments = cls.add_bool_option("plot_compartments", show_help=True, + default=False, + help="Plot compartments deps graph using graphviz") + + cls.loc_stats = cls.add_bool_option("loc_stats", show_help=True, + default=False, + help="Calculate detailed LoC stats for the built system") + + cls.compartmentalization_mode = cls.add_config_option("compartmentalization_mode", show_help=True, + default="objs", + help="'Comparmentalization mode (either objs or libs)") + + cls.use_virtio_blk = cls.add_bool_option("use_virtio_blk", show_help=True, + default=False, + help="Use VirtIO Block as a disk for FreeRTOS") + + cls.create_disk_image = cls.add_bool_option("create_disk_image", show_help=True, + default=False, + help="Create, parition, format and write data into an external blk disk image") + + cls.debug = cls.add_bool_option("debug", show_help=True, + default=False, + help="Enable FreeRTOS debug featuers") + + cls.enable_mpu = cls.add_bool_option("enable_mpu", show_help=True, + default=False, + help="Enable FreeRTOS-MPU") + + cls.log_udp = cls.add_bool_option("log_udp", show_help=True, + default=False, + help="Send output over UDP instead of stdout/serial") + + cls.demo_bsp = cls.add_config_option( + "bsp", metavar="BSP", show_help=True, + default=ComputedDefaultValue(function=lambda _, p: p.default_demo_bsp(), + as_string="target-dependent default"), + help="The FreeRTOS BSP to build. This is only valid for the " + "paramterized RISC-V-Generic. The BSP option chooses " + "platform, RISC-V arch and RISC-V abi in the " + "$platform-$arch-$abi format. See RISC-V-Generic/README for more details") + + cls.implicit_mem_0 = cls.add_bool_option( + "implicit_mem_0", show_help=True, default=False, + help="Set if running on a simulation platform which initializes memory to zero. " + "This allows the boot phase to skip zero-initialization steps.") def default_demo_bsp(self): return ( @@ -147,113 +227,116 @@ def default_demo_bsp(self): + self.target_info.get_riscv_abi(self.crosscompile_target, softfloat=True) ) + def run_compartmentalize(self, *args, **kwargs): + cmdline = ["./compartmentalize.py"] + return self.run_cmd(cmdline, cwd=self.source_dir / str("FreeRTOS/Demo/" + self.demo), **kwargs) + def compile(self, **kwargs): - self.make_args.set(BSP=self.demo_bsp) - - # Need to clean before/between building apps, otherwise - # irrelevant objs will be picked up from incompatible apps/builds - self.make_args.set(PROG=self.demo_app) - self.run_make("clean", cwd=self.source_dir / str("FreeRTOS/Demo/" + self.demo)) - self.run_make(cwd=self.source_dir / str("FreeRTOS/Demo/" + self.demo)) - self.move_file( - self.source_dir / str("FreeRTOS/Demo/" + self.demo + "/" + self.demo_app + ".elf"), - self.source_dir / str("FreeRTOS/Demo/" + self.demo + "/" + self.demo + self.demo_app + ".elf"), - ) - def configure(self): - pass + if self.build_system == "waf": + self._run_waf("install", self.config.make_j_flag) + return + + # Galois only currently has make build system + if self.demo == "RISC-V_Galois_demo": + # Need to clean before/between building apps, otherwise + # irrelevant objs will be picked up from incompatible apps/builds + self.make_args.set(PROG=self.demo_app) + self.make_args.set(DEMO="cyberphys") + self.run_make("clean", cwd=self.source_dir / str("FreeRTOS/Demo/" + self.demo)) - def needs_configure(self): - return False + self.run_make(cwd=self.source_dir / str("FreeRTOS/Demo/" + self.demo)) + self.move_file(self.source_dir / str("FreeRTOS/Demo/" + self.demo + "/" + self.demo_app + ".elf"), + self.source_dir / str("FreeRTOS/Demo/" + self.demo + "/" + self.demo + self.demo_app + ".elf")) + + def configure(self): + if self.build_system == "waf": + + if "servers" in self.demo_app: + program_root = "./demo/servers" + elif "aws_ota" in self.demo_app: + program_root = "coreMQTT-Agent" + elif "coremark" in self.demo_app: + program_root = "coremark" + elif "mibench" in self.demo_app: + program_root = "MiBench2" + elif "ipc_benchmark" in self.demo_app: + program_root = "./demo/ipc_benchmark" + elif "cyberphys" in self.demo_app: + program_root = "./demo/cyberphys" + elif "modbus" in self.demo_app: + program_root = "./modcap" + else: + program_root = "/no/path" + + config_options = [ + "--prefix", str(self.real_install_root_dir) + '/FreeRTOS/Demo/', + "--program", self.demo_app, + "--toolchain", self.toolchain, + "--riscv-arch", self.target_info.get_riscv_arch_string(self.crosscompile_target, softfloat=True), + "--riscv-abi", self.target_info.get_riscv_abi(self.crosscompile_target, softfloat=True), + "--riscv-platform", self.platform, + "--program-path", program_root, + "--sysroot", str(self.sdk_sysroot) + "/riscv" + str(self.xlen) + "-unknown-elf", + "--mem-start", self.mem_start, + "--ipaddr", self.ipaddr, + "--gateway", self.gateway + ] + + config_options += ["--purecap"] if self.target_info.target.is_cheri_purecap() else [] + + if self.compartmentalize: + config_options += ["--compartmentalize"] + config_options += ["--compartmentalization_mode", self.compartmentalization_mode] + if self.compartmentalize_stdlibs: + config_options += ["--compartmentalize_stdlibs"] + if self.plot_compartments: + config_options += ["--plot_compartments"] + + if self.loc_stats: + config_options += ["--loc_stats"] + + if self.use_virtio_blk: + config_options += ["--use-virtio-blk"] + + if self.create_disk_image: + config_options += ["--create-disk-image"] + + if self.debug: + config_options += ["--debug"] + + if self.enable_mpu: + config_options += ["--enable_mpu"] + + if self.log_udp: + config_options += ["--log_udp"] + + if self.implicit_mem_0: + config_options += ["--implicit-mem-0"] + + self._run_waf("distclean", "configure", *config_options) def install(self, **kwargs): + if self.build_system == "waf": + return + self.install_file( self.source_dir / str("FreeRTOS/Demo/" + self.demo + "/" + self.demo + self.demo_app + ".elf"), - self.real_install_root_dir / str("FreeRTOS/Demo/" + self.demo + "_" + self.demo_app + ".elf"), - ) + self.real_install_root_dir / str("FreeRTOS/Demo/bin/" + self.demo + "_" + self.demo_app + ".elf")) def process(self): - if self.demo not in self.supported_freertos_demos: - self.fatal("Demo " + self.demo + "is not supported") - - if self.demo_app not in self.supported_demo_apps[self.demo]: - self.fatal(self.demo + " Demo doesn't support/have " + self.demo_app) - - with self.set_env( - PATH=str(self.sdk_bindir) + ":" + os.getenv("PATH", ""), - # Add compiler-rt location to the search path - LDFLAGS="-L" + str(BuildCompilerRtBuiltins.get_install_dir(self) / "lib"), - ): - super().process() - - -class LaunchFreeRTOSQEMU(LaunchQEMUBase): - target = "run-freertos" - dependencies = ("freertos",) - supported_architectures = ( - CompilationTargets.BAREMETAL_NEWLIB_RISCV64_PURECAP, - CompilationTargets.BAREMETAL_NEWLIB_RISCV64, - ) - forward_ssh_port = False - qemu_user_networking = False - _enable_smbfs_support = False - _add_virtio_rng = False - _uses_disk_image = False - default_demo = "RISC-V-Generic" - default_demo_app = "main_blinky" + #if self.demo not in self.supported_freertos_demos: + # self.fatal("Demo " + self.demo + "is not supported") - def setup(self): - super().setup() - self.kernel_project = BuildFreeRTOS.get_instance(self) - self.current_kernel = self.kernel_project.install_dir / f"FreeRTOS/Demo/{self.demo}_{self.demo_app}.elf" + #if self.demo_app not in self.supported_demo_apps[self.demo]: + # self.fatal(self.demo + " Demo doesn't support/have " + self.demo_app) - @classmethod - def setup_config_options(cls, **kwargs): - super().setup_config_options(defaultSshPort=None, **kwargs) - - cls.demo: str = typing.cast( - str, - cls.add_config_option( - "demo", metavar="DEMO", show_help=True, default=cls.default_demo, help="The FreeRTOS Demo to run." - ), - ) - - cls.demo_app: str = typing.cast( - str, - cls.add_config_option( - "prog", - metavar="PROG", - show_help=True, - default=cls.default_demo_app, - help="The FreeRTOS program to run.", - ), - ) - - cls.demo_bsp = typing.cast( - str, - cls.add_config_option( - "bsp", - metavar="BSP", - show_help=True, - default=ComputedDefaultValue( - function=lambda _, p: p.default_demo_bsp(), as_string="target-dependent default" - ), - help="The FreeRTOS BSP to run. This is only valid for the " - "paramterized RISC-V-Generic. The BSP option chooses " - "platform, RISC-V arch and RISC-V abi in the " - "$platform-$arch-$abi format. See RISC-V-Generic/README for more details", - ), - ) - - 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_abi(self.crosscompile_target, softfloat=True) - ) - - def get_riscv_bios_args(self) -> "list[str]": - # Use -bios none to ensure the FreeRTOS demo application runs in machine mode. - return ["-bios", "none"] + if self.toolchain == "llvm": + with self.set_env(PATH=str(self.sdk_bindir) + ":" + os.getenv("PATH", ""), + # Add compiler-rt location to the search path + CFLAGS= ' '.join(self.target_info.get_essential_compiler_and_linker_flags()), + LDFLAGS="-L" + str(self.compiler_resource / "lib")): + super().process() + else: + super().process() diff --git a/pycheribuild/projects/cross/newlib.py b/pycheribuild/projects/cross/newlib.py index 6ba402d25..a5c9292b9 100644 --- a/pycheribuild/projects/cross/newlib.py +++ b/pycheribuild/projects/cross/newlib.py @@ -180,9 +180,16 @@ def install(self, **kwargs): if self.compiling_for_cheri(): # create some symlinks to make the current CMakeProject infrastructure happy root_dir = self.install_dir / self.target_info.target_triple - self.makedirs(root_dir / "usr") - self.create_symlink(root_dir / "lib", root_dir / "usr/libcheri") - self.create_symlink(root_dir / "lib", root_dir / "libcheri") + + if self.target_info.is_baremetal(): + if self.config.riscv_cheri_gprel: + self.move_file(root_dir / "lib/libc.a", root_dir / "lib/libc-gprel.a") + self.move_file(root_dir / "lib/libm.a", root_dir / "lib/libm-gprel.a") + self.move_file(root_dir / "lib/libg.a", root_dir / "lib/libg-gprel.a") + else: + self.makedirs(root_dir / "usr") + self.create_symlink(root_dir / "lib", root_dir / "usr/libcheri") + self.create_symlink(root_dir / "lib", root_dir / "libcheri") def run_tests(self): with tempfile.TemporaryDirectory(prefix="cheribuild-" + self.target + "-") as td: diff --git a/pycheribuild/projects/run_qemu.py b/pycheribuild/projects/run_qemu.py index 41062a8c3..2d4944e54 100644 --- a/pycheribuild/projects/run_qemu.py +++ b/pycheribuild/projects/run_qemu.py @@ -39,6 +39,7 @@ from .build_qemu import BuildQEMU, BuildQEMUBase, BuildUpstreamQEMU from .cross.cheribsd import BuildCHERIBSD, BuildCheriBsdMfsKernel, BuildFreeBSD, ConfigPlatform, KernelABI +from .cross.freertos import BuildFreeRTOS from .cross.gdb import BuildGDB from .cross.u_boot import BuildUBoot from .disk_image import ( @@ -130,6 +131,13 @@ def setup(self, launch): class LaunchQEMUBase(SimpleProject): do_not_add_to_targets = True forward_ssh_port = True + forward_ftp_port = False + forward_tftp_port = False + forward_http_port = False + forward_cli_port = False + forward_can_port = False + forward_nbns_port = False + forward_print_port = False _can_provide_src_via_smb = False ssh_forwarding_port: Optional[int] = None custom_qemu_smb_mount = None @@ -528,6 +536,48 @@ def add_smb_or_9p_dir(directory, target, share_name=None, readonly=False): if self.ephemeral: self._after_disk_options += ["-snapshot"] + if self.forward_ftp_port: + user_network_options += ",hostfwd=tcp::" + str(self.ftp_forwarding_port) + "-:21" + # bind the qemu ftp port to the hosts port + print(coloured(AnsiColour.green, "\nListening for FTP connections on localhost:", self.ftp_forwarding_port, + sep="")) + + if self.forward_tftp_port: + user_network_options += ",hostfwd=udp::" + str(self.tftp_forwarding_port) + "-:69" + # bind the qemu tftp port to the hosts port + print(coloured(AnsiColour.green, "\nListening for TFTP connections on localhost:", self.tftp_forwarding_port, + sep="")) + + if self.forward_nbns_port: + user_network_options += ",hostfwd=udp::" + str(self.nbns_forwarding_port) + "-:137" + # bind the qemu nbns port to the hosts port + print(coloured(AnsiColour.green, "\nListening for NBNS connections on localhost:", self.nbns_forwarding_port, + sep="")) + + if self.forward_can_port: + user_network_options += ",hostfwd=udp::" + str(self.can_forwarding_port) + "-:5002" + # bind the qemu CAN port to the hosts port + print(coloured(AnsiColour.green, "\nListening for CAN connections on localhost:", self.can_forwarding_port, + sep="")) + + if self.forward_cli_port: + user_network_options += ",hostfwd=tcp::" + str(self.cli_forwarding_port) + "-:23" + # bind the qemu CLI port to the hosts port + print(coloured(AnsiColour.green, "\nListening for CLI connections on localhost:", self.cli_forwarding_port, + sep="")) + + if self.forward_print_port: + user_network_options += ",hostfwd=udp::" + str(self.print_forwarding_port) + "-:45000" + # bind the qemu CLI port to the hosts port + print(coloured(AnsiColour.green, "\nListening for UDP/printf connections on localhost:", self.print_forwarding_port, + sep="")) + + if self.forward_http_port: + user_network_options += ",hostfwd=tcp::" + str(self.http_forwarding_port) + "-:80" + # bind the qemu http port to the hosts port + print(coloured(AnsiColour.green, "\nListening for HTTP connections on localhost:", self.http_forwarding_port, + sep="")) + # input("Press enter to continue") qemu_command = self.qemu_options.get_commandline( qemu_command=self.chosen_qemu.binary, @@ -905,6 +955,84 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.qemu_user_networking = False + +class LaunchFreeRTOSQEMU(LaunchQEMUBase): + target = "run-freertos" + supported_architectures = ( + CompilationTargets.BAREMETAL_NEWLIB_RISCV32, + CompilationTargets.BAREMETAL_NEWLIB_RISCV64, + CompilationTargets.BAREMETAL_NEWLIB_RISCV32_PURECAP, + CompilationTargets.BAREMETAL_NEWLIB_RISCV64_PURECAP) + forward_ssh_port = False + forward_ftp_port = True + forward_tftp_port = True + forward_nbns_port = True + forward_can_port = True + forward_http_port = True + forward_cli_port = True + forward_print_port = True + + default_ssh_port = 0 + + qemu_user_networking = True + _enable_smbfs_support = False + _add_virtio_rng = False + _uses_disk_image = False + ftp_forwarding_port = 10021 + tftp_forwarding_port = 10069 + nbns_forwarding_port = 10137 + cli_forwarding_port = 10023 + can_forwarding_port = 5002 + print_forwarding_port = 45000 + http_forwarding_port = 8080 + + default_demo = "RISC-V-Generic" + default_demo_app = "main_blinky" + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + if self.use_virtio_blk: + self._after_disk_options.extend([ + "-drive", "file=" + str(BuildFreeRTOS.get_install_dir(self)) + "/FreeRTOS/Demo/bin/freertos.img,id=drv,format=raw", + "-device", "virtio-blk-device,drive=drv" + ]) + + @classmethod + def setup_config_options(cls, **kwargs): + super().setup_config_options(defaultSshPort=None, **kwargs) + + cls.demo = cls.add_config_option( + "demo", metavar="DEMO", show_help=True, + default=cls.default_demo, + help="The FreeRTOS Demo to run.") # type: str + + cls.demo_app = cls.add_config_option( + "prog", metavar="PROG", show_help=True, + default=cls.default_demo_app, + help="The FreeRTOS program to run.") # type: str + + cls.demo_bsp = cls.add_config_option( + "bsp", metavar="BSP", show_help=True, + default=ComputedDefaultValue(function=lambda _, p: p.default_demo_bsp(), + as_string="target-dependent default"), + help="The FreeRTOS BSP to run. This is only valid for the " + "paramterized RISC-V-Generic. The BSP option chooses " + "platform, RISC-V arch and RISC-V abi in the " + "$platform-$arch-$abi format. See RISC-V-Generic/README for more details") + + cls.use_virtio_blk = cls.add_bool_option("use_virtio_blk", show_help=True, + default=False, + help="Use VirtIO Block as a disk for FreeRTOS") + + 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_abi(self.crosscompile_target, softfloat=True) + + def get_riscv_bios_args(self) -> typing.List[str]: + # Run a FreeRTOS demo application (run in machine mode using the -bios QEMU argument) + return ["-bios", str(BuildFreeRTOS.get_install_dir(self)) + "/FreeRTOS/Demo/bin/" + + self.demo + "_" + self.demo_app + ".elf"] + def process(self): super().process() diff --git a/pycheribuild/qemu_utils.py b/pycheribuild/qemu_utils.py index abb42ecea..7e10b9e0c 100644 --- a/pycheribuild/qemu_utils.py +++ b/pycheribuild/qemu_utils.py @@ -176,8 +176,8 @@ def get_commandline( 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 bios_args is None and 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)]