From 0162a6e72421b5cbec1905b4cae7bfab98afe83f Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Tue, 12 Nov 2019 16:31:13 -0800 Subject: In parse_isa_string, populate max_isa rather than state.misa reset will copy max_isa over to state.misa. --- riscv/processor.cc | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/riscv/processor.cc b/riscv/processor.cc index 59fa062..caf927e 100644 --- a/riscv/processor.cc +++ b/riscv/processor.cc @@ -135,10 +135,10 @@ void processor_t::parse_isa_string(const char* str) ""; max_xlen = 64; - state.misa = reg_t(2) << 62; + max_isa = reg_t(2) << 62; if (strncmp(p, "rv32", 4) == 0) - max_xlen = 32, state.misa = reg_t(1) << 30, p += 4; + max_xlen = 32, max_isa = reg_t(1) << 30, p += 4; else if (strncmp(p, "rv64", 4) == 0) p += 4; else if (strncmp(p, "rv", 2) == 0) @@ -154,11 +154,9 @@ void processor_t::parse_isa_string(const char* str) } isa_string = "rv" + std::to_string(max_xlen) + p; - state.misa |= 1L << ('s' - 'a'); // advertise support for supervisor mode - state.misa |= 1L << ('u' - 'a'); // advertise support for user mode while (*p) { - state.misa |= 1L << (*p - 'a'); + max_isa |= 1L << (*p - 'a'); if (auto next = strchr(all_subsets, *p)) { all_subsets = next + 1; @@ -179,8 +177,6 @@ void processor_t::parse_isa_string(const char* str) if (supports_extension('Q') && !supports_extension('D')) bad_isa_string(str); - - max_isa = state.misa; } void state_t::reset(reg_t max_isa) -- cgit v1.1 From 24e587d43315dabaac2b7b8a631d459fc12f3f14 Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Tue, 12 Nov 2019 16:33:02 -0800 Subject: Factor out boilerplate strtolower function --- riscv/processor.cc | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/riscv/processor.cc b/riscv/processor.cc index caf927e..21eb472 100644 --- a/riscv/processor.cc +++ b/riscv/processor.cc @@ -121,11 +121,17 @@ void processor_t::parse_varch_string(const char* s) VU.SLEN = slen; } -void processor_t::parse_isa_string(const char* str) +static std::string strtolower(const char* str) { - std::string lowercase, tmp; + std::string res; for (const char *r = str; *r; r++) - lowercase += std::tolower(*r); + res += std::tolower(*r); + return res; +} + +void processor_t::parse_isa_string(const char* str) +{ + std::string lowercase = strtolower(str), tmp; const char* p = lowercase.c_str(); const char* all_subsets = "imafdqc" -- cgit v1.1 From 8ffefbc9a1f7730d14a2f694906bcc681cbca2e5 Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Tue, 12 Nov 2019 16:57:10 -0800 Subject: Add --priv option to control which privilege modes are available --- ChangeLog.md | 1 + config.h.in | 3 +++ configure | 19 +++++++++++++++++++ riscv/processor.cc | 29 +++++++++++++++++++++++++++-- riscv/processor.h | 9 +++++---- riscv/riscv.ac | 6 ++++++ riscv/sim.cc | 7 ++++--- riscv/sim.h | 3 ++- spike_main/spike-dasm.cc | 2 +- spike_main/spike-log-parser.cc | 2 +- spike_main/spike.cc | 5 ++++- 11 files changed, 73 insertions(+), 13 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 9d456c2..2be2d4a 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -3,6 +3,7 @@ Version 1.0.1-dev - Preliminary support for a subset of the Vector Extension, v0.7.1. - Support S-mode vectored interrupts (i.e. `stvec[0]` is now writable). - Added support for dynamic linking of libraries containing MMIO devices. +- Added `--priv` flag to control which privilege modes are available. - When the commit log is enabled at configure time (`--enable-commitlog`), it must also be enabled at runtime with the `--log-commits` option. - Several debug-related additions and changes: diff --git a/config.h.in b/config.h.in index e82156d..4f7f39f 100644 --- a/config.h.in +++ b/config.h.in @@ -6,6 +6,9 @@ /* Default value for --isa switch */ #undef DEFAULT_ISA +/* Default value for --priv switch */ +#undef DEFAULT_PRIV + /* Default value for --vector switch */ #undef DEFAULT_VARCH diff --git a/configure b/configure index bf8dd50..7c46e7b 100755 --- a/configure +++ b/configure @@ -702,6 +702,7 @@ enable_option_checking enable_stow enable_optional_subprojects with_isa +with_priv with_varch enable_commitlog enable_histogram @@ -1360,6 +1361,7 @@ Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-isa=RV64IMAFDC Sets the default RISC-V ISA + --with-priv=MSU Sets the default RISC-V privilege modes supported --with-varch=v128:e32:s128 Sets the default vector config @@ -4620,6 +4622,23 @@ fi +# Check whether --with-priv was given. +if test "${with_priv+set}" = set; then : + withval=$with_priv; +cat >>confdefs.h <<_ACEOF +#define DEFAULT_PRIV "$withval" +_ACEOF + +else + +cat >>confdefs.h <<_ACEOF +#define DEFAULT_PRIV "MSU" +_ACEOF + +fi + + + # Check whether --with-varch was given. if test "${with_varch+set}" = set; then : withval=$with_varch; diff --git a/riscv/processor.cc b/riscv/processor.cc index 21eb472..7881484 100644 --- a/riscv/processor.cc +++ b/riscv/processor.cc @@ -20,14 +20,15 @@ #undef STATE #define STATE state -processor_t::processor_t(const char* isa, const char* varch, simif_t* sim, - uint32_t id, bool halt_on_reset) +processor_t::processor_t(const char* isa, const char* priv, const char* varch, + simif_t* sim, uint32_t id, bool halt_on_reset) : debug(false), halt_request(false), sim(sim), ext(NULL), id(id), histogram_enabled(false), log_commits_enabled(false), halt_on_reset(halt_on_reset), last_pc(1), executions(1) { VU.p = this; parse_isa_string(isa); + parse_priv_string(priv); parse_varch_string(varch); register_base_instructions(); mmu = new mmu_t(sim, this); @@ -61,6 +62,12 @@ static void bad_isa_string(const char* isa) abort(); } +static void bad_priv_string(const char* priv) +{ + fprintf(stderr, "error: bad --priv option %s\n", priv); + abort(); +} + static void bad_varch_string(const char* varch) { fprintf(stderr, "error: bad --varch option %s\n", varch); @@ -129,6 +136,24 @@ static std::string strtolower(const char* str) return res; } +void processor_t::parse_priv_string(const char* str) +{ + std::string lowercase = strtolower(str); + bool user = false, supervisor = false; + + if (lowercase == "m") + ; + else if (lowercase == "mu") + user = true; + else if (lowercase == "msu") + user = supervisor = true; + else + bad_priv_string(str); + + max_isa |= reg_t(user) << ('u' - 'a'); + max_isa |= reg_t(supervisor) << ('s' - 'a'); +} + void processor_t::parse_isa_string(const char* str) { std::string lowercase = strtolower(str), tmp; diff --git a/riscv/processor.h b/riscv/processor.h index 3e72282..bcf36c5 100644 --- a/riscv/processor.h +++ b/riscv/processor.h @@ -297,8 +297,8 @@ static int cto(reg_t val) class processor_t : public abstract_device_t { public: - processor_t(const char* isa, const char* varch, simif_t* sim, uint32_t id, - bool halt_on_reset=false); + processor_t(const char* isa, const char* priv, const char* varch, + simif_t* sim, uint32_t id, bool halt_on_reset=false); ~processor_t(); void set_debug(bool value); @@ -465,8 +465,9 @@ private: friend class clint_t; friend class extension_t; - void parse_varch_string(const char* isa); - void parse_isa_string(const char* isa); + void parse_varch_string(const char*); + void parse_priv_string(const char*); + void parse_isa_string(const char*); void build_opcode_map(); void register_base_instructions(); insn_func_t decode_insn(insn_t insn); diff --git a/riscv/riscv.ac b/riscv/riscv.ac index 40cf706..747c3e3 100644 --- a/riscv/riscv.ac +++ b/riscv/riscv.ac @@ -6,6 +6,12 @@ AC_ARG_WITH(isa, AC_DEFINE_UNQUOTED([DEFAULT_ISA], "$withval", [Default value for --isa switch]), AC_DEFINE_UNQUOTED([DEFAULT_ISA], "RV64IMAFDC", [Default value for --isa switch])) +AC_ARG_WITH(priv, + [AS_HELP_STRING([--with-priv=MSU], + [Sets the default RISC-V privilege modes supported])], + AC_DEFINE_UNQUOTED([DEFAULT_PRIV], "$withval", [Default value for --priv switch]), + AC_DEFINE_UNQUOTED([DEFAULT_PRIV], "MSU", [Default value for --priv switch])) + AC_ARG_WITH(varch, [AS_HELP_STRING([--with-varch=v128:e32:s128], [Sets the default vector config])], diff --git a/riscv/sim.cc b/riscv/sim.cc index eca7057..7d6f3c1 100644 --- a/riscv/sim.cc +++ b/riscv/sim.cc @@ -25,7 +25,8 @@ static void handle_signal(int sig) signal(sig, &handle_signal); } -sim_t::sim_t(const char* isa, const char* varch, size_t nprocs, bool halted, +sim_t::sim_t(const char* isa, const char* priv, const char* varch, + size_t nprocs, bool halted, reg_t start_pc, std::vector> mems, std::vector> plugin_devices, const std::vector& args, @@ -51,7 +52,7 @@ sim_t::sim_t(const char* isa, const char* varch, size_t nprocs, bool halted, if (hartids.size() == 0) { for (size_t i = 0; i < procs.size(); i++) { - procs[i] = new processor_t(isa, varch, this, i, halted); + procs[i] = new processor_t(isa, priv, varch, this, i, halted); } } else { @@ -60,7 +61,7 @@ sim_t::sim_t(const char* isa, const char* varch, size_t nprocs, bool halted, exit(1); } for (size_t i = 0; i < procs.size(); i++) { - procs[i] = new processor_t(isa, varch, this, hartids[i], halted); + procs[i] = new processor_t(isa, priv, varch, this, hartids[i], halted); } } diff --git a/riscv/sim.h b/riscv/sim.h index 0720ce4..3b7e25c 100644 --- a/riscv/sim.h +++ b/riscv/sim.h @@ -21,7 +21,8 @@ class remote_bitbang_t; class sim_t : public htif_t, public simif_t { public: - sim_t(const char* isa, const char* varch, size_t _nprocs, bool halted, + sim_t(const char* isa, const char* priv, const char* varch, size_t _nprocs, + bool halted, reg_t start_pc, std::vector> mems, std::vector> plugin_devices, const std::vector& args, const std::vector hartids, diff --git a/spike_main/spike-dasm.cc b/spike_main/spike-dasm.cc index 044f220..4ec9d35 100644 --- a/spike_main/spike-dasm.cc +++ b/spike_main/spike-dasm.cc @@ -25,7 +25,7 @@ int main(int argc, char** argv) parser.option(0, "isa", 1, [&](const char* s){isa = s;}); parser.parse(argv); - processor_t p(isa, DEFAULT_VARCH, 0, 0); + processor_t p(isa, DEFAULT_PRIV, DEFAULT_VARCH, 0, 0); if (extension) p.register_extension(extension()); diff --git a/spike_main/spike-log-parser.cc b/spike_main/spike-log-parser.cc index fd07f53..5de6220 100644 --- a/spike_main/spike-log-parser.cc +++ b/spike_main/spike-log-parser.cc @@ -27,7 +27,7 @@ int main(int argc, char** argv) parser.option(0, "isa", 1, [&](const char* s){isa = s;}); parser.parse(argv); - processor_t p(isa, DEFAULT_VARCH, 0, 0); + processor_t p(isa, DEFAULT_PRIV, DEFAULT_VARCH, 0, 0); if (extension) { p.register_extension(extension()); } diff --git a/spike_main/spike.cc b/spike_main/spike.cc index 19f877b..4656a0a 100644 --- a/spike_main/spike.cc +++ b/spike_main/spike.cc @@ -29,6 +29,7 @@ static void help(int exit_code = 1) fprintf(stderr, " -h, --help Print this help message\n"); fprintf(stderr, " -H Start halted, allowing a debugger to connect\n"); fprintf(stderr, " --isa= RISC-V ISA string [default %s]\n", DEFAULT_ISA); + fprintf(stderr, " --priv= RISC-V privilege modes supported [default %s]\n", DEFAULT_PRIV); fprintf(stderr, " --varch= RISC-V Vector uArch string [default %s]\n", DEFAULT_VARCH); fprintf(stderr, " --pc=
Override ELF entry point\n"); fprintf(stderr, " --hartids= Explicitly specify hartids, default is 0,1,...\n"); @@ -119,6 +120,7 @@ int main(int argc, char** argv) bool log_commits = false; std::function extension; const char* isa = DEFAULT_ISA; + const char* priv = DEFAULT_PRIV; const char* varch = DEFAULT_VARCH; uint16_t rbb_port = 0; bool use_rbb = false; @@ -207,6 +209,7 @@ int main(int argc, char** argv) parser.option(0, "l2", 1, [&](const char* s){l2.reset(cache_sim_t::construct(s, "L2$"));}); parser.option(0, "log-cache-miss", 0, [&](const char* s){log_cache = true;}); parser.option(0, "isa", 1, [&](const char* s){isa = s;}); + parser.option(0, "priv", 1, [&](const char* s){priv = s;}); parser.option(0, "varch", 1, [&](const char* s){varch = s;}); parser.option(0, "device", 1, device_parser); parser.option(0, "extension", 1, [&](const char* s){extension = find_extension(s);}); @@ -245,7 +248,7 @@ int main(int argc, char** argv) if (!*argv1) help(); - sim_t s(isa, varch, nprocs, halted, start_pc, mems, plugin_devices, htif_args, + sim_t s(isa, priv, varch, nprocs, halted, start_pc, mems, plugin_devices, htif_args, std::move(hartids), dm_config); std::unique_ptr remote_bitbang((remote_bitbang_t *) NULL); std::unique_ptr jtag_dtm( -- cgit v1.1 From 4b7e763d246b130a204e9068b692f1db7d17fb68 Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Tue, 12 Nov 2019 18:17:30 -0800 Subject: Remove S-mode CSRs when S-mode is not present --- riscv/decode.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/riscv/decode.h b/riscv/decode.h index a756607..f8ac020 100644 --- a/riscv/decode.h +++ b/riscv/decode.h @@ -292,8 +292,9 @@ inline freg_t f128_negate(freg_t a) if (!STATE.serialized) return PC_SERIALIZE_BEFORE; \ STATE.serialized = false; \ unsigned csr_priv = get_field((which), 0x300); \ + bool mode_unsupported = csr_priv == PRV_S && !P.supports_extension('S'); \ unsigned csr_read_only = get_field((which), 0xC00) == 3; \ - if (((write) && csr_read_only) || STATE.prv < csr_priv) \ + if (((write) && csr_read_only) || STATE.prv < csr_priv || mode_unsupported) \ throw trap_illegal_instruction(0); \ (which); }) -- cgit v1.1 From f29ea12a7714290ee993347b55aca5c9b14cd217 Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Tue, 12 Nov 2019 18:35:52 -0800 Subject: SRET requires S-mode --- riscv/insns/sret.h | 1 + 1 file changed, 1 insertion(+) diff --git a/riscv/insns/sret.h b/riscv/insns/sret.h index ae841de..be837a3 100644 --- a/riscv/insns/sret.h +++ b/riscv/insns/sret.h @@ -1,3 +1,4 @@ +require_extension('S'); require_privilege(get_field(STATE.mstatus, MSTATUS_TSR) ? PRV_M : PRV_S); set_pc_and_serialize(p->get_state()->sepc); reg_t s = STATE.mstatus; -- cgit v1.1 From 9b06f14085396b99c2a7e33cac8be8ee54948a52 Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Tue, 12 Nov 2019 18:36:32 -0800 Subject: Fix mode-transition logic when S-mode not present --- riscv/processor.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/riscv/processor.cc b/riscv/processor.cc index 7881484..888d1a4 100644 --- a/riscv/processor.cc +++ b/riscv/processor.cc @@ -376,7 +376,7 @@ reg_t processor_t::legalize_privilege(reg_t prv) if (!supports_extension('U')) return PRV_M; - if (prv == PRV_H || !supports_extension('S')) + if (prv == PRV_H || (prv == PRV_S && !supports_extension('S'))) return PRV_U; return prv; -- cgit v1.1 From 9a8ee5efdc97a44d3509abd616297edaf7e3800e Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Tue, 12 Nov 2019 18:37:07 -0800 Subject: Remove S-mode interrupts when S-mode not present --- riscv/processor.cc | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/riscv/processor.cc b/riscv/processor.cc index 888d1a4..3dff83e 100644 --- a/riscv/processor.cc +++ b/riscv/processor.cc @@ -488,8 +488,9 @@ int processor_t::paddr_bits() void processor_t::set_csr(int which, reg_t val) { val = zext_xlen(val); - reg_t delegable_ints = MIP_SSIP | MIP_STIP | MIP_SEIP - | ((ext != NULL) << IRQ_COP); + reg_t supervisor_ints = supports_extension('S') ? MIP_SSIP | MIP_STIP | MIP_SEIP : 0; + reg_t coprocessor_ints = (ext != NULL) << IRQ_COP; + reg_t delegable_ints = supervisor_ints | coprocessor_ints; reg_t all_ints = delegable_ints | MIP_MSIP | MIP_MTIP; if (which >= CSR_PMPADDR0 && which < CSR_PMPADDR0 + state.n_pmp) { @@ -561,7 +562,7 @@ void processor_t::set_csr(int which, reg_t val) break; } case CSR_MIP: { - reg_t mask = MIP_SSIP | MIP_STIP; + reg_t mask = supervisor_ints & (MIP_SSIP | MIP_STIP); state.mip = (state.mip & ~mask) | (val & mask); break; } @@ -836,8 +837,14 @@ reg_t processor_t::get_csr(int which) case CSR_MVENDORID: return 0; case CSR_MHARTID: return id; case CSR_MTVEC: return state.mtvec; - case CSR_MEDELEG: return state.medeleg; - case CSR_MIDELEG: return state.mideleg; + case CSR_MEDELEG: + if (!supports_extension('S')) + break; + return state.medeleg; + case CSR_MIDELEG: + if (!supports_extension('S')) + break; + return state.mideleg; case CSR_TSELECT: return state.tselect; case CSR_TDATA1: if (state.tselect < state.num_triggers) { -- cgit v1.1 From 86857aa3511d0a3bb1d28f8a6213013382545f77 Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Tue, 12 Nov 2019 19:17:12 -0800 Subject: mstatus.FS only exists if (S || V || F) --- riscv/processor.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/riscv/processor.cc b/riscv/processor.cc index 3dff83e..9b8050c 100644 --- a/riscv/processor.cc +++ b/riscv/processor.cc @@ -535,10 +535,14 @@ void processor_t::set_csr(int which, reg_t val) (MSTATUS_MPP | MSTATUS_MPRV | MSTATUS_SUM | MSTATUS_MXR)) mmu->flush_tlb(); + bool has_fs = supports_extension('S') || supports_extension('F') + || supports_extension('V'); + reg_t mask = MSTATUS_SIE | MSTATUS_SPIE | MSTATUS_MIE | MSTATUS_MPIE - | MSTATUS_FS | MSTATUS_MPRV | MSTATUS_SUM + | MSTATUS_MPRV | MSTATUS_SUM | MSTATUS_MXR | MSTATUS_TW | MSTATUS_TVM | MSTATUS_TSR | MSTATUS_UXL | MSTATUS_SXL | + (has_fs ? MSTATUS_FS : 0) | (ext ? MSTATUS_XS : 0); reg_t requested_mpp = legalize_privilege(get_field(val, MSTATUS_MPP)); -- cgit v1.1