summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Morris <[email protected]>2019-06-04 14:20:37 -0400
committerRobert Morris <[email protected]>2019-06-04 14:20:37 -0400
commita82772594e1807632b3650bff111108f250de3b7 (patch)
tree98581a6fa9bfd5ecbabe8052b112c4166c7f9e9e
parentcff3ce6e04ce4a353324630df788df21566807a6 (diff)
downloadxv6-labs-a82772594e1807632b3650bff111108f250de3b7.tar.gz
xv6-labs-a82772594e1807632b3650bff111108f250de3b7.tar.bz2
xv6-labs-a82772594e1807632b3650bff111108f250de3b7.zip
timer interrupts -> supervisor software interrupt
-rw-r--r--fs.c4
-rw-r--r--memlayout.h13
-rw-r--r--riscv.h62
-rw-r--r--start.c24
-rw-r--r--trap.c59
-rw-r--r--vm.c4
6 files changed, 148 insertions, 18 deletions
diff --git a/fs.c b/fs.c
index 7cb55a9..cc1e60b 100644
--- a/fs.c
+++ b/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);
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
diff --git a/riscv.h b/riscv.h
index d59503c..14c8738 100644
--- a/riscv.h
+++ b/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()
diff --git a/start.c b/start.c
index b7af38a..8743955 100644
--- a/start.c
+++ b/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");
}
diff --git a/trap.c b/trap.c
index 47739ac..e17f8fe 100644
--- a/trap.c
+++ b/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,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);
}
+
diff --git a/vm.c b/vm.c
index 9e24ad0..b24b271 100644
--- a/vm.c
+++ b/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);