summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Morris <[email protected]>2019-06-03 15:23:12 -0400
committerRobert Morris <[email protected]>2019-06-03 15:23:12 -0400
commit6eae1be7550ecdc85269ce57c4a2f2dd0e9297b9 (patch)
tree9a168c1fed57523f1683799ce5fb555629a29942
parente630e0743b8c1a0f9ebca702811bd59065c9f457 (diff)
downloadxv6-labs-6eae1be7550ecdc85269ce57c4a2f2dd0e9297b9.tar.gz
xv6-labs-6eae1be7550ecdc85269ce57c4a2f2dd0e9297b9.tar.bz2
xv6-labs-6eae1be7550ecdc85269ce57c4a2f2dd0e9297b9.zip
push/pop all registers when handling interrupt from kernel
-rw-r--r--Makefile4
-rw-r--r--defs.h6
-rw-r--r--entryother.S60
-rw-r--r--main.c1
-rw-r--r--memlayout.h1
-rw-r--r--trap.c57
-rw-r--r--uart.c2
7 files changed, 48 insertions, 83 deletions
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();
+
+ 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();
- panic("kerneltrap");
+ // 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);
}