Browse Source

New supervisor mode

confprec
Andrew Waterman 13 years ago
parent
commit
7a16302b4d
  1. 6
      riscv/insns/eret.h
  2. 26
      riscv/mmu.cc
  3. 20
      riscv/mmu.h
  4. 10
      riscv/opcodes.h
  5. 68
      riscv/pcr.h
  6. 15
      riscv/processor.cc

6
riscv/insns/eret.h

@ -1,5 +1,5 @@
require_supervisor;
if(sr & SR_ET)
throw trap_illegal_instruction;
set_pcr(PCR_SR, ((sr & SR_PS) ? sr : (sr & ~SR_S)) | SR_ET);
set_pcr(PCR_SR, ((sr & ~(SR_PS | SR_EI)) |
((sr & SR_PS) ? 0 : SR_S)) |
((sr & SR_PEI) ? SR_EI : 0));
set_pc(epc);

26
riscv/mmu.cc

@ -40,9 +40,9 @@ reg_t mmu_t::refill_tlb(reg_t addr, reg_t bytes, bool store, bool fetch)
reg_t pte_perm = pte & PTE_PERM;
if (proc == NULL || (proc->sr & SR_S))
pte_perm = (pte_perm/(PTE_SX/PTE_UX)) & PTE_PERM;
pte_perm |= pte & PTE_E;
pte_perm |= pte & PTE_V;
reg_t perm = (fetch ? PTE_UX : store ? PTE_UW : PTE_UR) | PTE_E;
reg_t perm = (fetch ? PTE_UX : store ? PTE_UW : PTE_UR) | PTE_V;
if(unlikely((pte_perm & perm) != perm))
{
if (fetch)
@ -53,7 +53,7 @@ reg_t mmu_t::refill_tlb(reg_t addr, reg_t bytes, bool store, bool fetch)
}
reg_t pgoff = addr & (PGSIZE-1);
reg_t pgbase = pte >> PTE_PPN_SHIFT << PGSHIFT;
reg_t pgbase = pte >> PGSHIFT << PGSHIFT;
reg_t paddr = pgbase + pgoff;
if (unlikely(tracer.interested_in_range(pgbase, pgbase + PGSIZE, store, fetch)))
@ -80,7 +80,7 @@ pte_t mmu_t::walk(reg_t addr)
else if (proc == NULL || !(proc->sr & SR_VM))
{
if(addr < memsz)
pte = PTE_E | PTE_PERM | ((addr >> PGSHIFT) << PTE_PPN_SHIFT);
pte = PTE_V | PTE_PERM | ((addr >> PGSHIFT) << PGSHIFT);
}
else
{
@ -97,23 +97,23 @@ pte_t mmu_t::walk(reg_t addr)
break;
ptd = *(pte_t*)(mem+pte_addr);
if(ptd & PTE_E)
if (!(ptd & PTE_V)) // invalid mapping
break;
else if (ptd & PTE_T) // next level of page table
base = (ptd >> PGSHIFT) << PGSHIFT;
else // the actual PTE
{
// if this PTE is from a larger PT, fake a leaf
// PTE so the TLB will work right
reg_t vpn = addr >> PGSHIFT;
ptd |= (vpn & ((1<<(ptshift))-1)) << PTE_PPN_SHIFT;
ptd |= (vpn & ((1<<(ptshift))-1)) << PGSHIFT;
// fault if physical addr is invalid
reg_t ppn = ptd >> PTE_PPN_SHIFT;
if((ppn << PGSHIFT) + (addr & (PGSIZE-1)) < memsz)
// fault if physical addr is out of range
if (((ptd >> PGSHIFT) << PGSHIFT) < memsz)
pte = ptd;
break;
}
else if(!(ptd & PTE_T))
break;
base = (ptd >> PTE_PPN_SHIFT) << PGSHIFT;
}
}

20
riscv/mmu.h

@ -13,28 +13,14 @@
// virtual memory configuration
typedef reg_t pte_t;
const reg_t LEVELS = sizeof(pte_t) == sizeof(uint64_t) ? 3 : 2;
const reg_t PGSHIFT = 13;
const reg_t LEVELS = sizeof(pte_t) == 8 ? 3 : 2;
const reg_t PTIDXBITS = 10;
const reg_t PGSHIFT = PTIDXBITS + (sizeof(pte_t) == 8 ? 3 : 2);
const reg_t PGSIZE = 1 << PGSHIFT;
const reg_t PTIDXBITS = PGSHIFT - (sizeof(pte_t) == 8 ? 3 : 2);
const reg_t VPN_BITS = PTIDXBITS * LEVELS;
const reg_t PPN_BITS = 8*sizeof(reg_t) - PGSHIFT;
const reg_t VA_BITS = VPN_BITS + PGSHIFT;
// page table entry (PTE) fields
#define PTE_T 0x001 // Entry is a page Table descriptor
#define PTE_E 0x002 // Entry is a page table Entry
#define PTE_R 0x004 // Referenced
#define PTE_D 0x008 // Dirty
#define PTE_UX 0x010 // User eXecute permission
#define PTE_UW 0x020 // User Read permission
#define PTE_UR 0x040 // User Write permission
#define PTE_SX 0x080 // Supervisor eXecute permission
#define PTE_SW 0x100 // Supervisor Read permission
#define PTE_SR 0x200 // Supervisor Write permission
#define PTE_PERM (PTE_SR | PTE_SW | PTE_SX | PTE_UR | PTE_UW | PTE_UX)
#define PTE_PPN_SHIFT 13 // LSB of physical page number in the PTE
// this class implements a processor's port into the virtual memory system.
// an MMU and instruction cache are maintained for simulator performance.
class mmu_t

