push/pop all registers when handling interrupt from kernel
This commit is contained in:
parent
e630e0743b
commit
6eae1be755
7 changed files with 48 additions and 83 deletions
4
Makefile
4
Makefile
|
@ -21,7 +21,9 @@ OBJS = \
|
||||||
pipe.o \
|
pipe.o \
|
||||||
ramdisk.o \
|
ramdisk.o \
|
||||||
exec.o \
|
exec.o \
|
||||||
sysfile.o
|
sysfile.o \
|
||||||
|
kernelvec.o \
|
||||||
|
plic.o
|
||||||
|
|
||||||
XXXOBJS = \
|
XXXOBJS = \
|
||||||
bio.o\
|
bio.o\
|
||||||
|
|
6
defs.h
6
defs.h
|
@ -191,5 +191,11 @@ int copyout(pagetable_t, uint64, char *, uint64);
|
||||||
int copyin(pagetable_t, char *, uint64, uint64);
|
int copyin(pagetable_t, char *, uint64, uint64);
|
||||||
int copyinstr(pagetable_t pagetable, char *dst, uint64 srcva, uint64 max);
|
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
|
// number of elements in fixed-size array
|
||||||
#define NELEM(x) (sizeof(x)/sizeof((x)[0]))
|
#define NELEM(x) (sizeof(x)/sizeof((x)[0]))
|
||||||
|
|
60
entryother.S
60
entryother.S
|
@ -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
1
main.c
|
@ -17,6 +17,7 @@ main()
|
||||||
kvminit(); // kernel page table
|
kvminit(); // kernel page table
|
||||||
procinit(); // process table
|
procinit(); // process table
|
||||||
trapinit(); // trap vectors
|
trapinit(); // trap vectors
|
||||||
|
plicinit(); // set up interrupt controller
|
||||||
binit(); // buffer cache
|
binit(); // buffer cache
|
||||||
fileinit(); // file table
|
fileinit(); // file table
|
||||||
ramdiskinit(); // disk
|
ramdiskinit(); // disk
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
|
|
||||||
// qemu puts UART registers here in physical memory.
|
// qemu puts UART registers here in physical memory.
|
||||||
#define UART0 0x10000000L
|
#define UART0 0x10000000L
|
||||||
|
#define UART0_IRQ 10
|
||||||
|
|
||||||
// qemu puts programmable interrupt controller here.
|
// qemu puts programmable interrupt controller here.
|
||||||
#define PLIC 0x0c000000L
|
#define PLIC 0x0c000000L
|
||||||
|
|
57
trap.c
57
trap.c
|
@ -11,28 +11,16 @@ uint ticks;
|
||||||
|
|
||||||
extern char trampout[], trampin[];
|
extern char trampout[], trampin[];
|
||||||
|
|
||||||
void kerneltrap();
|
// in kernelvec.S, calls kerneltrap().
|
||||||
|
void kernelvec();
|
||||||
|
|
||||||
void
|
void
|
||||||
trapinit(void)
|
trapinit(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
// send interrupts and exceptions to kerneltrap().
|
// set up to take exceptions and traps while in the kernel.
|
||||||
w_stvec((uint64)kerneltrap);
|
w_stvec((uint64)kernelvec);
|
||||||
|
|
||||||
// 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;
|
|
||||||
|
|
||||||
initlock(&tickslock, "time");
|
initlock(&tickslock, "time");
|
||||||
}
|
}
|
||||||
|
@ -49,7 +37,7 @@ usertrap(void)
|
||||||
|
|
||||||
// send interrupts and exceptions to kerneltrap(),
|
// send interrupts and exceptions to kerneltrap(),
|
||||||
// since we're now in the kernel.
|
// since we're now in the kernel.
|
||||||
w_stvec((uint64)kerneltrap);
|
w_stvec((uint64)kernelvec);
|
||||||
|
|
||||||
struct proc *p = myproc();
|
struct proc *p = myproc();
|
||||||
|
|
||||||
|
@ -83,8 +71,9 @@ usertrapret(void)
|
||||||
{
|
{
|
||||||
struct proc *p = myproc();
|
struct proc *p = myproc();
|
||||||
|
|
||||||
// XXX turn off interrupts, since we're switching
|
// turn off interrupts, since we're switching
|
||||||
// now from kerneltrap() to usertrap().
|
// now from kerneltrap() to usertrap().
|
||||||
|
intr_off();
|
||||||
|
|
||||||
// send interrupts and exceptions to trampoline.S
|
// send interrupts and exceptions to trampoline.S
|
||||||
w_stvec(TRAMPOLINE + (trampin - trampout));
|
w_stvec(TRAMPOLINE + (trampin - trampout));
|
||||||
|
@ -101,6 +90,7 @@ usertrapret(void)
|
||||||
// set S Previous Privilege mode to User.
|
// set S Previous Privilege mode to User.
|
||||||
unsigned long x = r_sstatus();
|
unsigned long x = r_sstatus();
|
||||||
x &= ~SSTATUS_SPP; // clear SPP to 0 for user mode
|
x &= ~SSTATUS_SPP; // clear SPP to 0 for user mode
|
||||||
|
x |= SSTATUS_SPIE; // enable interrupts in user mode
|
||||||
w_sstatus(x);
|
w_sstatus(x);
|
||||||
|
|
||||||
// set S Exception Program Counter to the saved user pc.
|
// set S Exception Program Counter to the saved user pc.
|
||||||
|
@ -121,11 +111,34 @@ usertrapret(void)
|
||||||
void __attribute__ ((aligned (4)))
|
void __attribute__ ((aligned (4)))
|
||||||
kerneltrap()
|
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");
|
panic("kerneltrap: not from supervisor mode");
|
||||||
|
|
||||||
printf("scause 0x%x\n", r_scause());
|
if((scause & 0x8000000000000000L) &&
|
||||||
printf("sepc=%p stval=%p\n", r_sepc(), r_stval());
|
(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
2
uart.c
|
@ -59,4 +59,6 @@ uartgetc(void)
|
||||||
void
|
void
|
||||||
uartintr(void)
|
uartintr(void)
|
||||||
{
|
{
|
||||||
|
int c = uartgetc();
|
||||||
|
printf("%x ", c & 0xff);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue