push/pop all registers when handling interrupt from kernel

This commit is contained in:
Robert Morris 2019-06-03 15:23:12 -04:00
parent e630e0743b
commit 6eae1be755
7 changed files with 48 additions and 83 deletions

View file

@ -21,7 +21,9 @@ OBJS = \
pipe.o \
ramdisk.o \
exec.o \
sysfile.o
sysfile.o \
kernelvec.o \
plic.o
XXXOBJS = \
bio.o\

6
defs.h
View file

@ -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]))

View file

@ -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

1
main.c
View file

@ -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

View file

@ -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

57
trap.c
View file

@ -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);
}

2
uart.c
View file

@ -59,4 +59,6 @@ uartgetc(void)
void
uartintr(void)
{
int c = uartgetc();
printf("%x ", c & 0xff);
}