Repository: probe-rs/probe-rs
Pull request #3115 (2025-02-21 10:03:12)

Handle errno semihosting calls


Patch:
diff --git a/changelog/added-errno-semihosting.md b/changelog/added-errno-semihosting.md
new file mode 100644
index 00000000..8f8f12bd
--- /dev/null
+++ b/changelog/added-errno-semihosting.md
@@ -0,0 +1,1 @@
+Probe-rs now handles (and ignores) the ERRNO semihosting command.
\ No newline at end of file
diff --git a/probe-rs-tools/src/bin/probe-rs/rpc/functions/monitor.rs b/probe-rs-tools/src/bin/probe-rs/rpc/functions/monitor.rs
index 0ce7834e..15a8f179 100644
--- a/probe-rs-tools/src/bin/probe-rs/rpc/functions/monitor.rs
+++ b/probe-rs-tools/src/bin/probe-rs/rpc/functions/monitor.rs
@@ -167,6 +167,7 @@ impl<F: FnMut(MonitorEvent)> MonitorEventHandler<F> {
                 tracing::warn!("Target wanted to run semihosting operation SYS_GET_CMDLINE, but probe-rs does not support this operation yet. Continuing...");
                 Ok(None) // Continue running
             }
+            SemihostingCommand::Errno(_) => Ok(None),
             other @ (SemihostingCommand::Open(_)
             | SemihostingCommand::Close(_)
             | SemihostingCommand::WriteConsole(_)
diff --git a/probe-rs/src/semihosting.rs b/probe-rs/src/semihosting.rs
index 81ed67dc..d583f6f4 100644
--- a/probe-rs/src/semihosting.rs
+++ b/probe-rs/src/semihosting.rs
@@ -32,6 +32,9 @@ pub enum SemihostingCommand {
     /// The target indicated that it would like to write to the console.
     Write(WriteRequest),
 
+    /// The target indicated that it would like to read the value of errno.
+    Errno(ErrnoRequest),
+
     /// The target indicated that it would like to run a semihosting operation which we don't support yet.
     Unknown(UnknownCommandDetails),
 }
@@ -194,6 +197,17 @@ impl WriteRequest {
     }
 }
 
+/// A request to read the errno
+#[derive(Debug, PartialEq, Eq, Copy, Clone)]
+pub struct ErrnoRequest {}
+impl ErrnoRequest {
+    /// Writes the errno to the target
+    pub fn write_errno(&self, core: &mut dyn CoreInterface, errno: i32) -> Result<(), Error> {
+        // On exit, the RETURN REGISTER contains the value of the C library errno variable.
+        write_status(core, errno)
+    }
+}
+
 fn write_status(core: &mut dyn CoreInterface, value: i32) -> Result<(), crate::Error> {
     let reg = core.registers().get_argument_register(0).unwrap();
     core.write_core_reg(reg.into(), RegisterValue::U32(value as u32))?;
@@ -309,6 +323,7 @@ pub fn decode_semihosting_syscall(
     const SYS_WRITEC: u32 = 0x03;
     const SYS_WRITE0: u32 = 0x04;
     const SYS_WRITE: u32 = 0x05;
+    const SYS_ERRNO: u32 = 0x13;
 
     Ok(match (operation, parameter) {
         (SYS_EXIT, SYS_EXIT_ADP_STOPPED_APPLICATIONEXIT) => SemihostingCommand::ExitSuccess,
@@ -410,6 +425,8 @@ pub fn decode_semihosting_syscall(
             SemihostingCommand::Write(WriteRequest { handle, bytes, len })
         }
 
+        (SYS_ERRNO, 0) => SemihostingCommand::Errno(ErrnoRequest {}),
+
         _ => {
             // signal to target: status = failure, in case the application does not answer this request
             // It is not guaranteed that a value of -1 will be treated as an error by the target, but it is a common value to indicate an error.


Test patch:
diff --git a/probe-rs-tools/src/bin/probe-rs/rpc/functions/test.rs b/probe-rs-tools/src/bin/probe-rs/rpc/functions/test.rs
index 801cb1d3..2e5a7c1b 100644
--- a/probe-rs-tools/src/bin/probe-rs/rpc/functions/test.rs
+++ b/probe-rs-tools/src/bin/probe-rs/rpc/functions/test.rs
@@ -340,6 +340,7 @@ impl<F: FnMut(MonitorEvent)> ListEventHandler<F> {
                 }
                 Ok(None)
             }
+            SemihostingCommand::Errno(_) => Ok(None),
             other => anyhow::bail!(
                 "Unexpected semihosting command {:?} cmdline_requested: {:?}",
                 other,
@@ -403,6 +404,7 @@ impl<F: FnMut(MonitorEvent)> RunEventHandler<F> {
                 }
                 Ok(None)
             }
+            SemihostingCommand::Errno(_) => Ok(None),
             other => {
                 // Invalid sequence of semihosting calls => Abort testing altogether
                 anyhow::bail!(