diff options
author | Robert Morris <[email protected]> | 2019-06-04 14:20:37 -0400 |
---|---|---|
committer | Robert Morris <[email protected]> | 2019-06-04 14:20:37 -0400 |
commit | a82772594e1807632b3650bff111108f250de3b7 (patch) | |
tree | 98581a6fa9bfd5ecbabe8052b112c4166c7f9e9e | |
parent | cff3ce6e04ce4a353324630df788df21566807a6 (diff) | |
download | xv6-labs-a82772594e1807632b3650bff111108f250de3b7.tar.gz xv6-labs-a82772594e1807632b3650bff111108f250de3b7.tar.bz2 xv6-labs-a82772594e1807632b3650bff111108f250de3b7.zip |
timer interrupts -> supervisor software interrupt
-rw-r--r-- | fs.c | 4 | ||||
-rw-r--r-- | memlayout.h | 13 | ||||
-rw-r--r-- | riscv.h | 62 | ||||
-rw-r--r-- | start.c | 24 | ||||
-rw-r--r-- | trap.c | 59 | ||||
-rw-r--r-- | vm.c | 4 |
6 files changed, 148 insertions, 18 deletions
@@ -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); diff --git a/memlayout.h b/memlayout.h index db233f7..db7c076 100644 --- a/memlayout.h +++ b/memlayout.h @@ -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 @@ -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() @@ -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() @@ -28,7 +41,16 @@ mstart() // delegate all interrupts and exceptions to supervisor mode. 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"); } @@ -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,6 +130,28 @@ kerneltrap() if((sstatus & SSTATUS_SPP) == 0) panic("kerneltrap: not from supervisor mode"); + if(devintr() == 0){ + printf("scause 0x%p\n", scause); + printf("sepc=%p stval=%p\n", r_sepc(), r_stval()); + panic("kerneltrap"); + } + + // turn off interrupts to ensure we + // return with the correct sstatus. + intr_off(); + + // 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. @@ -132,16 +164,21 @@ kerneltrap() } 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 { - printf("scause 0x%p\n", scause); - printf("sepc=%p stval=%p\n", r_sepc(), r_stval()); - panic("kerneltrap"); + return 0; } - - // turn off interrupts to ensure we - // return with the correct sstatus. - intr_off(); - - // restore previous interrupt status. - w_sstatus(sstatus); } + @@ -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); |