Skip to content

Commit 83a2035

Browse files
authored
Merge pull request #1718 from YenHaoChen/pr-pm
Implement pointer masking
2 parents 344a860 + 7f8c663 commit 83a2035

File tree

8 files changed

+156
-61
lines changed

8 files changed

+156
-61
lines changed

disasm/isa_parser.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,12 @@ isa_parser_t::isa_parser_t(const char* str, const char *priv)
318318
extension_table[EXT_ZICFILP] = true;
319319
} else if (ext_str == "zicfiss") {
320320
extension_table[EXT_ZICFISS] = true;
321+
} else if (ext_str == "smmpm") {
322+
extension_table[EXT_SMMPM] = true;
323+
} else if (ext_str == "smnpm") {
324+
extension_table[EXT_SMNPM] = true;
325+
} else if (ext_str == "ssnpm") {
326+
extension_table[EXT_SSNPM] = true;
321327
} else if (ext_str.substr(0, 3) == "zvl") {
322328
reg_t new_vlen;
323329
try {

riscv/csrs.cc

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,7 @@ mseccfg_csr_t::mseccfg_csr_t(processor_t* const proc, const reg_t addr):
286286
void mseccfg_csr_t::verify_permissions(insn_t insn, bool write) const {
287287
basic_csr_t::verify_permissions(insn, write);
288288
if (!proc->extension_enabled(EXT_SMEPMP) &&
289+
!proc->extension_enabled(EXT_SMMPM) &&
289290
!proc->extension_enabled(EXT_ZICFILP) &&
290291
!proc->extension_enabled(EXT_ZKR))
291292
throw trap_illegal_instruction(insn.bits());
@@ -342,6 +343,12 @@ bool mseccfg_csr_t::unlogged_write(const reg_t val) noexcept {
342343
new_val |= (val & MSECCFG_MLPE);
343344
}
344345

346+
if (proc->extension_enabled(EXT_SMMPM)) {
347+
const reg_t pmm_reserved = 1; // Reserved value of mseccfg.PMM
348+
reg_t pmm = get_field(val, MSECCFG_PMM);
349+
new_val = set_field(new_val, MSECCFG_PMM, pmm != pmm_reserved ? pmm : 0);
350+
}
351+
345352
return basic_csr_t::unlogged_write(new_val);
346353
}
347354

@@ -968,7 +975,15 @@ envcfg_csr_t::envcfg_csr_t(processor_t* const proc, const reg_t addr, const reg_
968975

969976
bool envcfg_csr_t::unlogged_write(const reg_t val) noexcept {
970977
const reg_t cbie_reserved = 2; // Reserved value of xenvcfg.CBIE
971-
const reg_t adjusted_val = get_field(val, MENVCFG_CBIE) != cbie_reserved ? val : set_field(val, MENVCFG_CBIE, 0);
978+
reg_t adjusted_val = get_field(val, MENVCFG_CBIE) != cbie_reserved ? val : set_field(val, MENVCFG_CBIE, 0);
979+
980+
const reg_t pmm_reserved = 1; // Reserved value of xseccfg.PMM
981+
const reg_t pmm = get_field(adjusted_val, MENVCFG_PMM);
982+
adjusted_val = set_field(adjusted_val, MENVCFG_PMM, pmm != pmm_reserved ? pmm : 0);
983+
984+
if (get_field(adjusted_val, MENVCFG_PMM) != get_field(read(), MENVCFG_PMM))
985+
proc->get_mmu()->flush_tlb();
986+
972987
return masked_csr_t::unlogged_write(adjusted_val);
973988
}
974989

@@ -1836,3 +1851,23 @@ void mtval2_csr_t::verify_permissions(insn_t insn, bool write) const {
18361851
if (!proc->extension_enabled('H') && !proc->extension_enabled(EXT_SSDBLTRP))
18371852
throw trap_illegal_instruction(insn.bits());
18381853
}
1854+
1855+
hstatus_csr_t::hstatus_csr_t(processor_t* const proc, const reg_t addr):
1856+
basic_csr_t(proc, addr, set_field((reg_t)0, HSTATUS_VSXL, xlen_to_uxl(proc->get_const_xlen()))) {
1857+
}
1858+
1859+
bool hstatus_csr_t::unlogged_write(const reg_t val) noexcept {
1860+
const reg_t mask = HSTATUS_VTSR | HSTATUS_VTW
1861+
| (proc->supports_impl(IMPL_MMU) ? HSTATUS_VTVM : 0)
1862+
| (proc->extension_enabled(EXT_SSNPM) ? HSTATUS_HUPMM : 0)
1863+
| HSTATUS_HU | HSTATUS_SPVP | HSTATUS_SPV | HSTATUS_GVA;
1864+
1865+
const reg_t pmm_reserved = 1; // Reserved value of mseccfg.PMM
1866+
reg_t pmm = get_field(val, HSTATUS_HUPMM);
1867+
const reg_t adjusted_val = set_field(val, HSTATUS_HUPMM, pmm != pmm_reserved ? pmm : 0);
1868+
1869+
const reg_t new_hstatus = (read() & ~mask) | (adjusted_val & mask);
1870+
if (get_field(new_hstatus, HSTATUS_HUPMM) != get_field(read(), HSTATUS_HUPMM))
1871+
proc->get_mmu()->flush_tlb();
1872+
return basic_csr_t::unlogged_write(new_hstatus);
1873+
}

riscv/csrs.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -891,4 +891,11 @@ class mtval2_csr_t: public hypervisor_csr_t {
891891
mtval2_csr_t(processor_t* const proc, const reg_t addr);
892892
virtual void verify_permissions(insn_t insn, bool write) const override;
893893
};
894+
895+
class hstatus_csr_t final: public basic_csr_t {
896+
public:
897+
hstatus_csr_t(processor_t* const proc, const reg_t addr);
898+
protected:
899+
virtual bool unlogged_write(const reg_t val) noexcept override;
900+
};
894901
#endif

riscv/decode_macros.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,8 +218,9 @@ static inline bool is_aligned(const unsigned val, const unsigned pos)
218218

219219
#define sext32(x) ((sreg_t)(int32_t)(x))
220220
#define zext32(x) ((reg_t)(uint32_t)(x))
221-
#define sext_xlen(x) (((sreg_t)(x) << (64 - xlen)) >> (64 - xlen))
221+
#define sext(x, pos) (((sreg_t)(x) << (64 - (pos))) >> (64 - (pos)))
222222
#define zext(x, pos) (((reg_t)(x) << (64 - (pos))) >> (64 - (pos)))
223+
#define sext_xlen(x) sext(x, xlen)
223224
#define zext_xlen(x) zext(x, xlen)
224225

225226
#define set_pc(x) \

riscv/isa_parser.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@ typedef enum {
8282
EXT_ZICFILP,
8383
EXT_ZICFISS,
8484
EXT_SSDBLTRP,
85+
EXT_SMMPM,
86+
EXT_SMNPM,
87+
EXT_SSNPM,
8588
NUM_ISA_EXTENSIONS
8689
} isa_extension_t;
8790

riscv/mmu.cc

Lines changed: 79 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "arith.h"
66
#include "simif.h"
77
#include "processor.h"
8+
#include "decode_macros.h"
89

910
mmu_t::mmu_t(simif_t* sim, endianness_t endianness, processor_t* proc)
1011
: sim(sim), proc(proc),
@@ -54,7 +55,7 @@ void throw_access_exception(bool virt, reg_t addr, access_type type)
5455

5556
reg_t mmu_t::translate(mem_access_info_t access_info, reg_t len)
5657
{
57-
reg_t addr = access_info.vaddr;
58+
reg_t addr = access_info.transformed_vaddr;
5859
access_type type = access_info.type;
5960
if (!proc)
6061
return addr;
@@ -192,17 +193,18 @@ void mmu_t::check_triggers(triggers::operation_t operation, reg_t address, bool
192193
void mmu_t::load_slow_path_intrapage(reg_t len, uint8_t* bytes, mem_access_info_t access_info)
193194
{
194195
reg_t addr = access_info.vaddr;
195-
reg_t vpn = addr >> PGSHIFT;
196+
reg_t transformed_addr = access_info.transformed_vaddr;
197+
reg_t vpn = transformed_addr >> PGSHIFT;
196198
if (!access_info.flags.is_special_access() && vpn == (tlb_load_tag[vpn % TLB_ENTRIES] & ~TLB_CHECK_TRIGGERS)) {
197-
auto host_addr = tlb_data[vpn % TLB_ENTRIES].host_offset + addr;
199+
auto host_addr = tlb_data[vpn % TLB_ENTRIES].host_offset + transformed_addr;
198200
memcpy(bytes, host_addr, len);
199201
return;
200202
}
201203

202204
reg_t paddr = translate(access_info, len);
203205

204206
if (access_info.flags.lr && !sim->reservable(paddr)) {
205-
throw trap_load_access_fault(access_info.effective_virt, addr, 0, 0);
207+
throw trap_load_access_fault(access_info.effective_virt, transformed_addr, 0, 0);
206208
}
207209

208210
if (auto host_addr = sim->addr_to_mem(paddr)) {
@@ -213,50 +215,52 @@ void mmu_t::load_slow_path_intrapage(reg_t len, uint8_t* bytes, mem_access_info_
213215
refill_tlb(addr, paddr, host_addr, LOAD);
214216

215217
} else if (!mmio_load(paddr, len, bytes)) {
216-
throw trap_load_access_fault(access_info.effective_virt, addr, 0, 0);
218+
throw trap_load_access_fault(access_info.effective_virt, transformed_addr, 0, 0);
217219
}
218220

219221
if (access_info.flags.lr) {
220222
load_reservation_address = paddr;
221223
}
222224
}
223225

224-
void mmu_t::load_slow_path(reg_t addr, reg_t len, uint8_t* bytes, xlate_flags_t xlate_flags)
226+
void mmu_t::load_slow_path(reg_t original_addr, reg_t len, uint8_t* bytes, xlate_flags_t xlate_flags)
225227
{
226-
auto access_info = generate_access_info(addr, LOAD, xlate_flags);
227-
check_triggers(triggers::OPERATION_LOAD, addr, access_info.effective_virt);
228+
auto access_info = generate_access_info(original_addr, LOAD, xlate_flags);
229+
reg_t transformed_addr = access_info.transformed_vaddr;
230+
check_triggers(triggers::OPERATION_LOAD, transformed_addr, access_info.effective_virt);
228231

229-
if ((addr & (len - 1)) == 0) {
232+
if ((transformed_addr & (len - 1)) == 0) {
230233
load_slow_path_intrapage(len, bytes, access_info);
231234
} else {
232235
bool gva = access_info.effective_virt;
233236
if (!is_misaligned_enabled())
234-
throw trap_load_address_misaligned(gva, addr, 0, 0);
237+
throw trap_load_address_misaligned(gva, transformed_addr, 0, 0);
235238

236239
if (access_info.flags.lr)
237-
throw trap_load_access_fault(gva, addr, 0, 0);
240+
throw trap_load_access_fault(gva, transformed_addr, 0, 0);
238241

239-
reg_t len_page0 = std::min(len, PGSIZE - addr % PGSIZE);
242+
reg_t len_page0 = std::min(len, PGSIZE - transformed_addr % PGSIZE);
240243
load_slow_path_intrapage(len_page0, bytes, access_info);
241244
if (len_page0 != len)
242245
load_slow_path_intrapage(len - len_page0, bytes + len_page0, access_info.split_misaligned_access(len_page0));
243246
}
244247

245248
while (len > sizeof(reg_t)) {
246-
check_triggers(triggers::OPERATION_LOAD, addr, access_info.effective_virt, reg_from_bytes(sizeof(reg_t), bytes));
249+
check_triggers(triggers::OPERATION_LOAD, transformed_addr, access_info.effective_virt, reg_from_bytes(sizeof(reg_t), bytes));
247250
len -= sizeof(reg_t);
248251
bytes += sizeof(reg_t);
249252
}
250-
check_triggers(triggers::OPERATION_LOAD, addr, access_info.effective_virt, reg_from_bytes(len, bytes));
253+
check_triggers(triggers::OPERATION_LOAD, transformed_addr, access_info.effective_virt, reg_from_bytes(len, bytes));
251254
}
252255

253256
void mmu_t::store_slow_path_intrapage(reg_t len, const uint8_t* bytes, mem_access_info_t access_info, bool actually_store)
254257
{
255258
reg_t addr = access_info.vaddr;
256-
reg_t vpn = addr >> PGSHIFT;
259+
reg_t transformed_addr = access_info.transformed_vaddr;
260+
reg_t vpn = transformed_addr >> PGSHIFT;
257261
if (!access_info.flags.is_special_access() && vpn == (tlb_store_tag[vpn % TLB_ENTRIES] & ~TLB_CHECK_TRIGGERS)) {
258262
if (actually_store) {
259-
auto host_addr = tlb_data[vpn % TLB_ENTRIES].host_offset + addr;
263+
auto host_addr = tlb_data[vpn % TLB_ENTRIES].host_offset + transformed_addr;
260264
memcpy(host_addr, bytes, len);
261265
}
262266
return;
@@ -272,34 +276,35 @@ void mmu_t::store_slow_path_intrapage(reg_t len, const uint8_t* bytes, mem_acces
272276
else if (!access_info.flags.is_special_access())
273277
refill_tlb(addr, paddr, host_addr, STORE);
274278
} else if (!mmio_store(paddr, len, bytes)) {
275-
throw trap_store_access_fault(access_info.effective_virt, addr, 0, 0);
279+
throw trap_store_access_fault(access_info.effective_virt, transformed_addr, 0, 0);
276280
}
277281
}
278282
}
279283

280-
void mmu_t::store_slow_path(reg_t addr, reg_t len, const uint8_t* bytes, xlate_flags_t xlate_flags, bool actually_store, bool UNUSED require_alignment)
284+
void mmu_t::store_slow_path(reg_t original_addr, reg_t len, const uint8_t* bytes, xlate_flags_t xlate_flags, bool actually_store, bool UNUSED require_alignment)
281285
{
282-
auto access_info = generate_access_info(addr, STORE, xlate_flags);
286+
auto access_info = generate_access_info(original_addr, STORE, xlate_flags);
287+
reg_t transformed_addr = access_info.transformed_vaddr;
283288
if (actually_store) {
284289
reg_t trig_len = len;
285290
const uint8_t* trig_bytes = bytes;
286291
while (trig_len > sizeof(reg_t)) {
287-
check_triggers(triggers::OPERATION_STORE, addr, access_info.effective_virt, reg_from_bytes(sizeof(reg_t), trig_bytes));
292+
check_triggers(triggers::OPERATION_STORE, transformed_addr, access_info.effective_virt, reg_from_bytes(sizeof(reg_t), trig_bytes));
288293
trig_len -= sizeof(reg_t);
289294
trig_bytes += sizeof(reg_t);
290295
}
291-
check_triggers(triggers::OPERATION_STORE, addr, access_info.effective_virt, reg_from_bytes(trig_len, trig_bytes));
296+
check_triggers(triggers::OPERATION_STORE, transformed_addr, access_info.effective_virt, reg_from_bytes(trig_len, trig_bytes));
292297
}
293298

294-
if (addr & (len - 1)) {
299+
if (transformed_addr & (len - 1)) {
295300
bool gva = access_info.effective_virt;
296301
if (!is_misaligned_enabled())
297-
throw trap_store_address_misaligned(gva, addr, 0, 0);
302+
throw trap_store_address_misaligned(gva, transformed_addr, 0, 0);
298303

299304
if (require_alignment)
300-
throw trap_store_access_fault(gva, addr, 0, 0);
305+
throw trap_store_access_fault(gva, transformed_addr, 0, 0);
301306

302-
reg_t len_page0 = std::min(len, PGSIZE - addr % PGSIZE);
307+
reg_t len_page0 = std::min(len, PGSIZE - transformed_addr % PGSIZE);
303308
store_slow_path_intrapage(len_page0, bytes, access_info, actually_store);
304309
if (len_page0 != len)
305310
store_slow_path_intrapage(len - len_page0, bytes + len_page0, access_info.split_misaligned_access(len_page0), actually_store);
@@ -484,7 +489,7 @@ reg_t mmu_t::s2xlate(reg_t gva, reg_t gpa, access_type type, access_type trap_ty
484489
reg_t mmu_t::walk(mem_access_info_t access_info)
485490
{
486491
access_type type = access_info.type;
487-
reg_t addr = access_info.vaddr;
492+
reg_t addr = access_info.transformed_vaddr;
488493
bool virt = access_info.effective_virt;
489494
bool hlvx = access_info.flags.hlvx;
490495
reg_t mode = access_info.effective_priv;
@@ -607,3 +612,51 @@ void mmu_t::register_memtracer(memtracer_t* t)
607612
flush_tlb();
608613
tracer.hook(t);
609614
}
615+
616+
reg_t mmu_t::get_pmlen(bool effective_virt, reg_t effective_priv, xlate_flags_t flags) const {
617+
if (!proc || proc->get_xlen() != 64 || (in_mprv() && (proc->state.sstatus->read() & MSTATUS_MXR)) || flags.hlvx)
618+
return 0;
619+
620+
reg_t pmm = 0;
621+
if (effective_priv == PRV_M)
622+
pmm = get_field(proc->state.mseccfg->read(), MSECCFG_PMM);
623+
else if (!effective_virt && (effective_priv == PRV_S || (!proc->extension_enabled('S') && effective_priv == PRV_U)))
624+
pmm = get_field(proc->state.menvcfg->read(), MENVCFG_PMM);
625+
else if (effective_virt && effective_priv == PRV_S)
626+
pmm = get_field(proc->state.henvcfg->read(), HENVCFG_PMM);
627+
else if (proc->state.prv == PRV_U && flags.forced_virt)
628+
pmm = get_field(proc->state.hstatus->read(), HSTATUS_HUPMM);
629+
else if (effective_priv == PRV_U)
630+
pmm = get_field(proc->state.senvcfg->read(), SENVCFG_PMM);
631+
else
632+
assert(false);
633+
634+
switch (pmm) {
635+
case 2: return 7;
636+
case 3: return 16;
637+
}
638+
return 0;
639+
}
640+
641+
mem_access_info_t mmu_t::generate_access_info(reg_t addr, access_type type, xlate_flags_t xlate_flags) {
642+
if (!proc)
643+
return {addr, addr, 0, false, {}, type};
644+
bool virt = proc->state.v;
645+
reg_t mode = proc->state.prv;
646+
if (type != FETCH) {
647+
if (in_mprv()) {
648+
mode = get_field(proc->state.mstatus->read(), MSTATUS_MPP);
649+
if (get_field(proc->state.mstatus->read(), MSTATUS_MPV) && mode != PRV_M)
650+
virt = true;
651+
}
652+
if (xlate_flags.forced_virt) {
653+
virt = true;
654+
mode = get_field(proc->state.hstatus->read(), HSTATUS_SPVP);
655+
}
656+
}
657+
reg_t pmlen = get_pmlen(virt, mode, xlate_flags);
658+
reg_t satp = proc->state.satp->readvirt(virt);
659+
bool is_physical_addr = mode == PRV_M || get_field(satp, SATP64_MODE) == SATP_MODE_OFF;
660+
reg_t transformed_addr = is_physical_addr ? zext(addr, 64 - pmlen) : sext(addr, 64 - pmlen);
661+
return {addr, transformed_addr, mode, virt, xlate_flags, type};
662+
}

0 commit comments

Comments
 (0)