mirror of
				https://github.com/qemu/qemu.git
				synced 2025-10-29 17:43:52 +00:00 
			
		
		
		
	 fb08790b35
			
		
	
	
		fb08790b35
		
	
	
	
	
		
			
			Rename qemu_semihosting_connect_chardevs to qemu_semihosting_chardev_init; pass the result directly to qemu_semihosting_console_init. Store the chardev in SemihostingConsole instead of SemihostingConfig, which lets us drop semihosting_get_chardev. Reviewed-by: Luc Michel <lmichel@kalray.eu> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
		
			
				
	
	
		
			185 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			185 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * 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 "semihosting/semihost.h"
 | |
| #include "chardev/char.h"
 | |
| 
 | |
| QemuOptsList qemu_semihosting_config_opts = {
 | |
|     .name = "semihosting-config",
 | |
|     .merge_lists = true,
 | |
|     .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 = "chardev",
 | |
|             .type = QEMU_OPT_STRING,
 | |
|         }, {
 | |
|             .name = "arg",
 | |
|             .type = QEMU_OPT_STRING,
 | |
|         },
 | |
|         { /* end of list */ }
 | |
|     },
 | |
| };
 | |
| 
 | |
| typedef struct SemihostingConfig {
 | |
|     bool enabled;
 | |
|     SemihostingTarget target;
 | |
|     char **argv;
 | |
|     int argc;
 | |
|     const char *cmdline; /* concatenated argv */
 | |
| } SemihostingConfig;
 | |
| 
 | |
| static SemihostingConfig semihosting;
 | |
| static const char *semihost_chardev;
 | |
| 
 | |
| 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_renew(char *, s->argv, s->argc + 1);
 | |
|         s->argv[s->argc - 1] = g_strdup(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");
 | |
|         /* setup of chardev is deferred until they are initialised */
 | |
|         semihost_chardev = qemu_opt_get(opts, "chardev");
 | |
|         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;
 | |
| }
 | |
| 
 | |
| /* We had to defer this until chardevs were created */
 | |
| void qemu_semihosting_chardev_init(void)
 | |
| {
 | |
|     Chardev *chr = NULL;
 | |
| 
 | |
|     if (semihost_chardev) {
 | |
|         chr = qemu_chr_find(semihost_chardev);
 | |
|         if (chr == NULL) {
 | |
|             error_report("semihosting chardev '%s' not found",
 | |
|                          semihost_chardev);
 | |
|             exit(1);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     qemu_semihosting_console_init(chr);
 | |
| }
 |