@@ -355,6 +355,18 @@ static enum {
remote gdb syscalls. Otherwise use native file IO. */
int use_gdb_syscalls(void)
{
+ if (semihosting_target == SEMIHOSTING_TARGET_NATIVE) {
+ if (gdb_syscall_mode == GDB_SYS_UNKNOWN) {
+ gdb_syscall_mode = GDB_SYS_DISABLED;
+ }
+ return FALSE;
+ } else if (semihosting_target == SEMIHOSTING_TARGET_GDB) {
+ if (gdb_syscall_mode == GDB_SYS_UNKNOWN) {
+ gdb_syscall_mode = GDB_SYS_ENABLED;
+ }
+ return TRUE;
+ }
+
if (gdb_syscall_mode == GDB_SYS_UNKNOWN) {
gdb_syscall_mode = (gdbserver_state ? GDB_SYS_ENABLED
: GDB_SYS_DISABLED);
@@ -7,13 +7,17 @@
* This code is licensed under the GPL.
*/
+#include "hw/boards.h"
#include "hw/sysbus.h"
#include "hw/arm/arm.h"
#include "hw/loader.h"
#include "elf.h"
+#include "sysemu/sysemu.h"
#include "sysemu/qtest.h"
#include "qemu/error-report.h"
+static struct arm_boot_info armv7m_binfo;
+
/* Bitbanded IO. Each word corresponds to a single bit. */
/* Get the byte address of the real memory for a bitband access. */
@@ -166,9 +170,9 @@ static void armv7m_reset(void *opaque)
flash_size and sram_size are in kb.
Returns the NVIC array. */
-qemu_irq *armv7m_init(MemoryRegion *system_memory,
- int flash_size, int sram_size,
- const char *kernel_filename, const char *cpu_model)
+qemu_irq *armv7m_init(MachineState *machine,
+ MemoryRegion *system_memory,
+ int flash_size, int sram_size)
{
ARMCPU *cpu;
CPUARMState *env;
@@ -180,6 +184,11 @@ qemu_irq *armv7m_init(MemoryRegion *system_memory,
uint64_t lowaddr;
int i;
int big_endian;
+
+ const char *kernel_filename = machine->kernel_filename;
+ const char *kernel_cmdline = machine->kernel_cmdline;
+ const char *cpu_model = machine->cpu_model;
+
MemoryRegion *sram = g_new(MemoryRegion, 1);
MemoryRegion *flash = g_new(MemoryRegion, 1);
MemoryRegion *hack = g_new(MemoryRegion, 1);
@@ -235,11 +244,19 @@ qemu_irq *armv7m_init(MemoryRegion *system_memory,
big_endian = 0;
#endif
- if (!kernel_filename && !qtest_enabled()) {
- fprintf(stderr, "Guest image must be specified (using -kernel)\n");
+ if (!kernel_filename && !qtest_enabled() && !with_gdb) {
+ fprintf(stderr,
+ "Guest image must be specified (using -image or -kernel)\n");
exit(1);
}
+ /* Fill-in a minimalistic boot info, required for semihosting */
+ armv7m_binfo.kernel_filename = kernel_filename;
+ armv7m_binfo.kernel_cmdline = kernel_cmdline;
+ armv7m_binfo.semihosting_cmdline = machine->semihosting_cmdline;
+
+ env->boot_info = &armv7m_binfo;
+
if (kernel_filename) {
image_size = load_elf(kernel_filename, NULL, NULL, &entry, &lowaddr,
NULL, big_endian, ELF_MACHINE, 1);
@@ -1198,7 +1198,7 @@ static stellaris_board_info stellaris_boards[] = {
}
};
-static void stellaris_init(const char *kernel_filename, const char *cpu_model,
+static void stellaris_init(MachineState *machine,
stellaris_board_info *board)
{
static const int uart_irq[] = {5, 6, 33, 34};
@@ -1222,8 +1222,8 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model,
flash_size = ((board->dc0 & 0xffff) + 1) << 1;
sram_size = (board->dc0 >> 18) + 1;
- pic = armv7m_init(get_system_memory(),
- flash_size, sram_size, kernel_filename, cpu_model);
+ pic = armv7m_init(machine, get_system_memory(),
+ flash_size, sram_size);
if (board->dc1 & (1 << 16)) {
dev = sysbus_create_varargs(TYPE_STELLARIS_ADC, 0x40038000,
@@ -1335,16 +1335,12 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model,
/* FIXME: Figure out how to generate these from stellaris_boards. */
static void lm3s811evb_init(MachineState *machine)
{
- const char *cpu_model = machine->cpu_model;
- const char *kernel_filename = machine->kernel_filename;
- stellaris_init(kernel_filename, cpu_model, &stellaris_boards[0]);
+ stellaris_init(machine, &stellaris_boards[0]);
}
static void lm3s6965evb_init(MachineState *machine)
{
- const char *cpu_model = machine->cpu_model;
- const char *kernel_filename = machine->kernel_filename;
- stellaris_init(kernel_filename, cpu_model, &stellaris_boards[1]);
+ stellaris_init(machine, &stellaris_boards[1]);
}
static QEMUMachine lm3s811evb_machine = {
@@ -15,9 +15,10 @@
#include "hw/irq.h"
/* armv7m.c */
-qemu_irq *armv7m_init(MemoryRegion *system_memory,
- int flash_size, int sram_size,
- const char *kernel_filename, const char *cpu_model);
+qemu_irq *armv7m_init(MachineState *machine,
+ MemoryRegion *system_memory,
+ int flash_size, int sram_size);
+
/* arm_boot.c */
struct arm_boot_info {
@@ -26,6 +27,7 @@ struct arm_boot_info {
const char *kernel_cmdline;
const char *initrd_filename;
const char *dtb_filename;
+ const char *semihosting_cmdline;
hwaddr loader_start;
/* multicore boards that use the default secondary core boot functions
* need to put the address of the secondary boot code, the boot reg,
@@ -142,6 +142,7 @@ struct MachineState {
char *kernel_cmdline;
char *initrd_filename;
const char *cpu_model;
+ char *semihosting_cmdline;
AccelState *accelerator;
};
@@ -104,6 +104,7 @@ typedef enum DisplayType
} DisplayType;
extern int autostart;
+extern int with_gdb;
typedef enum {
VGA_NONE, VGA_STD, VGA_CIRRUS, VGA_VMWARE, VGA_XENFB, VGA_QXL,
@@ -127,7 +128,13 @@ extern int cursor_hide;
extern int graphic_rotate;
extern int no_quit;
extern int no_shutdown;
+
extern int semihosting_enabled;
+extern int semihosting_target;
+#define SEMIHOSTING_TARGET_AUTO 0
+#define SEMIHOSTING_TARGET_NATIVE 1
+#define SEMIHOSTING_TARGET_GDB 2
+
extern int old_param;
extern int boot_menu;
extern bool boot_strict;
@@ -78,6 +78,14 @@ STEXI
Select CPU model (@code{-cpu help} for list and additional feature selection)
ETEXI
+DEF("image", HAS_ARG, QEMU_OPTION_image, \
+"-image elf use 'elf' as application image to emulate\n", QEMU_ARCH_ALL)
+STEXI
+@item -image @var{elf}
+@findex -image
+Load @var{elf} and use it as application image to emulate.
+ETEXI
+
DEF("smp", HAS_ARG, QEMU_OPTION_smp,
"-smp [cpus=]n[,maxcpus=cpus][,cores=cores][,threads=threads][,sockets=sockets]\n"
" set the number of CPUs to 'n' [default=1]\n"
@@ -2580,7 +2588,8 @@ DEF("append", HAS_ARG, QEMU_OPTION_append, \
STEXI
@item -append @var{cmdline}
@findex -append
-Use @var{cmdline} as kernel command line
+Append the space separated strings @var{cmdline} to the kernel
+full path to generate the complete kernel command line.
ETEXI
DEF("initrd", HAS_ARG, QEMU_OPTION_initrd, \
@@ -3210,14 +3219,41 @@ STEXI
@findex -prom-env
Set OpenBIOS nvram @var{variable} to given @var{value} (PPC, SPARC only).
ETEXI
+
DEF("semihosting", 0, QEMU_OPTION_semihosting,
- "-semihosting semihosting mode\n",
+ "-semihosting enable semihosting\n",
QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA | QEMU_ARCH_LM32)
STEXI
@item -semihosting
@findex -semihosting
-Semihosting mode (ARM, M68K, Xtensa only).
+Enable semihosting system calls emulation (ARM, M68K, Xtensa only). By default,
+the calls are addressed to QEMU, but, if a debug session is active, the
+calls are forwarded to GDB. This behaviour can be changed by
+@code{-semihosting-target}.
+ETEXI
+DEF("semihosting-target", HAS_ARG, QEMU_OPTION_semihosting_target,
+"-semihosting-target native|gdb|auto define semihosting target\n",
+QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA | QEMU_ARCH_LM32)
+STEXI
+@item -semihosting-target [native|gdb|auto]
+@findex -semihosting-target
+Enable semihosting and define where the semihosting calls will be addressed,
+to QEMU (@code{native}) or to GDB (@code{gdb}). Default is @code{auto}.
+(ARM, M68K, Xtensa only)
+ETEXI
+DEF("semihosting-cmdline", HAS_ARG, QEMU_OPTION_semihosting_cmdline, \
+"-semihosting-cmdline args use 'args' as semihosting command line\n", QEMU_ARCH_ALL)
+STEXI
+@item -semihosting-cmdline @var{args}
+@findex -cmdline
+Use the space separated strings @var{args} as the complete command line
+passed (via SYS_GET_CMDLINE) to the emulated program
+when semihosting is enabled. The first word is passed as argv[0], the
+program name. If missing, an empty string is passed to the program. Use
+quotes, apostrophes or backslashes (on POSIX) to make a multi-word string
+look like a single option.
ETEXI
+
DEF("old-param", 0, QEMU_OPTION_old_param,
"-old-param old param mode\n", QEMU_ARCH_ARM)
STEXI
@@ -58,6 +58,11 @@
#define TARGET_SYS_HEAPINFO 0x16
#define TARGET_SYS_EXIT 0x18
+/* ADP_Stopped_ApplicationExit is used for exit(0),
+ * anything else is implemented as exit(1) */
+#define ADP_Stopped_ApplicationExit ((2 << 16) + 38)
+#define ADP_Stopped_RunTimeError ((2 << 16) + 35)
+
#ifndef O_BINARY
#define O_BINARY 0
#endif
@@ -434,12 +439,37 @@ uint32_t do_arm_semihosting(CPUARMState *env)
GET_ARG(0);
GET_ARG(1);
input_size = arg1;
+
+ const char *argv0 = NULL;
+ const char *cmdline = NULL;
+
+ if (ts->boot_info) {
+ if (ts->boot_info->semihosting_cmdline != NULL) {
+ argv0 = ""; /* argv[0] is also passed by the user */
+ cmdline = ts->boot_info->semihosting_cmdline;
+ } else if (ts->boot_info->kernel_filename != NULL) {
+ /* Use the kernel filename as argv 0 */
+ argv0 = ts->boot_info->kernel_filename;
+ cmdline = ts->boot_info->kernel_cmdline;
+ }
+ }
+
+ if (argv0 == NULL) {
+ argv0 = "";
+ }
+
+ if (cmdline == NULL) {
+ cmdline = "";
+ }
+
/* Compute the size of the output string. */
#if !defined(CONFIG_USER_ONLY)
- output_size = strlen(ts->boot_info->kernel_filename)
- + 1 /* Separating space. */
- + strlen(ts->boot_info->kernel_cmdline)
- + 1; /* Terminating null byte. */
+ output_size = strlen(argv0);
+ if (output_size > 0) {
+ output_size += 1; /* Separating space. */
+ }
+ output_size += strlen(cmdline);
+ output_size += 1; /* Terminating null byte. */
#else
unsigned int i;
@@ -470,9 +500,11 @@ 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);
+ pstrcpy(output_buffer, output_size, argv0);
+ if (strlen(argv0) > 0) {
+ pstrcat(output_buffer, output_size, " ");
+ }
+ pstrcat(output_buffer, output_size, cmdline);
#else
if (output_size == 1) {
/* Empty command-line. */
@@ -551,8 +583,12 @@ uint32_t do_arm_semihosting(CPUARMState *env)
return 0;
}
case TARGET_SYS_EXIT:
- gdb_exit(env, 0);
- exit(0);
+ /* ARM specifies only Stopped_ApplicationExit as normal
+ * exit, everything else is considered an error */
+ ret = (args == ADP_Stopped_ApplicationExit) ? 0 : 1;
+ gdb_exit(env, ret);
+ exit(ret);
+
default:
fprintf(stderr, "qemu: Unsupported SemiHosting SWI 0x%02x\n", nr);
cpu_dump_state(cs, stderr, fprintf, 0);
@@ -138,6 +138,7 @@ bool enable_mlock = false;
int nb_nics;
NICInfo nd_table[MAX_NICS];
int autostart;
+int with_gdb = FALSE;
static int rtc_utc = 1;
static int rtc_date_offset = -1; /* -1 means no change */
QEMUClockType rtc_clock;
@@ -172,6 +173,7 @@ const char *watchdog;
QEMUOptionRom option_rom[MAX_OPTION_ROMS];
int nb_option_roms;
int semihosting_enabled = 0;
+int semihosting_target = SEMIHOSTING_TARGET_AUTO;
int old_param = 0;
const char *qemu_name;
int alt_grab = 0;
@@ -2739,8 +2741,11 @@ int main(int argc, char **argv, char **envp)
{
int i;
int snapshot, linux_boot;
+ const char *image_filename = NULL;
const char *initrd_filename;
- const char *kernel_filename, *kernel_cmdline;
+ const char *kernel_filename;
+ const char *kernel_cmdline;
+ const char *semihosting_cmdline = NULL;
const char *boot_order;
DisplayState *ds;
int cyls, heads, secs, translation;
@@ -3036,7 +3041,10 @@ int main(int argc, char **argv, char **envp)
exit(1);
}
break;
- case QEMU_OPTION_kernel:
+ case QEMU_OPTION_image:
+ image_filename = optarg;
+ break;
+ case QEMU_OPTION_kernel:
qemu_opts_set(qemu_find_opts("machine"), 0, "kernel", optarg);
break;
case QEMU_OPTION_initrd:
@@ -3219,9 +3227,11 @@ int main(int argc, char **argv, char **envp)
break;
case QEMU_OPTION_s:
add_device_config(DEV_GDB, "tcp::" DEFAULT_GDBSTUB_PORT);
+ with_gdb = TRUE;
break;
case QEMU_OPTION_gdb:
add_device_config(DEV_GDB, optarg);
+ with_gdb = TRUE;
break;
case QEMU_OPTION_L:
if (data_dir_idx < ARRAY_SIZE(data_dir)) {
@@ -3618,6 +3628,25 @@ int main(int argc, char **argv, char **envp)
break;
case QEMU_OPTION_semihosting:
semihosting_enabled = 1;
+ semihosting_target = SEMIHOSTING_TARGET_AUTO;
+ break;
+ case QEMU_OPTION_semihosting_target:
+ semihosting_enabled = 1;
+
+ if (strcmp(optarg, "auto") == 0) {
+ semihosting_target = SEMIHOSTING_TARGET_AUTO;
+ } else if (strcmp(optarg, "native") == 0) {
+ semihosting_target = SEMIHOSTING_TARGET_NATIVE;
+ } else if (strcmp(optarg, "gdb") == 0) {
+ semihosting_target = SEMIHOSTING_TARGET_GDB;
+ } else {
+ fprintf(stderr, "Unsupported semihosting-target %s\n",
+ optarg);
+ exit(1);
+ }
+ break;
+ case QEMU_OPTION_semihosting_cmdline:
+ semihosting_cmdline = optarg;
break;
case QEMU_OPTION_tdf:
fprintf(stderr, "Warning: user space PIT time drift fix "
@@ -4119,6 +4148,7 @@ int main(int argc, char **argv, char **envp)
kernel_cmdline = "";
current_machine->kernel_cmdline = (char *)kernel_cmdline;
}
+ current_machine->semihosting_cmdline = (char *)semihosting_cmdline;
linux_boot = (kernel_filename != NULL);
@@ -4137,6 +4167,24 @@ int main(int argc, char **argv, char **envp)
exit(1);
}
+ if (semihosting_cmdline != NULL && semihosting_enabled == 0) {
+ fprintf(stderr, "-semihosting-cmdline only allowed with "
+ "-semihosting or -semihosting-target\n");
+ exit(1);
+ }
+
+ if (kernel_filename != NULL && image_filename != NULL) {
+ fprintf(stderr, "-image and -kernel are mutually exclusive\n");
+ exit(1);
+ }
+
+ if (kernel_filename == NULL && image_filename != NULL) {
+ /* The rest of the code uses kernel_filename, so copy image there */
+ kernel_filename = image_filename;
+ current_machine->kernel_filename = image_filename;
+ qemu_opts_set(qemu_find_opts("machine"), 0, "kernel", image_filename);
+ }
+
os_set_line_buffering();
qemu_init_cpu_loop();
@@ -4385,7 +4433,8 @@ int main(int argc, char **argv, char **envp)
error_free(local_err);
exit(1);
}
- } else if (autostart) {
+ } else if (autostart && kernel_filename) {
+ /* If an image is defined and no -S is requested, start it. */
vm_start();
}
Signed-off-by: Liviu Ionescu <ilg@livius.net> --- gdbstub.c | 12 +++++++++++ hw/arm/armv7m.c | 27 +++++++++++++++++++----- hw/arm/stellaris.c | 14 +++++-------- include/hw/arm/arm.h | 8 ++++--- include/hw/boards.h | 1 + include/sysemu/sysemu.h | 7 +++++++ qemu-options.hx | 42 ++++++++++++++++++++++++++++++++++--- target-arm/arm-semi.c | 54 ++++++++++++++++++++++++++++++++++++++++-------- vl.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++--- 9 files changed, 188 insertions(+), 32 deletions(-)