From 8d09d845a7373cce52d3943f5dca1a2ac34a4f83 Mon Sep 17 00:00:00 2001 From: Marcus Comstedt Date: Sun, 11 Oct 2020 13:36:13 +0200 Subject: Implement support for big-endian targets --- fesvr/elfloader.cc | 23 ++++++++++++++++++----- fesvr/htif.cc | 4 ++-- fesvr/htif.h | 26 ++++++++++++++++++++++++++ fesvr/memif.h | 19 +++++++++++++++++++ fesvr/syscall.cc | 10 +++++----- 5 files changed, 70 insertions(+), 12 deletions(-) (limited to 'fesvr') diff --git a/fesvr/elfloader.cc b/fesvr/elfloader.cc index a4bae1e..6da3a41 100644 --- a/fesvr/elfloader.cc +++ b/fesvr/elfloader.cc @@ -31,7 +31,7 @@ std::map load_elf(const char* fn, memif_t* memif, reg_t* assert(size >= sizeof(Elf64_Ehdr)); const Elf64_Ehdr* eh64 = (const Elf64_Ehdr*)buf; assert(IS_ELF32(*eh64) || IS_ELF64(*eh64)); - assert(IS_ELFLE(*eh64)); + assert(IS_ELFLE(*eh64) || IS_ELFBE(*eh64)); assert(IS_ELF_EXEC(*eh64)); assert(IS_ELF_RISCV(*eh64) || IS_ELF_EM_NONE(*eh64)); assert(IS_ELF_VCURRENT(*eh64)); @@ -83,10 +83,23 @@ std::map load_elf(const char* fn, memif_t* memif, reg_t* } \ } while(0) - if (IS_ELF32(*eh64)) - LOAD_ELF(Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Sym, from_le); - else - LOAD_ELF(Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Sym, from_le); + if (IS_ELFLE(*eh64)) { + memif->set_target_endianness(memif_endianness_little); + if (IS_ELF32(*eh64)) + LOAD_ELF(Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Sym, from_le); + else + LOAD_ELF(Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Sym, from_le); + } else { +#ifndef RISCV_ENABLE_DUAL_ENDIAN + throw std::invalid_argument("Specified ELF is big endian. Configure with --enable-dual-endian to enable support"); +#else + memif->set_target_endianness(memif_endianness_big); + if (IS_ELF32(*eh64)) + LOAD_ELF(Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Sym, from_be); + else + LOAD_ELF(Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Sym, from_be); +#endif + } munmap(buf, size); diff --git a/fesvr/htif.cc b/fesvr/htif.cc index 30b13de..996e321 100644 --- a/fesvr/htif.cc +++ b/fesvr/htif.cc @@ -216,7 +216,7 @@ int htif_t::run() while (!signal_exit && exitcode == 0) { - if (auto tohost = from_le(mem.read_uint64(tohost_addr))) { + if (auto tohost = from_target(mem.read_uint64(tohost_addr))) { mem.write_uint64(tohost_addr, 0); command_t cmd(mem, tohost, fromhost_callback); device_list.handle_command(cmd); @@ -227,7 +227,7 @@ int htif_t::run() device_list.tick(); if (!fromhost_queue.empty() && mem.read_uint64(fromhost_addr) == 0) { - mem.write_uint64(fromhost_addr, to_le(fromhost_queue.front())); + mem.write_uint64(fromhost_addr, to_target(fromhost_queue.front())); fromhost_queue.pop(); } } diff --git a/fesvr/htif.h b/fesvr/htif.h index 44a3b12..66a626d 100644 --- a/fesvr/htif.h +++ b/fesvr/htif.h @@ -6,9 +6,11 @@ #include "memif.h" #include "syscall.h" #include "device.h" +#include "byteorder.h" #include #include #include +#include class htif_t : public chunked_memif_t { @@ -27,6 +29,30 @@ class htif_t : public chunked_memif_t virtual memif_t& memif() { return mem; } + template inline T from_target(T n) const + { +#ifdef RISCV_ENABLE_DUAL_ENDIAN + memif_endianness_t endianness = get_target_endianness(); + assert(endianness == memif_endianness_little || endianness == memif_endianness_big); + + return endianness == memif_endianness_big? from_be(n) : from_le(n); +#else + return from_le(n); +#endif + } + + template inline T to_target(T n) const + { +#ifdef RISCV_ENABLE_DUAL_ENDIAN + memif_endianness_t endianness = get_target_endianness(); + assert(endianness == memif_endianness_little || endianness == memif_endianness_big); + + return endianness == memif_endianness_big? to_be(n) : to_le(n); +#else + return to_le(n); +#endif + } + protected: virtual void reset() = 0; diff --git a/fesvr/memif.h b/fesvr/memif.h index 3854d66..aaa9f05 100644 --- a/fesvr/memif.h +++ b/fesvr/memif.h @@ -10,6 +10,12 @@ typedef uint64_t reg_t; typedef int64_t sreg_t; typedef reg_t addr_t; +typedef enum { + memif_endianness_undecided, + memif_endianness_little, + memif_endianness_big +} memif_endianness_t; + class chunked_memif_t { public: @@ -19,6 +25,11 @@ public: virtual size_t chunk_align() = 0; virtual size_t chunk_max_size() = 0; + + virtual void set_target_endianness(memif_endianness_t endianness) {} + virtual memif_endianness_t get_target_endianness() const { + return memif_endianness_undecided; + } }; class memif_t @@ -55,6 +66,14 @@ public: virtual void write_uint64(addr_t addr, uint64_t val); virtual void write_int64(addr_t addr, int64_t val); + // endianness + virtual void set_target_endianness(memif_endianness_t endianness) { + cmemif->set_target_endianness(endianness); + } + virtual memif_endianness_t get_target_endianness() const { + return cmemif->get_target_endianness(); + } + protected: chunked_memif_t* cmemif; }; diff --git a/fesvr/syscall.cc b/fesvr/syscall.cc index f0bdd25..6feb13b 100644 --- a/fesvr/syscall.cc +++ b/fesvr/syscall.cc @@ -300,21 +300,21 @@ reg_t syscall_t::sys_getmainvars(reg_t pbuf, reg_t limit, reg_t a2, reg_t a3, re { std::vector args = htif->target_args(); std::vector words(args.size() + 3); - words[0] = to_le(args.size()); + words[0] = htif->to_target(args.size()); words[args.size()+1] = 0; // argv[argc] = NULL words[args.size()+2] = 0; // envp[0] = NULL size_t sz = (args.size() + 3) * sizeof(words[0]); for (size_t i = 0; i < args.size(); i++) { - words[i+1] = to_le(sz + pbuf); + words[i+1] = htif->to_target(sz + pbuf); sz += args[i].length() + 1; } std::vector bytes(sz); memcpy(&bytes[0], &words[0], sizeof(words[0]) * words.size()); for (size_t i = 0; i < args.size(); i++) - strcpy(&bytes[from_le(words[i+1]) - pbuf], args[i].c_str()); + strcpy(&bytes[htif->from_target(words[i+1]) - pbuf], args[i].c_str()); if (bytes.size() > limit) return -ENOMEM; @@ -343,11 +343,11 @@ void syscall_t::dispatch(reg_t mm) reg_t magicmem[8]; memif->read(mm, sizeof(magicmem), magicmem); - reg_t n = from_le(magicmem[0]); + reg_t n = htif->from_target(magicmem[0]); if (n >= table.size() || !table[n]) throw std::runtime_error("bad syscall #" + std::to_string(n)); - magicmem[0] = to_le((this->*table[n])(from_le(magicmem[1]), from_le(magicmem[2]), from_le(magicmem[3]), from_le(magicmem[4]), from_le(magicmem[5]), from_le(magicmem[6]), from_le(magicmem[7]))); + magicmem[0] = htif->to_target((this->*table[n])(htif->from_target(magicmem[1]), htif->from_target(magicmem[2]), htif->from_target(magicmem[3]), htif->from_target(magicmem[4]), htif->from_target(magicmem[5]), htif->from_target(magicmem[6]), htif->from_target(magicmem[7]))); memif->write(mm, sizeof(magicmem), magicmem); } -- cgit v1.1