timer interrupts -> supervisor software interrupt

This commit is contained in:
Robert Morris 2019-06-04 14:20:37 -04:00
parent cff3ce6e04
commit a82772594e
6 changed files with 151 additions and 21 deletions

4
fs.c
View file

@ -182,10 +182,6 @@ iinit(int dev)
readsb(dev, &sb);
if(sb.magic != FSMAGIC)
panic("invalid file system");
printf("sb: size %d nblocks %d ninodes %d nlog %d logstart %d\
inodestart %d bmap start %d\n", sb.size, sb.nblocks,
sb.ninodes, sb.nlog, sb.logstart, sb.inodestart,
sb.bmapstart);
}
static struct inode* iget(uint dev, uint inum);

View file

@ -1,7 +1,10 @@
// Physical memory layout
// qemu -machine virt is set up like this:
// qemu -machine virt is set up like this,
// based on qemu's hw/riscv/virt.c:
//
// 00001000 -- boot ROM, provided by qemu
// 02000000 -- CLINT
// 0C000000 -- PLIC
// 10000000 -- uart0 registers
// 80000000 -- boot ROM jumps here in machine mode
@ -18,10 +21,16 @@
#define UART0 0x10000000L
#define UART0_IRQ 10
// local interrupt controller, which contains the timer.
#define CLINT 0x2000000L
#define CLINT_MSIP0 (CLINT + 0x0)
#define CLINT_MTIMECMP0 (CLINT + 0x4000)
#define CLINT_MTIME (CLINT + 0xBFF8)
// qemu puts programmable interrupt controller here.
#define PLIC 0x0c000000L
#define RAMDISK 0x88000000
#define RAMDISK 0x88000000L
// the kernel expects there to be RAM
// for use by the kernel and user pages

62
riscv.h
View file

@ -4,6 +4,7 @@
#define MSTATUS_MPP_M (3L << 11)
#define MSTATUS_MPP_S (1L << 11)
#define MSTATUS_MPP_U (0L << 11)
#define MSTATUS_MIE (1L << 3)
static inline uint64
r_mstatus()
@ -59,6 +60,12 @@ r_sip()
return x;
}
static inline void
w_sip(uint64 x)
{
asm("csrw sip, %0" : : "r" (x));
}
// Supervisor Interrupt Enable
#define SIE_SEIE (1L << 9) // external
#define SIE_STIE (1L << 5) // timer
@ -77,6 +84,24 @@ w_sie(uint64 x)
asm("csrw sie, %0" : : "r" (x));
}
// Machine-mode Interrupt Enable
#define MIE_MEIE (1L << 11) // external
#define MIE_MTIE (1L << 7) // timer
#define MIE_MSIE (1L << 3) // software
static inline uint64
r_mie()
{
uint64 x;
asm("csrr %0, mie" : "=r" (x) );
return x;
}
static inline void
w_mie(uint64 x)
{
asm("csrw mie, %0" : : "r" (x));
}
// machine exception program counter, holds the
// instruction address to which a return from
// exception will go.
@ -140,6 +165,13 @@ r_stvec()
return x;
}
// Machine-mode interrupt vector
static inline void
w_mtvec(uint64 x)
{
asm("csrw mtvec, %0" : : "r" (x));
}
// use riscv's sv39 page table scheme.
#define SATP_SV39 (8L << 60)
@ -168,6 +200,12 @@ w_sscratch(uint64 x)
asm("csrw sscratch, %0" : : "r" (x));
}
static inline void
w_mscratch(uint64 x)
{
asm("csrw mscratch, %0" : : "r" (x));
}
// Supervisor Trap Cause
static inline uint64
r_scause()
@ -186,6 +224,30 @@ r_stval()
return x;
}
// Machine-mode Counter-Enable
static inline void
w_mcounteren(uint64 x)
{
asm("csrw mcounteren, %0" : : "r" (x));
}
static inline uint64
r_mcounteren()
{
uint64 x;
asm("csrr %0, mcounteren" : "=r" (x) );
return x;
}
// machine-mode cycle counter
static inline uint64
r_time()
{
uint64 x;
asm("csrr %0, time" : "=r" (x) );
return x;
}
// enable interrupts
static inline void
intr_on()

22
start.c
View file