10
riscv/opcodes.h

@ -13,7 +13,7 @@ DECLARE_INSN(fcvt_d_w, 0xe0d3, 0x3ff1ff)
DECLARE_INSN(lw, 0x103, 0x3ff)
DECLARE_INSN(add, 0x33, 0x1ffff)
DECLARE_INSN(fcvt_d_s, 0x100d3, 0x3ff1ff)
DECLARE_INSN(mfpcr, 0x17b, 0x3fffff)
DECLARE_INSN(mfpcr, 0xf3, 0x3fffff)
DECLARE_INSN(fmax_d, 0x190d3, 0x1ffff)
DECLARE_INSN(bne, 0xe3, 0x3ff)
DECLARE_INSN(rdcycle, 0x277, 0x7ffffff)
@ -21,7 +21,7 @@ DECLARE_INSN(fcvt_s_d, 0x11053, 0x3ff1ff)
DECLARE_INSN(bgeu, 0x3e3, 0x3ff)
DECLARE_INSN(fadd_d, 0xd3, 0x1f1ff)
DECLARE_INSN(sltiu, 0x193, 0x3ff)
DECLARE_INSN(mtpcr, 0x1fb, 0x1ffff)
DECLARE_INSN(mtpcr, 0x73, 0x1ffff)
DECLARE_INSN(break, 0xf7, 0xffffffff)
DECLARE_INSN(fcvt_s_w, 0xe053, 0x3ff1ff)
DECLARE_INSN(mul, 0x433, 0x1ffff)
@ -47,7 +47,7 @@ DECLARE_INSN(addw, 0x3b, 0x1ffff)
DECLARE_INSN(sll, 0xb3, 0x1ffff)
DECLARE_INSN(xor, 0x233, 0x1ffff)
DECLARE_INSN(sub, 0x10033, 0x1ffff)
DECLARE_INSN(eret, 0x27b, 0xffffffff)
DECLARE_INSN(eret, 0x273, 0xffffffff)
DECLARE_INSN(blt, 0x263, 0x3ff)
DECLARE_INSN(mtfsr, 0x1f053, 0x3fffff)
DECLARE_INSN(sc_w, 0x1052b, 0x1ffff)
@ -90,7 +90,7 @@ DECLARE_INSN(amomaxu_w, 0x1d2b, 0x1ffff)
DECLARE_INSN(fcvt_wu_s, 0xb053, 0x3ff1ff)
DECLARE_INSN(rdtime, 0x677, 0x7ffffff)
DECLARE_INSN(andi, 0x393, 0x3ff)
DECLARE_INSN(clearpcr, 0x7b, 0x3ff)
DECLARE_INSN(clearpcr, 0x1f3, 0x3ff)
DECLARE_INSN(fmv_x_s, 0x1c053, 0x3fffff)
DECLARE_INSN(fsgnjn_d, 0x60d3, 0x1ffff)
DECLARE_INSN(fnmadd_s, 0x4f, 0x1ff)
@ -129,7 +129,7 @@ DECLARE_INSN(amomax_w, 0x152b, 0x1ffff)
DECLARE_INSN(fsgnj_d, 0x50d3, 0x1ffff)
DECLARE_INSN(mulhu, 0x5b3, 0x1ffff)
DECLARE_INSN(fence_v_g, 0x2af, 0x3ff)
DECLARE_INSN(setpcr, 0xfb, 0x3ff)
DECLARE_INSN(setpcr, 0x173, 0x3ff)
DECLARE_INSN(fcvt_lu_s, 0x9053, 0x3ff1ff)
DECLARE_INSN(fcvt_s_l, 0xc053, 0x3ff1ff)
DECLARE_INSN(auipc, 0x17, 0x7f)

68
riscv/pcr.h

