Skip to content

Commit

Permalink
Expose raw syscall interface as public API
Browse files Browse the repository at this point in the history
  • Loading branch information
t-moe committed Dec 22, 2023
1 parent 76b8c00 commit bfe1931
Show file tree
Hide file tree
Showing 9 changed files with 231 additions and 125 deletions.
2 changes: 1 addition & 1 deletion src/sys/arm_compat/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
pub(crate) mod errno;
#[cfg(feature = "fs")]
pub(crate) mod fs;
pub(crate) mod syscall;
pub mod syscall;

use core::{
ffi::{c_void, CStr},
Expand Down
11 changes: 7 additions & 4 deletions src/sys/arm_compat/syscall/aarch64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@ macro_rules! trap {
};
}

/// Raw semihosting call with a parameter that will be read + modified by the host
#[inline]
pub(crate) unsafe fn syscall(number: OperationNumber, parameter: ParamRegW<'_>) -> RetReg {
pub unsafe fn syscall(number: OperationNumber, parameter: ParamRegW<'_>) -> RetReg {
unsafe {
let r;
asm!(
trap!(),
in("w0") number as u32, // OPERATION NUMBER REGISTER
in("w0") number.as_u32(), // OPERATION NUMBER REGISTER
// Use inout because operation such as SYS_ELAPSED suggest that
// the PARAMETER REGISTER may be changed.
inout("x1") parameter.0 => _, // PARAMETER REGISTER
Expand All @@ -27,13 +28,15 @@ pub(crate) unsafe fn syscall(number: OperationNumber, parameter: ParamRegW<'_>)
RetReg(r)
}
}

/// Raw semihosting call with a parameter that will be read (but not modified) by the host
#[inline]
pub(crate) unsafe fn syscall_readonly(number: OperationNumber, parameter: ParamRegR<'_>) -> RetReg {
pub unsafe fn syscall_readonly(number: OperationNumber, parameter: ParamRegR<'_>) -> RetReg {
unsafe {
let r;
asm!(
trap!(),
in("w0") number as u32, // OPERATION NUMBER REGISTER
in("w0") number.as_u32(), // OPERATION NUMBER REGISTER
// Use inout because operation such as SYS_ELAPSED suggest that
// the PARAMETER REGISTER may be changed.
inout("x1") parameter.0 => _, // PARAMETER REGISTER
Expand Down
11 changes: 7 additions & 4 deletions src/sys/arm_compat/syscall/arm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,14 @@ macro_rules! trap {
// };
// }

/// Raw semihosting call with a parameter that will be read + modified by the host
#[inline]
pub(crate) unsafe fn syscall(number: OperationNumber, parameter: ParamRegW<'_>) -> RetReg {
pub unsafe fn syscall(number: OperationNumber, parameter: ParamRegW<'_>) -> RetReg {
unsafe {
let r;
asm!(
trap!(),
inout("r0") number as usize => r, // OPERATION NUMBER REGISTER => RETURN REGISTER
inout("r0") number.as_usize() => r, // OPERATION NUMBER REGISTER => RETURN REGISTER
// Use inout because operation such as SYS_ELAPSED suggest that
// PARAMETER REGISTER may be changed.
inout("r1") parameter.0 => _, // PARAMETER REGISTER
Expand All @@ -59,13 +60,15 @@ pub(crate) unsafe fn syscall(number: OperationNumber, parameter: ParamRegW<'_>)
RetReg(r)
}
}

/// Raw semihosting call with a parameter that will be read (but not modified) by the host
#[inline]
pub(crate) unsafe fn syscall_readonly(number: OperationNumber, parameter: ParamRegR<'_>) -> RetReg {
pub unsafe fn syscall_readonly(number: OperationNumber, parameter: ParamRegR<'_>) -> RetReg {
unsafe {
let r;
asm!(
trap!(),
inout("r0") number as usize => r, // OPERATION NUMBER REGISTER => RETURN REGISTER
inout("r0") number.as_usize() => r, // OPERATION NUMBER REGISTER => RETURN REGISTER
// Use inout because operation such as SYS_ELAPSED suggest that
// PARAMETER REGISTER may be changed.
inout("r1") parameter.0 => _, // PARAMETER REGISTER
Expand Down
108 changes: 78 additions & 30 deletions src/sys/arm_compat/syscall/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,88 +2,136 @@

//! Raw semihosting call.
// TODO: should we expose this as public API of `sys` module?

#![allow(clippy::needless_pass_by_value)]

pub(crate) use arch::{syscall, syscall_readonly};
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")]
mod arch;

pub(crate) use crate::sys::reg::{ParamRegR, ParamRegW, RetReg};
pub use crate::sys::reg::{ParamRegR, ParamRegW, RetReg};

/// Semihosting operation numbers.
///
/// - `0x00-0x31` Used by ARM.
/// - `0x32-0xFF` Reserved for future use by ARM.
/// - `0x100-0x1FF` Reserved for user applications.
/// - `0x200-0xFFFFFFFF` Undefined and currently unused.
#[repr(u32)]
pub(crate) enum OperationNumber {
#[derive(Debug, Copy, Clone)]
#[non_exhaustive]
pub enum OperationNumber {
/// [SYS_OPEN (0x01)](https://github.com/ARM-software/abi-aa/blob/HEAD/semihosting/semihosting.rst#612sys_open-0x01)
SYS_OPEN = 0x01,
SYS_OPEN,
/// [SYS_CLOSE (0x02)](https://github.com/ARM-software/abi-aa/blob/HEAD/semihosting/semihosting.rst#62sys_close-0x02)
SYS_CLOSE = 0x02,
SYS_CLOSE,
/// [SYS_WRITEC (0x03)](https://github.com/ARM-software/abi-aa/blob/HEAD/semihosting/semihosting.rst#623sys_writec-0x03)
SYS_WRITEC = 0x03,
SYS_WRITEC,
/// [SYS_WRITE0 (0x04)](https://github.com/ARM-software/abi-aa/blob/HEAD/semihosting/semihosting.rst#624sys_write0-0x04)
SYS_WRITE0 = 0x04,
SYS_WRITE0,
/// [SYS_WRITE (0x05)](https://github.com/ARM-software/abi-aa/blob/HEAD/semihosting/semihosting.rst#622sys_write-0x05)
SYS_WRITE = 0x05,
SYS_WRITE,
/// [SYS_READ (0x06)](https://github.com/ARM-software/abi-aa/blob/HEAD/semihosting/semihosting.rst#613sys_read-0x06)
SYS_READ = 0x06,
SYS_READ,
/// [SYS_READC (0x07)](https://github.com/ARM-software/abi-aa/blob/HEAD/semihosting/semihosting.rst#614sys_readc-0x07)
SYS_READC = 0x07,
SYS_READC,
/// [SYS_ISERROR (0x08)](https://github.com/ARM-software/abi-aa/blob/HEAD/semihosting/semihosting.rst#610sys_iserror-0x08)
SYS_ISERROR = 0x08,
SYS_ISERROR,
/// [SYS_ISTTY (0x09)](https://github.com/ARM-software/abi-aa/blob/HEAD/semihosting/semihosting.rst#611sys_istty-0x09)
SYS_ISTTY = 0x09,
SYS_ISTTY,
/// [SYS_SEEK (0x0A)](https://github.com/ARM-software/abi-aa/blob/HEAD/semihosting/semihosting.rst#617sys_seek-0x0a)
SYS_SEEK = 0x0A,
SYS_SEEK,
/// [SYS_FLEN (0x0C)](https://github.com/ARM-software/abi-aa/blob/HEAD/semihosting/semihosting.rst#67sys_flen-0x0c)
SYS_FLEN = 0x0C,
SYS_FLEN,
// /// [SYS_TMPNAM (0x0D)](https://github.com/ARM-software/abi-aa/blob/HEAD/semihosting/semihosting.rst#621sys_tmpnam-0x0d)
// #[deprecated = "tmpnam is deprecated as not secure on most host systems"]
// SYS_TMPNAM = 0x0D,
/// [SYS_REMOVE (0x0E)](https://github.com/ARM-software/abi-aa/blob/HEAD/semihosting/semihosting.rst#615sys_remove-0x0e)
SYS_REMOVE = 0x0E,
SYS_REMOVE,
/// [SYS_RENAME (0x0F)](https://github.com/ARM-software/abi-aa/blob/HEAD/semihosting/semihosting.rst#616sys_rename-0x0f)
SYS_RENAME = 0x0F,
SYS_RENAME,
/// [SYS_CLOCK (0x10)](https://github.com/ARM-software/abi-aa/blob/HEAD/semihosting/semihosting.rst#sys-clock-0x10)
SYS_CLOCK = 0x10,
SYS_CLOCK,
/// [SYS_TIME (0x11)](https://github.com/ARM-software/abi-aa/blob/HEAD/semihosting/semihosting.rst#620sys_time-0x11)
SYS_TIME = 0x11,
SYS_TIME,
/// [SYS_SYSTEM (0x12)](https://github.com/ARM-software/abi-aa/blob/HEAD/semihosting/semihosting.rst#618sys_system-0x12)
SYS_SYSTEM = 0x12,
SYS_SYSTEM,
/// [SYS_ERRNO (0x13)](https://github.com/ARM-software/abi-aa/blob/HEAD/semihosting/semihosting.rst#64sys_errno-0x13)
SYS_ERRNO = 0x13,
SYS_ERRNO,
/// [SYS_GET_CMDLINE (0x15)](https://github.com/ARM-software/abi-aa/blob/HEAD/semihosting/semihosting.rst#68sys_get_cmdline-0x15)
SYS_GET_CMDLINE = 0x15,
SYS_GET_CMDLINE,
/// [SYS_HEAPINFO (0x16)](https://github.com/ARM-software/abi-aa/blob/HEAD/semihosting/semihosting.rst#69sys_heapinfo-0x16)
SYS_HEAPINFO = 0x16,
SYS_HEAPINFO,
// #[deprecated = "obsoleted in semihosting specification version 2.0"]
// angel_SWIreason_EnterSVC = 0x17,
/// [SYS_EXIT (0x18)](https://github.com/ARM-software/abi-aa/blob/HEAD/semihosting/semihosting.rst#65sys_exit-0x18)
#[doc(alias = "angel_SWIreason_ReportException")] // old name
SYS_EXIT = 0x18,
SYS_EXIT,
// #[deprecated = "obsoleted in semihosting specification version 2.0"]
// angelSWI_Reason_SyncCacheRange = 0x19,
/// [SYS_EXIT_EXTENDED (0x20)](https://github.com/ARM-software/abi-aa/blob/HEAD/semihosting/semihosting.rst#66sys_exit_extended-0x20)
// we use SYS_EXIT on 64-bit system because SYS_EXIT_EXTENDED is identical to the behavior of the mandatory SYS_EXIT.
#[cfg_attr(target_pointer_width = "64", allow(dead_code))]
SYS_EXIT_EXTENDED = 0x20,
SYS_EXIT_EXTENDED,
/// [SYS_ELAPSED (0x30)](https://github.com/ARM-software/abi-aa/blob/HEAD/semihosting/semihosting.rst#63sys_elapsed-0x30)
SYS_ELAPSED = 0x30,
SYS_ELAPSED,
/// [SYS_TICKFREQ (0x31)](https://github.com/ARM-software/abi-aa/blob/HEAD/semihosting/semihosting.rst#619sys_tickfreq-0x31)
SYS_TICKFREQ = 0x31,
SYS_TICKFREQ,

/// Some other (e.g. user defined) operation number
Other(u32),
}

impl From<OperationNumber> for u32 {
fn from(op: OperationNumber) -> Self {
match op {
OperationNumber::SYS_OPEN => 0x01,
OperationNumber::SYS_CLOSE => 0x02,
OperationNumber::SYS_WRITEC => 0x03,
OperationNumber::SYS_WRITE0 => 0x04,
OperationNumber::SYS_WRITE => 0x05,
OperationNumber::SYS_READ => 0x06,
OperationNumber::SYS_READC => 0x07,
OperationNumber::SYS_ISERROR => 0x08,
OperationNumber::SYS_ISTTY => 0x09,
OperationNumber::SYS_SEEK => 0x0A,
OperationNumber::SYS_FLEN => 0x0C,
OperationNumber::SYS_REMOVE => 0x0E,
OperationNumber::SYS_RENAME => 0x0F,
OperationNumber::SYS_CLOCK => 0x10,
OperationNumber::SYS_TIME => 0x11,
OperationNumber::SYS_SYSTEM => 0x12,
OperationNumber::SYS_ERRNO => 0x13,
OperationNumber::SYS_GET_CMDLINE => 0x15,
OperationNumber::SYS_HEAPINFO => 0x16,
OperationNumber::SYS_EXIT => 0x18,
OperationNumber::SYS_EXIT_EXTENDED => 0x20,
OperationNumber::SYS_ELAPSED => 0x30,
OperationNumber::SYS_TICKFREQ => 0x31,
OperationNumber::Other(op) => op,
}
}
}

impl OperationNumber {
// Shortcut for <OperationNumber as Into<u32>>::into(op)
#[allow(dead_code)]
fn as_u32(self) -> u32 {
self.into()
}

// Shortcut for <OperationNumber as Into<u32>>::into(op) as usize
#[allow(dead_code)]
fn as_usize(self) -> usize {
self.as_u32() as usize
}
}

pub(crate) use OperationNumber::*;

/// `syscall_readonly(number, null)`
#[inline]
pub(crate) unsafe fn syscall0(number: OperationNumber) -> RetReg {
pub unsafe fn syscall0(number: OperationNumber) -> RetReg {
// In most operations that don't have parameters, such as SYS_ERRNO, and
// SYS_CLOCK, the PARAMETER REGISTER must be zero.
unsafe { syscall_readonly(number, ParamRegR::usize(0)) }
Expand Down
11 changes: 7 additions & 4 deletions src/sys/arm_compat/syscall/riscv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ 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(crate) unsafe fn syscall(number: OperationNumber, parameter: ParamRegW<'_>) -> RetReg {
pub unsafe fn syscall(number: OperationNumber, parameter: ParamRegW<'_>) -> RetReg {
unsafe {
let r;
asm!(
Expand All @@ -16,7 +17,7 @@ pub(crate) unsafe fn syscall(number: OperationNumber, parameter: ParamRegW<'_>)
"ebreak",
"srai zero, zero, 0x7",
".option pop",
inout("a0") number as usize => r, // OPERATION NUMBER REGISTER => RETURN REGISTER
inout("a0") number.as_usize() => r, // OPERATION NUMBER REGISTER => RETURN REGISTER
// Use inout because operation such as SYS_ELAPSED suggest that
// PARAMETER REGISTER may be changed.
inout("a1") parameter.0 => _, // PARAMETER REGISTER
Expand All @@ -25,8 +26,10 @@ pub(crate) unsafe fn syscall(number: OperationNumber, parameter: ParamRegW<'_>)
RetReg(r)
}
}

/// Raw semihosting call with a parameter that will be read (but not modified) by the host
#[inline]
pub(crate) unsafe fn syscall_readonly(number: OperationNumber, parameter: ParamRegR<'_>) -> RetReg {
pub unsafe fn syscall_readonly(number: OperationNumber, parameter: ParamRegR<'_>) -> RetReg {
unsafe {
let r;
asm!(
Expand All @@ -37,7 +40,7 @@ pub(crate) unsafe fn syscall_readonly(number: OperationNumber, parameter: ParamR
"ebreak",
"srai zero, zero, 0x7",
".option pop",
inout("a0") number as usize => r, // OPERATION NUMBER REGISTER => RETURN REGISTER
inout("a0") number.as_usize() => r, // OPERATION NUMBER REGISTER => RETURN REGISTER
// Use inout because operation such as SYS_ELAPSED suggest that
// PARAMETER REGISTER may be changed.
inout("a1") parameter.0 => _, // PARAMETER REGISTER
Expand Down
2 changes: 1 addition & 1 deletion src/sys/mips/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
pub(crate) mod errno;
#[cfg(feature = "fs")]
pub(crate) mod fs;
pub(crate) mod syscall;
pub mod syscall;

use core::{ffi::CStr, mem};

Expand Down
Loading

0 comments on commit bfe1931

Please sign in to comment.