2 * Semihosting configuration
4 * Copyright (c) 2015 Imagination Technologies
5 * Copyright (c) 2019 Linaro Ltd
7 * This controls the configuration of semihosting for all guest
8 * targets that support it. Architecture specific handling is handled
9 * in target/HW/HW-semi.c
11 * Semihosting is sightly strange in that it is also supported by some
12 * linux-user targets. However in that use case no configuration of
13 * the outputs and command lines is supported.
15 * The config module is common to all softmmu targets however as vl.c
16 * needs to link against the helpers.
18 * SPDX-License-Identifier: GPL-2.0-or-later
21 #include "qemu/osdep.h"
22 #include "qemu/option.h"
23 #include "qemu/config-file.h"
24 #include "qemu/error-report.h"
25 #include "semihosting/semihost.h"
26 #include "chardev/char.h"
28 QemuOptsList qemu_semihosting_config_opts
= {
29 .name
= "semihosting-config",
31 .implied_opt_name
= "enable",
32 .head
= QTAILQ_HEAD_INITIALIZER(qemu_semihosting_config_opts
.head
),
36 .type
= QEMU_OPT_BOOL
,
39 .type
= QEMU_OPT_BOOL
,
42 .type
= QEMU_OPT_STRING
,
45 .type
= QEMU_OPT_STRING
,
48 .type
= QEMU_OPT_STRING
,
54 typedef struct SemihostingConfig
{
56 bool userspace_enabled
;
57 SemihostingTarget target
;
60 const char *cmdline
; /* concatenated argv */
63 static SemihostingConfig semihosting
;
64 static const char *semihost_chardev
;
66 bool semihosting_enabled(bool is_user
)
68 return semihosting
.enabled
&& (!is_user
|| semihosting
.userspace_enabled
);
71 SemihostingTarget
semihosting_get_target(void)
73 return semihosting
.target
;
76 const char *semihosting_get_arg(int i
)
78 if (i
>= semihosting
.argc
) {
81 return semihosting
.argv
[i
];
84 int semihosting_get_argc(void)
86 return semihosting
.argc
;
89 const char *semihosting_get_cmdline(void)
91 if (semihosting
.cmdline
== NULL
&& semihosting
.argc
> 0) {
92 semihosting
.cmdline
= g_strjoinv(" ", (gchar
**)semihosting
.argv
);
94 return semihosting
.cmdline
;
97 static int add_semihosting_arg(void *opaque
,
98 const char *name
, const char *val
,
101 SemihostingConfig
*s
= opaque
;
102 if (strcmp(name
, "arg") == 0) {
104 /* one extra element as g_strjoinv() expects NULL-terminated array */
105 s
->argv
= g_renew(char *, s
->argv
, s
->argc
+ 1);
106 s
->argv
[s
->argc
- 1] = g_strdup(val
);
107 s
->argv
[s
->argc
] = NULL
;
112 /* Use strings passed via -kernel/-append to initialize semihosting.argv[] */
113 void semihosting_arg_fallback(const char *file
, const char *cmd
)
118 add_semihosting_arg(&semihosting
, "arg", file
, NULL
);
120 /* split -append and initialize argv[1..n] */
121 cmd_token
= strtok(g_strdup(cmd
), " ");
123 add_semihosting_arg(&semihosting
, "arg", cmd_token
, NULL
);
124 cmd_token
= strtok(NULL
, " ");
128 void qemu_semihosting_enable(void)
130 semihosting
.enabled
= true;
131 semihosting
.target
= SEMIHOSTING_TARGET_AUTO
;
134 int qemu_semihosting_config_options(const char *optarg
)
136 QemuOptsList
*opt_list
= qemu_find_opts("semihosting-config");
137 QemuOpts
*opts
= qemu_opts_parse_noisily(opt_list
, optarg
, false);
139 semihosting
.enabled
= true;
142 semihosting
.enabled
= qemu_opt_get_bool(opts
, "enable",
144 semihosting
.userspace_enabled
= qemu_opt_get_bool(opts
, "userspace",
146 const char *target
= qemu_opt_get(opts
, "target");
147 /* setup of chardev is deferred until they are initialised */
148 semihost_chardev
= qemu_opt_get(opts
, "chardev");
149 if (target
!= NULL
) {
150 if (strcmp("native", target
) == 0) {
151 semihosting
.target
= SEMIHOSTING_TARGET_NATIVE
;
152 } else if (strcmp("gdb", target
) == 0) {
153 semihosting
.target
= SEMIHOSTING_TARGET_GDB
;
154 } else if (strcmp("auto", target
) == 0) {
155 semihosting
.target
= SEMIHOSTING_TARGET_AUTO
;
157 error_report("unsupported semihosting-config %s",
162 semihosting
.target
= SEMIHOSTING_TARGET_AUTO
;
164 /* Set semihosting argument count and vector */
165 qemu_opt_foreach(opts
, add_semihosting_arg
,
168 error_report("unsupported semihosting-config %s", optarg
);
175 /* We had to defer this until chardevs were created */
176 void qemu_semihosting_chardev_init(void)
180 if (semihost_chardev
) {
181 chr
= qemu_chr_find(semihost_chardev
);
183 error_report("semihosting chardev '%s' not found",
189 qemu_semihosting_console_init(chr
);