xref: /openbmc/qemu/semihosting/config.c (revision 997ef293d229983fef0187fbcd99126412bd56e4)
18df9f0c3SPhilippe Mathieu-Daudé /*
28df9f0c3SPhilippe Mathieu-Daudé  * Semihosting configuration
38df9f0c3SPhilippe Mathieu-Daudé  *
48df9f0c3SPhilippe Mathieu-Daudé  * Copyright (c) 2015 Imagination Technologies
58df9f0c3SPhilippe Mathieu-Daudé  * Copyright (c) 2019 Linaro Ltd
68df9f0c3SPhilippe Mathieu-Daudé  *
78df9f0c3SPhilippe Mathieu-Daudé  * This controls the configuration of semihosting for all guest
88df9f0c3SPhilippe Mathieu-Daudé  * targets that support it. Architecture specific handling is handled
98df9f0c3SPhilippe Mathieu-Daudé  * in target/HW/HW-semi.c
108df9f0c3SPhilippe Mathieu-Daudé  *
11669dcb60SMichael Tokarev  * Semihosting is slightly strange in that it is also supported by some
128df9f0c3SPhilippe Mathieu-Daudé  * linux-user targets. However in that use case no configuration of
138df9f0c3SPhilippe Mathieu-Daudé  * the outputs and command lines is supported.
148df9f0c3SPhilippe Mathieu-Daudé  *
15f14eced5SPhilippe Mathieu-Daudé  * The config module is common to all system targets however as vl.c
168df9f0c3SPhilippe Mathieu-Daudé  * needs to link against the helpers.
178df9f0c3SPhilippe Mathieu-Daudé  *
188df9f0c3SPhilippe Mathieu-Daudé  * SPDX-License-Identifier: GPL-2.0-or-later
198df9f0c3SPhilippe Mathieu-Daudé  */
208df9f0c3SPhilippe Mathieu-Daudé 
218df9f0c3SPhilippe Mathieu-Daudé #include "qemu/osdep.h"
228df9f0c3SPhilippe Mathieu-Daudé #include "qemu/option.h"
238df9f0c3SPhilippe Mathieu-Daudé #include "qemu/config-file.h"
248df9f0c3SPhilippe Mathieu-Daudé #include "qemu/error-report.h"
258df9f0c3SPhilippe Mathieu-Daudé #include "semihosting/semihost.h"
268df9f0c3SPhilippe Mathieu-Daudé #include "chardev/char.h"
278df9f0c3SPhilippe Mathieu-Daudé 
288df9f0c3SPhilippe Mathieu-Daudé QemuOptsList qemu_semihosting_config_opts = {
298df9f0c3SPhilippe Mathieu-Daudé     .name = "semihosting-config",
3090c072e0SPeter Maydell     .merge_lists = true,
318df9f0c3SPhilippe Mathieu-Daudé     .implied_opt_name = "enable",
328df9f0c3SPhilippe Mathieu-Daudé     .head = QTAILQ_HEAD_INITIALIZER(qemu_semihosting_config_opts.head),
338df9f0c3SPhilippe Mathieu-Daudé     .desc = {
348df9f0c3SPhilippe Mathieu-Daudé         {
358df9f0c3SPhilippe Mathieu-Daudé             .name = "enable",
368df9f0c3SPhilippe Mathieu-Daudé             .type = QEMU_OPT_BOOL,
378df9f0c3SPhilippe Mathieu-Daudé         }, {
385202861bSPeter Maydell             .name = "userspace",
395202861bSPeter Maydell             .type = QEMU_OPT_BOOL,
405202861bSPeter Maydell         }, {
418df9f0c3SPhilippe Mathieu-Daudé             .name = "target",
428df9f0c3SPhilippe Mathieu-Daudé             .type = QEMU_OPT_STRING,
438df9f0c3SPhilippe Mathieu-Daudé         }, {
448df9f0c3SPhilippe Mathieu-Daudé             .name = "chardev",
458df9f0c3SPhilippe Mathieu-Daudé             .type = QEMU_OPT_STRING,
468df9f0c3SPhilippe Mathieu-Daudé         }, {
478df9f0c3SPhilippe Mathieu-Daudé             .name = "arg",
488df9f0c3SPhilippe Mathieu-Daudé             .type = QEMU_OPT_STRING,
498df9f0c3SPhilippe Mathieu-Daudé         },
508df9f0c3SPhilippe Mathieu-Daudé         { /* end of list */ }
518df9f0c3SPhilippe Mathieu-Daudé     },
528df9f0c3SPhilippe Mathieu-Daudé };
538df9f0c3SPhilippe Mathieu-Daudé 
548df9f0c3SPhilippe Mathieu-Daudé typedef struct SemihostingConfig {
558df9f0c3SPhilippe Mathieu-Daudé     bool enabled;
565202861bSPeter Maydell     bool userspace_enabled;
578df9f0c3SPhilippe Mathieu-Daudé     SemihostingTarget target;
5878beee80SAlex Bennée     char **argv;
598df9f0c3SPhilippe Mathieu-Daudé     int argc;
608df9f0c3SPhilippe Mathieu-Daudé     const char *cmdline; /* concatenated argv */
618df9f0c3SPhilippe Mathieu-Daudé } SemihostingConfig;
628df9f0c3SPhilippe Mathieu-Daudé 
638df9f0c3SPhilippe Mathieu-Daudé static SemihostingConfig semihosting;
648df9f0c3SPhilippe Mathieu-Daudé static const char *semihost_chardev;
658df9f0c3SPhilippe Mathieu-Daudé 
semihosting_enabled(bool is_user)665202861bSPeter Maydell bool semihosting_enabled(bool is_user)
678df9f0c3SPhilippe Mathieu-Daudé {
685202861bSPeter Maydell     return semihosting.enabled && (!is_user || semihosting.userspace_enabled);
698df9f0c3SPhilippe Mathieu-Daudé }
708df9f0c3SPhilippe Mathieu-Daudé 
semihosting_get_target(void)718df9f0c3SPhilippe Mathieu-Daudé SemihostingTarget semihosting_get_target(void)
728df9f0c3SPhilippe Mathieu-Daudé {
738df9f0c3SPhilippe Mathieu-Daudé     return semihosting.target;
748df9f0c3SPhilippe Mathieu-Daudé }
758df9f0c3SPhilippe Mathieu-Daudé 
semihosting_get_arg(int i)768df9f0c3SPhilippe Mathieu-Daudé const char *semihosting_get_arg(int i)
778df9f0c3SPhilippe Mathieu-Daudé {
788df9f0c3SPhilippe Mathieu-Daudé     if (i >= semihosting.argc) {
798df9f0c3SPhilippe Mathieu-Daudé         return NULL;
808df9f0c3SPhilippe Mathieu-Daudé     }
818df9f0c3SPhilippe Mathieu-Daudé     return semihosting.argv[i];
828df9f0c3SPhilippe Mathieu-Daudé }
838df9f0c3SPhilippe Mathieu-Daudé 
semihosting_get_argc(void)848df9f0c3SPhilippe Mathieu-Daudé int semihosting_get_argc(void)
858df9f0c3SPhilippe Mathieu-Daudé {
868df9f0c3SPhilippe Mathieu-Daudé     return semihosting.argc;
878df9f0c3SPhilippe Mathieu-Daudé }
888df9f0c3SPhilippe Mathieu-Daudé 
semihosting_get_cmdline(void)898df9f0c3SPhilippe Mathieu-Daudé const char *semihosting_get_cmdline(void)
908df9f0c3SPhilippe Mathieu-Daudé {
918df9f0c3SPhilippe Mathieu-Daudé     if (semihosting.cmdline == NULL && semihosting.argc > 0) {
928df9f0c3SPhilippe Mathieu-Daudé         semihosting.cmdline = g_strjoinv(" ", (gchar **)semihosting.argv);
938df9f0c3SPhilippe Mathieu-Daudé     }
948df9f0c3SPhilippe Mathieu-Daudé     return semihosting.cmdline;
958df9f0c3SPhilippe Mathieu-Daudé }
968df9f0c3SPhilippe Mathieu-Daudé 
add_semihosting_arg(void * opaque,const char * name,const char * val,Error ** errp)978df9f0c3SPhilippe Mathieu-Daudé static int add_semihosting_arg(void *opaque,
988df9f0c3SPhilippe Mathieu-Daudé                                const char *name, const char *val,
998df9f0c3SPhilippe Mathieu-Daudé                                Error **errp)
1008df9f0c3SPhilippe Mathieu-Daudé {
1018df9f0c3SPhilippe Mathieu-Daudé     SemihostingConfig *s = opaque;
1028df9f0c3SPhilippe Mathieu-Daudé     if (strcmp(name, "arg") == 0) {
1038df9f0c3SPhilippe Mathieu-Daudé         s->argc++;
1048df9f0c3SPhilippe Mathieu-Daudé         /* one extra element as g_strjoinv() expects NULL-terminated array */
10578beee80SAlex Bennée         s->argv = g_renew(char *, s->argv, s->argc + 1);
10678beee80SAlex Bennée         s->argv[s->argc - 1] = g_strdup(val);
1078df9f0c3SPhilippe Mathieu-Daudé         s->argv[s->argc] = NULL;
1088df9f0c3SPhilippe Mathieu-Daudé     }
1098df9f0c3SPhilippe Mathieu-Daudé     return 0;
1108df9f0c3SPhilippe Mathieu-Daudé }
1118df9f0c3SPhilippe Mathieu-Daudé 
1128df9f0c3SPhilippe Mathieu-Daudé /* Use strings passed via -kernel/-append to initialize semihosting.argv[] */
semihosting_arg_fallback(const char * file,const char * cmd)1138df9f0c3SPhilippe Mathieu-Daudé void semihosting_arg_fallback(const char *file, const char *cmd)
1148df9f0c3SPhilippe Mathieu-Daudé {
1158df9f0c3SPhilippe Mathieu-Daudé     char *cmd_token;
116*2eb71a0cSMatheus Tavares Bernardino     g_autofree char *cmd_dup = g_strdup(cmd);
1178df9f0c3SPhilippe Mathieu-Daudé 
1188df9f0c3SPhilippe Mathieu-Daudé     /* argv[0] */
1198df9f0c3SPhilippe Mathieu-Daudé     add_semihosting_arg(&semihosting, "arg", file, NULL);
1208df9f0c3SPhilippe Mathieu-Daudé 
1218df9f0c3SPhilippe Mathieu-Daudé     /* split -append and initialize argv[1..n] */
122*2eb71a0cSMatheus Tavares Bernardino     cmd_token = strtok(cmd_dup, " ");
1238df9f0c3SPhilippe Mathieu-Daudé     while (cmd_token) {
1248df9f0c3SPhilippe Mathieu-Daudé         add_semihosting_arg(&semihosting, "arg", cmd_token, NULL);
1258df9f0c3SPhilippe Mathieu-Daudé         cmd_token = strtok(NULL, " ");
1268df9f0c3SPhilippe Mathieu-Daudé     }
1278df9f0c3SPhilippe Mathieu-Daudé }
1288df9f0c3SPhilippe Mathieu-Daudé 
qemu_semihosting_enable(void)1298df9f0c3SPhilippe Mathieu-Daudé void qemu_semihosting_enable(void)
1308df9f0c3SPhilippe Mathieu-Daudé {
1318df9f0c3SPhilippe Mathieu-Daudé     semihosting.enabled = true;
1328df9f0c3SPhilippe Mathieu-Daudé     semihosting.target = SEMIHOSTING_TARGET_AUTO;
1338df9f0c3SPhilippe Mathieu-Daudé }
1348df9f0c3SPhilippe Mathieu-Daudé 
qemu_semihosting_config_options(const char * optstr)135afb81fe8SPhilippe Mathieu-Daudé int qemu_semihosting_config_options(const char *optstr)
1368df9f0c3SPhilippe Mathieu-Daudé {
1378df9f0c3SPhilippe Mathieu-Daudé     QemuOptsList *opt_list = qemu_find_opts("semihosting-config");
138afb81fe8SPhilippe Mathieu-Daudé     QemuOpts *opts = qemu_opts_parse_noisily(opt_list, optstr, false);
1398df9f0c3SPhilippe Mathieu-Daudé 
1408df9f0c3SPhilippe Mathieu-Daudé     semihosting.enabled = true;
1418df9f0c3SPhilippe Mathieu-Daudé 
1428df9f0c3SPhilippe Mathieu-Daudé     if (opts != NULL) {
1438df9f0c3SPhilippe Mathieu-Daudé         semihosting.enabled = qemu_opt_get_bool(opts, "enable",
1448df9f0c3SPhilippe Mathieu-Daudé                                                 true);
1455202861bSPeter Maydell         semihosting.userspace_enabled = qemu_opt_get_bool(opts, "userspace",
1465202861bSPeter Maydell                                                           false);
1478df9f0c3SPhilippe Mathieu-Daudé         const char *target = qemu_opt_get(opts, "target");
1488df9f0c3SPhilippe Mathieu-Daudé         /* setup of chardev is deferred until they are initialised */
1498df9f0c3SPhilippe Mathieu-Daudé         semihost_chardev = qemu_opt_get(opts, "chardev");
1508df9f0c3SPhilippe Mathieu-Daudé         if (target != NULL) {
1518df9f0c3SPhilippe Mathieu-Daudé             if (strcmp("native", target) == 0) {
1528df9f0c3SPhilippe Mathieu-Daudé                 semihosting.target = SEMIHOSTING_TARGET_NATIVE;
1538df9f0c3SPhilippe Mathieu-Daudé             } else if (strcmp("gdb", target) == 0) {
1548df9f0c3SPhilippe Mathieu-Daudé                 semihosting.target = SEMIHOSTING_TARGET_GDB;
1558df9f0c3SPhilippe Mathieu-Daudé             } else  if (strcmp("auto", target) == 0) {
1568df9f0c3SPhilippe Mathieu-Daudé                 semihosting.target = SEMIHOSTING_TARGET_AUTO;
1578df9f0c3SPhilippe Mathieu-Daudé             } else {
1588df9f0c3SPhilippe Mathieu-Daudé                 error_report("unsupported semihosting-config %s",
159afb81fe8SPhilippe Mathieu-Daudé                              optstr);
1608df9f0c3SPhilippe Mathieu-Daudé                 return 1;
1618df9f0c3SPhilippe Mathieu-Daudé             }
1628df9f0c3SPhilippe Mathieu-Daudé         } else {
1638df9f0c3SPhilippe Mathieu-Daudé             semihosting.target = SEMIHOSTING_TARGET_AUTO;
1648df9f0c3SPhilippe Mathieu-Daudé         }
1658df9f0c3SPhilippe Mathieu-Daudé         /* Set semihosting argument count and vector */
1668df9f0c3SPhilippe Mathieu-Daudé         qemu_opt_foreach(opts, add_semihosting_arg,
1678df9f0c3SPhilippe Mathieu-Daudé                          &semihosting, NULL);
1688df9f0c3SPhilippe Mathieu-Daudé     } else {
169afb81fe8SPhilippe Mathieu-Daudé         error_report("unsupported semihosting-config %s", optstr);
1708df9f0c3SPhilippe Mathieu-Daudé         return 1;
1718df9f0c3SPhilippe Mathieu-Daudé     }
1728df9f0c3SPhilippe Mathieu-Daudé 
1738df9f0c3SPhilippe Mathieu-Daudé     return 0;
1748df9f0c3SPhilippe Mathieu-Daudé }
1758df9f0c3SPhilippe Mathieu-Daudé 
1768df9f0c3SPhilippe Mathieu-Daudé /* We had to defer this until chardevs were created */
qemu_semihosting_chardev_init(void)177fb08790bSRichard Henderson void qemu_semihosting_chardev_init(void)
178fb08790bSRichard Henderson {
179fb08790bSRichard Henderson     Chardev *chr = NULL;
180fb08790bSRichard Henderson 
1818df9f0c3SPhilippe Mathieu-Daudé     if (semihost_chardev) {
182fb08790bSRichard Henderson         chr = qemu_chr_find(semihost_chardev);
1838df9f0c3SPhilippe Mathieu-Daudé         if (chr == NULL) {
1848df9f0c3SPhilippe Mathieu-Daudé             error_report("semihosting chardev '%s' not found",
1858df9f0c3SPhilippe Mathieu-Daudé                          semihost_chardev);
1868df9f0c3SPhilippe Mathieu-Daudé             exit(1);
1878df9f0c3SPhilippe Mathieu-Daudé         }
1888df9f0c3SPhilippe Mathieu-Daudé     }
189fb08790bSRichard Henderson 
190fb08790bSRichard Henderson     qemu_semihosting_console_init(chr);
1918df9f0c3SPhilippe Mathieu-Daudé }
192