Skip to content

Commit c846a9e

Browse files
committed
Machine: gate TLB updates by root register and privilege mode
Ensure that TLBs are only updated when the root register is set, and disable TLB updates while running in Machine mode.
1 parent 0ae766f commit c846a9e

File tree

4 files changed

+44
-13
lines changed

4 files changed

+44
-13
lines changed

src/machine/core.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include "common/logging.h"
44
#include "execute/alu.h"
5+
#include "memory/tlb/tlb.h"
56
#include "utils.h"
67

78
#include <cinttypes>
@@ -158,6 +159,12 @@ bool Core::handle_exception(
158159
control_state->exception_initiate(
159160
state.current_privilege(), CSR::PrivilegeLevel::MACHINE);
160161
state.set_current_privilege(CSR::PrivilegeLevel::MACHINE);
162+
if (auto prog_tlb = dynamic_cast<TLB *>(mem_program)) {
163+
prog_tlb->on_privilege_changed(CSR::PrivilegeLevel::MACHINE);
164+
}
165+
if (auto data_tlb = dynamic_cast<TLB *>(mem_data)) {
166+
data_tlb->on_privilege_changed(CSR::PrivilegeLevel::MACHINE);
167+
}
161168
regs->write_pc(control_state->exception_pc_address());
162169
}
163170
}
@@ -522,6 +529,12 @@ MemoryState Core::memory(const ExecuteInterstage &dt) {
522529
CSR::PrivilegeLevel restored
523530
= control_state->exception_return(state.current_privilege());
524531
state.set_current_privilege(restored);
532+
if (auto prog_tlb = dynamic_cast<TLB *>(mem_program)) {
533+
prog_tlb->on_privilege_changed(restored);
534+
}
535+
if (auto data_tlb = dynamic_cast<TLB *>(mem_data)) {
536+
data_tlb->on_privilege_changed(restored);
537+
}
525538
if (this->xlen == Xlen::_32)
526539
computed_next_inst_addr
527540
= Address(control_state->read_internal(CSR::Id::MEPC).as_u32());

src/machine/machine.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,11 @@ Machine::Machine(MachineConfig config, bool load_symtab, bool load_executable)
7272
cch_program, PROGRAM, machine_config.access_tlb_program(), machine_config.get_vm_enabled());
7373
tlb_data = new TLB(
7474
cch_data, DATA, machine_config.access_tlb_data(), machine_config.get_vm_enabled());
75-
controlst->write_internal(CSR::Id::SATP, 0);
7675
tlb_program->on_csr_write(CSR::Id::SATP, 0);
7776
tlb_data->on_csr_write(CSR::Id::SATP, 0);
77+
connect(controlst, &CSR::ControlState::write_signal, tlb_program, &machine::TLB::on_csr_write);
78+
connect(controlst, &CSR::ControlState::write_signal, tlb_data, &machine::TLB::on_csr_write);
79+
controlst->write_internal(CSR::Id::SATP, 0);
7880

