#pragma once #ifndef __ASSEMBLER__ #include "types.h" // which hart (core) is this? static inline u64 r_mhartid() { u64 x; asm volatile("csrr %0, mhartid" : "=r"(x)); return x; } // Machine Status Register, mstatus #define MSTATUS_MPP_MASK (3L << 11) // previous mode. #define MSTATUS_MPP_M (3L << 11) #define MSTATUS_MPP_S (1L << 11) #define MSTATUS_MPP_U (0L << 11) #define MSTATUS_MIE (1L << 3) // machine-mode interrupt enable. static inline u64 r_mstatus() { u64 x; asm volatile("csrr %0, mstatus" : "=r"(x)); return x; } static inline void w_mstatus(u64 x) { asm volatile("csrw mstatus, %0" : : "r"(x)); } // machine exception program counter, holds the // instruction address to which a return from // exception will go. static inline void w_mepc(u64 x) { asm volatile("csrw mepc, %0" : : "r"(x)); } // Supervisor Status Register, sstatus /** Supervisor Previous Privilege */ #define SSTATUS_SPP (1L << 8) // Previous mode, 1=Supervisor, 0=User /** Supervisor Previous Interrupt Enable */ #define SSTATUS_SPIE (1L << 5) /** User Previous Interrupt Enable */ #define SSTATUS_UPIE (1L << 4) /** Supervisor Interrupt Enable */ #define SSTATUS_SIE (1L << 1) /** User Interrupt Enable */ #define SSTATUS_UIE (1L << 0) /** * Read the value of the sstatus register. * (Supervisor Status Register) */ static inline u64 r_sstatus() { u64 x; asm volatile("csrr %0, sstatus" : "=r"(x)); return x; } /** * Write a value to the sstatus register. * (Supervisor Status Register) */ static inline void w_sstatus(u64 x) { asm volatile("csrw sstatus, %0" : : "r"(x)); } /** Read Suporvisor Interrupt Pending */ static inline u64 r_sip() { u64 x; asm volatile("csrr %0, sip" : "=r"(x)); return x; } /** Write Suporvisor Interrupt Pending */ static inline void w_sip(u64 x) { asm volatile("csrw sip, %0" : : "r"(x)); } /** Supervisor External Interrup Enable */ #define SIE_SEIE (1L << 9) /** Supervisor Timer Interrupt Enable */ #define SIE_STIE (1L << 5) /** Supervisor Software Interrupt Enable */ #define SIE_SSIE (1L << 1) /** * Read the value of the sie register. * (Supervisor Interrupt Enable) */ static inline u64 r_sie() { u64 x; asm volatile("csrr %0, sie" : "=r"(x)); return x; } /** * Write the valie to the sie rgister * (Supervisor Interrupt Enable) */ static inline void w_sie(u64 x) { asm volatile("csrw sie, %0" : : "r"(x)); } /** Machine External Interrupt Enable */ #define MIE_MEIE (1L << 11) /** Machine Timer Interrupt Enable */ #define MIE_MTIE (1L << 7) /** Machine Software Interrupt Enable */ #define MIE_MSIE (1L << 3) /** * Read the value of the mie register. * (Machine Interrupt Enable) */ static inline u64 r_mie() { u64 x; asm volatile("csrr %0, mie" : "=r"(x)); return x; } /** * Write the value to the mie register. * (Machine Interrupt Enable) */ static inline void w_mie(u64 x) { asm volatile("csrw mie, %0" : : "r"(x)); } // The supervisor exception program counter holds the // instruction address to which a return from // exception will go. // // It is automatically set when an exception occurs. // It can also be set with the w_sepc() function. // (A wrapper for csrw sepc, x) // // Information related to the cause of the exception // will be in the scause register. Readable with the // r_scause() defined below. /** Write Supervisor Exception Program Counter */ static inline void w_sepc(u64 x) { asm volatile("csrw sepc, %0" : : "r"(x)); } /** Read Supervisor Exception Program Counter */ static inline u64 r_sepc() { u64 x; asm volatile("csrr %0, sepc" : "=r"(x)); return x; } /** Read Machine Exception Delegation */ static inline u64 r_medeleg() { u64 x; asm volatile("csrr %0, medeleg" : "=r"(x)); return x; } /** Write Machine Exception Delegation */ static inline void w_medeleg(u64 x) { asm volatile("csrw medeleg, %0" : : "r"(x)); } /** Read Machine Interrupt Delegation */ static inline u64 r_mideleg() { u64 x; asm volatile("csrr %0, mideleg" : "=r"(x)); return x; } /** Write Machine Interrupt Delegation */ static inline void w_mideleg(u64 x) { asm volatile("csrw mideleg, %0" : : "r"(x)); } /** Write Supervisor Trap-Vector Base Address */ static inline void w_stvec(u64 x) { asm volatile("csrw stvec, %0" : : "r"(x)); } /** Read Supervisor Trap-Vector Base Address */ static inline u64 r_stvec() { u64 x; asm volatile("csrr %0, stvec" : "=r"(x)); return x; } /** Write Machine Trap-Vector Base Address */ static inline void w_mtvec(u64 x) { asm volatile("csrw mtvec, %0" : : "r"(x)); } /** Read Physical Memory Protection Configuration */ static inline void w_pmpcfg0(u64 x) { asm volatile("csrw pmpcfg0, %0" : : "r"(x)); } /** Write Physical Memory Protection Configuration */ static inline void w_pmpaddr0(u64 x) { asm volatile("csrw pmpaddr0, %0" : : "r"(x)); } /** Risc-v's sv39 page table scheme. */ #define SATP_SV39 (8L << 60) /** Make Supervisor Address Translation and Protection */ #define MAKE_SATP(pagetable) (SATP_SV39 | (((u64)pagetable) >> 12)) /** * Write the value to the satp register. * (Supervisor Address Translation and Protection) * * This register holds the address of the page table. */ static inline void w_satp(u64 x) { asm volatile("csrw satp, %0" : : "r"(x)); } /** * Read the value of the satp register. * (Supervisor Address Translation and Protection) * Returns the address of the page table. */ static inline u64 r_satp() { u64 x; asm volatile("csrr %0, satp" : "=r"(x)); return x; } /** Read Supervisor Scratch Register */ static inline void w_mscratch(u64 x) { asm volatile("csrw mscratch, %0" : : "r"(x)); } /** Supervisor Trap Cause */ static inline u64 r_scause() { u64 x; asm volatile("csrr %0, scause" : "=r"(x)); return x; } /** Supervisor Trap Value */ static inline u64 r_stval() { u64 x; asm volatile("csrr %0, stval" : "=r"(x)); return x; } /** Write Machine-mode Counter-Enable Register */ static inline void w_mcounteren(u64 x) { asm volatile("csrw mcounteren, %0" : : "r"(x)); } /** Read Machine-mode Counter-Enable Register */ static inline u64 r_mcounteren() { u64 x; asm volatile("csrr %0, mcounteren" : "=r"(x)); return x; } /** * Machine-mode cycle counter * Reports the current wall-clock time from the timer device. */ static inline u64 r_time() { u64 x; asm volatile("csrr %0, time" : "=r"(x)); return x; } /** Enable device interrupts */ static inline void intr_on() { w_sstatus(r_sstatus() | SSTATUS_SIE); } /** Disable device interrupts */ static inline void intr_off() { w_sstatus(r_sstatus() & ~SSTATUS_SIE); } /** Are device interrupts enabled? */ static inline int intr_get() { u64 x = r_sstatus(); return (x & SSTATUS_SIE) != 0; } /** Read stack pointer */ static inline u64 r_sp() { u64 x; asm volatile("mv %0, sp" : "=r"(x)); return x; } // read and write tp, the thread pointer, which xv6 uses to hold // this core's hartid (core number), the index into cpus[]. /** Read thread pointer */ static inline u64 r_tp() { u64 x; asm volatile("mv %0, tp" : "=r"(x)); return x; } /** Write thread pointer */ static inline void w_tp(u64 x) { asm volatile("mv tp, %0" : : "r"(x)); } /** Read the return address */ static inline u64 r_ra() { u64 x; asm volatile("mv %0, ra" : "=r"(x)); return x; } /** Flush the TLB (Translation Lookaside Buffer) */ static inline void sfence_vma() { // the zero, zero means flush all TLB entries. asm volatile("sfence.vma zero, zero"); } /** Page Table Entry Type */ typedef u64 pte_t; /** Page Table Type */ typedef u64 *pagetable_t; // 512 PTEs #endif // __ASSEMBLER__ /** Page Size */ #define PGSIZE 4096 // bytes per page /** Page Shift, bits of offset within a page */ #define PGSHIFT 12 #define PGROUNDUP(sz) (((sz) + PGSIZE - 1) & ~(PGSIZE - 1)) #define PGROUNDDOWN(a) (((a)) & ~(PGSIZE - 1)) /** * Page Table Entry Flags */ /** Valid */ #define PTE_V (1L << 0) /** Readable */ #define PTE_R (1L << 1) /** Writable */ #define PTE_W (1L << 2) /** Executable */ #define PTE_X (1L << 3) /** User-accessible */ #define PTE_U (1L << 4) #define PTE_V (1L << 0) /** PTE Valid */ #define PTE_R (1L << 1) /** PTE Readable */ #define PTE_W (1L << 2) /** PTE Writeable */ #define PTE_X (1L << 3) /** PTE Executable */ #define PTE_U (1L << 4) /** PTE User Accessible */ /** * Helper macros to shift a physical address * to the right place for a PTE. */ /** Physical Address to Page Table Entry */ #define PA2PTE(pa) ((((u64)pa) >> 12) << 10) /** Page Table Entry to Physical Address */ #define PTE2PA(pte) (((pte) >> 10) << 12) /** Page Table Entry Flags */ #define PTE_FLAGS(pte) ((pte) & 0x3FF) /** * Helper macros to extract the three 9-bit * page table indices from a virtual address. */ /** Page Extract Mask */ #define PXMASK 0x1FF // 9 bits, 0b111111111 /** Page Extract Shift */ #define PXSHIFT(level) (PGSHIFT + (9 * (level))) /** Page Extract */ #define PX(level, va) ((((u64)(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))