From patchwork Fri Apr 17 17:11:02 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Liviu Ionescu X-Patchwork-Id: 462164 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 9D8921402BD for ; Sat, 18 Apr 2015 03:11:32 +1000 (AEST) Received: from localhost ([::1]:42775 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Yj9ne-000061-29 for incoming@patchwork.ozlabs.org; Fri, 17 Apr 2015 13:11:30 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:50591) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Yj9nL-0008CF-LX for qemu-devel@nongnu.org; Fri, 17 Apr 2015 13:11:13 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Yj9nH-0006vQ-UT for qemu-devel@nongnu.org; Fri, 17 Apr 2015 13:11:11 -0400 Received: from mail-wg0-f48.google.com ([74.125.82.48]:35034) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Yj9nH-0006vG-Lm for qemu-devel@nongnu.org; Fri, 17 Apr 2015 13:11:07 -0400 Received: by wgyo15 with SMTP id o15so119942576wgy.2 for ; Fri, 17 Apr 2015 10:11:06 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:content-type:content-transfer-encoding :subject:date:message-id:cc:to:mime-version; bh=lGkAEHXevDPl3J3xMVTJ2FBjXHsPElVthoEN10XKvzQ=; b=c+0MSXoxuyK/kvaFJ+bKvng4eJbbt441ueStNwvsQLKIsx3R1koOPtlSB1RgsJTD3Y /gDOvJP91Cj9nVC3JuHWUPc4x4jKxPaBM5iWmz63llSk0l+BuzY4/w95n8tqkOtbHtkC NhkCxXwWi2CbeVUZb20WfEnZ3BUiDeImMeR3GqhfIemg7IcNHgdGG6+R9hq1z9CVxmec vESc9svm2ify1BXU9rLF2PlvtKzKl1vFeGWL6geF4yNp8bVSZRLCf9vzHNe5VmXKYqZM mgeNV2eBmcBUrdFjPIBiJKvn+0HIL1M0tljrra7Xig/aroDFk1UAQ6PcE9zLbX0eNGlo Ax3w== X-Gm-Message-State: ALoCoQmsCbutw0RODW8C9a9XarvAXinr65rEapQGdmcrp1wEikAEAdzs7irPoQdmMu8qrV0aYPnZ X-Received: by 10.180.77.195 with SMTP id u3mr3265476wiw.30.1429290666649; Fri, 17 Apr 2015 10:11:06 -0700 (PDT) Received: from [172.16.62.12] ([109.99.239.84]) by mx.google.com with ESMTPSA id cj9sm15432967wjc.42.2015.04.17.10.11.04 (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Fri, 17 Apr 2015 10:11:05 -0700 (PDT) From: Liviu Ionescu Date: Fri, 17 Apr 2015 20:11:02 +0300 Message-Id: <068896FD-4D91-4B5F-90CD-9FF4765EF103@livius.net> To: "qemu-devel@nongnu.org" Mime-Version: 1.0 (Mac OS X Mail 8.2 \(2098\)) X-Mailer: Apple Mail (2.2098) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 74.125.82.48 Cc: Peter Maydell , Leon Alrae , Matthew Fortune , "christopher.covington@linaro.org" Subject: [Qemu-devel] [PATCH] --semihosting-cmdline added X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org This patch adds a new option (--semihosting-cmdline) to define the entire command line to be passed via semihosting, since -kernal and -append might generate very long lines. This option must be placed at the end, all subsequent arguments are passed to the application. Other changes: - typedef struct ... Semihosting added, with all semihosting config variables - use a minimalistic boot info in armv7m.c Signed-off-by: Liviu Ionescu --- gdbstub.c | 6 ++-- hw/arm/armv7m.c | 12 +++++++ include/exec/gdbstub.h | 6 ---- include/sysemu/sysemu.h | 21 +++++++++++- qemu-options.hx | 13 ++++++++ target-arm/arm-semi.c | 21 +++++++++--- vl.c | 85 ++++++++++++++++++++++++++++++++++++++++++------- 7 files changed, 138 insertions(+), 26 deletions(-) diff --git a/gdbstub.c b/gdbstub.c index 8abcb8a..33805fe 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -317,8 +317,6 @@ static GDBState *gdbserver_state; bool gdb_has_xml; -int semihosting_target = SEMIHOSTING_TARGET_AUTO; - #ifdef CONFIG_USER_ONLY /* XXX: This is not thread safe. Do we care? */ static int gdbserver_fd = -1; @@ -356,10 +354,10 @@ static enum { /* Decide if either remote gdb syscalls or native file IO should be used. */ int use_gdb_syscalls(void) { - if (semihosting_target == SEMIHOSTING_TARGET_NATIVE) { + if (semihosting.target == SEMIHOSTING_TARGET_NATIVE) { /* -semihosting-config target=native */ return false; - } else if (semihosting_target == SEMIHOSTING_TARGET_GDB) { + } else if (semihosting.target == SEMIHOSTING_TARGET_GDB) { /* -semihosting-config target=gdb */ return true; } diff --git a/hw/arm/armv7m.c b/hw/arm/armv7m.c index c6eab6d..dc7fbef 100644 --- a/hw/arm/armv7m.c +++ b/hw/arm/armv7m.c @@ -179,6 +179,7 @@ qemu_irq *armv7m_init(MemoryRegion *system_memory, int mem_size, int num_irq, int i; int big_endian; MemoryRegion *hack = g_new(MemoryRegion, 1); + static struct arm_boot_info boot_info; if (cpu_model == NULL) { cpu_model = "cortex-m3"; @@ -213,6 +214,17 @@ qemu_irq *armv7m_init(MemoryRegion *system_memory, int mem_size, int num_irq, exit(1); } + /* + * Fill-in a minimalistic boot info, required for semihosting. + * kernel_cmdline should be initialised with machine->kernel_cmdline, + * but we do not have machine here. Suggestion: change prototype + * and add "MachineState *machine". + */ + boot_info.kernel_cmdline = ""; + boot_info.kernel_filename = kernel_filename; + + env->boot_info = &boot_info; + if (kernel_filename) { image_size = load_elf(kernel_filename, NULL, NULL, &entry, &lowaddr, NULL, big_endian, ELF_MACHINE, 1); diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h index c633248..a608a26 100644 --- a/include/exec/gdbstub.h +++ b/include/exec/gdbstub.h @@ -95,10 +95,4 @@ extern bool gdb_has_xml; /* in gdbstub-xml.c, generated by scripts/feature_to_c.sh */ extern const char *const xml_builtin[][2]; -/* Command line option defining whether semihosting should go via gdb or not */ -extern int semihosting_target; -#define SEMIHOSTING_TARGET_AUTO 0 -#define SEMIHOSTING_TARGET_NATIVE 1 -#define SEMIHOSTING_TARGET_GDB 2 - #endif diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h index 8a52934..932f2c3 100644 --- a/include/sysemu/sysemu.h +++ b/include/sysemu/sysemu.h @@ -125,7 +125,26 @@ extern int cursor_hide; extern int graphic_rotate; extern int no_quit; extern int no_shutdown; -extern int semihosting_enabled; + +/* Define where the semihosting calls are sent. */ +#define SEMIHOSTING_TARGET_AUTO 0 +#define SEMIHOSTING_TARGET_NATIVE 1 +#define SEMIHOSTING_TARGET_GDB 2 + +/* Semihosting status */ +typedef struct { + int enabled; /* 1 if enabled */ + int target; /* see above */ + int argc; + char **argv; + const char *cmdline; /* concatenated argv */ +} Semihosting; + +extern Semihosting semihosting; + +/* Temporary definition, until all references are replaced. */ +#define semihosting_enabled semihosting.enabled + extern int old_param; extern int boot_menu; extern bool boot_strict; diff --git a/qemu-options.hx b/qemu-options.hx index 319d971..242d97a 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -3305,6 +3305,19 @@ Enable semihosting and define where the semihosting calls will be addressed, to QEMU (@code{native}) or to GDB (@code{gdb}). The default is @code{auto}, which means @code{gdb} during debug sessions and @code{native} otherwise (ARM, M68K, Xtensa only). ETEXI +DEF("semihosting-cmdline", 0, QEMU_OPTION_semihosting_cmdline, + "-semihosting-cmdline semihosting command line\n", +QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA | QEMU_ARCH_LM32) +STEXI +@item -semihosting-cmdline +@findex -semihosting-cmdline +The +@code{cmdline} defines the entire command line passed to the application via the +semihosting calls, including the program name that will be +passed as argv[0]. Must be the last option, all following arguments +are passed to the application unchanged. +(ARM, M68K, Xtensa only) +ETEXI DEF("old-param", 0, QEMU_OPTION_old_param, "-old-param old param mode\n", QEMU_ARCH_ARM) STEXI diff --git a/target-arm/arm-semi.c b/target-arm/arm-semi.c index a8b83e6..6b302ad 100644 --- a/target-arm/arm-semi.c +++ b/target-arm/arm-semi.c @@ -35,6 +35,9 @@ #include "qemu-common.h" #include "exec/gdbstub.h" #include "hw/arm/arm.h" +#include "qemu/option.h" +#include "qemu/config-file.h" +#include "sysemu/sysemu.h" #endif #define TARGET_SYS_OPEN 0x01 @@ -440,10 +443,14 @@ uint32_t do_arm_semihosting(CPUARMState *env) input_size = arg1; /* Compute the size of the output string. */ #if !defined(CONFIG_USER_ONLY) - output_size = strlen(ts->boot_info->kernel_filename) + if (semihosting.cmdline) { + output_size = strlen(semihosting.cmdline) + 1; + } else { + output_size = strlen(ts->boot_info->kernel_filename) + 1 /* Separating space. */ + strlen(ts->boot_info->kernel_cmdline) + 1; /* Terminating null byte. */ + } #else unsigned int i; @@ -474,9 +481,15 @@ uint32_t do_arm_semihosting(CPUARMState *env) /* Copy the command-line arguments. */ #if !defined(CONFIG_USER_ONLY) - pstrcpy(output_buffer, output_size, ts->boot_info->kernel_filename); - pstrcat(output_buffer, output_size, " "); - pstrcat(output_buffer, output_size, ts->boot_info->kernel_cmdline); + if (semihosting.cmdline) { + pstrcpy(output_buffer, output_size, semihosting.cmdline); + } else { + pstrcpy(output_buffer, output_size, + ts->boot_info->kernel_filename); + pstrcat(output_buffer, output_size, " "); + pstrcat(output_buffer, output_size, + ts->boot_info->kernel_cmdline); + } #else if (output_size == 1) { /* Empty command-line. */ diff --git a/vl.c b/vl.c index 74c2681..3cd8cd5 100644 --- a/vl.c +++ b/vl.c @@ -170,7 +170,7 @@ int graphic_rotate = 0; const char *watchdog; QEMUOptionRom option_rom[MAX_OPTION_ROMS]; int nb_option_roms; -int semihosting_enabled = 0; +Semihosting semihosting; int old_param = 0; const char *qemu_name; int alt_grab = 0; @@ -2727,6 +2727,51 @@ static void set_memory_options(uint64_t *ram_slots, ram_addr_t *maxram_size) } } +static const char *concatenate_semihosting_cmdline(int argc, char **argv) +{ + int total_size = 0; + int i; + + for (i = 0; i < argc; ++i) { + total_size += strlen(argv[i]); + total_size += 1; /* Add separator spaces */ + if (rindex(argv[i], ' ') != NULL) { + total_size += 2; /* Provision for quotes */ + } + } + + char *cmdline = malloc(total_size); + char *p = cmdline; + *p = '\0'; /* Prepare for empty command line */ + for (i = 0; i < argc; ++i) { + if (i != 0) { + *p++ = ' '; + } + if (rindex(argv[i], ' ') == NULL) { + strcpy(p, argv[i]); + p += strlen(argv[i]); + } else { + /* If no quotes found, it is safe to use them for grouping */ + if (rindex(argv[i], '"') == NULL) { + *p++ = '"'; + strcpy(p, argv[i]); + p += strlen(argv[i]); + *p++ = '"'; + } else { + /* Does not work if string has both quotes and apostrophs */ + *p++ = '\''; + strcpy(p, argv[i]); + p += strlen(argv[i]); + *p++ = '\''; + } + } + *p = '\0'; + } + + return cmdline; +} + + int main(int argc, char **argv, char **envp) { int i; @@ -2768,6 +2813,13 @@ int main(int argc, char **argv, char **envp) FILE *vmstate_dump_file = NULL; Error *main_loop_err = NULL; + int actual_argc = argc; + + semihosting.enabled = 0; + semihosting.argc = 0; + semihosting.argv = NULL; + semihosting.cmdline = NULL; + qemu_init_cpu_loop(); qemu_mutex_lock_iothread(); @@ -2844,6 +2896,16 @@ int main(int argc, char **argv, char **envp) case QEMU_OPTION_nouserconfig: userconfig = false; break; + case QEMU_OPTION_semihosting_cmdline: + /* no HAS_ARGS, optind set to next option */ + semihosting.argc = argc - optind; + semihosting.argv = &argv[optind]; + /* Diminish count to hide semihosting command line */ + actual_argc = optind - 1; /* exclude current option */ + + semihosting.cmdline = concatenate_semihosting_cmdline( + semihosting.argc, semihosting.argv); + break; } } } @@ -2859,14 +2921,15 @@ int main(int argc, char **argv, char **envp) /* second pass of option parsing */ optind = 1; for(;;) { - if (optind >= argc) + if (optind >= actual_argc) { break; + } if (argv[optind][0] != '-') { hda_opts = drive_add(IF_DEFAULT, 0, argv[optind++], HD_OPTS); } else { const QEMUOption *popt; - popt = lookup_opt(argc, argv, &optarg, &optind); + popt = lookup_opt(actual_argc, argv, &optarg, &optind); if (!(popt->arch_mask & arch_type)) { printf("Option %s not supported for this target\n", popt->name); exit(1); @@ -3535,24 +3598,24 @@ int main(int argc, char **argv, char **envp) nb_option_roms++; break; case QEMU_OPTION_semihosting: - semihosting_enabled = 1; - semihosting_target = SEMIHOSTING_TARGET_AUTO; + semihosting.enabled = 1; + semihosting.target = SEMIHOSTING_TARGET_AUTO; break; case QEMU_OPTION_semihosting_config: - semihosting_enabled = 1; + semihosting.enabled = 1; opts = qemu_opts_parse(qemu_find_opts("semihosting-config"), optarg, 0); if (opts != NULL) { - semihosting_enabled = qemu_opt_get_bool(opts, "enable", + 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; + semihosting.target = SEMIHOSTING_TARGET_NATIVE; } else if (strcmp("gdb", target) == 0) { - semihosting_target = SEMIHOSTING_TARGET_GDB; + semihosting.target = SEMIHOSTING_TARGET_GDB; } else if (strcmp("auto", target) == 0) { - semihosting_target = SEMIHOSTING_TARGET_AUTO; + semihosting.target = SEMIHOSTING_TARGET_AUTO; } else { fprintf(stderr, "Unsupported semihosting-config" " %s\n", @@ -3560,7 +3623,7 @@ int main(int argc, char **argv, char **envp) exit(1); } } else { - semihosting_target = SEMIHOSTING_TARGET_AUTO; + semihosting.target = SEMIHOSTING_TARGET_AUTO; } } else { fprintf(stderr, "Unsupported semihosting-config %s\n",