diff options
| author | Robert Morris <rtm@csail.mit.edu> | 2019-06-04 14:20:37 -0400 | 
|---|---|---|
| committer | Robert Morris <rtm@csail.mit.edu> | 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); | 
