qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH 1/1] linux-user: add support for big endian variants of riscv


From: Rory Bolt
Subject: [PATCH 1/1] linux-user: add support for big endian variants of riscv
Date: Fri, 30 Jun 2023 04:14:09 -0700

RISCV architecture supports an optional big endian mode of operation.
In this mode, data accesses are treated as big endian, while code is
always in little endian format. This is similar to how the ARM
architecture treats it's optional bi-endian support. This patch adds
support for big endian RISCV operation to linux-user.

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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]