Skip to content

Commit ee811fa

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 7fd4f2d commit ee811fa

File tree

8 files changed

+59
-9
lines changed

8 files changed

+59
-9
lines changed

src/machine/core.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -480,8 +480,8 @@ MemoryState Core::memory(const ExecuteInterstage &dt) {
480480
excause = memory_special(
481481
dt.memctl, dt.inst.rt(), memread, memwrite, towrite_val, dt.val_rt, mem_addr);
482482
} else if (is_regular_access(dt.memctl)) {
483-
if (memwrite) { mem_data->write_ctl(dt.memctl, mem_addr, dt.val_rt); }
484-
if (memread) { towrite_val = mem_data->read_ctl(dt.memctl, mem_addr); }
483+
if (memwrite) { mem_data->write_ctl(dt.memctl, mem_addr, dt.val_rt, make_ctrl_info(state)); }
484+
if (memread) { towrite_val = mem_data->read_ctl(dt.memctl, mem_addr, make_ctrl_info(state)); }
485485
} else {
486486
Q_ASSERT(dt.memctl == AC_NONE);
487487
// AC_NONE is memory NOP

src/machine/core.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,11 @@ class Core : public QObject {
6060
bool get_step_over_exception(enum ExceptionCause excause) const;
6161
void set_current_privilege(CSR::PrivilegeLevel privilege);
6262
CSR::PrivilegeLevel get_current_privilege() const;
63+
static inline uint32_t make_ctrl_info(const CoreState &st) {
64+
uint32_t priv = static_cast<uint32_t>(st.current_privilege()) & 0x3u;
65+
uint32_t asid = static_cast<uint32_t>(st.current_asid()) & 0x1FFu;
66+
return priv | (asid << 2);
67+
}
6368

6469
/**
6570
* Abstracts XLEN from code flow. XLEN core will obtain XLEN value from register value.

src/machine/core/core_state.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ struct CoreState {
1919
uint32_t stall_count = 0;
2020
uint32_t cycle_count = 0;
2121
unsigned current_privilege_u = static_cast<unsigned>(CSR::PrivilegeLevel::MACHINE);
22+
unsigned current_asid_u = 0u;
2223

2324
[[nodiscard]] CSR::PrivilegeLevel current_privilege() const noexcept {
2425
return static_cast<CSR::PrivilegeLevel>(current_privilege_u);
@@ -27,6 +28,14 @@ struct CoreState {
2728
void set_current_privilege(CSR::PrivilegeLevel p) noexcept {
2829
current_privilege_u = static_cast<unsigned>(p);
2930
}
31+
32+
[[nodiscard]] uint16_t current_asid() const noexcept {
33+
return static_cast<uint16_t>(current_asid_u & 0x1FFu);
34+
}
35+
36+
void set_current_asid(uint16_t a) noexcept {
37+
current_asid_u = static_cast<unsigned>(a & 0x1FFu);
38+
}
3039
};
3140

3241
} // namespace machine

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/frontend_memory.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ uint64_t FrontendMemory::read_u64(Address address, AccessEffects type) const {
3737
return read_generic<uint64_t>(address, type);
3838
}
3939

40-
void FrontendMemory::write_ctl(enum AccessControl ctl, Address offset, RegisterValue value) {
40+
void FrontendMemory::write_ctl(enum AccessControl ctl, Address offset, RegisterValue value, uint32_t ctrl_info ) {
4141
switch (ctl) {
4242
case AC_NONE: {
4343
break;
@@ -68,9 +68,10 @@ void FrontendMemory::write_ctl(enum AccessControl ctl, Address offset, RegisterV
6868
QString::number(ctl));
6969
}
7070
}
71+
handle_control_signal(ctrl_info);
7172
}
7273

73-
RegisterValue FrontendMemory::read_ctl(enum AccessControl ctl, Address address) const {
74+
RegisterValue FrontendMemory::read_ctl(enum AccessControl ctl, Address address, uint32_t ctrl_info ) const {
7475
switch (ctl) {
7576
case AC_NONE: return 0;
7677
case AC_I8: return (int8_t)read_u8(address);
@@ -87,6 +88,7 @@ RegisterValue FrontendMemory::read_ctl(enum AccessControl ctl, Address address)
8788
QString::number(ctl));
8889
}
8990
}
91+
const_cast<FrontendMemory *>(this)->handle_control_signal(ctrl_info);
9092
}
9193

9294
void FrontendMemory::sync() {}

src/machine/memory/frontend_memory.h

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
#include <QObject>
1212
#include <cstdint>
1313

14+
#include "csr/address.h"
15+
1416
// Shortcut for enum class values, type is obvious from context.
1517
using ae = machine::AccessEffects;
1618

@@ -68,7 +70,7 @@ class FrontendMemory : public QObject {
6870
* REGULAR.
6971
* @param control_signal CPU control unit signal
7072
*/
71-
void write_ctl(AccessControl control_signal, Address destination, RegisterValue value);
73+
void write_ctl(AccessControl control_signal, Address destination, RegisterValue value, uint32_t ctrl_info = 0);
7274

7375
/**
7476
* Read with size specified by the CPU control unit.
@@ -77,12 +79,21 @@ class FrontendMemory : public QObject {
7779
* ae::REGULAR.
7880
* @param control_signal CPU control unit signal
7981
*/
80-
[[nodiscard]] RegisterValue read_ctl(enum AccessControl ctl, Address source) const;
82+
[[nodiscard]] RegisterValue read_ctl(enum AccessControl ctl, Address source, uint32_t ctrl_info = 0) const;
83+
84+
virtual void handle_control_signal(uint32_t ctrl_info) { Q_UNUSED(ctrl_info); }
8185

8286
virtual void sync();
8387
[[nodiscard]] virtual LocationStatus location_status(Address address) const;
8488
[[nodiscard]] virtual uint32_t get_change_counter() const = 0;
8589

90+
static inline CSR::PrivilegeLevel unpack_priv(uint32_t token) {
91+
return static_cast<CSR::PrivilegeLevel>(token & 0x3u);
92+
}
93+
static inline uint16_t unpack_asid(uint32_t token) {
94+
return static_cast<uint16_t>((token >> 2) & 0x1FFu);
95+
}
96+
8697
/**
8798
* Write byte sequence to memory
8899
*

src/machine/memory/tlb/tlb.cpp

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
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

@@ -64,6 +63,8 @@ void TLB::on_csr_write(size_t internal_id, RegisterValue val) {
6463
update_all_statistics();
6564
}
6665

66+
67+
6768
void TLB::flush_single(VirtualAddress va, uint16_t asid) {
6869
uint64_t vpn = va.get_raw() >> 12;
6970
size_t s = set_index(vpn);
@@ -111,7 +112,9 @@ void TLB::sync() {
111112
Address TLB::translate_virtual_to_physical(Address vaddr) {
112113
uint64_t virt = vaddr.get_raw();
113114

114-
if (!vm_enabled) { return vaddr; }
115+
if (!vm_enabled || !translation_enabled || is_in_uncached_area(vaddr)) {
116+
return vaddr;
117+
}
115118

116119
constexpr unsigned PAGE_SHIFT = 12;
117120
constexpr uint64_t PAGE_MASK = (1ULL << PAGE_SHIFT) - 1;
@@ -191,6 +194,20 @@ bool TLB::reverse_lookup(Address paddr, VirtualAddress &out_va) const {
191194
}
192195
return false;
193196
}
197+
198+
void TLB::handle_control_signal(uint32_t ctrl_info) {
199+
CSR::PrivilegeLevel priv = unpack_priv(ctrl_info);
200+
uint16_t asid = unpack_asid(ctrl_info);
201+
202+
bool satp_mode_on = is_mode_enabled_in_satp(current_satp_raw);
203+
bool should_translate = vm_enabled && satp_mode_on && (priv != CSR::PrivilegeLevel::MACHINE);
204+
205+
if (translation_enabled != should_translate) {
206+
translation_enabled = should_translate;
207+
LOG("TLB: translation_enabled -> %d (ASID=%u)", (int)translation_enabled, asid);
208+
}
209+
}
210+
194211
bool TLB::is_in_uncached_area(Address source) const {
195212
return (source >= uncached_start && source <= uncached_last);
196213
}

src/machine/memory/tlb/tlb.h

Lines changed: 4 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"
@@ -67,6 +68,7 @@ class TLB : public FrontendMemory {
6768

6869
void reset();
6970
void update_all_statistics();
71+
void handle_control_signal(uint32_t ctrl_info) override;
7072

7173
signals:
7274
void tlb_update(
@@ -98,6 +100,7 @@ class TLB : public FrontendMemory {
98100
TLBType type;
99101
const TLBConfig tlb_config;
100102
uint32_t current_satp_raw = 0;
103+
bool translation_enabled = false;
101104
const bool vm_enabled;
102105

103106
size_t num_sets_;
@@ -122,6 +125,7 @@ class TLB : public FrontendMemory {
122125
WriteResult translate_and_write(Address dst, const void *src, size_t sz, WriteOptions opts);
123126
ReadResult translate_and_read(void *dst, Address src, size_t sz, ReadOptions opts);
124127
inline size_t set_index(uint64_t vpn) const { return vpn & (num_sets_ - 1); }
128+
inline bool is_mode_enabled_in_satp(uint32_t satp_raw) { return (satp_raw & (1u << 31)) != 0; }
125129
};
126130

127131
} // namespace machine

0 commit comments

Comments
 (0)