diff options
-rw-r--r-- | riscv/dts.cc | 19 | ||||
-rw-r--r-- | riscv/dts.h | 2 | ||||
-rw-r--r-- | riscv/mmu.h | 54 | ||||
-rw-r--r-- | riscv/processor.h | 2 | ||||
-rw-r--r-- | riscv/sim.cc | 5 | ||||
-rw-r--r-- | riscv/sim.h | 13 | ||||
-rw-r--r-- | riscv/simif.h | 11 |
7 files changed, 95 insertions, 11 deletions
diff --git a/riscv/dts.cc b/riscv/dts.cc index 56b76e6..3f22046 100644 --- a/riscv/dts.cc +++ b/riscv/dts.cc @@ -51,6 +51,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" @@ -180,7 +181,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) { @@ -257,6 +257,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 1f01e0f..a1adfe4 100644 --- a/riscv/dts.h +++ b/riscv/dts.h @@ -20,4 +20,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 990f137..d8157d1 100644 --- a/riscv/mmu.h +++ b/riscv/mmu.h @@ -241,28 +241,64 @@ 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, 0 , 0); } inline void acquire_load_reservation(reg_t vaddr) { reg_t paddr = translate(vaddr, 1, LOAD, 0); - if (auto host_addr = sim->addr_to_mem(paddr)) - load_reservation_address = refill_tlb(vaddr, paddr, host_addr, LOAD).target_offset + vaddr; - else + 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,0, 0); // disallow nested LR + } + } + reserv_set[load_reservation_address] = {proc->id, true}; + check_reservation_set(); + } else { throw trap_load_access_fault(vaddr, 0, 0); // disallow LR to I/O space + } } inline bool check_load_reservation(reg_t vaddr, size_t size) { if (vaddr & (size-1)) throw trap_store_address_misaligned(vaddr, 0, 0); - + reg_t paddr = translate(vaddr, 1, STORE, 0); - 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, 0, 0); // disallow SC to I/O space + } } static const reg_t ICACHE_ENTRIES = 1024; @@ -346,7 +382,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 @@ -431,6 +466,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 6c16eb9..447d5a5 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, @@ -429,7 +430,6 @@ private: FILE *log_file; bool halt_on_reset; std::vector<bool> extension_table; - std::vector<insn_desc_t> instructions; std::map<reg_t,uint64_t> pc_histogram; diff --git a/riscv/sim.cc b/riscv/sim.cc index 2aced1b..f68e5c3 100644 --- a/riscv/sim.cc +++ b/riscv/sim.cc @@ -99,6 +99,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 c6e5582..1424b24 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<reg_t, reservation> 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<std::pair<reg_t, mem_t*>> mems; std::vector<std::pair<reg_t, abstract_device_t*>> plugin_devices; @@ -137,6 +148,8 @@ private: size_t chunk_align() { return 8; } size_t chunk_max_size() { return 8; } + std::map<reg_t, reservation>& 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 <map> + +// 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<reg_t, reservation>& get_reservation_set() = 0; + virtual reg_t get_reservation_set_size() = 0; }; #endif |