timer interrupts -> supervisor software interrupt
This commit is contained in:
		
							parent
							
								
									cff3ce6e04
								
							
						
					
					
						commit
						a82772594e
					
				
					 6 changed files with 151 additions and 21 deletions
				
			
		
							
								
								
									
										4
									
								
								fs.c
									
										
									
									
									
								
							
							
						
						
									
										4
									
								
								fs.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										13
									
								
								memlayout.h
									
										
									
									
									
								
							
							
						
						
									
										13
									
								
								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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										62
									
								
								riscv.h
									
										
									
									
									
								
							
							
						
						
									
										62
									
								
								riscv.h
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -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()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										24
									
								
								start.c
									
										
									
									
									
								
							
							
						
						
									
										24
									
								
								start.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -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");
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										65
									
								
								trap.c
									
										
									
									
									
								
							
							
						
						
									
										65
									
								
								trap.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -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
									
										
									
									
									
								
							
							
						
						
									
										4
									
								
								vm.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue