ETISS 0.8.0
Extendable Translating Instruction Set Simulator (version 0.8.0)
MMU.cpp
Go to the documentation of this file.
1 
59 #include "etiss/mm/MMU.h"
60 #include "etiss/CPUCore.h"
61 #include "etiss/jit/ReturnCode.h"
62 
63 namespace etiss
64 {
65 namespace mm
66 {
67 
68 MMU::MMU(bool hw_ptw, std::string name, bool pid_enabled)
69  : mmu_enabled_(false)
70  , mmu_control_reg_val_(0)
71  , pid_(0)
72  , name_(name)
73  , pid_enabled_(pid_enabled)
74  , hw_page_table_walker_(hw_ptw)
75 {
76  tlb_ = std::shared_ptr<etiss::mm::TLB<0>>(new TLB<0>());
77 
79  // REGISTER_PAGE_FAULT_HANDLER(TLBISFULL, tlb_full_handler);
80 }
81 
82 int32_t MMU::Translate(const uint64_t vma, uint64_t *const pma_buf, MM_ACCESS access, uint64_t data)
83 {
84 
85  if (!mmu_enabled_)
86  {
87  *pma_buf = vma;
88  return NOERROR;
89  }
90 
91  if (!this->CheckPrivilegedMode())
92  {
93  *pma_buf = vma;
94  return NOERROR;
95  }
96 
97  if (PTEFormat::Instance().GetFormatMap().find(std::string("PPN")) == PTEFormat::Instance().GetFormatMap().end())
98  etiss::log(etiss::FATALERROR, "PPN not defined in PTE format");
99 
100  if (PTEFormat::Instance().GetFormatMap().find(std::string("PAGEOFFSET")) ==
101  PTEFormat::Instance().GetFormatMap().end())
102  etiss::log(etiss::FATALERROR, "Page size offset not defined in PTE format");
103 
104  std::pair<uint32_t, uint32_t> page_offset_bitfield =
105  PTEFormat::Instance().GetFormatMap().find(std::string("PAGEOFFSET"))->second;
106 
107  std::pair<uint32_t, uint32_t> ppn_bitfield = PTEFormat::Instance().GetFormatMap().find(std::string("PPN"))->second;
108 
109  uint32_t page_offset_msb_pos = page_offset_bitfield.first;
110 
111  uint32_t ppn_msb_pos = ppn_bitfield.first;
112 
113  // Add PID as part of TLB tag to reduce flush possibility.
114  uint64_t vpn = vma >> (page_offset_msb_pos + 1);
115 
116  if (pid_enabled_)
117  {
118  vpn |= pid_ << (ppn_msb_pos + 1);
119  }
120 
121  PTE pte_buf = PTE(0);
122  int32_t fault = tlb_->Lookup(vpn, &pte_buf);
123  if (fault)
124  {
125  if ((fault = HANDLE_PAGE_FAULT(fault, this, vma, access)))
126  return fault;
127  if ((fault = tlb_->Lookup(vpn, &pte_buf)))
128  {
129  Dump();
130  etiss::log(etiss::FATALERROR, "TLB MISS is not correctly handled");
131  }
132  }
133 
134  if ((fault = CheckProtection(pte_buf, access)))
135  return fault;
136 
137  uint64_t offset_mask = (1 << (page_offset_msb_pos + 1)) - 1;
138  *pma_buf = (pte_buf.GetPPN() << (page_offset_msb_pos + 1)) | (vma & offset_mask);
139 
140  UpdatePTEFlags(pte_buf, access);
141 
142  // Check whether vma is trying to write the data cached in TLB, if so
143  // evict the PTE entry in the TLB
144  if (W_ACCESS == access)
145  {
146  std::map<uint64_t, PTE *>::iterator itr = tlb_entry_map_.find(*pma_buf);
147  if (itr != tlb_entry_map_.end())
148  tlb_entry_map_.erase(itr);
149  }
150 
151  return NOERROR;
152 }
153 
154 int32_t MMU::AddTLBEntry(const uint64_t vpn, const PTE &pte)
155 {
156  uint32_t fault = tlb_->AddPTE(vpn, pte);
157  if (fault)
158  {
159  if ((fault = HANDLE_PAGE_FAULT(fault, this, 0, R_ACCESS)))
160  return fault;
161  tlb_->AddPTE(vpn, pte);
162  }
163  return NOERROR;
164 }
165 
166 void MMU::SignalMMU(uint64_t control_reg_val_)
167 {
168  if (0 == control_reg_val_)
169  mmu_enabled_ = false;
170  else if (control_reg_val_ && (!mmu_enabled_))
171  {
172  mmu_enabled_ = true;
173  etiss::log(etiss::VERBOSE, GetName() + " : MMU is enabled.");
174  }
175  if (control_reg_val_ != mmu_control_reg_val_)
176  {
177  cache_flush_pending = true;
178  tlb_->Flush();
179  tlb_entry_map_.clear();
180  etiss::log(etiss::VERBOSE, GetName() + " : TLB flushed due to page directory update.");
181  mmu_control_reg_val_ = control_reg_val_;
182  if (pid_enabled_)
183  UpdatePid(GetPid(control_reg_val_));
184  }
185  else
186  etiss::log(etiss::WARNING, "Redundant MMU control register write");
187 }
188 
189 void MMU::Dump()
190 {
191  using std::cout;
192  using std::endl;
193  cout << "------------MMU Details-----------" << endl;
194  cout << "MMU name : " << name_ << endl;
195  cout << "MMU enabled: " << std::boolalpha << mmu_enabled_ << endl;
196  cout << "PID enabled: " << std::boolalpha << pid_enabled_ << endl;
197  if (pid_enabled_)
198  cout << "Current PID : 0x" << std::hex << pid_ << endl;
199  cout << "Current control register value : 0x" << std::hex << mmu_control_reg_val_ << endl;
200 
201  tlb_->Dump();
202 }
203 
204 void MMU::Init(ETISS_CPU *cpu, ETISS_System *system)
205 {
206  cpu_ = cpu;
207  system_ = system;
209  // Page table walker probe
211  etiss::log(etiss::FATALERROR, "No hardware page table walker, software page table walker is required ");
212 }
213 
214 void MMU::AddTLBEntryMap(uint64_t phy_addr_, PTE &pte)
215 {
216  if (tlb_entry_map_.find(phy_addr_) != tlb_entry_map_.end())
218  tlb_entry_map_[phy_addr_] = &pte;
219 }
220 
222 {
223  if (mmu->HasPageTableWalker())
224  {
225  int32_t handled_fault = NOERROR;
226  if ((handled_fault = mmu->WalkPageTable(vma, access)))
227  return handled_fault;
228  return NOERROR;
229  }
230 
231  switch (access)
232  {
233  case R_ACCESS:
234  return etiss::RETURNCODE::LOAD_PAGEFAULT;
235  case W_ACCESS:
236  return etiss::RETURNCODE::STORE_PAGEFAULT;
237  case X_ACCESS:
238  return etiss::RETURNCODE::INSTR_PAGEFAULT;
239  default:
240  abort();
241  }
242 }
243 
244 void DUMP_MMU(MMU *mmu)
245 {
246  mmu->Dump();
247 }
248 
249 } // namespace mm
250 } // namespace etiss
251 
252 using namespace etiss;
253 
254 extern "C"
255 {
256  void ETISS_SIGNAL_MMU(ETISS_CPU *cpu, etiss_uint64 mmu_signal_)
257  {
258  CPUCore *core = (CPUCore *)cpu->_etiss_private_handle_;
259  if (!core)
260  {
261  etiss::log(etiss::ERROR, "CPUArchRegListenerInterface::signalChangedRegisterValue() called from outside "
262  "etiss::CPUCore::execute(). this should not happen and indicates a faultiy "
263  "CPUArch (or Plugin) implementation. This function may have been called "
264  "indirectly from ETISS_signalChangedRegisterValue()");
265  return;
266  }
267  auto mmu = core->getMMU();
268  if (mmu)
269  mmu->SignalMMU(mmu_signal_);
270  }
271 }
defines main cpu core interface
void ETISS_SIGNAL_MMU(ETISS_CPU *cpu, etiss_uint64 mmu_signal_)
Definition: MMU.cpp:256
Modeling hardware memory management for virtual memory -> physical memory translation and protection.
#define DEFAULT_PAGE_TABLE_WALKER
Definition: MMU.h:78
#define REGISTER_PAGE_FAULT_HANDLER(fault, handler)
#define HANDLE_PAGE_FAULT(fault, mmu, vma, access)
if(__y==0) return __x
static __inline__ uint32_t
Definition: arm_cde.h:25
static __inline__ uint64_t
Definition: arm_cde.h:31
static __inline__ int32_t
Definition: arm_mve.h:51
uint64_t etiss_uint64
Definition: types.h:96
CPUCore is responsible for the simulation of a CPU core in ETISS.
Definition: CPUCore.h:113
virtual std::shared_ptr< etiss::mm::MMU > getMMU()
Get the Memory Management Unit(MMU) of this CPUCore instance.
Definition: CPUCore.h:181
int32_t AddTLBEntry(const uint64_t vfn, const PTE &pte)
Definition: MMU.cpp:154
virtual int32_t GetPid(uint64_t control_reg_val_)
Definition: MMU.h:175
virtual bool CheckPrivilegedMode()=0
MMU is enabled in certain mode.
std::string GetName() const
Definition: MMU.h:173
bool mmu_enabled_
Definition: MMU.h:182
MMU(bool hw_ptw, std::string name, bool pid_enabled)
MMU ctor.
Definition: MMU.cpp:68
virtual int32_t WalkPageTable(uint64_t, MM_ACCESS)
Page table walking is required to translate virtual address to physical address if TLB miss occurs.
Definition: MMU.h:147
const bool hw_page_table_walker_
Definition: MMU.h:198
void SignalMMU(uint64_t control_reg_val_)
Whenever the MMU control register changes, the MMU has to be notified with the updated control regist...
Definition: MMU.cpp:166
uint32_t pid_
Definition: MMU.h:194
void UpdatePid(uint32_t new_pid)
Definition: MMU.h:163
bool cache_flush_pending
Definition: MMU.h:177
std::shared_ptr< etiss::mm::TLB< 0 > > tlb_
Definition: MMU.h:186
const bool pid_enabled_
Definition: MMU.h:197
virtual int32_t CheckProtection(const PTE &, MM_ACCESS access)=0
Memory protection is architecture-dependent, which should be implemented with architecture model.
virtual void UpdatePTEFlags(PTE &, MM_ACCESS)
Reserved for some MMU that might update PTE when translating.
Definition: MMU.h:153
ETISS_System * system_
Definition: MMU.h:181
void AddTLBEntryMap(uint64_t phy_addr_, PTE &pte)
Keep a record of mapping between cached PTE with its physical address.
Definition: MMU.cpp:214
uint64_t mmu_control_reg_val_
Definition: MMU.h:193
bool HasPageTableWalker()
Definition: MMU.h:159
virtual int32_t Translate(const uint64_t vma, uint64_t *const pma_buf, MM_ACCESS access, uint64_t data=0)
Conduct the actual translation according to the format set by PTEFormatBuilder.
Definition: MMU.cpp:82
std::string name_
Definition: MMU.h:195
void Init(ETISS_CPU *cpu, ETISS_System *system)
Initialize the MMU, when DMMUWrapper is wrapping the MMU.
Definition: MMU.cpp:204
void Dump()
Dump the details of the MMU, when page fault cannot be handled.
Definition: MMU.cpp:189
std::map< uint64_t, PTE * > tlb_entry_map_
Definition: MMU.h:191
ETISS_CPU * cpu_
Definition: MMU.h:180
static PTEFormat & Instance()
Get the singleton instance.
Definition: PTEFormat.h:70
PTEFormatMap & GetFormatMap()
Definition: PTEFormat.h:95
Page Table Entry (PTE) defines the composition of Page Frame Number (PFN) and relavant flags.
Definition: PTE.h:69
uint64_t GetPPN() const
Definition: PTE.h:119
void DUMP_MMU(MMU *mmu)
Definition: MMU.cpp:244
int32_t tlb_miss_handler(int32_t fault, MMU *mmu, uint64_t vma, MM_ACCESS access)
Definition: MMU.cpp:221
MM_EXPORT const int32_t TLBMISS
MM_EXPORT const int32_t NOERROR
MM_EXPORT const int32_t PTEOVERLAP
Page Table Entry (PTE) defines the composition of Page Frame Number (PFN) and relavant flags.
Definition: Benchmark.h:53
@ VERBOSE
Definition: Misc.h:130
@ WARNING
Definition: Misc.h:128
@ ERROR
Definition: Misc.h:127
@ FATALERROR
Definition: Misc.h:126
void log(Verbosity level, std::string msg)
write log message at the given level.
Definition: Misc.cpp:125
#define false
Definition: stdbool.h:17
basic cpu state structure needed for execution of any cpu architecture.
Definition: CPU.h:89
void * _etiss_private_handle_
private helper handle for plugins
Definition: CPU.h:107
memory access and time synchronization functions.
Definition: System.h:78