From ad8ef88a22533e5e31ffaff9c64ecd7853a51555 Mon Sep 17 00:00:00 2001 From: Chih-Min Chao Date: Wed, 4 Nov 2020 22:24:13 -0800 Subject: [PATCH 1/5] mmu: add impl table and set function some features are optional to u-arch or could be selectively supported. Add an impl_table to keep implemented feature Signed-off-by: Chih-Min Chao --- riscv/decode.h | 1 + riscv/processor.cc | 33 ++++++++++++++++++++++++++++++++- riscv/processor.h | 14 ++++++++++++++ 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/riscv/decode.h b/riscv/decode.h index b4bb2e67..98d9dea7 100644 --- a/riscv/decode.h +++ b/riscv/decode.h @@ -236,6 +236,7 @@ private: #define require_rv64 require(xlen == 64) #define require_rv32 require(xlen == 32) #define require_extension(s) require(p->supports_extension(s)) +#define require_impl(s) require(p->supports_impl(s)) #define require_fp require((STATE.mstatus & MSTATUS_FS) != 0) #define require_accelerator require((STATE.mstatus & MSTATUS_XS) != 0) diff --git a/riscv/processor.cc b/riscv/processor.cc index b61bd331..28e16dd5 100644 --- a/riscv/processor.cc +++ b/riscv/processor.cc @@ -27,7 +27,7 @@ processor_t::processor_t(const char* isa, const char* priv, const char* varch, : debug(false), halt_request(HR_NONE), sim(sim), ext(NULL), id(id), xlen(0), histogram_enabled(false), log_commits_enabled(false), log_file(log_file), halt_on_reset(halt_on_reset), - extension_table(256, false), last_pc(1), executions(1) + extension_table(256, false), impl_table(256, false), last_pc(1), executions(1) { VU.p = this; @@ -45,6 +45,12 @@ processor_t::processor_t(const char* isa, const char* priv, const char* varch, set_pmp_granularity(1 << PMP_SHIFT); set_pmp_num(state.max_pmp); + + if (max_xlen == 32) + set_mmu_capability(IMPL_MMU_SV32); + else if (max_xlen == 64) + set_mmu_capability(IMPL_MMU_SV48); + reset(); } @@ -502,6 +508,31 @@ void processor_t::set_pmp_granularity(reg_t gran) { lg_pmp_granularity = ctz(gran); } +void processor_t::set_mmu_capability(int cap) +{ + switch (cap) { + case IMPL_MMU_SV32: + set_impl(cap, true); + set_impl(IMPL_MMU, true); + break; + case IMPL_MMU_SV39: + set_impl(cap, true); + set_impl(IMPL_MMU, true); + break; + case IMPL_MMU_SV48: + set_impl(cap, true); + set_impl(IMPL_MMU_SV39, true); + set_impl(IMPL_MMU, true); + break; + default: + set_impl(IMPL_MMU_SV32, false); + set_impl(IMPL_MMU_SV39, false); + set_impl(IMPL_MMU_SV48, false); + set_impl(IMPL_MMU, false); + break; + } +} + void processor_t::take_interrupt(reg_t pending_interrupts) { reg_t enabled_interrupts, deleg, status, mie, m_enabled; diff --git a/riscv/processor.h b/riscv/processor.h index 21876089..5e75e2fc 100644 --- a/riscv/processor.h +++ b/riscv/processor.h @@ -245,6 +245,14 @@ typedef enum { EXT_ZVEDIV, } isa_extension_t; +typedef enum { + IMPL_MMU_SV32, + IMPL_MMU_SV39, + IMPL_MMU_SV48, + IMPL_MMU_BARE, + IMPL_MMU, +} impl_extension_t; + // Count number of contiguous 1 bits starting from the LSB. static int cto(reg_t val) { @@ -292,6 +300,10 @@ public: else return extension_table[ext]; } + void set_impl(uint8_t impl, bool val) { impl_table[impl] = val; } + bool supports_impl(uint8_t impl) const { + return impl_table[impl]; + } reg_t pc_alignment_mask() { return ~(reg_t)(supports_extension('C') ? 0 : 2); } @@ -409,6 +421,7 @@ public: void set_pmp_num(reg_t pmp_num); void set_pmp_granularity(reg_t pmp_granularity); + void set_mmu_capability(int cap); const char* get_symbol(uint64_t addr); @@ -428,6 +441,7 @@ private: FILE *log_file; bool halt_on_reset; std::vector extension_table; + std::vector impl_table; std::vector instructions; From 51b5702b69083b87575ef8b03592499c3b8d89bd Mon Sep 17 00:00:00 2001 From: Chih-Min Chao Date: Wed, 4 Nov 2020 23:00:49 -0800 Subject: [PATCH 2/5] mmu: extract common part of satp and vsatp setting Signed-off-by: Chih-Min Chao --- riscv/processor.cc | 45 ++++++++++++++++++++------------------------- riscv/processor.h | 1 + 2 files changed, 21 insertions(+), 25 deletions(-) diff --git a/riscv/processor.cc b/riscv/processor.cc index 28e16dd5..15801b69 100644 --- a/riscv/processor.cc +++ b/riscv/processor.cc @@ -805,6 +805,21 @@ int processor_t::paddr_bits() return max_xlen == 64 ? 50 : 34; } +reg_t processor_t::cal_satp(reg_t val) const +{ + reg_t reg_val = 0; + reg_t rv64_ppn_mask = (reg_t(1) << (MAX_PADDR_BITS - PGSHIFT)) - 1; + mmu->flush_tlb(); + if (max_xlen == 32) + reg_val = val & (SATP32_PPN | SATP32_MODE); + + if (max_xlen == 64 && (get_field(val, SATP64_MODE) == SATP_MODE_OFF || + get_field(val, SATP64_MODE) == SATP_MODE_SV39 || + get_field(val, SATP64_MODE) == SATP_MODE_SV48)) + reg_val = val & (SATP64_PPN | SATP64_MODE | rv64_ppn_mask); + + return reg_val; +} void processor_t::set_csr(int which, reg_t val) { #if defined(RISCV_ENABLE_COMMITLOG) @@ -1001,22 +1016,12 @@ void processor_t::set_csr(int which, reg_t val) state.mie = (state.mie & ~mask) | (val & mask); break; } - case CSR_SATP: { - reg_t reg_val = 0; - reg_t rv64_ppn_mask = (reg_t(1) << (MAX_PADDR_BITS - PGSHIFT)) - 1; - mmu->flush_tlb(); - if (max_xlen == 32) - reg_val = val & (SATP32_PPN | SATP32_MODE); - if (max_xlen == 64 && (get_field(val, SATP64_MODE) == SATP_MODE_OFF || - get_field(val, SATP64_MODE) == SATP_MODE_SV39 || - get_field(val, SATP64_MODE) == SATP_MODE_SV48)) - reg_val = val & (SATP64_MODE | (SATP64_PPN & rv64_ppn_mask)); + case CSR_SATP: if (state.v) - state.vsatp = reg_val; + state.vsatp = cal_satp(val); else - state.satp = reg_val; + state.satp = cal_satp(val); break; - } case CSR_SEPC: if (state.v) state.vsepc = val & ~(reg_t)1; @@ -1171,19 +1176,9 @@ void processor_t::set_csr(int which, reg_t val) state.mip = (state.mip & ~mask) | ((val << 1) & mask); break; } - case CSR_VSATP: { - reg_t reg_val = 0; - reg_t rv64_ppn_mask = (reg_t(1) << (MAX_PADDR_BITS - PGSHIFT)) - 1; - mmu->flush_tlb(); - if (max_xlen == 32) - reg_val = val & (SATP32_PPN | SATP32_MODE); - if (max_xlen == 64 && (get_field(val, SATP64_MODE) == SATP_MODE_OFF || - get_field(val, SATP64_MODE) == SATP_MODE_SV39 || - get_field(val, SATP64_MODE) == SATP_MODE_SV48)) - reg_val = val & (SATP64_MODE | (SATP64_PPN & rv64_ppn_mask)); - state.vsatp = reg_val; + case CSR_VSATP: + state.vsatp = cal_satp(val); break; - } case CSR_TSELECT: if (val < state.num_triggers) { state.tselect = val; diff --git a/riscv/processor.h b/riscv/processor.h index 5e75e2fc..74ad526d 100644 --- a/riscv/processor.h +++ b/riscv/processor.h @@ -470,6 +470,7 @@ private: void build_opcode_map(); void register_base_instructions(); insn_func_t decode_insn(insn_t insn); + reg_t cal_satp(reg_t val) const; // Track repeated executions for processor_t::disasm() uint64_t last_pc, last_bits, executions; From bed716c601f5140afd595ea60f20d9eddab02032 Mon Sep 17 00:00:00 2001 From: Chih-Min Chao Date: Wed, 4 Nov 2020 22:43:18 -0800 Subject: [PATCH 3/5] mmu: check mmu support if no mmu 1. mask TVM and VTVM 2. wire satp and vsatp as 0 3. disable sfence_vma 4. allow only supported type 5. mask SUM/MXR Signed-off-by: Chih-Min Chao --- riscv/insns/sfence_vma.h | 1 + riscv/processor.cc | 47 ++++++++++++++++++++++++++++++++-------- 2 files changed, 39 insertions(+), 9 deletions(-) diff --git a/riscv/insns/sfence_vma.h b/riscv/insns/sfence_vma.h index ff949c7f..28960246 100644 --- a/riscv/insns/sfence_vma.h +++ b/riscv/insns/sfence_vma.h @@ -1,4 +1,5 @@ require_extension('S'); +require_impl(IMPL_MMU); if (STATE.v) { if (STATE.prv == PRV_U || get_field(STATE.hstatus, HSTATUS_VTVM)) require_novirt(); diff --git a/riscv/processor.cc b/riscv/processor.cc index 15801b69..c27dd927 100644 --- a/riscv/processor.cc +++ b/riscv/processor.cc @@ -810,13 +810,31 @@ reg_t processor_t::cal_satp(reg_t val) const reg_t reg_val = 0; reg_t rv64_ppn_mask = (reg_t(1) << (MAX_PADDR_BITS - PGSHIFT)) - 1; mmu->flush_tlb(); - if (max_xlen == 32) - reg_val = val & (SATP32_PPN | SATP32_MODE); + if (max_xlen == 32) { + reg_val = val & (SATP32_PPN | + (supports_impl(IMPL_MMU_SV32) ? SATP32_MODE : 0)); + } if (max_xlen == 64 && (get_field(val, SATP64_MODE) == SATP_MODE_OFF || get_field(val, SATP64_MODE) == SATP_MODE_SV39 || - get_field(val, SATP64_MODE) == SATP_MODE_SV48)) - reg_val = val & (SATP64_PPN | SATP64_MODE | rv64_ppn_mask); + get_field(val, SATP64_MODE) == SATP_MODE_SV48)) { + reg_val = val & (SATP64_PPN | rv64_ppn_mask); + reg_t mode = get_field(val, SATP64_MODE); + + switch(mode) { + case SATP_MODE_OFF: + default: + mode = SATP_MODE_OFF; + break; + case SATP_MODE_SV39: + mode = supports_impl(IMPL_MMU_SV39) ? SATP_MODE_SV39 : SATP_MODE_OFF; + break; + case SATP_MODE_SV48: + mode = supports_impl(IMPL_MMU_SV48) ? SATP_MODE_SV48 : SATP_MODE_OFF; + break; + } + reg_val = set_field(reg_val, SATP64_MODE, mode); + } return reg_val; } @@ -893,8 +911,11 @@ void processor_t::set_csr(int which, reg_t val) VU.vxrm = (val & VCSR_VXRM) >> VCSR_VXRM_SHIFT; break; case CSR_MSTATUS: { + bool has_page = supports_extension('S') && supports_impl(IMPL_MMU); if ((val ^ state.mstatus) & - (MSTATUS_MPP | MSTATUS_MPRV | MSTATUS_SUM | MSTATUS_MXR)) + (MSTATUS_MPP | MSTATUS_MPRV + | (has_page ? (MSTATUS_MXR | MSTATUS_SUM) : 0) + | MSTATUS_MXR)) mmu->flush_tlb(); bool has_fs = supports_extension('S') || supports_extension('F') @@ -904,8 +925,9 @@ void processor_t::set_csr(int which, reg_t val) bool has_gva = has_mpv; reg_t mask = MSTATUS_MIE | MSTATUS_MPIE | MSTATUS_MPRV - | (supports_extension('S') ? (MSTATUS_SUM | MSTATUS_SIE | MSTATUS_SPIE) : 0) - | MSTATUS_MXR | MSTATUS_TW | MSTATUS_TVM | MSTATUS_TSR + | (supports_extension('S') ? (MSTATUS_SIE | MSTATUS_SPIE) : 0) + | MSTATUS_TW | MSTATUS_TSR + | (has_page ? (MSTATUS_MXR | MSTATUS_SUM | MSTATUS_TVM) : 0) | (has_fs ? MSTATUS_FS : 0) | (has_vs ? MSTATUS_VS : 0) | (ext ? MSTATUS_XS : 0) @@ -1017,6 +1039,9 @@ void processor_t::set_csr(int which, reg_t val) break; } case CSR_SATP: + if (!supports_impl(IMPL_MMU)) + val = 0; + if (state.v) state.vsatp = cal_satp(val); else @@ -1088,8 +1113,9 @@ void processor_t::set_csr(int which, reg_t val) break; } case CSR_HSTATUS: { - reg_t mask = HSTATUS_VTSR | HSTATUS_VTW | HSTATUS_VTVM | - HSTATUS_HU | HSTATUS_SPVP | HSTATUS_SPV | HSTATUS_GVA; + reg_t mask = HSTATUS_VTSR | HSTATUS_VTW + | (supports_impl(IMPL_MMU) ? HSTATUS_VTVM : 0) + | HSTATUS_HU | HSTATUS_SPVP | HSTATUS_SPV | HSTATUS_GVA; state.hstatus = (state.hstatus & ~mask) | (val & mask); break; } @@ -1177,6 +1203,9 @@ void processor_t::set_csr(int which, reg_t val) break; } case CSR_VSATP: + if (!supports_impl(IMPL_MMU)) + val = 0; + state.vsatp = cal_satp(val); break; case CSR_TSELECT: From 0481b56f3496a77ad1251c887445957a3f3dc300 Mon Sep 17 00:00:00 2001 From: Chih-Min Chao Date: Thu, 5 Nov 2020 20:02:10 -0800 Subject: [PATCH 4/5] dts: extend dts api to get info of each cpu Signed-off-by: Chih-Min Chao --- riscv/dts.cc | 38 ++++++++++++++++++++++++++++++++++++++ riscv/dts.h | 5 +++++ 2 files changed, 43 insertions(+) diff --git a/riscv/dts.cc b/riscv/dts.cc index 56b76e6c..9469e3fb 100644 --- a/riscv/dts.cc +++ b/riscv/dts.cc @@ -225,6 +225,21 @@ static int fdt_get_node_addr_size(void *fdt, int node, reg_t *addr, return 0; } +int fdt_get_offset(void *fdt, const char *field) +{ + return fdt_path_offset(fdt, field); +} + +int fdt_get_first_subnode(void *fdt, int node) +{ + return fdt_first_subnode(fdt, node); +} + +int fdt_get_next_subnode(void *fdt, int node) +{ + return fdt_next_subnode(fdt, node); +} + int fdt_parse_clint(void *fdt, reg_t *clint_addr, const char *compatible) { @@ -273,3 +288,26 @@ int fdt_parse_pmp_alignment(void *fdt, reg_t *pmp_align, return 0; } + +int fdt_parse_mmu_type(void *fdt, int cpu_offset, char *mmu_type) +{ + int len; + const void *prop; + + if (!fdt || cpu_offset < 0) + return -EINVAL; + + prop = fdt_getprop(fdt, cpu_offset, "device_type", &len); + if (!prop || !len) + return -EINVAL; + if (strncmp ((char *)prop, "cpu", strlen ("cpu"))) + return -EINVAL; + + prop = fdt_getprop(fdt, cpu_offset, "mmu-type", &len); + if (!prop || !len) + return -EINVAL; + + strcpy(mmu_type, (char *)prop); + + return 0; +} diff --git a/riscv/dts.h b/riscv/dts.h index 1f01e0f8..69dcb319 100644 --- a/riscv/dts.h +++ b/riscv/dts.h @@ -14,10 +14,15 @@ std::string make_dts(size_t insns_per_rtc_tick, size_t cpu_hz, std::string dts_compile(const std::string& dts); +int fdt_get_offset(void *fdt, const char *field); +int fdt_get_first_subnode(void *fdt, int node); +int fdt_get_next_subnode(void *fdt, int node); + int fdt_parse_clint(void *fdt, reg_t *clint_addr, const char *compatible); int fdt_parse_pmp_num(void *fdt, reg_t *pmp_num, const char *compatible); int fdt_parse_pmp_alignment(void *fdt, reg_t *pmp_align, const char *compatible); +int fdt_parse_mmu_type(void *fdt, int cpu_offset, char *mmu_type); #endif From b675e0af5b55838cd20a1681757f747bdabf8398 Mon Sep 17 00:00:00 2001 From: Chih-Min Chao Date: Thu, 5 Nov 2020 22:21:46 -0800 Subject: [PATCH 5/5] dts: mmu: parse mmu-type in dts 1. setup allowed mmu-type from dts 2. change default mmu-type in dts from sv39 to sv48 Signed-off-by: Chih-Min Chao --- riscv/sim.cc | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/riscv/sim.cc b/riscv/sim.cc index ddf1f2c6..13329f42 100644 --- a/riscv/sim.cc +++ b/riscv/sim.cc @@ -83,6 +83,7 @@ sim_t::sim_t(const char* isa, const char* priv, const char* varch, make_dtb(); + //handle clic clint.reset(new clint_t(procs, CPU_HZ / INSNS_PER_RTC_TICK, real_time_clint)); reg_t clint_base; if (fdt_parse_clint((void *)dtb.c_str(), &clint_base, "riscv,clint0")) { @@ -91,6 +92,7 @@ sim_t::sim_t(const char* isa, const char* priv, const char* varch, bus.add_device(clint_base, clint.get()); } + //handle pmp for (size_t i = 0; i < nprocs; i++) { reg_t pmp_num = 0, pmp_granularity = 0; fdt_parse_pmp_num((void *)dtb.c_str(), &pmp_num, "riscv"); @@ -99,6 +101,52 @@ sim_t::sim_t(const char* isa, const char* priv, const char* varch, procs[i]->set_pmp_num(pmp_num); procs[i]->set_pmp_granularity(pmp_granularity); } + + void *fdt = (void *)dtb.c_str(); + int cpu_offset = 0, rc; + size_t cpu_idx = 0; + cpu_offset = fdt_get_offset(fdt, "/cpus"); + if (cpu_offset < 0) + return; + + for (cpu_offset = fdt_get_first_subnode(fdt, cpu_offset); cpu_offset >= 0; + cpu_offset = fdt_get_next_subnode(fdt, cpu_offset)) { + + if (cpu_idx >= nprocs) + break; + + //handle mmu-type + char mmu_type[256] = ""; + rc = fdt_parse_mmu_type(fdt, cpu_offset, mmu_type); + if (rc == 0) { + procs[cpu_idx]->set_mmu_capability(IMPL_MMU_BARE); + if (strncmp(mmu_type, "riscv,sv32", strlen("riscv,sv32")) == 0) { + procs[cpu_idx]->set_mmu_capability(IMPL_MMU_SV32); + } else if (strncmp(mmu_type, "riscv,sv39", strlen("riscv,sv39")) == 0) { + procs[cpu_idx]->set_mmu_capability(IMPL_MMU_SV39); + } else if (strncmp(mmu_type, "riscv,sv48", strlen("riscv,sv48")) == 0) { + procs[cpu_idx]->set_mmu_capability(IMPL_MMU_SV48); + } else if (strncmp(mmu_type, "riscv,bare", strlen("riscv,bare")) == 0) { + //has been set in the beginning + } else { + std::cerr << "core (" + << hartids.size() + << ") doesn't have valid 'mmu-type'" + << mmu_type << ").\n"; + exit(1); + } + } + + cpu_idx++; + } + + if (cpu_idx != nprocs) { + std::cerr << "core number in dts (" + << cpu_idx + << ") doesn't match it in command line (" + << nprocs << ").\n"; + exit(1); + } } sim_t::~sim_t()