Skip to content

Commit

Permalink
Merge pull request #170 from rust-embedded/semihosting
Browse files Browse the repository at this point in the history
add `riscv-semihosting`
  • Loading branch information
MabezDev authored Jan 2, 2024
2 parents 0f8305b + 4dc63f6 commit 1921b5e
Show file tree
Hide file tree
Showing 14 changed files with 899 additions and 7 deletions.
22 changes: 16 additions & 6 deletions .github/workflows/changelog.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,12 @@ jobs:
filters: |
riscv:
- 'riscv/**'
riscv-rt:
- 'riscv-rt/**'
riscv-pac:
- 'riscv-pac/**'
riscv-rt:
- 'riscv-rt/**'
riscv-semihosting:
- 'riscv-semihosting/**'
- name: Check for CHANGELOG.md (riscv)
if: steps.changes.outputs.riscv == 'true'
Expand All @@ -32,6 +34,14 @@ jobs:
skipLabels: 'skip changelog'
missingUpdateErrorMessage: 'Please add a changelog entry in the riscv/CHANGELOG.md file.'

- name: Check for CHANGELOG.md (riscv-pac)
if: steps.changes.outputs.riscv-pac == 'true'
uses: dangoslen/changelog-enforcer@v3
with:
changeLogPath: ./riscv-pac/CHANGELOG.md
skipLabels: 'skip changelog'
missingUpdateErrorMessage: 'Please add a changelog entry in the riscv-pac/CHANGELOG.md file.'

- name: Check for CHANGELOG.md (riscv-rt)
if: steps.changes.outputs.riscv-rt == 'true'
uses: dangoslen/changelog-enforcer@v3
Expand All @@ -40,10 +50,10 @@ jobs:
skipLabels: 'skip changelog'
missingUpdateErrorMessage: 'Please add a changelog entry in the riscv-rt/CHANGELOG.md file.'

- name: Check for CHANGELOG.md (riscv-pac)
if: steps.changes.outputs.riscv-pac == 'true'
- name: Check for CHANGELOG.md (riscv-semihosting)
if: steps.changes.outputs.riscv-semihosting == 'true'
uses: dangoslen/changelog-enforcer@v3
with:
changeLogPath: ./riscv-pac/CHANGELOG.md
changeLogPath: ./riscv-semihosting/CHANGELOG.md
skipLabels: 'skip changelog'
missingUpdateErrorMessage: 'Please add a changelog entry in the riscv-pac/CHANGELOG.md file.'
missingUpdateErrorMessage: 'Please add a changelog entry in the riscv-semihosting/CHANGELOG.md file.'
63 changes: 63 additions & 0 deletions .github/workflows/riscv-semihosting.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
on:
push:
branches: [ master ]
pull_request:
merge_group:

name: Build check (riscv-semihosting)

jobs:
# We check that the crate builds and links for all the toolchains and targets.
build-riscv:
strategy:
matrix:
# All generated code should be running on stable now, MRSV is 1.60.0
toolchain: [ stable, nightly, 1.60.0 ]
target:
- riscv32i-unknown-none-elf
- riscv32imc-unknown-none-elf
- riscv32imac-unknown-none-elf
- riscv64imac-unknown-none-elf
- riscv64gc-unknown-none-elf
include:
# Nightly is only for reference and allowed to fail
- toolchain: nightly
experimental: true
runs-on: ubuntu-latest
continue-on-error: ${{ matrix.experimental || false }}
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ matrix.toolchain }}
targets: ${{ matrix.target }}
- name: Build (M-mode)
run: cargo build --package riscv-semihosting --target ${{ matrix.target }}
- name: Build (U-mode)
run: cargo build --package riscv-semihosting --target ${{ matrix.target }} --features=u-mode
- name: Build (no semihosting)
run: cargo build --package riscv-semihosting --target ${{ matrix.target }} --features=no-semihosting

# On MacOS, Ubuntu, and Windows, we at least make sure that the crate builds and links.
build-others:
strategy:
matrix:
os: [ macos-latest, ubuntu-latest, windows-latest ]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v3
- uses: dtolnay/rust-toolchain@stable
- name: Build (no features)
run: cargo build --package riscv-semihosting
- name: Build (all features)
run: cargo build --package riscv-semihosting --all-features

