From b01490b5f31c3cabd4a55a747e85d8201050cd3d Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 23 Mar 2023 08:53:10 +0100 Subject: [PATCH] Implement counteren (1.10+ spec) --- src/main/scala/vexriscv/Riscv.scala | 1 + .../scala/vexriscv/plugin/CsrPlugin.scala | 22 +++ src/test/cpp/raw/privSpec/src/crt.S | 158 ++++++++++++++++- src/test/cpp/raw/privSpec/src/privileged.h | 159 ++++++++++++++++++ src/test/cpp/raw/privSpec/src/riscv_asm.h | 94 +++++++++++ 5 files changed, 432 insertions(+), 2 deletions(-) create mode 100644 src/test/cpp/raw/privSpec/src/privileged.h create mode 100644 src/test/cpp/raw/privSpec/src/riscv_asm.h diff --git a/src/main/scala/vexriscv/Riscv.scala b/src/main/scala/vexriscv/Riscv.scala index cb129a9..52ccf36 100644 --- a/src/main/scala/vexriscv/Riscv.scala +++ b/src/main/scala/vexriscv/Riscv.scala @@ -215,6 +215,7 @@ object Riscv{ def MINSTRET = 0xB02 // MRW Machine instructions-retired counter. def MCYCLEH = 0xB80 // MRW Upper 32 bits of mcycle, RV32I only. def MINSTRETH = 0xB82 // MRW Upper 32 bits of minstret, RV32I only. + val MCOUNTEREN = 0x306 val SSTATUS = 0x100 val SIE = 0x104 diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 4f4c481..1d03584 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -1058,6 +1058,28 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep utimeAccess(CSR.UTIMEH, utime(63 downto 32)) } + class Xcounteren(csrId : Int) extends Area{ + val IR,TM,CY = RegInit(True) //For backward compatibility + if(ucycleAccess != CsrAccess.NONE) rw(csrId, 0 -> CY) + if(utimeAccess != CsrAccess.NONE) rw(csrId, 1 -> TM) + if(uinstretAccess != CsrAccess.NONE) rw(csrId, 2 -> IR) + } + def xcounterChecks(access : CsrAccess, csrId : Int, enable : Xcounteren => Bool) = { + if(access != CsrAccess.NONE) during(csrId){ + if(userGen) when(privilege < 3 && !enable(mcounteren)){ forceFailCsr() } + if(supervisorGen) when(privilege < 1 && !enable(scounteren)){ forceFailCsr() } + } + } + + val mcounteren = userGen generate new Xcounteren(CSR.MCOUNTEREN) + val scounteren = supervisorGen generate new Xcounteren(CSR.SCOUNTEREN) + xcounterChecks(ucycleAccess , CSR.UCYCLE , _.CY) + xcounterChecks(ucycleAccess , CSR.UCYCLEH , _.CY) + xcounterChecks(utimeAccess , CSR.UTIME , _.TM) + xcounterChecks(utimeAccess , CSR.UTIMEH , _.TM) + xcounterChecks(uinstretAccess, CSR.UINSTRET , _.IR) + xcounterChecks(uinstretAccess, CSR.UINSTRETH, _.IR) + pipeline(MPP) := mstatus.MPP } diff --git a/src/test/cpp/raw/privSpec/src/crt.S b/src/test/cpp/raw/privSpec/src/crt.S index d9a095d..62a8801 100644 --- a/src/test/cpp/raw/privSpec/src/crt.S +++ b/src/test/cpp/raw/privSpec/src/crt.S @@ -1,6 +1,10 @@ .globl _star #define TEST_ID x28 +#include "privileged.h" + + + _start: la x1, fail csrw mtvec, x1 @@ -18,12 +22,15 @@ test1: csrr x2, stvec bnez x2, fail + la x1, fail + csrw mtvec, x1 + li x1, 9 csrw mcause, x1 csrr x2, mcause bne x2, x1, fail - csrr x0, pmpcfg0 + /*csrr x0, pmpcfg0 csrw pmpcfg0, x0 csrr x0, pmpcfg3 @@ -33,7 +40,154 @@ test1: csrw pmpaddr0, x0 csrr x0, pmpaddr15 - csrw pmpaddr15, x0 + csrw pmpaddr15, x0*/ + + li TEST_ID, 2 + csrr x1, mcycle + csrr x2, mcycle + bge x1, x2, fail + + csrr x1, minstret + csrr x2, minstret + bge x1, x2, fail + + csrr x1, cycle + csrr x2, cycle + bge x1, x2, fail + + csrr x1, instret + csrr x2, instret + bge x1, x2, fail + + csrr x1, time + csrr x2, time + bge x1, x2, fail + + //Test access to counters in supervisor + machine_setup_trap + machine_to_supervisor + li TEST_ID, 3 + + csrr x1, cycle + csrr x2, cycle + bge x1, x2, fail + + csrr x1, instret + csrr x2, instret + bge x1, x2, fail + + csrr x1, time + csrr x2, time + bge x1, x2, fail + + ecall + machine_handle_trap + + //Test access to counters in user + machine_setup_trap + machine_to_user + li TEST_ID, 4 + + csrr x1, cycle + csrr x2, cycle + bge x1, x2, fail + + csrr x1, instret + csrr x2, instret + bge x1, x2, fail + + csrr x1, time + csrr x2, time + bge x1, x2, fail + ecall + machine_handle_trap + + //Remove user access to counters + li x1, -1 + csrw mcounteren, x1 + li x1, 0 + csrw scounteren, x1 + + machine_setup_trap + machine_to_supervisor + li TEST_ID, 3 + + csrr x1, cycle + csrr x2, cycle + bge x1, x2, fail + + csrr x1, instret + csrr x2, instret + bge x1, x2, fail + + csrr x1, time + csrr x2, time + bge x1, x2, fail + + ecall + machine_handle_trap + + machine_setup_trap + machine_to_user + csrr x1, cycle + j fail + machine_handle_trap + + machine_setup_trap + machine_to_user + csrr x1, instret + j fail + machine_handle_trap + + machine_setup_trap + machine_to_user + csrr x1, time + j fail + machine_handle_trap + + + //Remove supervisor access to counters + li x1, 0 + csrw mcounteren, x1 + li x1, -1 + csrw scounteren, x1 + + machine_setup_trap + machine_to_supervisor + csrr x1, cycle + j fail + machine_handle_trap + + machine_setup_trap + machine_to_supervisor + csrr x1, instret + j fail + machine_handle_trap + + machine_setup_trap + machine_to_supervisor + csrr x1, time + j fail + machine_handle_trap + + machine_setup_trap + machine_to_user + csrr x1, cycle + j fail + machine_handle_trap + + machine_setup_trap + machine_to_user + csrr x1, instret + j fail + machine_handle_trap + + machine_setup_trap + machine_to_user + csrr x1, time + j fail + machine_handle_trap + j pass diff --git a/src/test/cpp/raw/privSpec/src/privileged.h b/src/test/cpp/raw/privSpec/src/privileged.h new file mode 100644 index 0000000..289be29 --- /dev/null +++ b/src/test/cpp/raw/privSpec/src/privileged.h @@ -0,0 +1,159 @@ +#pragma once + + +#include "riscv_asm.h" + +#define trap_setup \ + la x1, 1f; \ + csrw mtvec, x1; \ + addi x1, x1, 0x123; \ + csrw mtval, x1; \ + +#define trap_handle \ + j fail; \ + j fail; \ + j fail; \ + j fail; \ +.align 4; \ +1: \ + csrr x1, mepc; \ + csrr x1, mcause; \ + csrr x1, mstatus; \ + csrr x1, mtval; \ + csrr x1, mip; \ + +#define trap_handle_setup \ + trap_handle \ + trap_setup \ + + + +#define supervisor_read \ + csrr x1, sepc; \ + csrr x1, scause; \ + csrr x1, sstatus; \ + csrr x1, stval; \ + csrr x1, sip; + +#define machine_read \ + csrr x1, mepc; \ + csrr x1, mcause; \ + csrr x1, mstatus; \ + csrr x1, mtval; \ + csrr x1, mip; \ + supervisor_read + +#define user_read + +#define machine_to_supervisor \ + la x1,1f ;\ + csrw mepc, x1 ;\ + li x1, MSTATUS_MPP_SUPERVISOR ;\ + csrw mstatus, x1 ;\ + mret ;\ + j fail ;\ + j fail ;\ + j fail ;\ + j fail ;\ +1: ;\ + supervisor_read + +#define machine_to_supervisor_x1 \ + csrw mepc, x1 ;\ + li x1, MSTATUS_MPP_SUPERVISOR ;\ + csrw mstatus, x1 ;\ + mret ;\ + j fail ;\ + j fail ;\ + j fail ;\ + j fail ;\ + + + +#define machine_to_user \ + la x1,1f ;\ + csrw mepc, x1 ;\ + li x1, MSTATUS_MPP_USER ;\ + csrw mstatus, x1 ;\ + mret ;\ + j fail ;\ + j fail ;\ + j fail ;\ + j fail ;\ +1: ;\ + user_read + +#define machine_setup_trap \ + la x1, 2f ;\ + csrw mtvec,x1; + +#define machine_handle_trap \ + j fail ;\ +.align 4 ;\ +2: ;\ + machine_read + +#define supervisor_setup_trap \ + la x1, 3f ;\ + csrw stvec,x1; + + +#define supervisor_handle_trap \ + j fail ;\ +.align 4 ;\ +3: ;\ + supervisor_read + + + +#define supervisor_check \ + supervisor_setup_trap \ + csrr x1, mstatus; \ + supervisor_handle_trap \ + supervisor_read + +#define supervisor_external_interrupt_set \ + li x1, SUPERVISOR_EXTERNAL_INTERRUPT_CTRL; \ + li x2, 1; \ + sw x2, 0(x1); + +#define supervisor_external_interrupt_clear \ + li x1, SUPERVISOR_EXTERNAL_INTERRUPT_CTRL; \ + sw x0, 0(x1); + +#define wait_interrupt nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;j fail; +#define delay_long nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop; + + +#define machine_enable_supervisor_external_interrupt \ + li x1, 1 << CAUSE_SUPERVISOR_EXTERNAL; \ + csrw mie, x1; \ + li x1, MSTATUS_MIE ; \ + csrw mstatus, x1 ; + +#define supervisor_enable_supervisor_external_interrupt \ + li x1, 1 << CAUSE_SUPERVISOR_EXTERNAL; \ + csrw sie, x1; \ + li x1, MSTATUS_SIE ; \ + csrw sstatus, x1 ; + + +#define machine_trap_failure \ + la x1, 1f; \ + csrw mtvec, x1; \ + j 4f \ +1: \ + nop; \ + j fail; \ +4: + +#define supervisor_trap_failure \ + la x1, 1f; \ + csrw stvec, x1; \ + j 4f; \ +.align 4; \ +1: \ + nop; \ + j fail; \ +4: + diff --git a/src/test/cpp/raw/privSpec/src/riscv_asm.h b/src/test/cpp/raw/privSpec/src/riscv_asm.h new file mode 100644 index 0000000..347f311 --- /dev/null +++ b/src/test/cpp/raw/privSpec/src/riscv_asm.h @@ -0,0 +1,94 @@ +#pragma once + +//exceptions +#define CAUSE_ILLEGAL_INSTRUCTION 2 +#define CAUSE_UCALL 8 +#define CAUSE_SCALL 9 + +//interrupts +#define CAUSE_MACHINE_SOFTWARE 3 +#define CAUSE_MACHINE_TIMER 7 +#define CAUSE_MACHINE_EXTERNAL 11 +#define CAUSE_SUPERVISOR_SOFTWARE 1 +#define CAUSE_SUPERVISOR_TIMER 5 +#define CAUSE_SUPERVISOR_EXTERNAL 9 + + +#define MIE_MTIE (1 << CAUSE_MACHINE_TIMER) +#define MIE_MEIE (1 << CAUSE_MACHINE_EXTERNAL) +#define MIE_MSIE (1 << CAUSE_MACHINE_SOFTWARE) +#define MIE_SEIE (1 << CAUSE_SUPERVISOR_EXTERNAL) + +#define MEDELEG_INSTRUCTION_PAGE_FAULT (1 << 12) +#define MEDELEG_LOAD_PAGE_FAULT (1 << 13) +#define MEDELEG_STORE_PAGE_FAULT (1 << 15) +#define MEDELEG_USER_ENVIRONNEMENT_CALL (1 << 8) +#define MIDELEG_SUPERVISOR_SOFTWARE (1 << 1) +#define MIDELEG_SUPERVISOR_TIMER (1 << 5) +#define MIDELEG_SUPERVISOR_EXTERNAL (1 << 9) + + +#define MSTATUS_UIE 0x00000001 +#define MSTATUS_SIE 0x00000002 +#define MSTATUS_HIE 0x00000004 +#define MSTATUS_MIE 0x00000008 +#define MSTATUS_UPIE 0x00000010 +#define MSTATUS_SPIE 0x00000020 +#define MSTATUS_HPIE 0x00000040 +#define MSTATUS_MPIE 0x00000080 +#define MSTATUS_SPP 0x00000100 +#define MSTATUS_HPP 0x00000600 +#define MSTATUS_MPP 0x00001800 +#define MSTATUS_FS 0x00006000 +#define MSTATUS_XS 0x00018000 +#define MSTATUS_MPRV 0x00020000 +#define MSTATUS_SUM 0x00040000 +#define MSTATUS_MXR 0x00080000 +#define MSTATUS_TVM 0x00100000 +#define MSTATUS_TW 0x00200000 +#define MSTATUS_TSR 0x00400000 +#define MSTATUS32_SD 0x80000000 +#define MSTATUS_UXL 0x0000000300000000 +#define MSTATUS_SXL 0x0000000C00000000 +#define MSTATUS64_SD 0x8000000000000000 +#define MSTATUS_FS_INITIAL (1 << 13) +#define MSTATUS_FS_CLEAN (2 << 13) +#define MSTATUS_FS_DIRTY (3 << 13) +#define MSTATUS_FS_MASK (3 << 13) + + +#define MSTATUS_MPP_SUPERVISOR 0x00000800 +#define MSTATUS_MPP_USER 0x00000000 + +#define SSTATUS_UIE 0x00000001 +#define SSTATUS_SIE 0x00000002 +#define SSTATUS_UPIE 0x00000010 +#define SSTATUS_SPIE 0x00000020 +#define SSTATUS_SPP 0x00000100 +#define SSTATUS_FS 0x00006000 +#define SSTATUS_XS 0x00018000 +#define SSTATUS_SUM 0x00040000 +#define SSTATUS_MXR 0x00080000 +#define SSTATUS32_SD 0x80000000 +#define SSTATUS_UXL 0x0000000300000000 +#define SSTATUS64_SD 0x8000000000000000 + + +#define PMP_R 0x01 +#define PMP_W 0x02 +#define PMP_X 0x04 +#define PMP_A 0x18 +#define PMP_L 0x80 +#define PMP_SHIFT 2 + +#define PMP_TOR 0x08 +#define PMP_NA4 0x10 +#define PMP_NAPOT 0x18 + +#define RDCYCLE 0xC00 //Read-only cycle Cycle counter for RDCYCLE instruction. +#define RDTIME 0xC01 //Read-only time Timer for RDTIME instruction. +#define RDINSTRET 0xC02 //Read-only instret Instructions-retired counter for RDINSTRET instruction. +#define RDCYCLEH 0xC80 //Read-only cycleh Upper 32 bits of cycle, RV32I only. +#define RDTIMEH 0xC81 //Read-only timeh Upper 32 bits of time, RV32I only. +#define RDINSTRETH 0xC82 //Read-only instreth Upper 32 bits of instret, RV32I only. +