From 298473d5b67072e53a0a7b07e9e915b597ddfa75 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Wed, 20 Mar 2024 02:42:20 +0900 Subject: [PATCH] Support Xtensa (OpenOCD Semihosting) --- .github/.cspell/project-dictionary.txt | 1 + .github/workflows/ci.yml | 12 ++++++++ Cargo.toml | 2 +- README.md | 3 +- src/experimental/env.rs | 1 + src/experimental/time.rs | 1 + src/lib.rs | 5 +++- src/sys/arm_compat/mod.rs | 1 + src/sys/arm_compat/syscall/mod.rs | 1 + src/sys/arm_compat/syscall/xtensa.rs | 39 ++++++++++++++++++++++++++ src/sys/mod.rs | 3 ++ src/sys/reg.rs | 3 ++ 12 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 src/sys/arm_compat/syscall/xtensa.rs diff --git a/.github/.cspell/project-dictionary.txt b/.github/.cspell/project-dictionary.txt index 523ddb4..ec24448 100644 --- a/.github/.cspell/project-dictionary.txt +++ b/.github/.cspell/project-dictionary.txt @@ -11,6 +11,7 @@ ebreak EINTR EINVAL errno +espup fipe FLEN fopen diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4406402..8687002 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -117,6 +117,12 @@ jobs: - uses: taiki-e/checkout-action@v1 - name: Install Rust run: rustup toolchain add ${{ matrix.rust }} --no-self-update --component rust-src && rustup default ${{ matrix.rust }} + - uses: taiki-e/install-action@v2 + with: + tool: espup + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + if: startsWith(matrix.rust, 'nightly') && (startsWith(matrix.os, 'ubuntu') || matrix.os == '') - run: | set -eEuxo pipefail sudo apt-get -o Acquire::Retries=10 -qq update && sudo apt-get -o Acquire::Retries=10 -o Dpkg::Use-Pty=0 install -y --no-install-recommends \ @@ -164,6 +170,12 @@ jobs: echo "C:\Program Files\qemu" >>"${GITHUB_PATH}" "C:\Program Files\qemu\qemu-system-arm" --version if: startsWith(matrix.os, 'windows') + - run: espup install --targets esp32 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + if: startsWith(matrix.rust, 'nightly') && (startsWith(matrix.os, 'ubuntu') || matrix.os == '') - run: tools/no-std.sh - run: TEST_RUNNER=qemu-user tools/no-std.sh if: startsWith(matrix.os, 'ubuntu') || matrix.os == '' + - run: cargo +esp build --target xtensa-esp32-none-elf -Z build-std=core,alloc --features $TEST_FEATURES + if: startsWith(matrix.rust, 'nightly') && (startsWith(matrix.os, 'ubuntu') || matrix.os == '') diff --git a/Cargo.toml b/Cargo.toml index a91c210..33818d4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ keywords = ["qemu"] categories = ["embedded", "hardware-support", "no-std", "no-std::no-alloc"] exclude = ["/.*", "/tools", "/target-specs"] description = """ -Semihosting for AArch64, ARM, RISC-V, MIPS32, and MIPS64. +Semihosting for AArch64, ARM, RISC-V, MIPS32, MIPS64, and Xtensa. """ [package.metadata.docs.rs] diff --git a/README.md b/README.md index 1ad3e24..5eba9a8 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ [![github actions](https://img.shields.io/github/actions/workflow/status/taiki-e/semihosting/ci.yml?branch=main&style=flat-square&logo=github)](https://github.com/taiki-e/semihosting/actions) -Semihosting for AArch64, ARM, RISC-V, MIPS32, and MIPS64. +Semihosting for AArch64, ARM, RISC-V, MIPS32, MIPS64, and Xtensa. This library provides access to semihosting, a mechanism for programs running on the real or virtual (e.g., QEMU) target to communicate with I/O facilities on the host system. See the [ARM documentation](https://github.com/ARM-software/abi-aa/blob/HEAD/semihosting/semihosting.rst) for more information on semihosting. @@ -40,6 +40,7 @@ The following target architectures are supported: | ----------- | ------------- | ------------------------- | | arm/aarch64 | [Semihosting for AArch32 and AArch64](https://github.com/ARM-software/abi-aa/blob/HEAD/semihosting/semihosting.rst) | `sys::arm_compat` | | riscv32/riscv64 | [RISC-V Semihosting](https://github.com/riscv-software-src/riscv-semihosting/blob/HEAD/riscv-semihosting-spec.adoc) | `sys::arm_compat` | +| xtensa | [OpenOCD Semihosting](https://github.com/espressif/openocd-esp32/blob/HEAD/src/target/espressif/esp_xtensa_semihosting.c) | `sys::arm_compat` | | mips/mips32r6/mips64/mips64r6 | Unified Hosting Interface (MD01069) | `sys::mips` | The host must be running an emulator or a debugger attached to the target. diff --git a/src/experimental/env.rs b/src/experimental/env.rs index 7e2cb30..95feec8 100644 --- a/src/experimental/env.rs +++ b/src/experimental/env.rs @@ -81,6 +81,7 @@ mod sys { target_arch = "arm", target_arch = "riscv32", target_arch = "riscv64", + target_arch = "xtensa", ))] mod imp { use core::cell::Cell; diff --git a/src/experimental/time.rs b/src/experimental/time.rs index d2ed8b3..ebdd491 100644 --- a/src/experimental/time.rs +++ b/src/experimental/time.rs @@ -206,6 +206,7 @@ mod sys { target_arch = "arm", target_arch = "riscv32", target_arch = "riscv64", + target_arch = "xtensa", ))] mod inner { use super::{SystemTime, Timespec}; diff --git a/src/lib.rs b/src/lib.rs index e5b01db..ccb15e7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,7 +2,7 @@ /*! -Semihosting for AArch64, ARM, RISC-V, MIPS32, and MIPS64. +Semihosting for AArch64, ARM, RISC-V, MIPS32, MIPS64, and Xtensa. This library provides access to semihosting, a mechanism for programs running on the real or virtual (e.g., QEMU) target to communicate with I/O facilities on the host system. See the [ARM documentation](https://github.com/ARM-software/abi-aa/blob/HEAD/semihosting/semihosting.rst) for more information on semihosting. @@ -35,6 +35,7 @@ The following target architectures are supported: | ----------- | ------------- | ------------------------- | | arm/aarch64 | [Semihosting for AArch32 and AArch64](https://github.com/ARM-software/abi-aa/blob/HEAD/semihosting/semihosting.rst) | `sys::arm_compat` | | riscv32/riscv64 | [RISC-V Semihosting](https://github.com/riscv-software-src/riscv-semihosting/blob/HEAD/riscv-semihosting-spec.adoc) | `sys::arm_compat` | +| xtensa | [OpenOCD Semihosting](https://github.com/espressif/openocd-esp32/blob/HEAD/src/target/espressif/esp_xtensa_semihosting.c) | `sys::arm_compat` | | mips/mips32r6/mips64/mips64r6 | Unified Hosting Interface (MD01069) | `sys::mips` | The host must be running an emulator or a debugger attached to the target. @@ -212,6 +213,7 @@ semihosting = { version = "0.1", features = ["stdio", "panic-handler"] } target_arch = "mips32r6", target_arch = "mips64", target_arch = "mips64r6", + target_arch = "xtensa", ), feature(asm_experimental_arch) )] @@ -227,6 +229,7 @@ semihosting = { version = "0.1", features = ["stdio", "panic-handler"] } target_arch = "mips32r6", target_arch = "mips64", target_arch = "mips64r6", + target_arch = "xtensa", )))] compile_error!("unsupported target"); diff --git a/src/sys/arm_compat/mod.rs b/src/sys/arm_compat/mod.rs index 7e92f61..7d11822 100644 --- a/src/sys/arm_compat/mod.rs +++ b/src/sys/arm_compat/mod.rs @@ -7,6 +7,7 @@ //! - Semihosting for AArch32 and AArch64 //! - RISC-V Semihosting //! - +//! - #![allow(clippy::missing_safety_doc)] // TODO diff --git a/src/sys/arm_compat/syscall/mod.rs b/src/sys/arm_compat/syscall/mod.rs index f88ae4c..4a9f096 100644 --- a/src/sys/arm_compat/syscall/mod.rs +++ b/src/sys/arm_compat/syscall/mod.rs @@ -8,6 +8,7 @@ pub use arch::{syscall, syscall_readonly}; #[cfg_attr(target_arch = "aarch64", path = "aarch64.rs")] #[cfg_attr(target_arch = "arm", path = "arm.rs")] #[cfg_attr(any(target_arch = "riscv32", target_arch = "riscv64"), path = "riscv.rs")] +#[cfg_attr(target_arch = "xtensa", path = "xtensa.rs")] mod arch; pub use crate::sys::reg::{ParamRegR, ParamRegW, RetReg}; diff --git a/src/sys/arm_compat/syscall/xtensa.rs b/src/sys/arm_compat/syscall/xtensa.rs new file mode 100644 index 0000000..db817fa --- /dev/null +++ b/src/sys/arm_compat/syscall/xtensa.rs @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: Apache-2.0 OR MIT + +use core::arch::asm; + +use super::{OperationNumber, ParamRegR, ParamRegW, RetReg}; + +/// Raw semihosting call with a parameter that will be read + modified by the host +#[inline] +pub unsafe fn syscall(number: OperationNumber, parameter: ParamRegW<'_>) -> RetReg { + unsafe { + let r; + asm!( + "break 1, 14", + inout("a2") number.0 as usize => r, // OPERATION NUMBER REGISTER => RETURN REGISTER + // Use inout because operation such as SYS_ELAPSED suggest that + // PARAMETER REGISTER may be changed. + inout("a3") parameter.0 => _, // PARAMETER REGISTER + options(nostack, preserves_flags), + ); + RetReg(r) + } +} + +/// Raw semihosting call with a parameter that will be read (but not modified) by the host +#[inline] +pub unsafe fn syscall_readonly(number: OperationNumber, parameter: ParamRegR<'_>) -> RetReg { + unsafe { + let r; + asm!( + "break 1, 14", + inout("a2") number.0 as usize => r, // OPERATION NUMBER REGISTER => RETURN REGISTER + // Use inout because operation such as SYS_ELAPSED suggest that + // PARAMETER REGISTER may be changed. + inout("a3") parameter.0 => _, // PARAMETER REGISTER + options(nostack, preserves_flags, readonly), + ); + RetReg(r) + } +} diff --git a/src/sys/mod.rs b/src/sys/mod.rs index b6aec6d..99bfa08 100644 --- a/src/sys/mod.rs +++ b/src/sys/mod.rs @@ -14,6 +14,7 @@ target_arch = "arm", target_arch = "riscv32", target_arch = "riscv64", + target_arch = "xtensa", ))] use arm_compat as arch; #[cfg(any( @@ -21,6 +22,7 @@ use arm_compat as arch; target_arch = "arm", target_arch = "riscv32", target_arch = "riscv64", + target_arch = "xtensa", ))] #[cfg_attr( semihosting_doc_cfg, @@ -29,6 +31,7 @@ use arm_compat as arch; target_arch = "arm", target_arch = "riscv32", target_arch = "riscv64", + target_arch = "xtensa", ))) )] pub mod arm_compat; diff --git a/src/sys/reg.rs b/src/sys/reg.rs index ba88d3d..aaa54bb 100644 --- a/src/sys/reg.rs +++ b/src/sys/reg.rs @@ -51,6 +51,7 @@ impl<'a> ParamRegW<'a> { target_arch = "arm", target_arch = "riscv32", target_arch = "riscv64", + target_arch = "xtensa", ))] impl<'a> ParamRegW<'a> { #[inline] @@ -100,6 +101,7 @@ impl<'a> ParamRegR<'a> { target_arch = "arm", target_arch = "riscv32", target_arch = "riscv64", + target_arch = "xtensa", ))] impl<'a> ParamRegR<'a> { #[inline] @@ -157,6 +159,7 @@ impl RetReg { target_arch = "arm", target_arch = "riscv32", target_arch = "riscv64", + target_arch = "xtensa", ))] impl RetReg { #[allow(clippy::cast_possible_truncation)]