@@ -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;
}
@@ -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);
@@ -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
@@ -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;
@@ -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
@@ -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. */
@@ -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",
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 <ilg@livius.net> --- 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(-)