From 5720fb6d79c67d4a18de367aa546a1728202a407 Mon Sep 17 00:00:00 2001 From: "Dave.Wen" Date: Wed, 20 May 2020 07:11:31 -0700 Subject: add configurable LR/SC reservation set --- riscv/dts.cc | 19 ++++++++++++++++++- riscv/dts.h | 2 ++ riscv/mmu.h | 55 ++++++++++++++++++++++++++++++++++++++++++++++--------- riscv/processor.h | 2 +- riscv/sim.cc | 5 +++++ riscv/sim.h | 13 +++++++++++++ riscv/simif.h | 11 +++++++++++ 7 files changed, 96 insertions(+), 11 deletions(-) diff --git a/riscv/dts.cc b/riscv/dts.cc index 6a38ba0..01444ec 100644 --- a/riscv/dts.cc +++ b/riscv/dts.cc @@ -40,6 +40,7 @@ std::string make_dts(size_t insns_per_rtc_tick, size_t cpu_hz, s << " CPU" << i << ": cpu@" << i << " {\n" " device_type = \"cpu\";\n" " reg = <" << i << ">;\n" + " reservation-set-size = <64>;\n" " status = \"okay\";\n" " compatible = \"riscv\";\n" " riscv,isa = \"" << procs[i]->get_isa_string() << "\";\n" @@ -169,7 +170,6 @@ std::string dts_compile(const std::string& dts) return dtb.str(); } - static int fdt_get_node_addr_size(void *fdt, int node, reg_t *addr, unsigned long *size, const char *field) { @@ -246,6 +246,23 @@ int fdt_parse_pmp_num(void *fdt, reg_t *pmp_num, const char *compatible) return 0; } +int fdt_parse_reservation_set_size(void *fdt, reg_t *reservation_set_size, + const char *compatible) +{ + int nodeoffset, rc; + + nodeoffset = fdt_node_offset_by_compatible(fdt, -1, compatible); + if (nodeoffset < 0) + return nodeoffset; + + rc = fdt_get_node_addr_size(fdt, nodeoffset, reservation_set_size, NULL, + "reservation-set-size"); + if (rc < 0 || !reservation_set_size) + return -ENODEV; + + return 0; +} + int fdt_parse_pmp_alignment(void *fdt, reg_t *pmp_align, const char *compatible) { diff --git a/riscv/dts.h b/riscv/dts.h index 1c3f701..341f383 100644 --- a/riscv/dts.h +++ b/riscv/dts.h @@ -19,4 +19,6 @@ 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_reservation_set_size(void *fdt, reg_t *reservation_set_size, + const char *compatible); #endif diff --git a/riscv/mmu.h b/riscv/mmu.h index b84fd4a..2d215da 100644 --- a/riscv/mmu.h +++ b/riscv/mmu.h @@ -210,25 +210,62 @@ public: inline void yield_load_reservation() { - load_reservation_address = (reg_t)-1; + auto reserv_set = sim->get_reservation_set(); + for (auto& entry: reserv_set) { + if (entry.second.id == proc->id) { + entry.second.valid = false; + } + } + } + + inline void check_reservation_set() + { + if (sim->get_reservation_set().size() > sim->get_reservation_set_size()) + throw trap_load_access_fault(0); } inline void acquire_load_reservation(reg_t vaddr) { reg_t paddr = translate(vaddr, 1, LOAD); - if (auto host_addr = sim->addr_to_mem(paddr)) - load_reservation_address = refill_tlb(vaddr, paddr, host_addr, LOAD).target_offset + vaddr; - else - throw trap_load_access_fault(vaddr); // disallow LR to I/O space + if (auto host_addr = sim->addr_to_mem(paddr)) { + reg_t load_reservation_address = refill_tlb(vaddr, paddr, host_addr, LOAD).target_offset + vaddr; + auto& reserv_set = sim->get_reservation_set(); + auto exist = reserv_set.count(load_reservation_address); + if (exist > 1) { + auto& entry = reserv_set[load_reservation_address]; + if (entry.id == proc->id && entry.valid) { + throw trap_load_access_fault(vaddr); // disallow nested LR + } + } + reserv_set[load_reservation_address] = {proc->id, true}; + check_reservation_set(); + + } else { + throw trap_load_access_fault(vaddr); // disallow LR to I/O space + } } inline bool check_load_reservation(reg_t vaddr) { reg_t paddr = translate(vaddr, 1, STORE); - if (auto host_addr = sim->addr_to_mem(paddr)) - return load_reservation_address == refill_tlb(vaddr, paddr, host_addr, STORE).target_offset + vaddr; - else + if (auto host_addr = sim->addr_to_mem(paddr)) { + reg_t reserved_addr = refill_tlb(vaddr, paddr, host_addr, STORE).target_offset + vaddr; + auto reserv_set = sim->get_reservation_set(); + auto exist = reserv_set.count(reserved_addr); + if (exist > 0) { + auto entry = reserv_set[reserved_addr]; + if (entry.id == proc->id && entry.valid) { + sim->get_reservation_set().erase(reserved_addr); + return true; + } else { + return false; + } + } else { + return false; + } + } else { throw trap_store_access_fault(vaddr); // disallow SC to I/O space + } } static const reg_t ICACHE_ENTRIES = 1024; @@ -312,7 +349,6 @@ private: simif_t* sim; processor_t* proc; memtracer_list_t tracer; - reg_t load_reservation_address; uint16_t fetch_temp; // implement an instruction cache for simulator performance @@ -394,6 +430,7 @@ private: trigger_matched_t *matched_trigger; friend class processor_t; + }; struct vm_info { diff --git a/riscv/processor.h b/riscv/processor.h index 529a4f6..e5520e6 100644 --- a/riscv/processor.h +++ b/riscv/processor.h @@ -47,6 +47,7 @@ typedef struct uint8_t cause; } dcsr_t; + typedef enum { ACTION_DEBUG_EXCEPTION = MCONTROL_ACTION_DEBUG_EXCEPTION, @@ -408,7 +409,6 @@ private: FILE *log_file; bool halt_on_reset; std::vector extension_table; - std::vector instructions; std::map pc_histogram; diff --git a/riscv/sim.cc b/riscv/sim.cc index b25d79e..c3fcc4e 100644 --- a/riscv/sim.cc +++ b/riscv/sim.cc @@ -98,6 +98,11 @@ 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); } + + reg_t reservation_set_size = 0; + fdt_parse_reservation_set_size((void *)dtb.c_str(), &reservation_set_size, "riscv"); + set_reservation_set_size(reservation_set_size); + } sim_t::~sim_t() diff --git a/riscv/sim.h b/riscv/sim.h index eee24e5..5ee53ae 100644 --- a/riscv/sim.h +++ b/riscv/sim.h @@ -57,6 +57,17 @@ public: // Callback for processors to let the simulation know they were reset. void proc_reset(unsigned id); + std::map reservation_set; + reg_t reservation_set_size; + + void set_reservation_set_size(reg_t set_size) { + if(set_size == 0) { + reservation_set_size = 1; + } else { + reservation_set_size = set_size; + } + } + private: std::vector> mems; std::vector> plugin_devices; @@ -135,6 +146,8 @@ private: size_t chunk_align() { return 8; } size_t chunk_max_size() { return 8; } + std::map& get_reservation_set() { return reservation_set; } + reg_t get_reservation_set_size() { return reservation_set_size; } public: // Initialize this after procs, because in debug_module_t::reset() we // enumerate processors, which segfaults if procs hasn't been initialized diff --git a/riscv/simif.h b/riscv/simif.h index 1d982b3..5834a87 100644 --- a/riscv/simif.h +++ b/riscv/simif.h @@ -4,6 +4,13 @@ #define _RISCV_SIMIF_H #include "decode.h" +#include + +// LR/SC +struct reservation { + uint32_t id; + bool valid; +}; // this is the interface to the simulator used by the processors and memory class simif_t @@ -16,6 +23,10 @@ public: virtual bool mmio_store(reg_t addr, size_t len, const uint8_t* bytes) = 0; // Callback for processors to let the simulation know they were reset. virtual void proc_reset(unsigned id) = 0; + + // get the LR/SC's reservation set + virtual std::map& get_reservation_set() = 0; + virtual reg_t get_reservation_set_size() = 0; }; #endif -- cgit v1.1