Skip to content

Commit 038396e

Browse files
bors[bot]adamgreig
andauthored
Merge #299
299: Expose __syscall and add new bootstrap method r=jonas-schievink a=adamgreig We added `__syscall` in the new inline asm, but did not expose it in the crate API, and the cortex-m-semihosting crate can't use it directly because the pre-built binaries would contain duplicate symbols (#271). This PR renames it to `__sh_syscall` (since we could imagine other different syscalls; this one is explicitly semihosting with the `bkpt 0xAB`) and exposes it in `cortex_m::asm::sh_syscall`. This PR also adds the new methods discussed in #297 to permit sound bootstrapping, either from an MSP and RV or a vector table address. Co-authored-by: Adam Greig <adam@adamgreig.com>
2 parents d34b1ce + 6484246 commit 038396e

18 files changed

+74
-3
lines changed

CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
77

88
## [Unreleased]
99

10+
### Added
11+
12+
- New assembly methods `asm::semihosting_syscall`, `asm::bootstrap`, and
13+
`asm::bootload`.
14+
1015
## [v0.7.0] - 2020-11-09
1116

1217
### Added

asm/inline.rs

+21-1
Original file line numberDiff line numberDiff line change
@@ -177,11 +177,31 @@ pub unsafe fn __wfi() {
177177

178178
/// Semihosting syscall.
179179
#[inline(always)]
180-
pub unsafe fn __syscall(mut nr: u32, arg: u32) -> u32 {
180+
pub unsafe fn __sh_syscall(mut nr: u32, arg: u32) -> u32 {
181181
asm!("bkpt #0xab", inout("r0") nr, in("r1") arg);
182182
nr
183183
}
184184

185+
/// Set CONTROL.SPSEL to 0, write `msp` to MSP, branch to `rv`.
186+
#[inline(always)]
187+
pub unsafe fn __bootstrap(msp: u32, rv: u32) -> ! {
188+
asm!(
189+
"mrs {tmp}, CONTROL",
190+
"bics {tmp}, {spsel}",
191+
"msr CONTROL, {tmp}",
192+
"isb",
193+
"msr MSP, {msp}",
194+
"bx {rv}",
195+
// `out(reg) _` is not permitted in a `noreturn` asm! call,
196+
// so instead use `in(reg) 0` and don't restore it afterwards.
197+
tmp = in(reg) 0,
198+
spsel = in(reg) 2,
199+
msp = in(reg) msp,
200+
rv = in(reg) rv,
201+
options(noreturn),
202+
);
203+
}
204+
185205
// v7m *AND* v8m.main, but *NOT* v8m.base
186206
#[cfg(any(armv7m, armv8m_main))]
187207
pub use self::v7m::*;

asm/lib.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,11 @@ shims! {
6969
fn __psp_r() -> u32;
7070
fn __psp_w(val: u32);
7171
fn __sev();
72-
fn __udf();
72+
fn __udf() -> !;
7373
fn __wfe();
7474
fn __wfi();
75-
fn __syscall(nr: u32, arg: u32) -> u32;
75+
fn __sh_syscall(nr: u32, arg: u32) -> u32;
76+
fn __bootstrap(msp: u32, rv: u32) -> !;
7677
}
7778

7879
// v7m *AND* v8m.main, but *NOT* v8m.base

bin/thumbv6m-none-eabi-lto.a

736 Bytes
Binary file not shown.

bin/thumbv6m-none-eabi.a

636 Bytes
Binary file not shown.

bin/thumbv7em-none-eabi-lto.a

632 Bytes
Binary file not shown.

bin/thumbv7em-none-eabi.a

668 Bytes
Binary file not shown.

bin/thumbv7em-none-eabihf-lto.a

512 Bytes
Binary file not shown.

bin/thumbv7em-none-eabihf.a

672 Bytes
Binary file not shown.

bin/thumbv7m-none-eabi-lto.a

676 Bytes
Binary file not shown.

bin/thumbv7m-none-eabi.a

668 Bytes
Binary file not shown.

bin/thumbv8m.base-none-eabi-lto.a

752 Bytes
Binary file not shown.

bin/thumbv8m.base-none-eabi.a

640 Bytes
Binary file not shown.

bin/thumbv8m.main-none-eabi-lto.a

460 Bytes
Binary file not shown.

bin/thumbv8m.main-none-eabi.a

672 Bytes
Binary file not shown.

bin/thumbv8m.main-none-eabihf-lto.a

360 Bytes
Binary file not shown.

bin/thumbv8m.main-none-eabihf.a

672 Bytes
Binary file not shown.

src/asm.rs

+45
Original file line numberDiff line numberDiff line change
@@ -164,3 +164,48 @@ pub fn ttat(addr: *mut u32) -> u32 {
164164
pub unsafe fn bx_ns(addr: u32) {
165165
call_asm!(__bxns(addr: u32));
166166
}
167+
168+
/// Semihosting syscall.
169+
///
170+
/// This method is used by cortex-m-semihosting to provide semihosting syscalls.
171+
#[inline]
172+
pub unsafe fn semihosting_syscall(nr: u32, arg: u32) -> u32 {
173+
call_asm!(__sh_syscall(nr: u32, arg: u32) -> u32)
174+
}
175+
176+
/// Bootstrap.
177+
///
178+
/// Clears CONTROL.SPSEL (setting the main stack to be the active stack),
179+
/// updates the main stack pointer to the address in `msp`, then jumps
180+
/// to the address in `rv`.
181+
///
182+
/// # Safety
183+
///
184+
/// `msp` and `rv` must point to valid stack memory and executable code,
185+
/// respectively.
186+
#[inline]
187+
pub unsafe fn bootstrap(msp: *const u32, rv: *const u32) -> ! {
188+
// Ensure thumb mode is set.
189+
let rv = (rv as u32) | 1;
190+
let msp = msp as u32;
191+
call_asm!(__bootstrap(msp: u32, rv: u32) -> !);
192+
}
193+
194+
/// Bootload.
195+
///
196+
/// Reads the initial stack pointer value and reset vector from
197+
/// the provided vector table address, sets the active stack to
198+
/// the main stack, sets the main stack pointer to the new initial
199+
/// stack pointer, then jumps to the reset vector.
200+
///
201+
/// # Safety
202+
///
203+
/// The provided `vector_table` must point to a valid vector
204+
/// table, with a valid stack pointer as the first word and
205+
/// a valid reset vector as the second word.
206+
#[inline]
207+
pub unsafe fn bootload(vector_table: *const u32) -> ! {
208+
let msp = core::ptr::read_volatile(vector_table);
209+
let rv = core::ptr::read_volatile(vector_table.offset(1));
210+
bootstrap(msp as *const u32, rv as *const u32);
211+
}

0 commit comments

Comments
 (0)