@ -8,6 +8,19 @@ void main();
// entry.S uses this as the initial stack.
__attribute__ ((aligned (16))) char stack0[4096];
// assembly code in kernelvec for machine-mode timer interrupt.
extern void machinevec();
// scratch area for timer interrupt.
uint64 mscratch0[8];
__attribute__ ((aligned (16)))
void
xyzzy()
{
uartputc('I');
}
// entry.S jumps here in machine mode on stack0.
void
mstart()
@ -29,6 +42,15 @@ mstart()
w_medeleg(0xffff);
w_mideleg(0xffff);
// set up to receive timer interrupts in machine mode.
*(uint64*)CLINT_MTIMECMP0 = *(uint64*)CLINT_MTIME + 10000;
mscratch0[4] = CLINT_MTIMECMP0;
mscratch0[5] = 10000000;
w_mscratch((uint64)mscratch0);
w_mtvec((uint64)machinevec);
w_mstatus(r_mstatus() | MSTATUS_MIE);
w_mie(r_mie() | MIE_MTIE);
// jump to main in supervisor mode.
asm("mret");
}

65
trap.c
View file

@ -14,6 +14,8 @@ extern char trampout[], trampin[];
// in kernelvec.S, calls kerneltrap().
void kernelvec();
extern int devintr();
void
trapinit(void)
{
@ -22,6 +24,8 @@ trapinit(void)
// set up to take exceptions and traps while in the kernel.
w_stvec((uint64)kernelvec);
// time, cycle, instret CSRs
initlock(&tickslock, "time");
}
@ -39,6 +43,10 @@ usertrap(void)
// since we're now in the kernel.
w_stvec((uint64)kernelvec);
//printf("mtimecmp %x mtime %x\n", *(uint64*)CLINT_MTIMECMP0, *(uint64*)CLINT_MTIME);
*(uint64*)CLINT_MTIMECMP0 = *(uint64*)CLINT_MTIME + 10000;
struct proc *p = myproc();
// save user program counter.
@ -54,8 +62,10 @@ usertrap(void)
p->tf->epc += 4;
syscall();
} else if(devintr()){
// ok
} else {
printf("usertrap(): unexpected scause 0x%x pid=%d\n", r_scause(), p->pid);
printf("usertrap(): unexpected scause 0x%p pid=%d\n", r_scause(), p->pid);
printf(" sepc=%p stval=%p\n", r_sepc(), r_stval());
p->killed = 1;
}
@ -120,19 +130,7 @@ kerneltrap()
if((sstatus & SSTATUS_SPP) == 0)
panic("kerneltrap: not from supervisor mode");
if((scause & 0x8000000000000000L) &&
(scause & 0xff) == 9){
// supervisor external interrupt, via PLIC.
int irq = plic_claim();
if(irq == UART0_IRQ){
uartintr();
} else {
printf("stray interrupt irq=%d\n", irq);
}
plic_complete(irq);
} else {
if(devintr() == 0){
printf("scause 0x%p\n", scause);
printf("sepc=%p stval=%p\n", r_sepc(), r_stval());
panic("kerneltrap");
@ -145,3 +143,42 @@ kerneltrap()
// restore previous interrupt status.
w_sstatus(sstatus);
}
// check if it's an external interrupt or software interrupt,
// and handle it.
// returns 1 if handled, 0 if not recognized.
int
devintr()
{
uint64 scause = r_scause();
if((scause & 0x8000000000000000L) &&
(scause & 0xff) == 9){
// supervisor external interrupt, via PLIC.
int irq = plic_claim();
if(irq == UART0_IRQ){
uartintr();
} else {
printf("stray interrupt irq=%d\n", irq);
}
plic_complete(irq);
return 1;
} else if(scause == 0x8000000000000001){
// software interrupt from a machine-mode timer interrupt.
acquire(&tickslock);
ticks++;
wakeup(&ticks);
release(&tickslock);
// acknowledge.
w_sip(r_sip() & ~2);
return 1;
} else {
return 0;
}
}

4
vm.c
View file

@ -30,6 +30,10 @@ kvminit()
mappages(kernel_pagetable, UART0, PGSIZE,
UART0, PTE_R | PTE_W);
// CLINT
mappages(kernel_pagetable, CLINT, 0x10000,
CLINT, PTE_R | PTE_W);
// PLIC
mappages(kernel_pagetable, PLIC, 0x4000000,
PLIC, PTE_R | PTE_W);