7981
predictor = new BranchPredictor(
8082
machine_config.get_bp_enabled(), machine_config.get_bp_type(),

src/machine/memory/tlb/tlb.cpp

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,13 @@
33
#include "csr/controlstate.h"
44
#include "machine.h"
55
#include "memory/virtual/page_table_walker.h"
6-
#include "memory/virtual/sv32.h"
76

87
LOG_CATEGORY("machine.TLB");
98

109
namespace machine {
1110

12-
static bool is_mmio_region(uint64_t virt) {
13-
if (virt >= 0xFFFFC000u && virt <= 0xFFFFC1FFu) return true;
14-
if (virt >= 0xFFE00000u && virt <= 0xFFE4AFFFu) return true;
15-
if (virt >= 0xFFFD0000u && virt <= 0xFFFDBFFFu) return true;
16-
return false;
17-
}
18-
19-
static Address bypass_mmio(Address vaddr) {
20-
return vaddr; // VA == PA for devices
11+
inline bool is_mode_enabled_in_satp(uint32_t satp_raw) {
12+
return (satp_raw & (1u << 31)) != 0;
2113
}
2214

2315
TLB::TLB(
@@ -31,6 +23,8 @@ TLB::TLB(
3123
bool memory_access_enable_b)
3224
: FrontendMemory(memory->simulated_machine_endian)
3325
, mem(memory)
26+
, uncached_start(0xf0000000_addr)
27+
, uncached_last(0xfffffffe_addr)
3428
, type(type_)
3529
, tlb_config(config)
3630
, vm_enabled(vm_enabled)
@@ -73,6 +67,18 @@ void TLB::on_csr_write(size_t internal_id, RegisterValue val) {
7367
update_all_statistics();
7468
}
7569

70+
void TLB::on_privilege_changed(CSR::PrivilegeLevel new_priv) {
71+
if (new_priv == current_priv_) return;
72+
73+
current_priv_ = new_priv;
74+
flush();
75+
LOG("TLB: privilege changed -> %d; flushed TLB", static_cast<int>(new_priv));
76+
}
77+
78+
bool TLB::is_in_uncached_area(Address source) const {
79+
return (source >= uncached_start && source <= uncached_last);
80+
}
81+
7682
void TLB::flush_single(VirtualAddress va, uint16_t asid) {
7783
uint64_t vpn = va.get_raw() >> 12;
7884
size_t s = set_index(vpn);
@@ -119,9 +125,11 @@ void TLB::sync() {
119125

120126
Address TLB::translate_virtual_to_physical(Address vaddr) {
121127
uint64_t virt = vaddr.get_raw();
122-
if (is_mmio_region(virt)) { return bypass_mmio(vaddr); }
123128

124-
if (!vm_enabled) { return vaddr; }
129+
if (!vm_enabled || current_priv_ == CSR::PrivilegeLevel::MACHINE
130+
|| !is_mode_enabled_in_satp(current_satp_raw) || is_in_uncached_area(vaddr)) {
131+
return vaddr;
132+
}
125133

126134
constexpr unsigned PAGE_SHIFT = 12;
127135
constexpr uint64_t PAGE_MASK = (1ULL << PAGE_SHIFT) - 1;

src/machine/memory/tlb/tlb.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#define TLB_H
33

44
#include "common/logging.h"
5+
#include "csr/address.h"
56
#include "memory/frontend_memory.h"
67
#include "memory/virtual/sv32.h"
78
#include "memory/virtual/virtual_address.h"
@@ -83,6 +84,9 @@ class TLB : public FrontendMemory {
8384
void memory_reads_update(uint32_t val);
8485
void memory_writes_update(uint32_t val);
8586

87+
public slots:
88+
void on_privilege_changed(CSR::PrivilegeLevel new_priv);
89+
8690
private:
8791
struct Entry {
8892
bool valid = false;
@@ -96,7 +100,10 @@ class TLB : public FrontendMemory {
96100
TLBType type;
97101
const TLBConfig tlb_config;
98102
uint32_t current_satp_raw = 0;
103+
CSR::PrivilegeLevel current_priv_ = CSR::PrivilegeLevel::MACHINE;
99104
const bool vm_enabled;
105+
const Address uncached_start;
106+
const Address uncached_last;
100107

101108
size_t num_sets_;
102109
size_t associativity_;
@@ -116,6 +123,7 @@ class TLB : public FrontendMemory {
116123
mutable uint32_t burst_writes = 0;
117124
mutable uint32_t change_counter = 0;
118125

126+
bool is_in_uncached_area(Address source) const;
119127
WriteResult translate_and_write(Address dst, const void *src, size_t sz, WriteOptions opts);
120128
ReadResult translate_and_read(void *dst, Address src, size_t sz, ReadOptions opts);
121129
inline size_t set_index(uint64_t vpn) const { return vpn & (num_sets_ - 1); }

0 commit comments

Comments
 (0)