# Job to check that all the builds succeeded
build-check:
needs:
- build-riscv
- build-others
runs-on: ubuntu-latest
if: always()
steps:
- run: jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}'
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ members = [
"riscv",
"riscv-pac",
"riscv-rt",
"riscv-semihosting",
]
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ This repository contains various crates useful for writing Rust programs on RISC
* [`riscv`]: CPU registers access and intrinsics
* [`riscv-pac`]: Common traits to be implemented by RISC-V PACs
* [`riscv-rt`]: Startup code and interrupt handling

* [`riscv-semihosting`]: Semihosting for RISC-V processors

This project is developed and maintained by the [RISC-V team][team].

Expand All @@ -22,6 +22,8 @@ Conduct][CoC], the maintainer of this crate, the [RISC-V team][team], promises
to intervene to uphold that code of conduct.

[`riscv`]: https://crates.io/crates/riscv
[`riscv-pac`]: https://crates.io/crates/riscv-pac
[`riscv-rt`]: https://crates.io/crates/riscv-rt
[`riscv-semihosting`]: https://crates.io/crates/riscv-semihosting
[team]: https://github.com/rust-embedded/wg#the-risc-v-team
[CoC]: CODE_OF_CONDUCT.md
33 changes: 33 additions & 0 deletions riscv-semihosting/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Change Log

All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased]