@ -3,18 +3,18 @@
#ifndef _RISCV_PCR_H
#define _RISCV_PCR_H
#define SR_ET 0x00000001
#define SR_EF 0x00000002
#define SR_EV 0x00000004
#define SR_EC 0x00000008
#define SR_PS 0x00000010
#define SR_S 0x00000020
#define SR_U64 0x00000040
#define SR_S64 0x00000080
#define SR_VM 0x00000100
#define SR_S 0x00000001
#define SR_PS 0x00000002
#define SR_EI 0x00000004
#define SR_PEI 0x00000008
#define SR_EF 0x00000010
#define SR_U64 0x00000020
#define SR_S64 0x00000040
#define SR_VM 0x00000080
#define SR_EV 0x00000100
#define SR_IM 0x00FF0000
#define SR_IP 0xFF000000
#define SR_ZERO ~(SR_ET|SR_EF|SR_EV|SR_EC|SR_PS|SR_S|SR_U64|SR_S64|SR_VM|SR_IM|SR_IP)
#define SR_ZERO ~(SR_S|SR_PS|SR_EI|SR_PEI|SR_EF|SR_U64|SR_S64|SR_VM|SR_EV|SR_IM|SR_IP)
#define SR_IM_SHIFT 16
#define SR_IP_SHIFT 24
@ -22,16 +22,18 @@
#define PCR_EPC 1
#define PCR_BADVADDR 2
#define PCR_EVEC 3
#define PCR_COUNT 4
#define PCR_COMPARE 5
#define PCR_CAUSE 6
#define PCR_PTBR 7
#define PCR_SEND_IPI 8
#define PCR_CLR_IPI 9
#define PCR_COREID 10
#define PCR_IMPL 11
#define PCR_K0 12
#define PCR_K1 13
#define PCR_CAUSE 4
#define PCR_PTBR 5
#define PCR_ASID 6
#define PCR_FATC 7
#define PCR_COUNT 8
#define PCR_COMPARE 9
#define PCR_SEND_IPI 10
#define PCR_CLR_IPI 11
#define PCR_HARTID 12
#define PCR_IMPL 13
#define PCR_K0 14
#define PCR_K1 15
#define PCR_VECBANK 18
#define PCR_VECCFG 19
#define PCR_RESET 29
@ -65,8 +67,30 @@
#define CAUSE_VECTOR_FAULT_LOAD 30
#define CAUSE_VECTOR_FAULT_STORE 31
// page table entry (PTE) fields
#define PTE_V 0x001 // Entry is a page Table descriptor
#define PTE_T 0x002 // Entry is a page Table, not a terminal node
#define PTE_G 0x004 // Global
#define PTE_UR 0x008 // User Write permission
#define PTE_UW 0x010 // User Read permission
#define PTE_UX 0x020 // User eXecute permission
#define PTE_SR 0x040 // Supervisor Read permission
#define PTE_SW 0x080 // Supervisor Write permission
#define PTE_SX 0x100 // Supervisor eXecute permission
#define PTE_PERM (PTE_SR | PTE_SW | PTE_SX | PTE_UR | PTE_UW | PTE_UX)
#ifdef __riscv
#ifdef __riscv64
# define RISCV_PGLEVELS 3
# define RISCV_PGSHIFT 13
#else
# define RISCV_PGLEVELS 2
# define RISCV_PGSHIFT 12
#endif
#define RISCV_PGLEVEL_BITS 10
#define RISCV_PGSIZE (1 << RISCV_PGSHIFT)
#define ASM_CR(r) _ASM_CR(r)
#define _ASM_CR(r) cr##r
@ -88,6 +112,10 @@
asm volatile ("clearpcr %0,cr%2,%1" : "=r"(__tmp) : "i"(val), "i"(reg)); \
__tmp; })
#define rdcycle() ({ unsigned long __tmp; \
asm volatile ("rdcycle %0" : "=r"(__tmp)); \
__tmp; })
#endif
#endif

15
riscv/processor.cc

@ -68,7 +68,7 @@ void processor_t::take_interrupt()
uint32_t interrupts = (sr & SR_IP) >> SR_IP_SHIFT;
interrupts &= (sr & SR_IM) >> SR_IM_SHIFT;
if(interrupts && (sr & SR_ET))
if(interrupts && (sr & SR_EI))
for(int i = 0; ; i++, interrupts >>= 1)
if(interrupts & 1)
throw interrupt_t(i);
@ -144,7 +144,9 @@ void processor_t::take_trap(reg_t t, bool noisy)
}
// switch to supervisor, set previous supervisor bit, disable traps
set_pcr(PCR_SR, (((sr & ~SR_ET) | SR_S) & ~SR_PS) | ((sr & SR_S) ? SR_PS : 0));
set_pcr(PCR_SR, (((sr & ~SR_EI) | SR_S) & ~SR_PS & ~SR_PEI) |
((sr & SR_S) ? SR_PS : 0) |
((sr & SR_EI) ? SR_PEI : 0));
cause = t;
epc = pc;
pc = evec;
@ -177,9 +179,6 @@ void processor_t::set_pcr(int which, reg_t val)
#ifndef RISCV_ENABLE_FPU
sr &= ~SR_EF;
#endif
#ifndef RISCV_ENABLE_RVC
sr &= ~SR_EC;
#endif
#ifndef RISCV_ENABLE_VEC
sr &= ~SR_EV;
#endif
@ -245,7 +244,11 @@ reg_t processor_t::get_pcr(int which)
return cause;
case PCR_PTBR:
return mmu.get_ptbr();
case PCR_COREID:
case PCR_ASID:
return 0;
case PCR_FATC:
mmu.flush_tlb();
case PCR_HARTID:
return id;
case PCR_IMPL:
return 1;

Loading…
Cancel
Save