qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

config.c (5492B)


      1 /*
      2  * Semihosting configuration
      3  *
      4  * Copyright (c) 2015 Imagination Technologies
      5  * Copyright (c) 2019 Linaro Ltd
      6  *
      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
     10  *
     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.
     14  *
     15  * The config module is common to all softmmu targets however as vl.c
     16  * needs to link against the helpers.
     17  *
     18  * SPDX-License-Identifier: GPL-2.0-or-later
     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 
     28 QemuOptsList qemu_semihosting_config_opts = {
     29     .name = "semihosting-config",
     30     .merge_lists = true,
     31     .implied_opt_name = "enable",
     32     .head = QTAILQ_HEAD_INITIALIZER(qemu_semihosting_config_opts.head),
     33     .desc = {
     34         {
     35             .name = "enable",
     36             .type = QEMU_OPT_BOOL,
     37         }, {
     38             .name = "userspace",
     39             .type = QEMU_OPT_BOOL,
     40         }, {
     41             .name = "target",
     42             .type = QEMU_OPT_STRING,
     43         }, {
     44             .name = "chardev",
     45             .type = QEMU_OPT_STRING,
     46         }, {
     47             .name = "arg",
     48             .type = QEMU_OPT_STRING,
     49         },
     50         { /* end of list */ }
     51     },
     52 };
     53 
     54 typedef struct SemihostingConfig {
     55     bool enabled;
     56     bool userspace_enabled;
     57     SemihostingTarget target;
     58     char **argv;
     59     int argc;
     60     const char *cmdline; /* concatenated argv */
     61 } SemihostingConfig;
     62 
     63 static SemihostingConfig semihosting;
     64 static const char *semihost_chardev;
     65 
     66 bool semihosting_enabled(bool is_user)
     67 {
     68     return semihosting.enabled && (!is_user || semihosting.userspace_enabled);
     69 }
     70 
     71 SemihostingTarget semihosting_get_target(void)
     72 {
     73     return semihosting.target;
     74 }
     75 
     76 const char *semihosting_get_arg(int i)
     77 {
     78     if (i >= semihosting.argc) {
     79         return NULL;
     80     }
     81     return semihosting.argv[i];
     82 }
     83 
     84 int semihosting_get_argc(void)
     85 {
     86     return semihosting.argc;
     87 }
     88 
     89 const char *semihosting_get_cmdline(void)
     90 {
     91     if (semihosting.cmdline == NULL && semihosting.argc > 0) {
     92         semihosting.cmdline = g_strjoinv(" ", (gchar **)semihosting.argv);
     93     }
     94     return semihosting.cmdline;
     95 }
     96 
     97 static int add_semihosting_arg(void *opaque,
     98                                const char *name, const char *val,
     99                                Error **errp)
    100 {
    101     SemihostingConfig *s = opaque;
    102     if (strcmp(name, "arg") == 0) {
    103         s->argc++;
    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;
    108     }
    109     return 0;
    110 }
    111 
    112 /* Use strings passed via -kernel/-append to initialize semihosting.argv[] */
    113 void semihosting_arg_fallback(const char *file, const char *cmd)
    114 {
    115     char *cmd_token;
    116 
    117     /* argv[0] */
    118     add_semihosting_arg(&semihosting, "arg", file, NULL);
    119 
    120     /* split -append and initialize argv[1..n] */
    121     cmd_token = strtok(g_strdup(cmd), " ");
    122     while (cmd_token) {
    123         add_semihosting_arg(&semihosting, "arg", cmd_token, NULL);
    124         cmd_token = strtok(NULL, " ");
    125     }
    126 }
    127 
    128 void qemu_semihosting_enable(void)
    129 {
    130     semihosting.enabled = true;
    131     semihosting.target = SEMIHOSTING_TARGET_AUTO;
    132 }
    133 
    134 int qemu_semihosting_config_options(const char *optarg)
    135 {
    136     QemuOptsList *opt_list = qemu_find_opts("semihosting-config");
    137     QemuOpts *opts = qemu_opts_parse_noisily(opt_list, optarg, false);
    138 
    139     semihosting.enabled = true;
    140 
    141     if (opts != NULL) {
    142         semihosting.enabled = qemu_opt_get_bool(opts, "enable",
    143                                                 true);
    144         semihosting.userspace_enabled = qemu_opt_get_bool(opts, "userspace",
    145                                                           false);
    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;
    156             } else {
    157                 error_report("unsupported semihosting-config %s",
    158                              optarg);
    159                 return 1;
    160             }
    161         } else {
    162             semihosting.target = SEMIHOSTING_TARGET_AUTO;
    163         }
    164         /* Set semihosting argument count and vector */
    165         qemu_opt_foreach(opts, add_semihosting_arg,
    166                          &semihosting, NULL);
    167     } else {
    168         error_report("unsupported semihosting-config %s", optarg);
    169         return 1;
    170     }
    171 
    172     return 0;
    173 }
    174 
    175 /* We had to defer this until chardevs were created */
    176 void qemu_semihosting_chardev_init(void)
    177 {
    178     Chardev *chr = NULL;
    179 
    180     if (semihost_chardev) {
    181         chr = qemu_chr_find(semihost_chardev);
    182         if (chr == NULL) {
    183             error_report("semihosting chardev '%s' not found",
    184                          semihost_chardev);
    185             exit(1);
    186         }
    187     }
    188 
    189     qemu_semihosting_console_init(chr);
    190 }