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 \
 | 
			
		||||
  ramdisk.o \
 | 
			
		||||
  exec.o \
 | 
			
		||||
  sysfile.o
 | 
			
		||||
  sysfile.o \
 | 
			
		||||
  kernelvec.o \
 | 
			
		||||
  plic.o
 | 
			
		||||
 | 
			
		||||
XXXOBJS = \
 | 
			
		||||
	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             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]))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										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
 | 
			
		||||
  procinit();      // process table
 | 
			
		||||
  trapinit();      // trap vectors
 | 
			
		||||
  plicinit();      // set up interrupt controller
 | 
			
		||||
  binit();         // buffer cache
 | 
			
		||||
  fileinit();      // file table
 | 
			
		||||
  ramdiskinit();   // disk
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										55
									
								
								trap.c
									
										
									
									
									
								
							
							
						
						
									
										55
									
								
								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();
 | 
			
		||||
 | 
			
		||||
  // restore previous interrupt status.
 | 
			
		||||
  w_sstatus(sstatus);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										2
									
								
								uart.c
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								uart.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -59,4 +59,6 @@ uartgetc(void)
 | 
			
		|||
void
 | 
			
		||||
uartintr(void)
 | 
			
		||||
{
 | 
			
		||||
  int c = uartgetc();
 | 
			
		||||
  printf("%x ", c & 0xff);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue