On Fri, Jun 30, 2023 at 7:45 AM Palmer Dabbelt <pal...@dabbelt.com> wrote: > > On Fri, 30 Jun 2023 04:14:09 PDT (-0700), rory.opensou...@gmail.com wrote: > > 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. > > We don't have BE support in Linux yet. IIRC we've had some other > linux-user stuff go in with a "we'll change it to match whatever uABI > Linux ends up with" sort of caveat, but I might be mistaken. I'm not > opposed to doing that sort of thing for BE as well. I don't remember > what the right way to indicate that is, though. > > > Signed-off-by: rory.opensou...@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)) { > > Nothing's jumping out as wrong to me, but I haven't given BE much > thought so I wouldn't be surprised if there's something wrong somewhere. > I'm happy to look a bit deeper, but let's see if the unstable uABI stuff > is OK with folks first?
If there isn't Linux support I'm reluctant to accept this as we have no way to test it. Alistair >