#ifndef _RISCV_H_ #define _RISCV_H_ #include "util/types.h" #include "config.h" // fields of mstatus, the Machine mode Status register #define MSTATUS_MPP_MASK (3L << 11) // previous mode mask #define MSTATUS_MPP_M (3L << 11) // machine mode (m-mode) #define MSTATUS_MPP_S (1L << 11) // supervisor mode (s-mode) #define MSTATUS_MPP_U (0L << 11) // user mode (u-mode) #define MSTATUS_MIE (1L << 3) // machine-mode interrupt enable #define MSTATUS_MPIE (1L << 7) // preserve MIE bit // values of mcause, the Machine Cause register #define IRQ_S_EXT 9 // s-mode external interrupt #define IRQ_S_TIMER 5 // s-mode timer interrupt #define IRQ_S_SOFT 1 // s-mode software interrupt #define IRQ_M_SOFT 3 // m-mode software interrupt // fields of mip, the Machine Interrupt Pending register #define MIP_SEIP (1 << IRQ_S_EXT) // s-mode external interrupt pending #define MIP_SSIP (1 << IRQ_S_SOFT) // s-mode software interrupt pending #define MIP_STIP (1 << IRQ_S_TIMER) // s-mode timer interrupt pending #define MIP_MSIP (1 << IRQ_M_SOFT) // m-mode software interrupt pending // pysical memory protection choices #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 // exceptions #define CAUSE_MISALIGNED_FETCH 0x0 // Instruction address misaligned #define CAUSE_FETCH_ACCESS 0x1 // Instruction access fault #define CAUSE_ILLEGAL_INSTRUCTION 0x2 // Illegal Instruction #define CAUSE_BREAKPOINT 0x3 // Breakpoint #define CAUSE_MISALIGNED_LOAD 0x4 // Load address misaligned #define CAUSE_LOAD_ACCESS 0x5 // Load access fault #define CAUSE_MISALIGNED_STORE 0x6 // Store/AMO address misaligned #define CAUSE_STORE_ACCESS 0x7 // Store/AMO access fault #define CAUSE_USER_ECALL 0x8 // Environment call from U-mode #define CAUSE_SUPERVISOR_ECALL 0x9 // Environment call from S-mode #define CAUSE_MACHINE_ECALL 0xb // Environment call from M-mode #define CAUSE_FETCH_PAGE_FAULT 0xc // Instruction page fault #define CAUSE_LOAD_PAGE_FAULT 0xd // Load page fault #define CAUSE_STORE_PAGE_FAULT 0xf // Store/AMO page fault // irqs (interrupts). added @lab1_3 #define CAUSE_MTIMER 0x8000000000000007 #define CAUSE_MTIMER_S_TRAP 0x8000000000000001 //Supervisor interrupt-pending register #define SIP_SSIP (1L << 1) // core local interruptor (CLINT), which contains the timer. #define CLINT 0x2000000L #define CLINT_MTIMECMP(hartid) (CLINT + 0x4000 + 8 * (hartid)) #define CLINT_MTIME (CLINT + 0xBFF8) // cycles since boot. // fields of sstatus, the Supervisor mode Status register #define SSTATUS_SPP (1L << 8) // Previous mode, 1=Supervisor, 0=User #define SSTATUS_SPIE (1L << 5) // Supervisor Previous Interrupt Enable #define SSTATUS_UPIE (1L << 4) // User Previous Interrupt Enable #define SSTATUS_SIE (1L << 1) // Supervisor Interrupt Enable #define SSTATUS_UIE (1L << 0) // User Interrupt Enable #define SSTATUS_SUM 0x00040000 #define SSTATUS_FS 0x00006000 // Supervisor Interrupt Enable #define SIE_SEIE (1L << 9) // external #define SIE_STIE (1L << 5) // timer #define SIE_SSIE (1L << 1) // software // Machine-mode Interrupt Enable #define MIE_MEIE (1L << 11) // external #define MIE_MTIE (1L << 7) // timer #define MIE_MSIE (1L << 3) // software #define read_const_csr(reg) \ ({ \ unsigned long __tmp; \ asm("csrr %0, " #reg : "=r"(__tmp)); \ __tmp; \ }) static inline int supports_extension(char ext) { return read_const_csr(misa) & (1 << (ext - 'A')); } #define read_csr(reg) \ ({ \ unsigned long __tmp; \ asm volatile("csrr %0, " #reg : "=r"(__tmp)); \ __tmp; \ }) #define write_csr(reg, val) ({ asm volatile("csrw " #reg ", %0" ::"rK"(val)); }) #define swap_csr(reg, val) \ ({ \ unsigned long __tmp; \ asm volatile("csrrw %0, " #reg ", %1" : "=r"(__tmp) : "rK"(val)); \ __tmp; \ }) #define set_csr(reg, bit) \ ({ \ unsigned long __tmp; \ asm volatile("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "rK"(bit)); \ __tmp; \ }) // enable device interrupts static inline void intr_on(void) { write_csr(sstatus, read_csr(sstatus) | SSTATUS_SIE); } // disable device interrupts static inline void intr_off(void) { write_csr(sstatus, read_csr(sstatus) & ~SSTATUS_SIE); } // are device interrupts enabled? static inline int is_intr_enable(void) { // uint64 x = r_sstatus(); uint64 x = read_csr(sstatus); return (x & SSTATUS_SIE) != 0; } // read sp, the stack pointer static inline uint64 read_sp(void) { uint64 x; asm volatile("mv %0, sp" : "=r"(x)); return x; } // read tp, the thread pointer, holding hartid (core number), the index into cpus[]. static inline uint64 read_tp(void) { uint64 x; asm volatile("mv %0, tp" : "=r"(x)); return x; } // write tp, the thread pointer, holding hartid (core number), the index into cpus[]. static inline void write_tp(uint64 x) { asm volatile("mv tp, %0" : : "r"(x)); } typedef struct riscv_regs_t { /* 0 */ uint64 ra; /* 8 */ uint64 sp; /* 16 */ uint64 gp; /* 24 */ uint64 tp; /* 32 */ uint64 t0; /* 40 */ uint64 t1; /* 48 */ uint64 t2; /* 56 */ uint64 s0; /* 64 */ uint64 s1; /* 72 */ uint64 a0; /* 80 */ uint64 a1; /* 88 */ uint64 a2; /* 96 */ uint64 a3; /* 104 */ uint64 a4; /* 112 */ uint64 a5; /* 120 */ uint64 a6; /* 128 */ uint64 a7; /* 136 */ uint64 s2; /* 144 */ uint64 s3; /* 152 */ uint64 s4; /* 160 */ uint64 s5; /* 168 */ uint64 s6; /* 176 */ uint64 s7; /* 184 */ uint64 s8; /* 192 */ uint64 s9; /* 196 */ uint64 s10; /* 208 */ uint64 s11; /* 216 */ uint64 t3; /* 224 */ uint64 t4; /* 232 */ uint64 t5; /* 240 */ uint64 t6; }riscv_regs; // following lines are added @lab2_1 static inline void flush_tlb(void) { asm volatile("sfence.vma zero, zero"); } #define PGSIZE 4096 // bytes per page #define PGSHIFT 12 // offset bits within a page // use riscv's sv39 page table scheme. #define SATP_SV39 (8L << 60) #define MAKE_SATP(pagetable) (SATP_SV39 | (((uint64)pagetable) >> 12)) #define PTE_V (1L << 0) // valid #define PTE_R (1L << 1) // readable #define PTE_W (1L << 2) // writable #define PTE_X (1L << 3) // executable #define PTE_U (1L << 4) // 1->user can access, 0->otherwise #define PTE_G (1L << 5) // global #define PTE_A (1L << 6) // accessed #define PTE_D (1L << 7) // dirty // shift a physical address to the right place for a PTE. #define PA2PTE(pa) ((((uint64)pa) >> 12) << 10) // convert a pte content into its corresponding physical address #define PTE2PA(pte) (((pte) >> 10) << 12) // extract the property bits of a pte #define PTE_FLAGS(pte) ((pte)&0x3FF) // extract the three 9-bit page table indices from a virtual address. #define PXMASK 0x1FF // 9 bits #define PXSHIFT(level) (PGSHIFT + (9 * (level))) #define PX(level, va) ((((uint64)(va)) >> PXSHIFT(level)) & PXMASK) // one beyond the highest possible virtual address. // MAXVA is actually one bit less than the max allowed by // Sv39, to avoid having to sign-extend virtual addresses // that have the high bit set. #define MAXVA (1L << (9 + 9 + 9 + 12 - 1)) typedef uint64 pte_t; typedef uint64 *pagetable_t; // 512 PTEs #endif