Commit f1672e6f authored by Alex Bennée's avatar Alex Bennée
Browse files

semihosting: move semihosting configuration into its own directory



In preparation for having some more common semihosting code let's
excise the current config magic from vl.c into its own file. We shall
later add more conditionals to the build configurations so we can
avoid building this if we don't need it.

Signed-off-by: default avatarAlex Bennée <alex.bennee@linaro.org>
Reviewed-by: default avatarPhilippe Mathieu-Daudé <philmd@redhat.com>
Tested-by: default avatarPhilippe Mathieu-Daudé <philmd@redhat.com>
Reviewed-by: default avatarRichard Henderson <richard.henderson@linaro.org>
parent a7b21f67
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -37,7 +37,7 @@
#include "qemu/sockets.h"
#include "sysemu/hw_accel.h"
#include "sysemu/kvm.h"
#include "exec/semihost.h"
#include "hw/semihosting/semihost.h"
#include "exec/exec-all.h"

#ifdef CONFIG_USER_ONLY
+1 −0
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ devices-dirs-$(CONFIG_SOFTMMU) += watchdog/
devices-dirs-$(CONFIG_SOFTMMU) += xen/
devices-dirs-$(CONFIG_MEM_DEVICE) += mem/
devices-dirs-$(CONFIG_SOFTMMU) += smbios/
devices-dirs-y += semihosting/
devices-dirs-y += core/
common-obj-y += $(devices-dirs-y)
obj-y += $(devices-dirs-y)
+1 −1
Original line number Diff line number Diff line
@@ -55,7 +55,7 @@
#include "qemu/error-report.h"
#include "hw/empty_slot.h"
#include "sysemu/kvm.h"
#include "exec/semihost.h"
#include "hw/semihosting/semihost.h"
#include "hw/mips/cps.h"

#define ENVP_ADDR		0x80002000l
+1 −0
Original line number Diff line number Diff line
common-obj-$(CONFIG_SOFTMMU) += config.o
+160 −0
Original line number Diff line number Diff line
/*
 * Semihosting configuration
 *
 * Copyright (c) 2015 Imagination Technologies
 * Copyright (c) 2019 Linaro Ltd
 *
 * This controls the configuration of semihosting for all guest
 * targets that support it. Architecture specific handling is handled
 * in target/HW/HW-semi.c
 *
 * Semihosting is sightly strange in that it is also supported by some
 * linux-user targets. However in that use case no configuration of
 * the outputs and command lines is supported.
 *
 * The config module is common to all softmmu targets however as vl.c
 * needs to link against the helpers.
 *
 * SPDX-License-Identifier: GPL-2.0-or-later
 */

#include "qemu/osdep.h"
#include "qemu/option.h"
#include "qemu/config-file.h"
#include "qemu/error-report.h"
#include "hw/semihosting/semihost.h"

QemuOptsList qemu_semihosting_config_opts = {
    .name = "semihosting-config",
    .implied_opt_name = "enable",
    .head = QTAILQ_HEAD_INITIALIZER(qemu_semihosting_config_opts.head),
    .desc = {
        {
            .name = "enable",
            .type = QEMU_OPT_BOOL,
        }, {
            .name = "target",
            .type = QEMU_OPT_STRING,
        }, {
            .name = "arg",
            .type = QEMU_OPT_STRING,
        },
        { /* end of list */ }
    },
};

typedef struct SemihostingConfig {
    bool enabled;
    SemihostingTarget target;
    const char **argv;
    int argc;
    const char *cmdline; /* concatenated argv */
} SemihostingConfig;

static SemihostingConfig semihosting;

bool semihosting_enabled(void)
{
    return semihosting.enabled;
}

SemihostingTarget semihosting_get_target(void)
{
    return semihosting.target;
}

const char *semihosting_get_arg(int i)
{
    if (i >= semihosting.argc) {
        return NULL;
    }
    return semihosting.argv[i];
}

int semihosting_get_argc(void)
{
    return semihosting.argc;
}

const char *semihosting_get_cmdline(void)
{
    if (semihosting.cmdline == NULL && semihosting.argc > 0) {
        semihosting.cmdline = g_strjoinv(" ", (gchar **)semihosting.argv);
    }
    return semihosting.cmdline;
}

static int add_semihosting_arg(void *opaque,
                               const char *name, const char *val,
                               Error **errp)
{
    SemihostingConfig *s = opaque;
    if (strcmp(name, "arg") == 0) {
        s->argc++;
        /* one extra element as g_strjoinv() expects NULL-terminated array */
        s->argv = g_realloc(s->argv, (s->argc + 1) * sizeof(void *));
        s->argv[s->argc - 1] = val;
        s->argv[s->argc] = NULL;
    }
    return 0;
}

/* Use strings passed via -kernel/-append to initialize semihosting.argv[] */
void semihosting_arg_fallback(const char *file, const char *cmd)
{
    char *cmd_token;

    /* argv[0] */
    add_semihosting_arg(&semihosting, "arg", file, NULL);

    /* split -append and initialize argv[1..n] */
    cmd_token = strtok(g_strdup(cmd), " ");
    while (cmd_token) {
        add_semihosting_arg(&semihosting, "arg", cmd_token, NULL);
        cmd_token = strtok(NULL, " ");
    }
}

void qemu_semihosting_enable(void)
{
    semihosting.enabled = true;
    semihosting.target = SEMIHOSTING_TARGET_AUTO;
}

int qemu_semihosting_config_options(const char *optarg)
{
    QemuOptsList *opt_list = qemu_find_opts("semihosting-config");
    QemuOpts *opts = qemu_opts_parse_noisily(opt_list, optarg, false);

    semihosting.enabled = true;

    if (opts != NULL) {
        semihosting.enabled = qemu_opt_get_bool(opts, "enable",
                                                true);
        const char *target = qemu_opt_get(opts, "target");
        if (target != NULL) {
            if (strcmp("native", target) == 0) {
                semihosting.target = SEMIHOSTING_TARGET_NATIVE;
            } else if (strcmp("gdb", target) == 0) {
                semihosting.target = SEMIHOSTING_TARGET_GDB;
            } else  if (strcmp("auto", target) == 0) {
                semihosting.target = SEMIHOSTING_TARGET_AUTO;
            } else {
                error_report("unsupported semihosting-config %s",
                             optarg);
                return 1;
            }
        } else {
            semihosting.target = SEMIHOSTING_TARGET_AUTO;
        }
        /* Set semihosting argument count and vector */
        qemu_opt_foreach(opts, add_semihosting_arg,
                         &semihosting, NULL);
    } else {
        error_report("unsupported semihosting-config %s", optarg);
        return 1;
    }

    return 0;
}
Loading