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)) {
