mirror of https://github.com/xemu-project/xemu.git
semihosting: enable chardev backed output for console
It will be useful for a number of use-cases to be able to re-direct output to a file like we do with serial output. This does the wiring to allow us to treat then semihosting console like just another character output device. Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
This commit is contained in:
parent
a331c6d774
commit
4e7f9032cf
|
@ -23,6 +23,7 @@
|
||||||
#include "qemu/config-file.h"
|
#include "qemu/config-file.h"
|
||||||
#include "qemu/error-report.h"
|
#include "qemu/error-report.h"
|
||||||
#include "hw/semihosting/semihost.h"
|
#include "hw/semihosting/semihost.h"
|
||||||
|
#include "chardev/char.h"
|
||||||
|
|
||||||
QemuOptsList qemu_semihosting_config_opts = {
|
QemuOptsList qemu_semihosting_config_opts = {
|
||||||
.name = "semihosting-config",
|
.name = "semihosting-config",
|
||||||
|
@ -35,6 +36,9 @@ QemuOptsList qemu_semihosting_config_opts = {
|
||||||
}, {
|
}, {
|
||||||
.name = "target",
|
.name = "target",
|
||||||
.type = QEMU_OPT_STRING,
|
.type = QEMU_OPT_STRING,
|
||||||
|
}, {
|
||||||
|
.name = "chardev",
|
||||||
|
.type = QEMU_OPT_STRING,
|
||||||
}, {
|
}, {
|
||||||
.name = "arg",
|
.name = "arg",
|
||||||
.type = QEMU_OPT_STRING,
|
.type = QEMU_OPT_STRING,
|
||||||
|
@ -46,12 +50,14 @@ QemuOptsList qemu_semihosting_config_opts = {
|
||||||
typedef struct SemihostingConfig {
|
typedef struct SemihostingConfig {
|
||||||
bool enabled;
|
bool enabled;
|
||||||
SemihostingTarget target;
|
SemihostingTarget target;
|
||||||
|
Chardev *chardev;
|
||||||
const char **argv;
|
const char **argv;
|
||||||
int argc;
|
int argc;
|
||||||
const char *cmdline; /* concatenated argv */
|
const char *cmdline; /* concatenated argv */
|
||||||
} SemihostingConfig;
|
} SemihostingConfig;
|
||||||
|
|
||||||
static SemihostingConfig semihosting;
|
static SemihostingConfig semihosting;
|
||||||
|
static const char *semihost_chardev;
|
||||||
|
|
||||||
bool semihosting_enabled(void)
|
bool semihosting_enabled(void)
|
||||||
{
|
{
|
||||||
|
@ -115,6 +121,11 @@ void semihosting_arg_fallback(const char *file, const char *cmd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Chardev *semihosting_get_chardev(void)
|
||||||
|
{
|
||||||
|
return semihosting.chardev;
|
||||||
|
}
|
||||||
|
|
||||||
void qemu_semihosting_enable(void)
|
void qemu_semihosting_enable(void)
|
||||||
{
|
{
|
||||||
semihosting.enabled = true;
|
semihosting.enabled = true;
|
||||||
|
@ -132,6 +143,8 @@ int qemu_semihosting_config_options(const char *optarg)
|
||||||
semihosting.enabled = qemu_opt_get_bool(opts, "enable",
|
semihosting.enabled = qemu_opt_get_bool(opts, "enable",
|
||||||
true);
|
true);
|
||||||
const char *target = qemu_opt_get(opts, "target");
|
const char *target = qemu_opt_get(opts, "target");
|
||||||
|
/* setup of chardev is deferred until they are initialised */
|
||||||
|
semihost_chardev = qemu_opt_get(opts, "chardev");
|
||||||
if (target != NULL) {
|
if (target != NULL) {
|
||||||
if (strcmp("native", target) == 0) {
|
if (strcmp("native", target) == 0) {
|
||||||
semihosting.target = SEMIHOSTING_TARGET_NATIVE;
|
semihosting.target = SEMIHOSTING_TARGET_NATIVE;
|
||||||
|
@ -158,3 +171,16 @@ int qemu_semihosting_config_options(const char *optarg)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void qemu_semihosting_connect_chardevs(void)
|
||||||
|
{
|
||||||
|
/* We had to defer this until chardevs were created */
|
||||||
|
if (semihost_chardev) {
|
||||||
|
Chardev *chr = qemu_chr_find(semihost_chardev);
|
||||||
|
if (chr == NULL) {
|
||||||
|
error_report("semihosting chardev '%s' not found",
|
||||||
|
semihost_chardev);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
semihosting.chardev = chr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -17,13 +17,20 @@
|
||||||
|
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
|
#include "hw/semihosting/semihost.h"
|
||||||
#include "hw/semihosting/console.h"
|
#include "hw/semihosting/console.h"
|
||||||
#include "exec/gdbstub.h"
|
#include "exec/gdbstub.h"
|
||||||
#include "qemu/log.h"
|
#include "qemu/log.h"
|
||||||
|
#include "chardev/char.h"
|
||||||
|
|
||||||
int qemu_semihosting_log_out(const char *s, int len)
|
int qemu_semihosting_log_out(const char *s, int len)
|
||||||
{
|
{
|
||||||
return write(STDERR_FILENO, s, len);
|
Chardev *chardev = semihosting_get_chardev();
|
||||||
|
if (chardev) {
|
||||||
|
return qemu_chr_write_all(chardev, (uint8_t *) s, len);
|
||||||
|
} else {
|
||||||
|
return write(STDERR_FILENO, s, len);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -51,6 +51,11 @@ static inline const char *semihosting_get_cmdline(void)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline Chardev *semihosting_get_chardev(void)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
#else /* !CONFIG_USER_ONLY */
|
#else /* !CONFIG_USER_ONLY */
|
||||||
bool semihosting_enabled(void);
|
bool semihosting_enabled(void);
|
||||||
SemihostingTarget semihosting_get_target(void);
|
SemihostingTarget semihosting_get_target(void);
|
||||||
|
@ -58,9 +63,11 @@ const char *semihosting_get_arg(int i);
|
||||||
int semihosting_get_argc(void);
|
int semihosting_get_argc(void);
|
||||||
const char *semihosting_get_cmdline(void);
|
const char *semihosting_get_cmdline(void);
|
||||||
void semihosting_arg_fallback(const char *file, const char *cmd);
|
void semihosting_arg_fallback(const char *file, const char *cmd);
|
||||||
|
Chardev *semihosting_get_chardev(void);
|
||||||
/* for vl.c hooks */
|
/* for vl.c hooks */
|
||||||
void qemu_semihosting_enable(void);
|
void qemu_semihosting_enable(void);
|
||||||
int qemu_semihosting_config_options(const char *opt);
|
int qemu_semihosting_config_options(const char *opt);
|
||||||
|
void qemu_semihosting_connect_chardevs(void);
|
||||||
#endif /* CONFIG_USER_ONLY */
|
#endif /* CONFIG_USER_ONLY */
|
||||||
|
|
||||||
#endif /* SEMIHOST_H */
|
#endif /* SEMIHOST_H */
|
||||||
|
|
|
@ -4025,12 +4025,12 @@ STEXI
|
||||||
Enable semihosting mode (ARM, M68K, Xtensa, MIPS, Nios II only).
|
Enable semihosting mode (ARM, M68K, Xtensa, MIPS, Nios II only).
|
||||||
ETEXI
|
ETEXI
|
||||||
DEF("semihosting-config", HAS_ARG, QEMU_OPTION_semihosting_config,
|
DEF("semihosting-config", HAS_ARG, QEMU_OPTION_semihosting_config,
|
||||||
"-semihosting-config [enable=on|off][,target=native|gdb|auto][,arg=str[,...]]\n" \
|
"-semihosting-config [enable=on|off][,target=native|gdb|auto][,chardev=id][,arg=str[,...]]\n" \
|
||||||
" semihosting configuration\n",
|
" semihosting configuration\n",
|
||||||
QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA | QEMU_ARCH_LM32 |
|
QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA | QEMU_ARCH_LM32 |
|
||||||
QEMU_ARCH_MIPS | QEMU_ARCH_NIOS2)
|
QEMU_ARCH_MIPS | QEMU_ARCH_NIOS2)
|
||||||
STEXI
|
STEXI
|
||||||
@item -semihosting-config [enable=on|off][,target=native|gdb|auto][,arg=str[,...]]
|
@item -semihosting-config [enable=on|off][,target=native|gdb|auto][,chardev=id][,arg=str[,...]]
|
||||||
@findex -semihosting-config
|
@findex -semihosting-config
|
||||||
Enable and configure semihosting (ARM, M68K, Xtensa, MIPS, Nios II only).
|
Enable and configure semihosting (ARM, M68K, Xtensa, MIPS, Nios II only).
|
||||||
@table @option
|
@table @option
|
||||||
|
@ -4038,6 +4038,8 @@ Enable and configure semihosting (ARM, M68K, Xtensa, MIPS, Nios II only).
|
||||||
Defines where the semihosting calls will be addressed, to QEMU (@code{native})
|
Defines where the semihosting calls will be addressed, to QEMU (@code{native})
|
||||||
or to GDB (@code{gdb}). The default is @code{auto}, which means @code{gdb}
|
or to GDB (@code{gdb}). The default is @code{auto}, which means @code{gdb}
|
||||||
during debug sessions and @code{native} otherwise.
|
during debug sessions and @code{native} otherwise.
|
||||||
|
@item chardev=@var{str1}
|
||||||
|
Send the output to a chardev backend output for native or auto output when not in gdb
|
||||||
@item arg=@var{str1},arg=@var{str2},...
|
@item arg=@var{str1},arg=@var{str2},...
|
||||||
Allows the user to pass input arguments, and can be used multiple times to build
|
Allows the user to pass input arguments, and can be used multiple times to build
|
||||||
up a list. The old-style @code{-kernel}/@code{-append} method of passing a
|
up a list. The old-style @code{-kernel}/@code{-append} method of passing a
|
||||||
|
|
|
@ -64,3 +64,7 @@ const char *semihosting_get_cmdline(void)
|
||||||
void semihosting_arg_fallback(const char *file, const char *cmd)
|
void semihosting_arg_fallback(const char *file, const char *cmd)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void qemu_semihosting_connect_chardevs(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
2
vl.c
2
vl.c
|
@ -4170,6 +4170,8 @@ int main(int argc, char **argv, char **envp)
|
||||||
|
|
||||||
qemu_opts_foreach(qemu_find_opts("chardev"),
|
qemu_opts_foreach(qemu_find_opts("chardev"),
|
||||||
chardev_init_func, NULL, &error_fatal);
|
chardev_init_func, NULL, &error_fatal);
|
||||||
|
/* now chardevs have been created we may have semihosting to connect */
|
||||||
|
qemu_semihosting_connect_chardevs();
|
||||||
|
|
||||||
#ifdef CONFIG_VIRTFS
|
#ifdef CONFIG_VIRTFS
|
||||||
qemu_opts_foreach(qemu_find_opts("fsdev"),
|
qemu_opts_foreach(qemu_find_opts("fsdev"),
|
||||||
|
|
Loading…
Reference in New Issue