zephyr/arch/common/semihost.c
Jordan Yates d8f186aa4a 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
2022-04-21 13:04:52 +02:00

132 lines
2.1 KiB
C

/*
* 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);
}