Module Name:    src
Committed By:   matt
Date:           Tue Mar 31 01:30:50 UTC 2015

Modified Files:
        src/sys/arch/riscv/riscv: locore.S

Log Message:
Since there is only "scratch" system register for use on exception, come
up with a new scheme for its use.  Use PTR_LA, INT_S/INT_L, etc.  Disable
interrupts when returning from exceptions.  Use L_CPU(tp) to get the curcpu
pointer.

When the cpu gets an exception from kernel mode, the sscratch register will be
0 and curlwp will be in the "tp" register.  When the cpu gets an exception from
user mode, the sscratch register will be a pointer to the current lwp.

When an exception happends, the sp is atomically swapped with the sscratch
register.

        If the sp is zero, the exception was a kernel exception and the
        kernel exception path is taken: sp and sscratch are swapped again
        so sscratch is zero again and then a trapframe is allocated from
        the kernel stack.  The t1 register is saved and then the pre-trapframe
        sp is written to the trapframe.

        If sp was non-zero, the exception was from user mode.  The tp register
        is temporarily saved in L_MD_TP(sp) and sp is moved tp.  tp now
        contains a pointer to the current lwp.  A pointer to the user
        trapframe is loaded from L_MD_UTF(tp).  Then t1 is saved in the
        trapframe so it can be used.  The old sp is fetched from sscratch
        while sscratch is zeroed (indicated kernel mode).  The old sp is
        saved in the trapframe.

        Upon exiting the exception, if the exception is returning to user
        mode, the contents of tp is written to sscratch.


