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

>

Reply via email to