1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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"
27
28QemuOptsList qemu_semihosting_config_opts = {
29 .name = "semihosting-config",
30 .implied_opt_name = "enable",
31 .head = QTAILQ_HEAD_INITIALIZER(qemu_semihosting_config_opts.head),
32 .desc = {
33 {
34 .name = "enable",
35 .type = QEMU_OPT_BOOL,
36 }, {
37 .name = "target",
38 .type = QEMU_OPT_STRING,
39 }, {
40 .name = "chardev",
41 .type = QEMU_OPT_STRING,
42 }, {
43 .name = "arg",
44 .type = QEMU_OPT_STRING,
45 },
46 { }
47 },
48};
49
50typedef struct SemihostingConfig {
51 bool enabled;
52 SemihostingTarget target;
53 Chardev *chardev;
54 const char **argv;
55 int argc;
56 const char *cmdline;
57} SemihostingConfig;
58
59static SemihostingConfig semihosting;
60static const char *semihost_chardev;
61
62bool semihosting_enabled(void)
63{
64 return semihosting.enabled;
65}
66
67SemihostingTarget semihosting_get_target(void)
68{
69 return semihosting.target;
70}
71
72const char *semihosting_get_arg(int i)
73{
74 if (i >= semihosting.argc) {
75 return NULL;
76 }
77 return semihosting.argv[i];
78}
79
80int semihosting_get_argc(void)
81{
82 return semihosting.argc;
83}
84
85const char *semihosting_get_cmdline(void)
86{
87 if (semihosting.cmdline == NULL && semihosting.argc > 0) {
88 semihosting.cmdline = g_strjoinv(" ", (gchar **)semihosting.argv);
89 }
90 return semihosting.cmdline;
91}
92
93static int add_semihosting_arg(void *opaque,
94 const char *name, const char *val,
95 Error **errp)
96{
97 SemihostingConfig *s = opaque;
98 if (strcmp(name, "arg") == 0) {
99 s->argc++;
100
101 s->argv = g_realloc(s->argv, (s->argc + 1) * sizeof(void *));
102 s->argv[s->argc - 1] = val;
103 s->argv[s->argc] = NULL;
104 }
105 return 0;
106}
107
108
109void semihosting_arg_fallback(const char *file, const char *cmd)
110{
111 char *cmd_token;
112
113
114 add_semihosting_arg(&semihosting, "arg", file, NULL);
115
116
117 cmd_token = strtok(g_strdup(cmd), " ");
118 while (cmd_token) {
119 add_semihosting_arg(&semihosting, "arg", cmd_token, NULL);
120 cmd_token = strtok(NULL, " ");
121 }
122}
123
124Chardev *semihosting_get_chardev(void)
125{
126 return semihosting.chardev;
127}
128
129void qemu_semihosting_enable(void)
130{
131 semihosting.enabled = true;
132 semihosting.target = SEMIHOSTING_TARGET_AUTO;
133}
134
135int qemu_semihosting_config_options(const char *optarg)
136{
137 QemuOptsList *opt_list = qemu_find_opts("semihosting-config");
138 QemuOpts *opts = qemu_opts_parse_noisily(opt_list, optarg, false);
139
140 semihosting.enabled = true;
141
142 if (opts != NULL) {
143 semihosting.enabled = qemu_opt_get_bool(opts, "enable",
144 true);
145 const char *target = qemu_opt_get(opts, "target");
146
147 semihost_chardev = qemu_opt_get(opts, "chardev");
148 if (target != NULL) {
149 if (strcmp("native", target) == 0) {
150 semihosting.target = SEMIHOSTING_TARGET_NATIVE;
151 } else if (strcmp("gdb", target) == 0) {
152 semihosting.target = SEMIHOSTING_TARGET_GDB;
153 } else if (strcmp("auto", target) == 0) {
154 semihosting.target = SEMIHOSTING_TARGET_AUTO;
155 } else {
156 error_report("unsupported semihosting-config %s",
157 optarg);
158 return 1;
159 }
160 } else {
161 semihosting.target = SEMIHOSTING_TARGET_AUTO;
162 }
163
164 qemu_opt_foreach(opts, add_semihosting_arg,
165 &semihosting, NULL);
166 } else {
167 error_report("unsupported semihosting-config %s", optarg);
168 return 1;
169 }
170
171 return 0;
172}
173
174void qemu_semihosting_connect_chardevs(void)
175{
176
177 if (semihost_chardev) {
178 Chardev *chr = qemu_chr_find(semihost_chardev);
179 if (chr == NULL) {
180 error_report("semihosting chardev '%s' not found",
181 semihost_chardev);
182 exit(1);
183 }
184 semihosting.chardev = chr;
185 }
186}
187