diff --git a/riscv/sim.cc b/riscv/sim.cc index 0ef13b8bfb..741e685cdd 100644 --- a/riscv/sim.cc +++ b/riscv/sim.cc @@ -267,9 +267,43 @@ void sim_t::set_procs_debug(bool value) procs[i]->set_debug(value); } -static bool paddr_ok(reg_t addr) +static bool is_ascending(const std::pair &L, + const std::pair &R) { - return (addr >> MAX_PADDR_BITS) == 0; + return L.first < R.first; +} + +bool sim_t::paddr_ok(reg_t addr) const +{ + // TODO: this implementation erroneously assumes that a maximum physical + // address is limited to (1 << MAX_PADDR_BITS). + // There are a few issues with this assumption: + // 1. if satp.MODE == Bare, then virtual addresses are equal to physical + // and there are no limitations on the number of bits one may use. + // 2. the actual limit can only be derived from the current privilege + // mode and CSR configuration and thus can be determined only in runtime. + // + // To do such a check properly the translation routine must return some + // auxiliary attributes, like translation mode, memory attributes, etc. + // These could be later consumed by routines like paddr_ok. + // + // In the meantime, to allow access to large physical addresses and to + // minimize the scope of changes we implement a small add-hoc solution to + // lookup platform configuration and figure out if we have any memory + // above (1 << MAX_PADDR_BITS) + if ((addr >> MAX_PADDR_BITS) == 0) + return true; + + if (mems.empty()) + return false; + + assert(std::is_sorted(mems.begin(), mems.end(), is_ascending)); + // last-ditch effort to detect if the platform has physical memory + // at the addresses greater than (1 << MAX_PADDR_BITS) + reg_t base_addr = mems.back().first; + reg_t size = mems.back().second->size(); + reg_t last_available_pa = base_addr + size - 1; + return (last_available_pa >= (1ull << MAX_PADDR_BITS)); } bool sim_t::mmio_load(reg_t addr, size_t len, uint8_t* bytes) diff --git a/riscv/sim.h b/riscv/sim.h index c355f3167c..8ff0777320 100644 --- a/riscv/sim.h +++ b/riscv/sim.h @@ -68,6 +68,8 @@ class sim_t : public htif_t, public simif_t // Callback for processors to let the simulation know they were reset. void proc_reset(unsigned id); + bool paddr_ok(reg_t addr) const; + private: isa_parser_t isa; const cfg_t * const cfg; diff --git a/spike_main/spike.cc b/spike_main/spike.cc index 52cee90f8a..86857fdf2d 100644 --- a/spike_main/spike.cc +++ b/spike_main/spike.cc @@ -236,17 +236,6 @@ static std::vector parse_mem_layout(const char* arg) exit(EXIT_FAILURE); } - const uint64_t max_allowed_pa = (1ull << MAX_PADDR_BITS) - 1ull; - if (mem_region.get_inclusive_end() > max_allowed_pa) { - fprintf(stderr, "unsupported memory region [0x%llX, 0x%llX] specified (" - "currently, spike does not support physical adresses " - "larger than 0x%llX)\n", - (unsigned long long)mem_region.get_base(), - (unsigned long long)mem_region.get_inclusive_end(), - (unsigned long long)max_allowed_pa); - exit(EXIT_FAILURE); - } - res.push_back(mem_region); if (!*p) break;