Signed-off-by: rory.opensource@gmail.com
---
configs/targets/riscv64be-linux-user.mak | 7 +++++++
configure | 1 +
linux-user/elfload.c | 10 ++++++++++
linux-user/include/host/riscv/host-signal.h | 3 +++
linux-user/riscv/signal.c | 5 +++++
linux-user/riscv/target_syscall.h | 8 ++++++++
scripts/probe-gdb-support.py | 4 ++--
scripts/qemu-binfmt-conf.sh | 12 ++++++++++--
target/riscv/cpu.c | 5 +++++
target/riscv/translate.c | 13 +++++++++++++
10 files changed, 64 insertions(+), 4 deletions(-)
create mode 100644 configs/targets/riscv64be-linux-user.mak
diff --git a/configs/targets/riscv64be-linux-user.mak
b/configs/targets/riscv64be-linux-user.mak
new file mode 100644
index 0000000000..f22f5f0971
--- /dev/null
+++ b/configs/targets/riscv64be-linux-user.mak
@@ -0,0 +1,7 @@
+TARGET_ARCH=riscv64
+TARGET_BASE_ARCH=riscv
+TARGET_ABI_DIR=riscv
+TARGET_BIG_ENDIAN=y
+TARGET_XML_FILES= gdb-xml/riscv-64bit-cpu.xml gdb-xml/riscv-32bit-fpu.xml
gdb-xml/riscv-64bit-fpu.xml gdb-xml/riscv-64bit-virtual.xml
+CONFIG_SEMIHOSTING=y
+CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
diff --git a/configure b/configure
index 2b41c49c0d..90795a0e9f 100755
--- a/configure
+++ b/configure
@@ -1190,6 +1190,7 @@ fi
: ${cross_prefix_ppc64="powerpc64-linux-gnu-"}
: ${cross_prefix_ppc64le="$cross_prefix_ppc64"}
: ${cross_prefix_riscv64="riscv64-linux-gnu-"}
+: ${cross_prefix_riscv64be="riscv64be-linux-gnu-"}
: ${cross_prefix_s390x="s390x-linux-gnu-"}
: ${cross_prefix_sh4="sh4-linux-gnu-"}
: ${cross_prefix_sparc64="sparc64-linux-gnu-"}
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 9a2ec568b0..e0204c7069 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -1681,8 +1681,18 @@ static void elf_core_copy_regs(target_elf_gregset_t
*regs,
#ifdef TARGET_RISCV32
#define ELF_CLASS ELFCLASS32
+#if TARGET_BIG_ENDIAN
+#define ELF_PLATFORM "riscv32be"
+#else
+#define ELF_PLATFORM "riscv32"
+#endif
#else
#define ELF_CLASS ELFCLASS64
+#if TARGET_BIG_ENDIAN
+#define ELF_PLATFORM "riscv64be"
+#else
+#define ELF_PLATFORM "riscv64"
+#endif
#endif
#define ELF_HWCAP get_elf_hwcap()
diff --git a/linux-user/include/host/riscv/host-signal.h
b/linux-user/include/host/riscv/host-signal.h
index decacb2325..b3f2735261 100644
--- a/linux-user/include/host/riscv/host-signal.h
+++ b/linux-user/include/host/riscv/host-signal.h
@@ -38,6 +38,9 @@ static inline bool host_signal_write(siginfo_t *info,
host_sigcontext *uc)
*/
const uint16_t *pinsn = (const uint16_t *)host_signal_pc(uc);
uint16_t insn = pinsn[0];
+#if TARGET_BIG_ENDIAN
+ insn = (insn << 8) | (insn >> 8);
+#endif
/* 16-bit instructions */
switch (insn & 0xe003) {
diff --git a/linux-user/riscv/signal.c b/linux-user/riscv/signal.c
index eaa168199a..1d9e3413fb 100644
--- a/linux-user/riscv/signal.c
+++ b/linux-user/riscv/signal.c
@@ -199,8 +199,13 @@ void setup_sigtramp(abi_ulong sigtramp_page)
uint32_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 8, 0);
assert(tramp != NULL);
+#if TARGET_BIG_ENDIAN
+ __put_user(0x9308b008, tramp + 0); /* li a7, 139 = __NR_rt_sigreturn */
+ __put_user(0x73000000, tramp + 1); /* ecall */
+#else
__put_user(0x08b00893, tramp + 0); /* li a7, 139 = __NR_rt_sigreturn */
__put_user(0x00000073, tramp + 1); /* ecall */
+#endif
default_rt_sigreturn = sigtramp_page;
unlock_user(tramp, sigtramp_page, 8);
diff --git a/linux-user/riscv/target_syscall.h
b/linux-user/riscv/target_syscall.h
index 7601f10c28..88c0ac1351 100644
--- a/linux-user/riscv/target_syscall.h
+++ b/linux-user/riscv/target_syscall.h
@@ -44,10 +44,18 @@ struct target_pt_regs {
};
#ifdef TARGET_RISCV32
+#if TARGET_BIG_ENDIAN
+#define UNAME_MACHINE "riscv32be"
+#else
#define UNAME_MACHINE "riscv32"
+#endif
#define UNAME_MINIMUM_RELEASE "5.4.0"
#else
+#if TARGET_BIG_ENDIAN
+#define UNAME_MACHINE "riscv64be"
+#else
#define UNAME_MACHINE "riscv64"
+#endif
#define UNAME_MINIMUM_RELEASE "4.15.0"
#endif
diff --git a/scripts/probe-gdb-support.py b/scripts/probe-gdb-support.py
index 5755255966..a1e0905a10 100644
--- a/scripts/probe-gdb-support.py
+++ b/scripts/probe-gdb-support.py
@@ -41,8 +41,8 @@
"or1k" : "or1k",
"powerpc:common" : "ppc",
"powerpc:common64" : ["ppc64", "ppc64le"],
- "riscv:rv32" : "riscv32",
- "riscv:rv64" : "riscv64",
+ "riscv:rv32" : ["riscv32", "riscv32be"],
+ "riscv:rv64" : ["riscv64", "riscv64be"],
"s390:64-bit" : "s390x",
"sh4" : ["sh4", "sh4eb"],
"sparc": "sparc",
diff --git a/scripts/qemu-binfmt-conf.sh b/scripts/qemu-binfmt-conf.sh
index 6ef9f118d9..e1ee9f831b 100755
--- a/scripts/qemu-binfmt-conf.sh
+++ b/scripts/qemu-binfmt-conf.sh
@@ -3,8 +3,8 @@
qemu_target_list="i386 i486 alpha arm armeb sparc sparc32plus sparc64 \
ppc ppc64 ppc64le m68k mips mipsel mipsn32 mipsn32el mips64 mips64el \
-sh4 sh4eb s390x aarch64 aarch64_be hppa riscv32 riscv64 xtensa xtensaeb \
-microblaze microblazeel or1k x86_64 hexagon loongarch64"
+sh4 sh4eb s390x aarch64 aarch64_be hppa riscv32 riscv32be riscv64 riscv64be \
+xtensa xtensaeb microblaze microblazeel or1k x86_64 hexagon loongarch64"
i386_magic='\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x03\x00'
i386_mask='\xff\xff\xff\xff\xff\xfe\xfe\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'
@@ -112,10 +112,18 @@
riscv32_magic='\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x
riscv32_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'
riscv32_family=riscv
+riscv32be_magic='\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xf3'
+riscv32be_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'
+riscv32be_family=riscv
+
riscv64_magic='\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xf3\x00'
riscv64_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'
riscv64_family=riscv
+riscv64be_magic='\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xf3'
+riscv64be_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'
+riscv64be_family=riscv
+
xtensa_magic='\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x5e\x00'
xtensa_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'
xtensa_family=xtensa
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 881bddf393..26fb3e830d 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -873,6 +873,11 @@ static void riscv_cpu_disas_set_info(CPUState *s,
disassemble_info *info)
default:
g_assert_not_reached();
}
+#if TARGET_BIG_ENDIAN
+ info->endian = BFD_ENDIAN_LITTLE;
+#else
+ info->endian = BFD_ENDIAN_BIG;
+#endif
}
static void riscv_cpu_validate_v(CPURISCVState *env, RISCVCPUConfig *cfg,
diff --git a/target/riscv/translate.c b/target/riscv/translate.c
index 8a33da811e..3991ff6be0 100644
--- a/target/riscv/translate.c
+++ b/target/riscv/translate.c
@@ -1157,9 +1157,16 @@ static void decode_opc(CPURISCVState *env, DisasContext
*ctx, uint16_t opcode)
}
} else {
uint32_t opcode32 = opcode;
+#if TARGET_BIG_ENDIAN
+ opcode32 = bswap16(opcode);
+#endif
opcode32 = deposit32(opcode32, 16, 16,
translator_lduw(env, &ctx->base,
ctx->base.pc_next + 2));
+#if TARGET_BIG_ENDIAN
+ opcode32 = (opcode32) << 16 | (opcode32 >> 16);
+ opcode32 = bswap32(opcode32);
+#endif
ctx->opcode = opcode32;
for (size_t i = 0; i < ARRAY_SIZE(decoders); ++i) {
@@ -1230,6 +1237,9 @@ static void riscv_tr_translate_insn(DisasContextBase
*dcbase, CPUState *cpu)
DisasContext *ctx = container_of(dcbase, DisasContext, base);
CPURISCVState *env = cpu->env_ptr;
uint16_t opcode16 = translator_lduw(env, &ctx->base, ctx->base.pc_next);
+#if TARGET_BIG_ENDIAN
+ opcode16 = bswap16(opcode16);
+#endif
ctx->ol = ctx->xl;
decode_opc(env, ctx, opcode16);
@@ -1244,6 +1254,9 @@ static void riscv_tr_translate_insn(DisasContextBase
*dcbase, CPUState *cpu)
if (page_ofs > TARGET_PAGE_SIZE - MAX_INSN_LEN) {
uint16_t next_insn = cpu_lduw_code(env, ctx->base.pc_next);
+#if TARGET_BIG_ENDIAN
+ next_insn = bswap16(next_insn);
+#endif
int len = insn_len(next_insn);
if (!is_same_page(&ctx->base, ctx->base.pc_next + len - 1)) {