arch: common: semihost: add semihosting operations
Add an API that utilizes the ARM semihosting mechanism to interact with the host system when a device is being emulated or run under a debugger. RISCV is implemented in terms of the ARM implementation, and therefore the ARM definitions cross enough architectures to be defined 'common'. Functionality is exposed as a separate API instead of syscall implementations (`_lseek`, `_open`, etc) due to various quirks with the ARM mechanisms that means function arguments are not standard. For more information see: https://developer.arm.com/documentation/dui0471/m/what-is-semihosting- Signed-off-by: Jordan Yates <jordan.yates@data61.csiro.au> impl
This commit is contained in:
parent
070422db46
commit
d8f186aa4a
|
@ -15,3 +15,4 @@ zephyr_library_sources(
|
||||||
)
|
)
|
||||||
|
|
||||||
zephyr_library_sources_ifdef(CONFIG_USERSPACE thread.c)
|
zephyr_library_sources_ifdef(CONFIG_USERSPACE thread.c)
|
||||||
|
zephyr_library_sources_ifdef(CONFIG_SEMIHOST semihost.c)
|
||||||
|
|
27
arch/arm/core/aarch32/cortex_a_r/semihost.c
Normal file
27
arch/arm/core/aarch32/cortex_a_r/semihost.c
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022, Commonwealth Scientific and Industrial Research
|
||||||
|
* Organisation (CSIRO) ABN 41 687 119 230.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <zephyr/sys/util_macro.h>
|
||||||
|
#include <zephyr/arch/common/semihost.h>
|
||||||
|
|
||||||
|
#if !(defined(CONFIG_ISA_ARM) || defined(CONFIG_ISA_THUMB2))
|
||||||
|
#error Unsupported ISA
|
||||||
|
#endif
|
||||||
|
|
||||||
|
long semihost_exec(enum semihost_instr instr, void *args)
|
||||||
|
{
|
||||||
|
register unsigned long r0 __asm__ ("r0") = instr;
|
||||||
|
register void *r1 __asm__ ("r1") = args;
|
||||||
|
register long ret __asm__ ("r0");
|
||||||
|
|
||||||
|
if (IS_ENABLED(CONFIG_ISA_THUMB2)) {
|
||||||
|
__asm__ __volatile__ ("svc 0xab" : : "r" (r0), "r" (r1) : "memory");
|
||||||
|
} else {
|
||||||
|
__asm__ __volatile__ ("svc 0x123456" : : "r" (r0), "r" (r1) : "memory");
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
|
@ -17,6 +17,7 @@ zephyr_library_sources(
|
||||||
zephyr_library_sources_ifdef(CONFIG_USERSPACE thread.c)
|
zephyr_library_sources_ifdef(CONFIG_USERSPACE thread.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_DEBUG_COREDUMP coredump.c)
|
zephyr_library_sources_ifdef(CONFIG_DEBUG_COREDUMP coredump.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_THREAD_LOCAL_STORAGE __aeabi_read_tp.S)
|
zephyr_library_sources_ifdef(CONFIG_THREAD_LOCAL_STORAGE __aeabi_read_tp.S)
|
||||||
|
zephyr_library_sources_ifdef(CONFIG_SEMIHOST semihost.c)
|
||||||
|
|
||||||
if(CONFIG_NULL_POINTER_EXCEPTION_DETECTION_DWT)
|
if(CONFIG_NULL_POINTER_EXCEPTION_DETECTION_DWT)
|
||||||
zephyr_library_sources(debug.c)
|
zephyr_library_sources(debug.c)
|
||||||
|
|
18
arch/arm/core/aarch32/cortex_m/semihost.c
Normal file
18
arch/arm/core/aarch32/cortex_m/semihost.c
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022, Commonwealth Scientific and Industrial Research
|
||||||
|
* Organisation (CSIRO) ABN 41 687 119 230.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <zephyr/arch/common/semihost.h>
|
||||||
|
|
||||||
|
long semihost_exec(enum semihost_instr instr, void *args)
|
||||||
|
{
|
||||||
|
register unsigned int r0 __asm__ ("r0") = instr;
|
||||||
|
register void *r1 __asm__ ("r1") = args;
|
||||||
|
register int ret __asm__ ("r0");
|
||||||
|
|
||||||
|
__asm__ __volatile__ ("bkpt 0xab" : : "r" (r0), "r" (r1) : "memory");
|
||||||
|
return ret;
|
||||||
|
}
|
|
@ -25,6 +25,7 @@ zephyr_library_sources_ifdef(CONFIG_THREAD_LOCAL_STORAGE tls.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_HAS_ARM_SMCCC smccc-call.S)
|
zephyr_library_sources_ifdef(CONFIG_HAS_ARM_SMCCC smccc-call.S)
|
||||||
zephyr_library_sources_ifdef(CONFIG_AARCH64_IMAGE_HEADER header.S)
|
zephyr_library_sources_ifdef(CONFIG_AARCH64_IMAGE_HEADER header.S)
|
||||||
zephyr_library_sources_ifdef(CONFIG_CACHE_MANAGEMENT cache.c)
|
zephyr_library_sources_ifdef(CONFIG_CACHE_MANAGEMENT cache.c)
|
||||||
|
zephyr_library_sources_ifdef(CONFIG_SEMIHOST semihost.c)
|
||||||
if ((CONFIG_MP_NUM_CPUS GREATER 1) OR (CONFIG_SMP))
|
if ((CONFIG_MP_NUM_CPUS GREATER 1) OR (CONFIG_SMP))
|
||||||
zephyr_library_sources(smp.c)
|
zephyr_library_sources(smp.c)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
18
arch/arm64/core/semihost.c
Normal file
18
arch/arm64/core/semihost.c
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022, Commonwealth Scientific and Industrial Research
|
||||||
|
* Organisation (CSIRO) ABN 41 687 119 230.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <zephyr/arch/common/semihost.h>
|
||||||
|
|
||||||
|
long semihost_exec(enum semihost_instr instr, void *args)
|
||||||
|
{
|
||||||
|
register unsigned long w0 __asm__ ("w0") = instr;
|
||||||
|
register void *x1 __asm__ ("x1") = args;
|
||||||
|
register long ret __asm__ ("x0");
|
||||||
|
|
||||||
|
__asm__ volatile ("hlt 0xf000" : : "r" (w0), "r" (x1) : "memory");
|
||||||
|
return ret;
|
||||||
|
}
|
|
@ -67,3 +67,5 @@ if(CONFIG_COVERAGE)
|
||||||
zephyr_compile_options($<TARGET_PROPERTY:compiler,coverage>)
|
zephyr_compile_options($<TARGET_PROPERTY:compiler,coverage>)
|
||||||
zephyr_link_libraries($<TARGET_PROPERTY:linker,coverage>)
|
zephyr_link_libraries($<TARGET_PROPERTY:linker,coverage>)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
zephyr_sources_ifdef(CONFIG_SEMIHOST semihost.c)
|
||||||
|
|
131
arch/common/semihost.c
Normal file
131
arch/common/semihost.c
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022, Commonwealth Scientific and Industrial Research
|
||||||
|
* Organisation (CSIRO) ABN 41 687 119 230.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <zephyr/kernel.h>
|
||||||
|
#include <zephyr/arch/common/semihost.h>
|
||||||
|
|
||||||
|
struct semihost_poll_in_args {
|
||||||
|
long zero;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct semihost_open_args {
|
||||||
|
const char *path;
|
||||||
|
long mode;
|
||||||
|
long path_len;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct semihost_close_args {
|
||||||
|
long fd;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct semihost_flen_args {
|
||||||
|
long fd;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct semihost_seek_args {
|
||||||
|
long fd;
|
||||||
|
long offset;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct semihost_read_args {
|
||||||
|
long fd;
|
||||||
|
char *buf;
|
||||||
|
long len;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct semihost_write_args {
|
||||||
|
long fd;
|
||||||
|
const char *buf;
|
||||||
|
long len;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
char semihost_poll_in(void)
|
||||||
|
{
|
||||||
|
struct semihost_poll_in_args args = {
|
||||||
|
.zero = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
return (char)semihost_exec(SEMIHOST_READC, &args);
|
||||||
|
}
|
||||||
|
|
||||||
|
void semihost_poll_out(char c)
|
||||||
|
{
|
||||||
|
/* WRITEC takes a pointer directly to the character */
|
||||||
|
(void)semihost_exec(SEMIHOST_WRITEC, &c);
|
||||||
|
}
|
||||||
|
|
||||||
|
long semihost_open(const char *path, long mode)
|
||||||
|
{
|
||||||
|
struct semihost_open_args args = {
|
||||||
|
.path = path,
|
||||||
|
.mode = mode,
|
||||||
|
.path_len = strlen(path)
|
||||||
|
};
|
||||||
|
|
||||||
|
return semihost_exec(SEMIHOST_OPEN, &args);
|
||||||
|
}
|
||||||
|
|
||||||
|
long semihost_close(long fd)
|
||||||
|
{
|
||||||
|
struct semihost_close_args args = {
|
||||||
|
.fd = fd
|
||||||
|
};
|
||||||
|
|
||||||
|
return semihost_exec(SEMIHOST_CLOSE, &args);
|
||||||
|
}
|
||||||
|
|
||||||
|
long semihost_flen(long fd)
|
||||||
|
{
|
||||||
|
struct semihost_flen_args args = {
|
||||||
|
.fd = fd
|
||||||
|
};
|
||||||
|
|
||||||
|
return semihost_exec(SEMIHOST_FLEN, &args);
|
||||||
|
}
|
||||||
|
|
||||||
|
long semihost_seek(long fd, long offset)
|
||||||
|
{
|
||||||
|
struct semihost_seek_args args = {
|
||||||
|
.fd = fd,
|
||||||
|
.offset = offset
|
||||||
|
};
|
||||||
|
|
||||||
|
return semihost_exec(SEMIHOST_SEEK, &args);
|
||||||
|
}
|
||||||
|
|
||||||
|
long semihost_read(long fd, void *buf, long len)
|
||||||
|
{
|
||||||
|
struct semihost_read_args args = {
|
||||||
|
.fd = fd,
|
||||||
|
.buf = buf,
|
||||||
|
.len = len
|
||||||
|
};
|
||||||
|
long ret;
|
||||||
|
|
||||||
|
ret = semihost_exec(SEMIHOST_READ, &args);
|
||||||
|
/* EOF condition */
|
||||||
|
if (ret == len) {
|
||||||
|
ret = -EIO;
|
||||||
|
}
|
||||||
|
/* All bytes read */
|
||||||
|
else if (ret == 0) {
|
||||||
|
ret = len;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
long semihost_write(long fd, const void *buf, long len)
|
||||||
|
{
|
||||||
|
struct semihost_write_args args = {
|
||||||
|
.fd = fd,
|
||||||
|
.buf = buf,
|
||||||
|
.len = len
|
||||||
|
};
|
||||||
|
|
||||||
|
return semihost_exec(SEMIHOST_WRITE, &args);
|
||||||
|
}
|
|
@ -21,3 +21,4 @@ zephyr_library_sources_ifdef(CONFIG_DEBUG_COREDUMP coredump.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_IRQ_OFFLOAD irq_offload.c)
|
zephyr_library_sources_ifdef(CONFIG_IRQ_OFFLOAD irq_offload.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_THREAD_LOCAL_STORAGE tls.c)
|
zephyr_library_sources_ifdef(CONFIG_THREAD_LOCAL_STORAGE tls.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_USERSPACE userspace.S)
|
zephyr_library_sources_ifdef(CONFIG_USERSPACE userspace.S)
|
||||||
|
zephyr_library_sources_ifdef(CONFIG_SEMIHOST semihost.c)
|
||||||
|
|
26
arch/riscv/core/semihost.c
Normal file
26
arch/riscv/core/semihost.c
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022, Commonwealth Scientific and Industrial Research
|
||||||
|
* Organisation (CSIRO) ABN 41 687 119 230.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <zephyr/arch/common/semihost.h>
|
||||||
|
|
||||||
|
long semihost_exec(enum semihost_instr instr, void *args)
|
||||||
|
{
|
||||||
|
register unsigned long a0 __asm__ ("a0") = instr;
|
||||||
|
register void *a1 __asm__ ("a1") = args;
|
||||||
|
register long ret __asm__ ("a0");
|
||||||
|
|
||||||
|
__asm__ volatile (
|
||||||
|
".option push\n\t"
|
||||||
|
".option norvc\n\t"
|
||||||
|
"slli zero, zero, 0x1f\n\t"
|
||||||
|
"ebreak\n\t"
|
||||||
|
"srai zero, zero, 0x7\n\t"
|
||||||
|
".option pop"
|
||||||
|
: : "r" (a0), "r" (a1) : "memory");
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
200
include/zephyr/arch/common/semihost.h
Normal file
200
include/zephyr/arch/common/semihost.h
Normal file
|
@ -0,0 +1,200 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022, Commonwealth Scientific and Industrial Research
|
||||||
|
* Organisation (CSIRO) ABN 41 687 119 230.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Based on the ARM semihosting API from:
|
||||||
|
* https://github.com/ARM-software/abi-aa/blob/main/semihosting/semihosting.rst
|
||||||
|
*
|
||||||
|
* RISC-V semihosting also follows these conventions:
|
||||||
|
* https://github.com/riscv/riscv-semihosting-spec/blob/main/riscv-semihosting-spec.adoc
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
*
|
||||||
|
* @brief public Semihosting APIs based on ARM definitions.
|
||||||
|
* @defgroup semihost Semihosting APIs
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ZEPHYR_INCLUDE_ARCH_COMMON_SEMIHOST_H_
|
||||||
|
#define ZEPHYR_INCLUDE_ARCH_COMMON_SEMIHOST_H_
|
||||||
|
|
||||||
|
/** @brief Semihosting instructions */
|
||||||
|
enum semihost_instr {
|
||||||
|
/*
|
||||||
|
* File I/O operations
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Open a file or stream on the host system. */
|
||||||
|
SEMIHOST_OPEN = 0x01,
|
||||||
|
/** Check whether a file is associated with a stream/terminal */
|
||||||
|
SEMIHOST_ISTTY = 0x09,
|
||||||
|
/** Write to a file or stream. */
|
||||||
|
SEMIHOST_WRITE = 0x05,
|
||||||
|
/** Read from a file at the current cursor position. */
|
||||||
|
SEMIHOST_READ = 0x06,
|
||||||
|
/** Closes a file on the host which has been opened by SEMIHOST_OPEN. */
|
||||||
|
SEMIHOST_CLOSE = 0x02,
|
||||||
|
/** Get the length of a file. */
|
||||||
|
SEMIHOST_FLEN = 0x0C,
|
||||||
|
/** Set the file cursor to a given position in a file. */
|
||||||
|
SEMIHOST_SEEK = 0x0A,
|
||||||
|
/** Get a temporary absolute file path to create a temporary file. */
|
||||||
|
SEMIHOST_TMPNAM = 0x0D,
|
||||||
|
/** Remove a file on the host system. Possibly insecure! */
|
||||||
|
SEMIHOST_REMOVE = 0x0E,
|
||||||
|
/** Rename a file on the host system. Possibly insecure! */
|
||||||
|
SEMIHOST_RENAME = 0x0F,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Terminal I/O operations
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Write one character to the debug terminal. */
|
||||||
|
SEMIHOST_WRITEC = 0x03,
|
||||||
|
/** Write a NULL terminated string to the debug terminal. */
|
||||||
|
SEMIHOST_WRITE0 = 0x04,
|
||||||
|
/** Read one character from the debug terminal. */
|
||||||
|
SEMIHOST_READC = 0x07,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Time operations
|
||||||
|
*/
|
||||||
|
SEMIHOST_CLOCK = 0x10,
|
||||||
|
SEMIHOST_ELAPSED = 0x30,
|
||||||
|
SEMIHOST_TICKFREQ = 0x31,
|
||||||
|
SEMIHOST_TIME = 0x11,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* System/Misc. operations
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Retrieve the errno variable from semihosting operations. */
|
||||||
|
SEMIHOST_ERRNO = 0x13,
|
||||||
|
/** Get commandline parameters for the application to run with */
|
||||||
|
SEMIHOST_GET_CMDLINE = 0x15,
|
||||||
|
SEMIHOST_HEAPINFO = 0x16,
|
||||||
|
SEMIHOST_ISERROR = 0x08,
|
||||||
|
SEMIHOST_SYSTEM = 0x12
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Modes to open a file with
|
||||||
|
*
|
||||||
|
* Behaviour corresponds to equivalent fopen strings.
|
||||||
|
* i.e. SEMIHOST_OPEN_RB_PLUS == "rb+"
|
||||||
|
*/
|
||||||
|
enum semihost_open_mode {
|
||||||
|
SEMIHOST_OPEN_R = 0,
|
||||||
|
SEMIHOST_OPEN_RB = 1,
|
||||||
|
SEMIHOST_OPEN_R_PLUS = 2,
|
||||||
|
SEMIHOST_OPEN_RB_PLUS = 3,
|
||||||
|
SEMIHOST_OPEN_W = 4,
|
||||||
|
SEMIHOST_OPEN_WB = 5,
|
||||||
|
SEMIHOST_OPEN_W_PLUS = 6,
|
||||||
|
SEMIHOST_OPEN_WB_PLUS = 7,
|
||||||
|
SEMIHOST_OPEN_A = 8,
|
||||||
|
SEMIHOST_OPEN_AB = 9,
|
||||||
|
SEMIHOST_OPEN_A_PLUS = 10,
|
||||||
|
SEMIHOST_OPEN_AB_PLUS = 11,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Manually execute a semihosting instruction
|
||||||
|
*
|
||||||
|
* @param instr instruction code to run
|
||||||
|
* @param args instruction specific arguments
|
||||||
|
*
|
||||||
|
* @return integer return code of instruction
|
||||||
|
*/
|
||||||
|
long semihost_exec(enum semihost_instr instr, void *args);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read a byte from the console
|
||||||
|
*
|
||||||
|
* @return char byte read from the console.
|
||||||
|
*/
|
||||||
|
char semihost_poll_in(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Write a byte to the console
|
||||||
|
*
|
||||||
|
* @param c byte to write to console
|
||||||
|
*/
|
||||||
|
void semihost_poll_out(char c);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Open a file on the host system
|
||||||
|
*
|
||||||
|
* @param path file path to open. Can be absolute or relative to current
|
||||||
|
* directory of the running process.
|
||||||
|
* @param mode value from @ref semihost_open_mode.
|
||||||
|
*
|
||||||
|
* @retval handle positive handle on success.
|
||||||
|
* @retval -1 on failure.
|
||||||
|
*/
|
||||||
|
long semihost_open(const char *path, long mode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Close a file
|
||||||
|
*
|
||||||
|
* @param fd handle returned by @ref semihost_open.
|
||||||
|
*
|
||||||
|
* @retval 0 on success.
|
||||||
|
* @retval -1 on failure.
|
||||||
|
*/
|
||||||
|
long semihost_close(long fd);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Query the size of a file
|
||||||
|
*
|
||||||
|
* @param fd handle returned by @ref semihost_open.
|
||||||
|
*
|
||||||
|
* @retval positive file size on success.
|
||||||
|
* @retval -1 on failure.
|
||||||
|
*/
|
||||||
|
long semihost_flen(long fd);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Seeks to an absolute position in a file.
|
||||||
|
*
|
||||||
|
* @param fd handle returned by @ref semihost_open.
|
||||||
|
* @param offset offset from the start of the file in bytes.
|
||||||
|
*
|
||||||
|
* @retval 0 on success.
|
||||||
|
* @retval -errno negative error code on failure.
|
||||||
|
*/
|
||||||
|
long semihost_seek(long fd, long offset);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read the contents of a file into a buffer.
|
||||||
|
*
|
||||||
|
* @param fd handle returned by @ref semihost_open.
|
||||||
|
* @param buf buffer to read data into.
|
||||||
|
* @param len number of bytes to read.
|
||||||
|
*
|
||||||
|
* @retval read number of bytes read on success.
|
||||||
|
* @retval -errno negative error code on failure.
|
||||||
|
*/
|
||||||
|
long semihost_read(long fd, void *buf, long len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Write the contents of a buffer into a file.
|
||||||
|
*
|
||||||
|
* @param fd handle returned by @ref semihost_open.
|
||||||
|
* @param buf buffer to write data from.
|
||||||
|
* @param len number of bytes to write.
|
||||||
|
*
|
||||||
|
* @retval 0 on success.
|
||||||
|
* @retval -errno negative error code on failure.
|
||||||
|
*/
|
||||||
|
long semihost_write(long fd, const void *buf, long len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#endif /* ZEPHYR_INCLUDE_ARCH_COMMON_SEMIHOST_H_ */
|
Loading…
Reference in a new issue