To generate a diff of this commit:
cvs rdiff -u -r1.1 -r1.2 src/sys/arch/riscv/riscv/locore.S

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/riscv/riscv/locore.S
diff -u src/sys/arch/riscv/riscv/locore.S:1.1 src/sys/arch/riscv/riscv/locore.S:1.2
--- src/sys/arch/riscv/riscv/locore.S:1.1	Sat Mar 28 16:13:56 2015
+++ src/sys/arch/riscv/riscv/locore.S	Tue Mar 31 01:30:50 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: locore.S,v 1.1 2015/03/28 16:13:56 matt Exp $ */
+/* $NetBSD: locore.S,v 1.2 2015/03/31 01:30:50 matt Exp $ */
 /*-
  * Copyright (c) 2014 The NetBSD Foundation, Inc.
  * All rights reserved.
@@ -78,10 +78,10 @@ ENTRY_NP(start)
 	call	memset			// zero through kernel_end
 
 	// As a temporary hack, word 0 contains the amount of memory in MB
-	lw	a7, (zero)			// load memory size
+	INT_L	a7, (zero)			// load memory size
 	slli	a7, a7, (20-PGSHIFT)		// convert MB to pages
-	auipc	t0, %pcrel_hi(physmem)
-	sw	a7, %pcrel_lo(physmem)(t0)	// store it in physmem
+.L01:	auipc	t0, %pcrel_hi(physmem)
+	INT_S	a7, %pcrel_lo(.L01)(t0)		// store it in physmem
 
 	li	t4, PTE_V | PTE_SX | PTE_SW | PTE_SR | PTE_G
 #ifdef _LP64
@@ -115,11 +115,11 @@ ENTRY_NP(start)
 	//
 	// Fill in the PDEs to direct map memory.
 	//
-1:	REG_S	t4, 0(s3)		// store PDE
+.Lfill:	REG_S	t4, 0(s3)		// store PDE
 	add	t4, t4, t3		// advance PA in PDE to next segment
 	add	s3, s3, SZREG		// advance to next PDE slot
 	addi	a7, a7, -1		// count down segment
-	bgtz	a6, 1b			// loop if more
+	bgtz	a6, .Lfill		// loop if more
 
 	csrw	sptbr, s1		// set the page table base
 	li	t0, SR_VM
@@ -131,8 +131,7 @@ ENTRY_NP(start)
 
 .Lmmu_on:
 	// MMU is on!
-	PTR_LA	a0, _C_LABEL(cpu_info_store)
-	csrw	sscratch, a0		// curcpu() in sscratch
+	csrw	sscratch, zero		// zero in sscratch to mark kernel
 
 	PTR_LA	tp, _C_LABEL(lwp0)	// put curlwp in tp
 
@@ -151,8 +150,8 @@ ENTRY_NP(start)
 	// Now we should ready to start initializing the kernel.
 	PTR_LA	a0, _C_LABEL(start)	// kernel_start
 	add	a1, s5, s11		// kernel_end
-	PTR_LA	ra, _C_LABEL(main)	// return to main
-	tail	_C_LABEL(init_riscv)	// do MD startup
+	call	_C_LABEL(init_riscv)	// do MD startup
+	tail	_C_LABEL(main)		// and transfer to main
 	// not reached
 END(start)
 
@@ -162,7 +161,7 @@ END(start)
 ENTRY_NP(cpu_switchto)
 	addi	sp, sp, -TF_LEN		// allocate trapframe
 
-	beqz	a0, 1f			// can skip saving oldl state?
+	beqz	a0, .Lswitchto_newlwp	// can skip saving oldl state?
 
 	REG_S	ra, TF_RA(sp)		// save return address
 	REG_S	s0, TF_S0(sp)		// save callee saved address
@@ -181,17 +180,17 @@ ENTRY_NP(cpu_switchto)
 	REG_S	t4, TF_SR(sp)		// save it
 	
 	REG_S	sp, L_MD_KTF(a0)	// record trapframe pointer
-1:
-	csrrci	t0, sstatus, SR_EI	// disable interrupts
+.Lswitchto_newlwp:
+	csrrci	t0, sstatus, SR_EI	// # disable interrupts
 
-	move	tp, a1			// put the new lwp in thread pointer
+	move	tp, a1			// # put the new lwp in thread pointer
 
-	csrr	t1, sscratch		// get curcpu
-	PTR_S	tp, CI_CURLWP(t1)	// update curcpu with the new curlwp
+	PTR_L	t1, L_CPU(tp)		// # get curcpu
+	PTR_S	tp, CI_CURLWP(t1)	// # update curcpu with the new curlwp
 
-	REG_L	sp, L_MD_KTF(tp)	// load its kernel stack pointer
-	REG_L	t4, TF_SR(sp)		// fetch status register
-	csrw	sstatus, t4		// restore it (and interrutps?)
+	REG_L	sp, L_MD_KTF(tp)	// # load its kernel stack pointer
+	REG_L	t4, TF_SR(sp)		// # fetch status register
+	csrw	sstatus, t4		// # restore it (and interrutps?)
 
 	REG_L	s0, TF_S0(sp)		// restore callee saved
 	REG_L	s1, TF_S1(sp)		// restore callee saved
@@ -206,6 +205,8 @@ ENTRY_NP(cpu_switchto)
 	REG_L	s10, TF_S10(sp)		// restore callee saved
 	REG_L	s11, TF_S11(sp)		// restore callee saved
 
+	REG_L	ra, TF_RA(sp)		// restore return address
+
 	addi	sp, sp, TF_LEN		// remove trapframe
 
 	//	a0 = oldl
@@ -227,11 +228,11 @@ ENTRY_NP(cpu_lwp_trampoline)
 END(cpu_lwp_trampoline)
 
 ENTRY_NP(cpu_fast_switchto_cleanup)
-	lw	t0, CI_MTX_COUNT(a1)	// get mutex count
+	INT_L	t0, CI_MTX_COUNT(a1)	// get mutex count
 	REG_L	ra, CALLFRAME_RA(sp)	// get return address
 	REG_L	a0, CALLFRAME_S0(sp)	// get pinned LWP
 	addi	t0, t0, 1		// increment mutex count
-	sw	t0, CI_MTX_COUNT(a1)	// save it
+	INT_S	t0, CI_MTX_COUNT(a1)	// save it
 	PTR_S	zero, L_CTXSWTCH(a0)	// clear l_ctxswitch
 	addi	sp, sp, CALLFRAME_SIZ	// remove callframe
 #if IPL_SCHED != IPL_HIGH
@@ -273,7 +274,7 @@ ENTRY_NP(cpu_fast_switchto)
 #if 0
 	csrrci	t0, sstatus, SR_EI	// disable interrupts
 #endif
-	csrr	t1, sscratch		// get curcpu()
+	PTR_L	t1, L_CPU(tp)		// get curcpu()
 
 	PTR_S	sp, L_MD_KTF(tp)	// save trapframe ptr in oldlwp
 	move	tp, a0			// set thread pointer to newlwp
@@ -286,7 +287,7 @@ ENTRY_NP(cpu_fast_switchto)
 #if 0
 	csrrci	t0, sstatus, SR_EI	// disable interrupts
 #endif
-	csrr	t1, sscratch		// get curcpu() again
+	PTR_L	t1, L_CPU(tp)		// get curcpu() again
 	move	tp, s0			// return to pinned lwp
 	PTR_S	tp, CI_CURLWP(t1)	// restore curlwp
 #if 0
@@ -305,26 +306,24 @@ END(cpu_fast_switchto)
 // RISCV only has a simple exception handler handles both synchronous traps
 // and interrupts.
 ENTRY_NP(cpu_exception_handler)
-	csrw	uarch0, sp		// save stack pointer
-	csrr	sp, sstatus		// get status
-	andi	sp, sp, SR_PS		// user fault?
-	bnez	sp, 1f			//   no, already on kernel stack
+	csrrw	sp, sscratch, sp	// swap scratch and stack pointer
+	beqz	sp, .Lexception_kernel	//   sp == 0, already on kernel stack
 	//
 	// The execption happened while user code was executing.  We need to
 	// get the pointer to the user trapframe from the LWP md area.  Then we
 	// save t1 and tp so we have a register to work with and to get curlwp
 	// into tp.  We also save the saved SP into the trapframe.
+	// Upon entry on an exception from user, sscratch will contain curlwp.
 	//
-	csrr	sp, sscratch		// get curcpu()
-	PTR_L	sp, CI_CURLWP(sp)	// get curlwp
+	REG_S	tp, L_MD_TP(sp)		// save thread pointer temporarily
+	mv	tp, sp			// put curlwp in thread pointer
 	PTR_L	sp, L_MD_UTF(sp)	// trapframe pointer loaded
-	REG_S	tp, TF_TP(sp)		// save thread pointer
 	REG_S	t1, TF_T1(sp)		// save t1
-	csrr	t1, uarch0		// get saved SP
+	csrrw	t1, sscratch, zero	// save saved stack pointer with 0
 	REG_S	t1, TF_SP(sp)		// save stack pointer
-	csrr	t1, sscratch		// get curcpu()
-	PTR_L	tp, CI_CURLWP(t1)	// put curlwp in thread pointer
-	j	2f
+	REG_S	t1, L_MD_TP(tp)		// get thread pointer from temp store
+	REG_L	t1, TF_SP(sp)		// save thread pointer in trapframe
+	j	.Lexception_common
 
 	//
 	// The exception happened while we were already in the kernel.  That
@@ -333,12 +332,13 @@ ENTRY_NP(cpu_exception_handler)
 	// trap frame.  We save t1 so we can use it the original sp into the
 	// trapframe for use by the exception exiting code.
 	//
-1:	csrr	sp, uarch0		// get back our stack pointer
+.Lexception_kernel:
+	csrrw	sp, sscratch, zero	// get back our stack pointer
 	addi	sp, sp, -TF_LEN		// allocate stack frame
 	REG_S	t1, TF_T1(sp)		// save t1
 	addi	t1, sp, TF_LEN
 	REG_S	t1, TF_SP(sp)		// save SP
-2:
+.Lexception_common:
 	// Now we save all the temporary registers into the trapframe since
 	// they will most certainly be changed.
 	REG_S	ra, TF_RA(sp)		// save return address
@@ -352,6 +352,7 @@ ENTRY_NP(cpu_exception_handler)
 	REG_S	a6, TF_A6(sp)		// save a6
 	REG_S	a7, TF_A7(sp)		// save a7
 	REG_S	t0, TF_T0(sp)		// save t0
+					// t1 is already saved
 	REG_S	t2, TF_T2(sp)		// save t2
 	REG_S	t3, TF_T3(sp)		// save t3
 	REG_S	t4, TF_T4(sp)		// save t4
@@ -366,8 +367,8 @@ ENTRY_NP(cpu_exception_handler)
 	csrr	a4, sbadaddr		// get badaddr
 
 	REG_S	a1, TF_PC(sp)
-	sw	a2, TF_SR(sp)
-	sw	a3, TF_CAUSE(sp)	// save cause
+	INT_S	a2, TF_SR(sp)
+	INT_S	a3, TF_CAUSE(sp)	// save cause
 	REG_S	a4, TF_BADADDR(sp)
 
 	// Now we've saved the trapfame, the cause is still in a3.
@@ -383,6 +384,8 @@ exception_kernexit:
 	// trap or interrupt).  Simply return the volatile registers and the
 	// exception PC and status, load the saved SP from the trapframe, and
 	// return from the exception
+	csrrci	zero, sstatus, SR_EI	// disable interrupts
+
 	REG_L	ra, TF_RA(sp)		// restore return address
 	REG_L	gp, TF_GP(sp)		// restore gp
 	REG_L	a0, TF_A0(sp)		// restore a0
@@ -431,8 +434,10 @@ trap_user:
 
 	call	_C_LABEL(cpu_trap)	// nope, just a regular trap
 _C_LABEL(exception_userexit):
-	lw	t0, L_MD_ASTPENDING(tp)	// ast pending?
+	INT_L	t0, L_MD_ASTPENDING(tp)	// ast pending?
 	bnez	t0, trap_doast		//   yes, handle it.
+	csrrci	zero, sstatus, SR_EI	// disable interrupts
+	csrw	sscratch, tp		// show we are coming from userland
 	REG_L	s0, TF_S0(sp)		// only restore from userland
 	REG_L	s1, TF_S1(sp)		// only restore from userland
 	REG_L	s2, TF_S2(sp)		// only restore from userland
@@ -449,9 +454,7 @@ _C_LABEL(exception_userexit):
 	j	exception_kernexit
 
 trap_syscall:
-.L0:	auipc	ra, %pcrel_hi(exception_userexit)
-	addi	ra, ra, %pcrel_lo(.L0)
-
+.L0:	PTR_L	ra, exception_userexit
 	PTR_L	t0, L_PROC(tp)		// get proc struct
 	PTR_L	t0, P_MD_SYSCALL(t0)	// get syscall address from proc
 	jr	t0			// and jump to it
@@ -469,15 +472,14 @@ intr_usersave:
 	REG_S	s9, TF_S9(sp)		// only save from userland
 	REG_S	s10, TF_S10(sp)		// only save from userland
 	REG_S	s11, TF_S11(sp)		// only save from userland
-	auipc	ra, %pcrel_hi(exception_userexit)
-	addi	ra, ra, %pcrel_lo(exception_userexit)
+	PTR_LA	ra, exception_userexit
 trap_doast:
 	move	a0, sp			// only argument is trapframe
 	tail	_C_LABEL(cpu_ast)
 
 intr_user:
 	call	_C_LABEL(cpu_intr)	// handle interrupt
-	lw	t0, L_MD_ASTPENDING(tp)	// get astpending
+	INT_L	t0, L_MD_ASTPENDING(tp)	// get astpending
 	bnez	t0, intr_usersave	//    if one is pending, deal with in
 
 	REG_L	tp, TF_TP(sp)		// restore thread pointer

Reply via email to