Skip to content

Commit 6e35584

Browse files
authored
Added features to select privilege level (#5)
Currently, the library attempts to execute some semihosting operations in a completely interrupt-free context. It does this by using `riscv::interrupt::free`, which saves and restores the `mie` field of `mstatus`. As a result, attempts to initiate semihosting calls outside of M mode cause illegal instruction exceptions. This commit provides a solution, by requiring users to choose one of two features, "machine-mode" or "user-mode", which will compile different versions of the functions in src/export.rs that do and do not suspend interrupts, respectively. Failure to do so will throw a compiler error, unless the "no-semihosting" feature was enabled. A "supervisor-mode" feature was left out as the `riscv` crate does not yet have an equivalent of `interrupt::free` for supervisor mode. CI now also checks builds with both of these features.
1 parent 45ac4e8 commit 6e35584

File tree

6 files changed

+104
-32
lines changed

6 files changed

+104
-32
lines changed

.github/workflows/check.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ jobs:
99
# All generated code should be running on stable now, MRSV is 1.59.0
1010
toolchain: [nightly, stable, 1.59.0]
1111
target: [riscv32i-unknown-none-elf, riscv32imc-unknown-none-elf, riscv32imac-unknown-none-elf, riscv64imac-unknown-none-elf, riscv64gc-unknown-none-elf]
12+
privilege: [machine, user]
1213

1314
include:
1415
# Nightly is only for reference and allowed to fail
@@ -27,4 +28,4 @@ jobs:
2728
with:
2829
use-cross: true
2930
command: check
30-
args: --verbose --target ${{ matrix.target }}
31+
args: --verbose --target ${{ matrix.target }} --features=${{matrix.privilege}}-mode

.github/workflows/doc.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ on: [push, pull_request]
55
jobs:
66
doc:
77
runs-on: ubuntu-latest
8+
strategy:
9+
matrix:
10+
privilege: [machine, user]
811
steps:
912
- uses: actions/checkout@v2
1013
- uses: actions-rs/toolchain@v1
@@ -15,3 +18,4 @@ jobs:
1518
- uses: actions-rs/cargo@v1
1619
with:
1720
command: doc
21+
args: --features=${{matrix.privilege}}-mode

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
2121
- Clean up documentation, removing unnecessary references to
2222
cortex-m-semihosting and improving clarity.
2323
- Added GitHub Actions CI
24+
- Add features to select the privilege level the semihosting operations will be
25+
started from
2426

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

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,11 @@ rust-version = "1.59.0"
1818

1919
[features]
2020
default = ["jlink-quirks"]
21+
machine-mode = []
22+
user-mode = []
2123
jlink-quirks = []
2224
no-semihosting = []
2325

2426
[dependencies]
2527
riscv = "0.8.0"
28+
cfg-if = "1.0.0"

README.md

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,20 @@ This is a fork of the
77
to support the RISC-V Semihosting Specification as documented
88
[here](https://github.com/riscv/riscv-semihosting-spec/blob/main/riscv-semihosting-spec.adoc)
99

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

16+
A major difference between this library and cortex-m-semihosting is that there
17+
are mandatory features to choose the privilege level at which the semihosting
18+
calls are executed. The "machine-mode" feature will cause the macros in `export`
19+
to execute the semihosting operation in an interrupt-free context, while
20+
"user-mode" causes them to just execute the operation. Failure to select one of
21+
these two features will cause a compiler error.
22+
23+
1624
# Minimum Supported Rust Version (MSRV)
1725

1826
This crate is guaranteed to compile on stable Rust 1.59.0 and up. It **won't**

src/export.rs

Lines changed: 82 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,50 +2,104 @@
22
33
use core::fmt::{self, Write};
44

5+
#[cfg(feature = "machine-mode")]
56
use riscv::interrupt;
67

78
use crate::hio::{self, HostStream};
89

910
static mut HSTDOUT: Option<HostStream> = None;
1011

11-
pub fn hstdout_str(s: &str) {
12-
let _result = interrupt::free(|_| unsafe {
13-
if HSTDOUT.is_none() {
14-
HSTDOUT = Some(hio::hstdout()?);
12+
#[cfg(not(feature = "no-semihosting"))]
13+
cfg_if::cfg_if! {
14+
if #[cfg(feature="machine-mode")] {
15+
pub fn hstdout_str(s: &str) {
16+
let _result = interrupt::free(|_| unsafe {
17+
if HSTDOUT.is_none() {
18+
HSTDOUT = Some(hio::hstdout()?);
19+
}
20+
21+
HSTDOUT.as_mut().unwrap().write_str(s).map_err(drop)
22+
});
1523
}
1624

17-
HSTDOUT.as_mut().unwrap().write_str(s).map_err(drop)
18-
});
19-
}
25+
pub fn hstdout_fmt(args: fmt::Arguments) {
26+
let _result = interrupt::free(|_| unsafe {
27+
if HSTDOUT.is_none() {
28+
HSTDOUT = Some(hio::hstdout()?);
29+
}
2030

21-
pub fn hstdout_fmt(args: fmt::Arguments) {
22-
let _result = interrupt::free(|_| unsafe {
23-
if HSTDOUT.is_none() {
24-
HSTDOUT = Some(hio::hstdout()?);
31+
HSTDOUT.as_mut().unwrap().write_fmt(args).map_err(drop)
32+
});
2533
}
2634

27-
HSTDOUT.as_mut().unwrap().write_fmt(args).map_err(drop)
28-
});
29-
}
35+
static mut HSTDERR: Option<HostStream> = None;
3036

31-
static mut HSTDERR: Option<HostStream> = None;
37+
pub fn hstderr_str(s: &str) {
38+
let _result = interrupt::free(|_| unsafe {
39+
if HSTDERR.is_none() {
40+
HSTDERR = Some(hio::hstderr()?);
41+
}
3242

33-
pub fn hstderr_str(s: &str) {
34-
let _result = interrupt::free(|_| unsafe {
35-
if HSTDERR.is_none() {
36-
HSTDERR = Some(hio::hstderr()?);
43+
HSTDERR.as_mut().unwrap().write_str(s).map_err(drop)
44+
});
3745
}
3846

39-
HSTDERR.as_mut().unwrap().write_str(s).map_err(drop)
40-
});
41-
}
47+
pub fn hstderr_fmt(args: fmt::Arguments) {
48+
let _result = interrupt::free(|_| unsafe {
49+
if HSTDERR.is_none() {
50+
HSTDERR = Some(hio::hstderr()?);
51+
}
4252

43-
pub fn hstderr_fmt(args: fmt::Arguments) {
44-
let _result = interrupt::free(|_| unsafe {
45-
if HSTDERR.is_none() {
46-
HSTDERR = Some(hio::hstderr()?);
53+
HSTDERR.as_mut().unwrap().write_fmt(args).map_err(drop)
54+
});
4755
}
56+
}
57+
else if #[cfg(feature = "user-mode")] {
58+
pub fn hstdout_str(s: &str) {
59+
let _result = unsafe {
60+
if HSTDOUT.is_none() {
61+
HSTDOUT = Some(hio::hstdout().unwrap());
62+
}
4863

49-
HSTDERR.as_mut().unwrap().write_fmt(args).map_err(drop)
50-
});
64+
HSTDOUT.as_mut().unwrap().write_str(s).map_err(drop)
65+
};
66+
}
67+
68+
pub fn hstdout_fmt(args: fmt::Arguments) {
69+
let _result = unsafe {
70+
if HSTDOUT.is_none() {
71+
HSTDOUT = Some(hio::hstdout().unwrap());
72+
}
73+
74+
HSTDOUT.as_mut().unwrap().write_fmt(args).map_err(drop)
75+
};
76+
}
77+
78+
static mut HSTDERR: Option<HostStream> = None;
79+
80+
pub fn hstderr_str(s: &str) {
81+
let _result = unsafe {
82+
if HSTDERR.is_none() {
83+
HSTDERR = Some(hio::hstderr().unwrap());
84+
}
85+
86+
HSTDERR.as_mut().unwrap().write_str(s).map_err(drop)
87+
};
88+
}
89+
90+
pub fn hstderr_fmt(args: fmt::Arguments) {
91+
let _result = unsafe {
92+
if HSTDERR.is_none() {
93+
HSTDERR = Some(hio::hstderr().unwrap());
94+
}
95+
96+
HSTDERR.as_mut().unwrap().write_fmt(args).map_err(drop)
97+
};
98+
}
99+
}
100+
else {
101+
compile_error!("A privilege level has not been selected. Enable either \
102+
the machine-mode or user-mode features as appropriate \
103+
for your use case.");
104+
}
51105
}

0 commit comments

Comments
 (0)