diff --git a/Makefile b/Makefile index abd819e..84355e0 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,9 @@ OBJS = \ pipe.o \ ramdisk.o \ exec.o \ - sysfile.o + sysfile.o \ + kernelvec.o \ + plic.o XXXOBJS = \ bio.o\ diff --git a/defs.h b/defs.h index 91a997d..2a6c47a 100644 --- a/defs.h +++ b/defs.h @@ -191,5 +191,11 @@ int copyout(pagetable_t, uint64, char *, uint64); int copyin(pagetable_t, char *, uint64, uint64); int copyinstr(pagetable_t pagetable, char *dst, uint64 srcva, uint64 max); +// plic.c +void plicinit(void); +uint64 plic_pending(void); +int plic_claim(void); +void plic_complete(int); + // number of elements in fixed-size array #define NELEM(x) (sizeof(x)/sizeof((x)[0])) diff --git a/entryother.S b/entryother.S deleted file mode 100644 index dd33680..0000000 --- a/entryother.S +++ /dev/null @@ -1,60 +0,0 @@ -#include "asm.h" -#include "memlayout.h" -#include "mmu.h" - -# Each non-boot CPU ("AP") is started up in response to a STARTUP -# IPI from the boot CPU. Section B.4.2 of the Multi-Processor -# Specification says that the AP will start in real mode with CS:IP -# set to XY00:0000, where XY is an 8-bit value sent with the -# STARTUP. Thus this code must start at a 4096-byte boundary. -# -# Because this code sets DS to zero, it must sit -# at an address in the low 2^16 bytes. -# -# Startothers (in main.c) sends the STARTUPs one at a time. -# It copies this code (start) at 0x7000. It puts the address of -# a newly allocated per-core stack in start-12,the address of the -# place to jump to (apstart32) in start-4, and the physical address -# of entrypgdir in start-12. - -.code16 -.globl start -start: - cli - - # Zero data segment registers DS, ES, and SS. - xorw %ax,%ax - movw %ax,%ds - movw %ax,%es - movw %ax,%ss - - # Switch from real to protected mode. Use a bootstrap GDT that makes - # virtual addresses map directly to physical addresses so that the - # effective memory map doesn't change during the transition. - lgdt gdtdesc - movl %cr0, %eax - orl $CR0_PE, %eax - movl %eax, %cr0 - - # Complete the transition to 32-bit protected mode by using a long jmp - # to reload %cs and %eip. The segment descriptors are set up with no - # translation, so that the mapping is still the identity mapping. - ljmpl $(SEG_KCODE32), $start32 - -.code32 -start32: - movl $start-12, %esp - movl start-4, %ecx - jmp *%ecx - -.align 4 -gdt: - SEG_NULLASM - SEG_ASM(0xa, 0, 0xffffffff) - SEG_ASM(0x2, 0, 0xffffffff) - -.align 16 -gdtdesc: - .word 0x17 # sizeof(gdt)-1 - .long gdt - diff --git a/main.c b/main.c index d4a30f0..db9a6b9 100644 --- a/main.c +++ b/main.c @@ -17,6 +17,7 @@ main() kvminit(); // kernel page table procinit(); // process table trapinit(); // trap vectors + plicinit(); // set up interrupt controller binit(); // buffer cache fileinit(); // file table ramdiskinit(); // disk diff --git a/memlayout.h b/memlayout.h index 9782ff1..1a6b200 100644 --- a/memlayout.h +++ b/memlayout.h @@ -15,6 +15,7 @@ // qemu puts UART registers here in physical memory. #define UART0 0x10000000L +#define UART0_IRQ 10 // qemu puts programmable interrupt controller here. #define PLIC 0x0c000000L diff --git a/trap.c b/trap.c index 9fe3c85..98ab143 100644 --- a/trap.c +++ b/trap.c @@ -11,28 +11,16 @@ uint ticks; extern char trampout[], trampin[]; -void kerneltrap(); +// in kernelvec.S, calls kerneltrap(). +void kernelvec(); void trapinit(void) { int i; - // send interrupts and exceptions to kerneltrap(). - w_stvec((uint64)kerneltrap); - - // set up the riscv Platform Level Interrupt Controller - // to send uart interrupts to hart 0 S-Mode. - - // qemu makes UART0 be interrupt number 10. - int irq = 10; - // set uart's priority to be non-zero (otherwise disabled). - *(uint*)(0x0c000000L + irq*4) = 1; - // set uart's enable bit for hart 0 S-mode. - *(uint*)0x0c002080 = (1 << irq); - - // set hart 0 S-mode priority threshold to 0. - *(uint*)0x0c201000 = 0; + // set up to take exceptions and traps while in the kernel. + w_stvec((uint64)kernelvec); initlock(&tickslock, "time"); } @@ -49,7 +37,7 @@ usertrap(void) // send interrupts and exceptions to kerneltrap(), // since we're now in the kernel. - w_stvec((uint64)kerneltrap); + w_stvec((uint64)kernelvec); struct proc *p = myproc(); @@ -83,8 +71,9 @@ usertrapret(void) { struct proc *p = myproc(); - // XXX turn off interrupts, since we're switching + // turn off interrupts, since we're switching // now from kerneltrap() to usertrap(). + intr_off(); // send interrupts and exceptions to trampoline.S w_stvec(TRAMPOLINE + (trampin - trampout)); @@ -101,6 +90,7 @@ usertrapret(void) // set S Previous Privilege mode to User. unsigned long x = r_sstatus(); x &= ~SSTATUS_SPP; // clear SPP to 0 for user mode + x |= SSTATUS_SPIE; // enable interrupts in user mode w_sstatus(x); // set S Exception Program Counter to the saved user pc. @@ -121,11 +111,34 @@ usertrapret(void) void __attribute__ ((aligned (4))) kerneltrap() { - if((r_sstatus() & SSTATUS_SPP) == 0) + uint64 sstatus = r_sstatus(); + uint64 scause = r_scause(); + + if((sstatus & SSTATUS_SPP) == 0) panic("kerneltrap: not from supervisor mode"); - printf("scause 0x%x\n", r_scause()); - printf("sepc=%p stval=%p\n", r_sepc(), r_stval()); + if((scause & 0x8000000000000000L) && + (scause & 0xff) == 9){ + // supervisor external interrupt, via PLIC. + int irq = plic_claim(); - panic("kerneltrap"); + if(irq == UART0_IRQ){ + uartintr(); + } else { + printf("stray interrupt irq=%d\n", irq); + } + + plic_complete(irq); + } else { + 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); } diff --git a/uart.c b/uart.c index 807c46e..659c574 100644 --- a/uart.c +++ b/uart.c @@ -59,4 +59,6 @@ uartgetc(void) void uartintr(void) { + int c = uartgetc(); + printf("%x ", c & 0xff); }