From faceda27e60c0721b3233658198bcf50d09b02cc Mon Sep 17 00:00:00 2001 From: YenHaoChen Date: Thu, 13 Jul 2023 09:27:46 +0800 Subject: [PATCH 1/3] refactor: mcontrol/mcontrol6: extend check_triggers() with tval parameter --- riscv/mmu.cc | 6 +++--- riscv/mmu.h | 5 ++++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/riscv/mmu.cc b/riscv/mmu.cc index 3f90060e82..f6d23a3bf6 100644 --- a/riscv/mmu.cc +++ b/riscv/mmu.cc @@ -169,7 +169,7 @@ bool mmu_t::mmio(reg_t paddr, size_t len, uint8_t* bytes, access_type type) return true; } -void mmu_t::check_triggers(triggers::operation_t operation, reg_t address, bool virt, std::optional data) +void mmu_t::check_triggers(triggers::operation_t operation, reg_t address, bool virt, reg_t tval, std::optional data) { if (matched_trigger || !proc) return; @@ -179,13 +179,13 @@ void mmu_t::check_triggers(triggers::operation_t operation, reg_t address, bool if (match.has_value()) switch (match->timing) { case triggers::TIMING_BEFORE: - throw triggers::matched_t(operation, address, match->action, virt); + throw triggers::matched_t(operation, tval, match->action, virt); case triggers::TIMING_AFTER: // We want to take this exception on the next instruction. We check // whether to do so in the I$ refill path, so flush the I$. flush_icache(); - matched_trigger = new triggers::matched_t(operation, address, match->action, virt); + matched_trigger = new triggers::matched_t(operation, tval, match->action, virt); } } diff --git a/riscv/mmu.h b/riscv/mmu.h index 46c54ce88a..62e9a73b79 100644 --- a/riscv/mmu.h +++ b/riscv/mmu.h @@ -402,7 +402,10 @@ class mmu_t bool mmio_store(reg_t paddr, size_t len, const uint8_t* bytes); bool mmio(reg_t paddr, size_t len, uint8_t* bytes, access_type type); bool mmio_ok(reg_t paddr, access_type type); - void check_triggers(triggers::operation_t operation, reg_t address, bool virt, std::optional data = std::nullopt); + void check_triggers(triggers::operation_t operation, reg_t address, bool virt, std::optional data = std::nullopt) { + check_triggers(operation, address, virt, address, data); + } + void check_triggers(triggers::operation_t operation, reg_t address, bool virt, reg_t tval, std::optional data); reg_t translate(mem_access_info_t access_info, reg_t len); reg_t pte_load(reg_t pte_paddr, reg_t addr, bool virt, access_type trap_type, size_t ptesize) { From 4aea5a05ad7bf1b48b2d87e000e6575f68747033 Mon Sep 17 00:00:00 2001 From: YenHaoChen Date: Thu, 13 Jul 2023 10:57:32 +0800 Subject: [PATCH 2/3] fix mcontrol's tval on cbo_zero The tval should capture the effective address on an (trigger) exception. Reference: https://github.com/riscv/riscv-CMOs/issues/55 --- riscv/mmu.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/riscv/mmu.h b/riscv/mmu.h index 62e9a73b79..cfbe57cc6a 100644 --- a/riscv/mmu.h +++ b/riscv/mmu.h @@ -219,8 +219,10 @@ class mmu_t void cbo_zero(reg_t addr) { auto base = addr & ~(blocksz - 1); - for (size_t offset = 0; offset < blocksz; offset += 1) + for (size_t offset = 0; offset < blocksz; offset += 1) { + check_triggers(triggers::OPERATION_STORE, base + offset, false, addr, std::nullopt); store(base + offset, 0); + } } void clean_inval(reg_t addr, bool clean, bool inval) { From 8658429647eb6952707e2bf2a3bb4eca75a8e379 Mon Sep 17 00:00:00 2001 From: YenHaoChen Date: Wed, 19 Jul 2023 14:15:57 +0800 Subject: [PATCH 3/3] mcontrol/mcontrol6 triggers on cbo.flush/clean The mcontrol/mcontrol6 store address before has a higher priority over page faults and access faults. Thus, trigger checking should before the translate(). This commit checks all address of the cache block. Reference: Debug spec 1.0, 5.5.3 Cache Operations Reference: CMO spec 1.0.1, 2.5.4 Breakpoint Exceptions and Debug Mode Entry --- riscv/mmu.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/riscv/mmu.h b/riscv/mmu.h index cfbe57cc6a..a54a4838d0 100644 --- a/riscv/mmu.h +++ b/riscv/mmu.h @@ -226,6 +226,9 @@ class mmu_t } void clean_inval(reg_t addr, bool clean, bool inval) { + auto base = addr & ~(blocksz - 1); + for (size_t offset = 0; offset < blocksz; offset += 1) + check_triggers(triggers::OPERATION_STORE, base + offset, false, addr, std::nullopt); convert_load_traps_to_store_traps({ const reg_t paddr = translate(generate_access_info(addr, LOAD, {false, false, false}), 1); if (sim->reservable(paddr)) {