* [Qemu-devel] [PATCH 1/4] include/softmmu-semi.h: Make semihosting support 64-bit clean
2015-02-27 17:00 [Qemu-devel] [PATCH 0/4] target-mips: add UHI semihosting support Leon Alrae
@ 2015-02-27 17:00 ` Leon Alrae
2015-02-27 17:00 ` [Qemu-devel] [PATCH 2/4] target-mips: add Unified Hosting Interface (UHI) support Leon Alrae
` (2 subsequent siblings)
3 siblings, 0 replies; 9+ messages in thread
From: Leon Alrae @ 2015-02-27 17:00 UTC (permalink / raw)
To: qemu-devel; +Cc: Maciej W. Rozycki, matthew.fortune, aurelien
From: "Maciej W. Rozycki" <macro@codesourcery.com>
Correct addresses passed around in semihosting to use a data type suitable
for both 32-bit and 64-bit targets.
Signed-off-by: Maciej W. Rozycki <macro@codesourcery.com>
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
---
Maciej,
I kept the same fix locally. I'm replacing it in this patchset with your
patch since you submitted it first :)
Leon
---
include/exec/softmmu-semi.h | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/include/exec/softmmu-semi.h b/include/exec/softmmu-semi.h
index 8401f7d..1819cc2 100644
--- a/include/exec/softmmu-semi.h
+++ b/include/exec/softmmu-semi.h
@@ -9,14 +9,14 @@
#ifndef SOFTMMU_SEMI_H
#define SOFTMMU_SEMI_H 1
-static inline uint32_t softmmu_tget32(CPUArchState *env, uint32_t addr)
+static inline uint32_t softmmu_tget32(CPUArchState *env, target_ulong addr)
{
uint32_t val;
cpu_memory_rw_debug(ENV_GET_CPU(env), addr, (uint8_t *)&val, 4, 0);
return tswap32(val);
}
-static inline uint32_t softmmu_tget8(CPUArchState *env, uint32_t addr)
+static inline uint32_t softmmu_tget8(CPUArchState *env, target_ulong addr)
{
uint8_t val;
@@ -28,7 +28,8 @@ static inline uint32_t softmmu_tget8(CPUArchState *env, uint32_t addr)
#define get_user_u8(arg, p) ({ arg = softmmu_tget8(env, p) ; 0; })
#define get_user_ual(arg, p) get_user_u32(arg, p)
-static inline void softmmu_tput32(CPUArchState *env, uint32_t addr, uint32_t val)
+static inline void softmmu_tput32(CPUArchState *env,
+ target_ulong addr, uint32_t val)
{
val = tswap32(val);
cpu_memory_rw_debug(ENV_GET_CPU(env), addr, (uint8_t *)&val, 4, 1);
@@ -36,8 +37,8 @@ static inline void softmmu_tput32(CPUArchState *env, uint32_t addr, uint32_t val
#define put_user_u32(arg, p) ({ softmmu_tput32(env, p, arg) ; 0; })
#define put_user_ual(arg, p) put_user_u32(arg, p)
-static void *softmmu_lock_user(CPUArchState *env, uint32_t addr, uint32_t len,
- int copy)
+static void *softmmu_lock_user(CPUArchState *env,
+ target_ulong addr, target_ulong len, int copy)
{
uint8_t *p;
/* TODO: Make this something that isn't fixed size. */
@@ -48,7 +49,7 @@ static void *softmmu_lock_user(CPUArchState *env, uint32_t addr, uint32_t len,
return p;
}
#define lock_user(type, p, len, copy) softmmu_lock_user(env, p, len, copy)
-static char *softmmu_lock_user_string(CPUArchState *env, uint32_t addr)
+static char *softmmu_lock_user_string(CPUArchState *env, target_ulong addr)
{
char *p;
char *s;
--
2.1.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [Qemu-devel] [PATCH 2/4] target-mips: add Unified Hosting Interface (UHI) support
2015-02-27 17:00 [Qemu-devel] [PATCH 0/4] target-mips: add UHI semihosting support Leon Alrae
2015-02-27 17:00 ` [Qemu-devel] [PATCH 1/4] include/softmmu-semi.h: Make semihosting support 64-bit clean Leon Alrae
@ 2015-02-27 17:00 ` Leon Alrae
2015-03-01 22:17 ` Matthew Fortune
2015-02-27 17:00 ` [Qemu-devel] [PATCH 3/4] target-mips: add "-semihosting-arg" option and implement UHI Arg* ops Leon Alrae
2015-02-27 17:00 ` [Qemu-devel] [PATCH 4/4] hw/mips: Do not clear BEV for MIPS malta kernel load Leon Alrae
3 siblings, 1 reply; 9+ messages in thread
From: Leon Alrae @ 2015-02-27 17:00 UTC (permalink / raw)
To: qemu-devel; +Cc: matthew.fortune, aurelien
Add UHI semihosting support for MIPS. QEMU run with "-semihosting" option will
alter the behaviour of SDBBP 1 instruction -- UHI operation will be called
instead of generating a debug exception.
This commit implements all UHI operations apart from Argc, Argnlen and Argn.
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
---
qemu-options.hx | 5 +-
target-mips/Makefile.objs | 2 +-
target-mips/helper.h | 2 +
target-mips/mips-semi.c | 304 ++++++++++++++++++++++++++++++++++++++++++++++
target-mips/translate.c | 75 ++++++++----
5 files changed, 360 insertions(+), 28 deletions(-)
create mode 100644 target-mips/mips-semi.c
diff --git a/qemu-options.hx b/qemu-options.hx
index 85ca3ad..99ad1ae 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -3223,11 +3223,12 @@ Set OpenBIOS nvram @var{variable} to given @var{value} (PPC, SPARC only).
ETEXI
DEF("semihosting", 0, QEMU_OPTION_semihosting,
"-semihosting semihosting mode\n",
- QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA | QEMU_ARCH_LM32)
+ QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA | QEMU_ARCH_LM32 |
+ QEMU_ARCH_MIPS)
STEXI
@item -semihosting
@findex -semihosting
-Enable semihosting mode (ARM, M68K, Xtensa only).
+Enable semihosting mode (ARM, M68K, Xtensa, MIPS only).
ETEXI
DEF("semihosting-config", HAS_ARG, QEMU_OPTION_semihosting_config,
"-semihosting-config [enable=on|off,]target=native|gdb|auto semihosting configuration\n",
diff --git a/target-mips/Makefile.objs b/target-mips/Makefile.objs
index 108fd9b..bc5ed85 100644
--- a/target-mips/Makefile.objs
+++ b/target-mips/Makefile.objs
@@ -1,4 +1,4 @@
obj-y += translate.o dsp_helper.o op_helper.o lmi_helper.o helper.o cpu.o
-obj-y += gdbstub.o msa_helper.o
+obj-y += gdbstub.o msa_helper.o mips-semi.o
obj-$(CONFIG_SOFTMMU) += machine.o
obj-$(CONFIG_KVM) += kvm.o
diff --git a/target-mips/helper.h b/target-mips/helper.h
index 3bd0b02..7c7582f 100644
--- a/target-mips/helper.h
+++ b/target-mips/helper.h
@@ -1,6 +1,8 @@
DEF_HELPER_3(raise_exception_err, noreturn, env, i32, int)
DEF_HELPER_2(raise_exception, noreturn, env, i32)
+DEF_HELPER_1(do_semihosting, void, env)
+
#ifdef TARGET_MIPS64
DEF_HELPER_4(sdl, void, env, tl, tl, int)
DEF_HELPER_4(sdr, void, env, tl, tl, int)
diff --git a/target-mips/mips-semi.c b/target-mips/mips-semi.c
new file mode 100644
index 0000000..3bf7b2a
--- /dev/null
+++ b/target-mips/mips-semi.c
@@ -0,0 +1,304 @@
+/*
+ * Unified Hosting Interface syscalls.
+ *
+ * Copyright (c) 2014 Imagination Technologies
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/stat.h>
+#include "cpu.h"
+#include "exec/helper-proto.h"
+#include "exec/softmmu-semi.h"
+
+typedef enum UHIOp {
+ UHI_exit = 1,
+ UHI_open = 2,
+ UHI_close = 3,
+ UHI_read = 4,
+ UHI_write = 5,
+ UHI_lseek = 6,
+ UHI_unlink = 7,
+ UHI_fstat = 8,
+ UHI_argc = 9,
+ UHI_argnlen = 10,
+ UHI_argn = 11,
+ UHI_plog = 13,
+ UHI_assert = 14,
+ UHI_pread = 19,
+ UHI_pwrite = 20,
+ UHI_link = 22
+} UHIOp;
+
+typedef struct UHIStat {
+ int16_t uhi_st_dev;
+ uint16_t uhi_st_ino;
+ uint32_t uhi_st_mode;
+ uint16_t uhi_st_nlink;
+ uint16_t uhi_st_uid;
+ uint16_t uhi_st_gid;
+ int16_t uhi_st_rdev;
+ uint64_t uhi_st_size;
+ uint64_t uhi_st_atime;
+ uint64_t uhi_st_spare1;
+ uint64_t uhi_st_mtime;
+ uint64_t uhi_st_spare2;
+ uint64_t uhi_st_ctime;
+ uint64_t uhi_st_spare3;
+ uint64_t uhi_st_blksize;
+ uint64_t uhi_st_blocks;
+ uint64_t uhi_st_spare4[2];
+} UHIStat;
+
+enum UHIOpenFlags {
+ UHIOpen_RDONLY = 0x0,
+ UHIOpen_WRONLY = 0x1,
+ UHIOpen_RDWR = 0x2,
+ UHIOpen_APPEND = 0x8,
+ UHIOpen_CREAT = 0x200,
+ UHIOpen_TRUNC = 0x400,
+ UHIOpen_EXCL = 0x800
+};
+
+static int copy_stat_to_target(CPUMIPSState *env, const struct stat *src,
+ target_ulong vaddr)
+{
+ hwaddr len = sizeof(struct UHIStat);
+ UHIStat *dst = lock_user(VERIFY_WRITE, vaddr, len, 0);
+ if (!dst) {
+ return -1;
+ }
+
+ dst->uhi_st_dev = tswap16(src->st_dev);
+ dst->uhi_st_ino = tswap16(src->st_ino);
+ dst->uhi_st_mode = tswap32(src->st_mode);
+ dst->uhi_st_nlink = tswap16(src->st_nlink);
+ dst->uhi_st_uid = tswap16(src->st_uid);
+ dst->uhi_st_gid = tswap16(src->st_gid);
+ dst->uhi_st_rdev = tswap16(src->st_rdev);
+ dst->uhi_st_size = tswap64(src->st_size);
+ dst->uhi_st_atime = tswap64(src->st_atime);
+ dst->uhi_st_mtime = tswap64(src->st_mtime);
+ dst->uhi_st_ctime = tswap64(src->st_ctime);
+#ifdef _WIN32
+ dst->uhi_st_blksize = 0;
+ dst->uhi_st_blocks = 0;
+#else
+ dst->uhi_st_blksize = tswap64(src->st_blksize);
+ dst->uhi_st_blocks = tswap64(src->st_blocks);
+#endif
+ unlock_user(dst, vaddr, len);
+ return 0;
+}
+
+static int get_open_flags(target_ulong target_flags)
+{
+ int open_flags = 0;
+
+ if (target_flags & UHIOpen_RDWR) {
+ open_flags |= O_RDWR;
+ } else if (target_flags & UHIOpen_WRONLY) {
+ open_flags |= O_WRONLY;
+ } else {
+ open_flags |= O_RDONLY;
+ }
+
+ open_flags |= (target_flags & UHIOpen_APPEND) ? O_APPEND : 0;
+ open_flags |= (target_flags & UHIOpen_CREAT) ? O_CREAT : 0;
+ open_flags |= (target_flags & UHIOpen_TRUNC) ? O_TRUNC : 0;
+ open_flags |= (target_flags & UHIOpen_EXCL) ? O_EXCL : 0;
+
+ return open_flags;
+}
+
+static int write_to_file(CPUMIPSState *env, target_ulong fd, target_ulong vaddr,
+ target_ulong len, target_ulong offset)
+{
+ int num_of_bytes;
+ void *dst = lock_user(VERIFY_READ, vaddr, len, 1);
+ if (!dst) {
+ return 0;
+ }
+
+ if (offset) {
+#ifdef _WIN32
+ num_of_bytes = 0;
+#else
+ num_of_bytes = pwrite(fd, dst, len, offset);
+#endif
+ } else {
+ num_of_bytes = write(fd, dst, len);
+ }
+
+ unlock_user(dst, vaddr, 0);
+ return num_of_bytes;
+}
+
+static int read_from_file(CPUMIPSState *env, target_ulong fd,
+ target_ulong vaddr, target_ulong len,
+ target_ulong offset)
+{
+ int num_of_bytes;
+ void *dst = lock_user(VERIFY_WRITE, vaddr, len, 0);
+ if (!dst) {
+ return 0;
+ }
+
+ if (offset) {
+#ifdef _WIN32
+ num_of_bytes = 0;
+#else
+ num_of_bytes = pread(fd, dst, len, offset);
+#endif
+ } else {
+ num_of_bytes = read(fd, dst, len);
+ }
+
+ unlock_user(dst, vaddr, len);
+ return num_of_bytes;
+}
+
+#define GET_TARGET_STRING(p, addr) \
+ do { \
+ p = lock_user_string(addr); \
+ if (!p) { \
+ gpr[2] = -1; \
+ gpr[3] = ENAMETOOLONG; \
+ goto uhi_done; \
+ } \
+ } while (0)
+
+#define FREE_TARGET_STRING(p, gpr) \
+ do { \
+ unlock_user(p, gpr, 0); \
+ } while (0)
+
+void helper_do_semihosting(CPUMIPSState *env)
+{
+ target_ulong *gpr = env->active_tc.gpr;
+ const UHIOp op = gpr[25];
+ char *p, *p2;
+
+ switch (op) {
+ case UHI_exit:
+ qemu_log("UHI(%d): exit(%d)\n", op, (int)gpr[4]);
+ exit(gpr[4]);
+ case UHI_open:
+ GET_TARGET_STRING(p, gpr[4]);
+ if (!strcmp("/dev/stdin", p)) {
+ gpr[2] = 0;
+ } else if (!strcmp("/dev/stdout", p)) {
+ gpr[2] = 1;
+ } else if (!strcmp("/dev/stderr", p)) {
+ gpr[2] = 2;
+ } else {
+ gpr[2] = open(p, get_open_flags(gpr[5]), gpr[6]);
+ gpr[3] = errno;
+ }
+ FREE_TARGET_STRING(p, gpr[4]);
+ break;
+ case UHI_close:
+ if (gpr[4] < 3) {
+ /* ignore closing stdin/stdout/stderr */
+ gpr[2] = 0;
+ goto uhi_done;
+ }
+ gpr[2] = close(gpr[4]);
+ gpr[3] = errno;
+ break;
+ case UHI_read:
+ gpr[2] = read_from_file(env, gpr[4], gpr[5], gpr[6], 0);
+ gpr[3] = errno;
+ break;
+ case UHI_write:
+ gpr[2] = write_to_file(env, gpr[4], gpr[5], gpr[6], 0);
+ gpr[3] = errno;
+ break;
+ case UHI_lseek:
+ gpr[2] = lseek(gpr[4], gpr[5], gpr[6]);
+ gpr[3] = errno;
+ break;
+ case UHI_unlink:
+ GET_TARGET_STRING(p, gpr[4]);
+ gpr[2] = remove(p);
+ gpr[3] = errno;
+ FREE_TARGET_STRING(p, gpr[4]);
+ break;
+ case UHI_fstat:
+ {
+ struct stat sbuf;
+ memset(&sbuf, 0, sizeof(sbuf));
+ gpr[2] = fstat(gpr[4], &sbuf);
+ gpr[3] = errno;
+ if (gpr[2]) {
+ goto uhi_done;
+ }
+ gpr[2] = copy_stat_to_target(env, &sbuf, gpr[5]);
+ }
+ break;
+ case UHI_argc:
+ case UHI_argnlen:
+ case UHI_argn:
+ /* TODO */
+ break;
+ case UHI_plog:
+ GET_TARGET_STRING(p, gpr[4]);
+ p2 = strstr(p, "%d");
+ if (p2) {
+ int char_num = p2 - p;
+ char *buf = g_malloc(char_num + 1);
+ strncpy(buf, p, char_num);
+ buf[char_num] = '\0';
+ gpr[2] = printf("%s%d%s", buf, (int)gpr[5], p2 + 2);
+ g_free(buf);
+ } else {
+ gpr[2] = printf("%s", p);
+ }
+ FREE_TARGET_STRING(p, gpr[4]);
+ break;
+ case UHI_assert:
+ GET_TARGET_STRING(p, gpr[4]);
+ GET_TARGET_STRING(p2, gpr[5]);
+ printf("assertion '");
+ printf("\"%s\"", p);
+ printf("': file \"%s\", line %d\n", p2, (int)gpr[6]);
+ FREE_TARGET_STRING(p2, gpr[5]);
+ FREE_TARGET_STRING(p, gpr[4]);
+ abort();
+ break;
+ case UHI_pread:
+ gpr[2] = read_from_file(env, gpr[4], gpr[5], gpr[6], gpr[7]);
+ gpr[3] = errno;
+ break;
+ case UHI_pwrite:
+ gpr[2] = write_to_file(env, gpr[4], gpr[5], gpr[6], gpr[7]);
+ gpr[3] = errno;
+ break;
+#ifndef _WIN32
+ case UHI_link:
+ GET_TARGET_STRING(p, gpr[4]);
+ GET_TARGET_STRING(p2, gpr[5]);
+ gpr[2] = link(p, p2);
+ gpr[3] = errno;
+ FREE_TARGET_STRING(p2, gpr[5]);
+ FREE_TARGET_STRING(p, gpr[4]);
+ break;
+#endif
+ default:
+ fprintf(stderr, "Unknown UHI operation %d\n", op);
+ abort();
+ }
+uhi_done:
+ return;
+}
diff --git a/target-mips/translate.c b/target-mips/translate.c
index ca51149..82fa5a4 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -25,6 +25,7 @@
#include "disas/disas.h"
#include "tcg-op.h"
#include "exec/cpu_ldst.h"
+#include "sysemu/sysemu.h"
#include "exec/helper-proto.h"
#include "exec/helper-gen.h"
@@ -11267,6 +11268,15 @@ static int decode_extended_mips16_opc (CPUMIPSState *env, DisasContext *ctx)
return 4;
}
+static inline bool is_uhi(int sdbbp_code)
+{
+#ifdef CONFIG_USER_ONLY
+ return false;
+#else
+ return semihosting_enabled && sdbbp_code == 1;
+#endif
+}
+
static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx)
{
int rx, ry;
@@ -11566,14 +11576,18 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx)
}
break;
case RR_SDBBP:
- /* XXX: not clear which exception should be raised
- * when in debug mode...
- */
- check_insn(ctx, ISA_MIPS32);
- if (!(ctx->hflags & MIPS_HFLAG_DM)) {
- generate_exception(ctx, EXCP_DBp);
+ if (is_uhi(extract32(ctx->opcode, 5, 6))) {
+ gen_helper_do_semihosting(cpu_env);
} else {
- generate_exception(ctx, EXCP_DBp);
+ /* XXX: not clear which exception should be raised
+ * when in debug mode...
+ */
+ check_insn(ctx, ISA_MIPS32);
+ if (!(ctx->hflags & MIPS_HFLAG_DM)) {
+ generate_exception(ctx, EXCP_DBp);
+ } else {
+ generate_exception(ctx, EXCP_DBp);
+ }
}
break;
case RR_SLT:
@@ -12421,14 +12435,18 @@ static void gen_pool16c_insn(DisasContext *ctx)
generate_exception(ctx, EXCP_BREAK);
break;
case SDBBP16:
- /* XXX: not clear which exception should be raised
- * when in debug mode...
- */
- check_insn(ctx, ISA_MIPS32);
- if (!(ctx->hflags & MIPS_HFLAG_DM)) {
- generate_exception(ctx, EXCP_DBp);
+ if (is_uhi(extract32(ctx->opcode, 0, 4))) {
+ gen_helper_do_semihosting(cpu_env);
} else {
- generate_exception(ctx, EXCP_DBp);
+ /* XXX: not clear which exception should be raised
+ * when in debug mode...
+ */
+ check_insn(ctx, ISA_MIPS32);
+ if (!(ctx->hflags & MIPS_HFLAG_DM)) {
+ generate_exception(ctx, EXCP_DBp);
+ } else {
+ generate_exception(ctx, EXCP_DBp);
+ }
}
break;
case JRADDIUSP + 0:
@@ -16190,10 +16208,14 @@ static void decode_opc_special_r6(CPUMIPSState *env, DisasContext *ctx)
}
break;
case R6_OPC_SDBBP:
- if (ctx->hflags & MIPS_HFLAG_SBRI) {
- generate_exception(ctx, EXCP_RI);
+ if (is_uhi(extract32(ctx->opcode, 6, 20))) {
+ gen_helper_do_semihosting(cpu_env);
} else {
- generate_exception(ctx, EXCP_DBp);
+ if (ctx->hflags & MIPS_HFLAG_SBRI) {
+ generate_exception(ctx, EXCP_RI);
+ } else {
+ generate_exception(ctx, EXCP_DBp);
+ }
}
break;
#if defined(TARGET_MIPS64)
@@ -16563,16 +16585,19 @@ static void decode_opc_special2_legacy(CPUMIPSState *env, DisasContext *ctx)
gen_cl(ctx, op1, rd, rs);
break;
case OPC_SDBBP:
- /* XXX: not clear which exception should be raised
- * when in debug mode...
- */
- check_insn(ctx, ISA_MIPS32);
- if (!(ctx->hflags & MIPS_HFLAG_DM)) {
- generate_exception(ctx, EXCP_DBp);
+ if (is_uhi(extract32(ctx->opcode, 6, 20))) {
+ gen_helper_do_semihosting(cpu_env);
} else {
- generate_exception(ctx, EXCP_DBp);
+ /* XXX: not clear which exception should be raised
+ * when in debug mode...
+ */
+ check_insn(ctx, ISA_MIPS32);
+ if (!(ctx->hflags & MIPS_HFLAG_DM)) {
+ generate_exception(ctx, EXCP_DBp);
+ } else {
+ generate_exception(ctx, EXCP_DBp);
+ }
}
- /* Treat as NOP. */
break;
#if defined(TARGET_MIPS64)
case OPC_DCLO:
--
2.1.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [Qemu-devel] [PATCH 3/4] target-mips: add "-semihosting-arg" option and implement UHI Arg* ops
2015-02-27 17:00 [Qemu-devel] [PATCH 0/4] target-mips: add UHI semihosting support Leon Alrae
2015-02-27 17:00 ` [Qemu-devel] [PATCH 1/4] include/softmmu-semi.h: Make semihosting support 64-bit clean Leon Alrae
2015-02-27 17:00 ` [Qemu-devel] [PATCH 2/4] target-mips: add Unified Hosting Interface (UHI) support Leon Alrae
@ 2015-02-27 17:00 ` Leon Alrae
2015-03-01 22:39 ` Matthew Fortune
2015-02-27 17:00 ` [Qemu-devel] [PATCH 4/4] hw/mips: Do not clear BEV for MIPS malta kernel load Leon Alrae
3 siblings, 1 reply; 9+ messages in thread
From: Leon Alrae @ 2015-02-27 17:00 UTC (permalink / raw)
To: qemu-devel; +Cc: matthew.fortune, aurelien
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(-)
diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c
index 5845158..2dfe964 100644
--- a/hw/mips/mips_malta.c
+++ b/hw/mips/mips_malta.c
@@ -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) */
diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
index 1ab7063..7d63da2 100644
--- a/include/sysemu/sysemu.h
+++ b/include/sysemu/sysemu.h
@@ -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;
diff --git a/qemu-options.hx b/qemu-options.hx
index 99ad1ae..bd058d0 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -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
diff --git a/target-mips/mips-semi.c b/target-mips/mips-semi.c
index 3bf7b2a..63f2700 100644
--- a/target-mips/mips-semi.c
+++ b/target-mips/mips-semi.c
@@ -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]);
diff --git a/target-mips/translate.c b/target-mips/translate.c
index 82fa5a4..678c3d5 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -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)
diff --git a/vl.c b/vl.c
index e1ffd0a..b2d3422 100644
--- a/vl.c
+++ b/vl.c
@@ -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') {
--
2.1.0
^ permalink raw reply related [flat|nested] 9+ messages in thread