- Moved to the `riscv` Cargo workspace
- Bring in API changes from
[cortex-m-semihosting](https://github.com/rust-embedded/cortex-m/tree/master/cortex-m-semihosting),
including:
- Addition of the `hprint`, `hprintln`, `heprint`, `heprintln`, and `dbg`
macros.
- `hprint` and `heprintln` print to host stdout without and with a
newline, respectively.
- `heprint` and `heprintln` do the same, except to host stderr.
- `dbg` works exactly like
[`std::dbg`](https://doc.rust-lang.org/std/macro.dbg.html).
- `HStdout` and `HStderr` have been combined into `HostStream`.
- `inline-asm` feature removed, switched to stabilized inline asm and MSRV
bumped to 1.59.0
- Clean up documentation, removing unnecessary references to
cortex-m-semihosting and improving clarity.
- Added GitHub Actions CI
- Add features to select the privilege level the semihosting operations will be
started from

## [v0.0.1] - 2018-02-27

- Initial release

[Unreleased]: https://github.com/riscv-rust/riscv-semihosting/compare/cb1afe4002d576b87bfd4c199f42a43815984ce4..HEAD
[v0.0.1]: https://github.com/riscv-rust/riscv-semihosting/tree/cb1afe4002d576b87bfd4c199f42a43815984ce4
27 changes: 27 additions & 0 deletions riscv-semihosting/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
[package]
authors = [
"The Cortex-M Team <cortex-m@teams.rust-embedded.org>",
"Jorge Aparicio <japaricious@gmail.com>",
"The RISC-V Team <risc-v@teams.rust-embedded.org>",
]
description = "Semihosting for RISCV processors"
documentation = "https://docs.rs/riscv-semihosting"
keywords = ["semihosting", "riscv"]
categories = ["no-std", "embedded"]
license = "MIT OR Apache-2.0"
name = "riscv-semihosting"
readme = "README.md"
repository = "https://github.com/riscv-rust/riscv"
version = "0.0.1"
edition = "2021"
rust-version = "1.60.0"

[features]
u-mode = []
jlink-quirks = []
no-semihosting = []
default = ["jlink-quirks"]

[dependencies]
critical-section = "1.0.0"
riscv = {path = "../riscv", version = "0.10.1"}
61 changes: 61 additions & 0 deletions riscv-semihosting/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
[![crates.io](https://img.shields.io/crates/d/riscv-semihosting.svg)](https://crates.io/crates/riscv-semihosting)
[![crates.io](https://img.shields.io/crates/v/riscv-semihosting.svg)](https://crates.io/crates/riscv-semihosting)

# `riscv-semihosting`

> Semihosting for RISC-V processors
This is a fork of the
[cortex-m-semihosting](https://docs.rs/cortex-m-semihosting) crate with changes
to support the RISC-V Semihosting Specification as documented
[here](https://github.com/riscv/riscv-semihosting-spec/blob/main/riscv-semihosting-spec.adoc)

This crate can (almost) be used in exactly the same way as cortex-m-semihosting,
simply by changing calls to `cortex_m_semihosting::*` to `riscv_semihosting::*`.
Given this, the
[`cortex-m-semihosting documentation`](https://docs.rs/cortex-m-semihosting) is
generally sufficient for using this library.

A major difference between this library and `cortex-m-semihosting` is that there
are mandatory features to choose the privilege level at which the semihosting
calls are executed. The *machine-mode (M-mode)* feature will cause the macros in `export`
to execute the semihosting operation in an interrupt-free context, while
*user-mode (U-mode)* causes them to just execute the operation.
By default, M-mode is used. You can activate the U-mode via the `u-mode` feature.


# Minimum Supported Rust Version (MSRV)

This crate is guaranteed to compile on stable Rust 1.60.0 and up. It **won't**
compile with older versions.

## License

Copyright 2018-2023 [RISC-V team][team]

Permission to use, copy, modify, and/or distribute this software for any purpose
with or without fee is hereby granted, provided that the above copyright notice
and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.

### Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
dual licensed as above, without any additional terms or conditions.

## Code of Conduct

Contribution to this crate is organized under the terms of the [Rust Code of
Conduct][CoC], the maintainer of this crate, the [RISC-V team][team], promises
to intervene to uphold that code of conduct.

[CoC]: ../CODE_OF_CONDUCT.md
[team]: https://github.com/rust-embedded/wg#the-risc-v-team
9 changes: 9 additions & 0 deletions riscv-semihosting/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
use std::env;

fn main() {
let target = env::var("TARGET").unwrap();

if target.starts_with("riscv") {
println!("cargo:rustc-cfg=riscv");
}
}
94 changes: 94 additions & 0 deletions riscv-semihosting/src/debug.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
//! Interacting with debugging agent
//!
//! # Example
//!
//! This example will show how to terminate the QEMU session. The program
//! should be running under QEMU with semihosting enabled
//! (use `-semihosting` flag).
//!
//! Target program:
//!
//! ```no_run
//! use riscv_semihosting::debug::{self, EXIT_SUCCESS, EXIT_FAILURE};
//!
//! if 2 == 2 {
//! // report success
//! debug::exit(EXIT_SUCCESS);
//! } else {
//! // report failure
//! debug::exit(EXIT_FAILURE);
//! }
//!```
/// This values are taken from section 5.5.2 of
/// ADS Debug Target Guide (DUI0058).
// TODO document
#[allow(missing_docs)]
pub enum Exception {
// Hardware reason codes
BranchThroughZero = 0x20000,
UndefinedInstr = 0x20001,
SoftwareInterrupt = 0x20002,
PrefetchAbort = 0x20003,
DataAbort = 0x20004,
AddressException = 0x20005,
IRQ = 0x20006,
FIQ = 0x20007,
// Software reason codes
BreakPoint = 0x20020,
WatchPoint = 0x20021,
StepComplete = 0x20022,
RunTimeErrorUnknown = 0x20023,
InternalError = 0x20024,
UserInterruption = 0x20025,
ApplicationExit = 0x20026,
StackOverflow = 0x20027,
DivisionByZero = 0x20028,
OSSpecific = 0x20029,
}

/// Status enum for `exit` syscall.
pub type ExitStatus = Result<(), ()>;

/// Successful execution of a program.
pub const EXIT_SUCCESS: ExitStatus = Ok(());

/// Unsuccessful execution of a program.
pub const EXIT_FAILURE: ExitStatus = Err(());

/// Reports to the debugger that the execution has completed.
///
/// This call can be used to terminate QEMU session and report back success
/// or failure. If you need to pass more than one type of error, consider
/// using `report_exception` syscall instead.
///
/// This call should not return. However, it is possible for the debugger
/// to request that the application continue. In that case this call
/// returns normally.
///
pub fn exit(status: ExitStatus) {
match status {
EXIT_SUCCESS => report_exception(Exception::ApplicationExit),
EXIT_FAILURE => report_exception(Exception::RunTimeErrorUnknown),
}
}

/// Report an exception to the debugger directly.
///
/// Exception handlers can use this SWI at the end of handler chains
/// as the default action, to indicate that the exception has not been handled.
///
/// This call should not return. However, it is possible for the debugger
/// to request that the application continue. In that case this call
/// returns normally.
///
/// # Arguments
///
/// * `reason` - A reason code reported back to the debugger.
///
pub fn report_exception(reason: Exception) {
let code = reason as usize;
unsafe {
syscall1!(REPORT_EXCEPTION, code);
}
}
Loading

0 comments on commit 1921b5e

Please sign in to comment.