@@ -634,7 +634,13 @@ static void write_bootloader (CPUMIPSState *env, uint8_t *base,
/* Second part of the bootloader */
p = (uint32_t *) (base + 0x580);
- stl_p(p++, 0x24040002); /* addiu a0, zero, 2 */
+
+ if (semihosting_enabled) {
+ /* Preserve a0 content when semihosting is enabled. */
+ stl_p(p++, 0x00000000); /* nop */
+ } else {
+ stl_p(p++, 0x24040002); /* addiu a0, zero, 2 */
+ }
stl_p(p++, 0x3c1d0000 | (((ENVP_ADDR - 64) >> 16) & 0xffff)); /* lui sp, high(ENVP_ADDR) */
stl_p(p++, 0x37bd0000 | ((ENVP_ADDR - 64) & 0xffff)); /* ori sp, sp, low(ENVP_ADDR) */
stl_p(p++, 0x3c050000 | ((ENVP_ADDR >> 16) & 0xffff)); /* lui a1, high(ENVP_ADDR) */
@@ -125,6 +125,8 @@ extern int graphic_rotate;
extern int no_quit;
extern int no_shutdown;
extern int semihosting_enabled;
+extern const char **semihosting_argv;
+extern int semihosting_argc;
extern int old_param;
extern int boot_menu;
extern bool boot_strict;
@@ -3240,6 +3240,14 @@ 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-arg", HAS_ARG, QEMU_OPTION_semihosting_arg,
+ "-semihosting-arg arguments passed to the guest program\n",
+ QEMU_ARCH_MIPS)
+STEXI
+@item -semihosting-arg
+@findex -semihosting-arg
+Arguments passed to the guest program (MIPS only).
+ETEXI
DEF("old-param", 0, QEMU_OPTION_old_param,
"-old-param old param mode\n", QEMU_ARCH_ARM)
STEXI
@@ -21,6 +21,9 @@
#include "cpu.h"
#include "exec/helper-proto.h"
#include "exec/softmmu-semi.h"
+#ifndef CONFIG_USER_ONLY
+#include "sysemu/sysemu.h"
+#endif
typedef enum UHIOp {
UHI_exit = 1,
@@ -71,6 +74,12 @@ enum UHIOpenFlags {
UHIOpen_EXCL = 0x800
};
+#ifdef CONFIG_USER_ONLY
+/* Suppress compiler errors in linux-user. */
+static const char **semihosting_argv;
+static int semihosting_argc;
+#endif
+
static int copy_stat_to_target(CPUMIPSState *env, const struct stat *src,
target_ulong vaddr)
{
@@ -169,6 +178,21 @@ static int read_from_file(CPUMIPSState *env, target_ulong fd,
return num_of_bytes;
}
+static int copy_argn_to_target(CPUMIPSState *env, int arg_num,
+ target_ulong vaddr)
+{
+ int strsize = strlen(semihosting_argv[arg_num]) + 1;
+ char *dst = lock_user(VERIFY_WRITE, vaddr, strsize, 0);
+ if (!dst) {
+ return -1;
+ }
+
+ strcpy(dst, semihosting_argv[arg_num]);
+
+ unlock_user(dst, vaddr, strsize);
+ return 0;
+}
+
#define GET_TARGET_STRING(p, addr) \
do { \
p = lock_user_string(addr); \
@@ -248,9 +272,21 @@ void helper_do_semihosting(CPUMIPSState *env)
}
break;
case UHI_argc:
+ gpr[2] = semihosting_argc;
+ break;
case UHI_argnlen:
+ if (gpr[4] >= semihosting_argc) {
+ gpr[2] = -1;
+ goto uhi_done;
+ }
+ gpr[2] = strlen(semihosting_argv[gpr[4]]);
+ break;
case UHI_argn:
- /* TODO */
+ if (gpr[4] >= semihosting_argc) {
+ gpr[2] = -1;
+ goto uhi_done;
+ }
+ gpr[2] = copy_argn_to_target(env, gpr[4], gpr[5]);
break;
case UHI_plog:
GET_TARGET_STRING(p, gpr[4]);
@@ -19652,6 +19652,13 @@ void cpu_state_reset(CPUMIPSState *env)
restore_rounding_mode(env);
restore_flush_mode(env);
cs->exception_index = EXCP_NONE;
+
+#ifndef CONFIG_USER_ONLY
+ if (semihosting_enabled) {
+ /* When $4 is -1 the UHI interface will be used for argc and argv */
+ env->active_tc.gpr[4] = -1;
+ }
+#endif
}
void restore_state_to_opc(CPUMIPSState *env, TranslationBlock *tb, int pc_pos)
@@ -169,6 +169,8 @@ const char *watchdog;
QEMUOptionRom option_rom[MAX_OPTION_ROMS];
int nb_option_roms;
int semihosting_enabled = 0;
+const char **semihosting_argv;
+int semihosting_argc;
int old_param = 0;
const char *qemu_name;
int alt_grab = 0;
@@ -3560,6 +3562,22 @@ int main(int argc, char **argv, char **envp)
exit(1);
}
break;
+ case QEMU_OPTION_semihosting_arg:
+ if (semihosting_argc == 0) {
+ /* If arguments are present then the first argument goes to
+ argv[1] as argv[0] is reserved for the program name */
+ semihosting_argc = 2;
+ semihosting_argv =
+ g_malloc(semihosting_argc * sizeof(void *));
+ semihosting_argv[1] = optarg;
+ } else {
+ semihosting_argc++;
+ semihosting_argv =
+ g_realloc(semihosting_argv,
+ semihosting_argc * sizeof(void *));
+ semihosting_argv[semihosting_argc - 1] = optarg;
+ }
+ break;
case QEMU_OPTION_tdf:
fprintf(stderr, "Warning: user space PIT time drift fix "
"is no longer supported.\n");
@@ -4078,6 +4096,16 @@ int main(int argc, char **argv, char **envp)
current_machine->kernel_cmdline = (char *)kernel_cmdline;
}
+ if (semihosting_argc) {
+ if (kernel_filename) {
+ semihosting_argv[0] = kernel_filename;
+ } else if (bios_name) {
+ semihosting_argv[0] = bios_name;
+ } else {
+ semihosting_argv[0] = "";
+ }
+ }
+
linux_boot = (kernel_filename != NULL);
if (!linux_boot && *kernel_cmdline != '\0') {
Add new command line option "-semihosting-arg". It is used for passing input arguments to the guest in semihosting mode. The option can be used multiple times. If n arguments are passed, then argument count (semihosting_argc) will be equal to n+1 as semihosting_argv[0] points at the program name. However, if no arguments are passed then argument count will be 0. Also tweak Malta's pseudo-bootloader. On CPU reset the $4 register is set to -1 when semihosting is enabled in order to indicate that the UHI operations should be used to obtain input arguments. Signed-off-by: Leon Alrae <leon.alrae@imgtec.com> --- hw/mips/mips_malta.c | 8 +++++++- include/sysemu/sysemu.h | 2 ++ qemu-options.hx | 8 ++++++++ target-mips/mips-semi.c | 38 +++++++++++++++++++++++++++++++++++++- target-mips/translate.c | 7 +++++++ vl.c | 28 ++++++++++++++++++++++++++++ 6 files changed, 89 insertions(+), 2 deletions(-)