#include "opt_compat_netbsd.h"
#include "opt_cputype.h"
#include "opt_ddb.h"
#include "opt_kgdb.h"
#include "opt_modular.h"
#include "assym.h"
#include <sys/syscall.h>
#include <sh3/asm.h>
#include <sh3/locore.h>
#include <sh3/param.h>
#include <sh3/mmu_sh3.h>
#include <sh3/mmu_sh4.h>
__KERNEL_RCSID(0, "$NetBSD: locore_subr.S,v 1.61 2021/07/15 04:58:33 rin Exp $")
#define SAVEPCB_AND_JUMP(pcb, jump) \
add #SF_SIZE, pcb ; \
stc.l r7_bank, @-pcb ; \
stc.l r6_bank, @-pcb ; \
mov.l r15, @-pcb ; \
mov.l r14, @-pcb ; \
mov.l r13, @-pcb ; \
mov.l r12, @-pcb ; \
mov.l r11, @-pcb ; \
mov.l r10, @-pcb ; \
mov.l r9, @-pcb ; \
mov.l r8, @-pcb ; \
sts.l pr, @-pcb ; \
stc.l sr, @-pcb ; \
jump ; \
stc.l gbr, @-pcb
#define SAVEPCB(pcb) \
SAVEPCB_AND_JUMP(pcb, )
.text
.align 5
ENTRY(cpu_switchto)
!! save old lwp's context to switchframe
mov.l @(L_MD_PCB, r4), r1 ! olwp->l_md.md_pcb
SAVEPCB(r1)
!! free to use callee-save registers now
mov.l .L_curlwp, r2
mov.l .L_curpcb, r3
mov.l @(L_MD_PCB, r5), r10 ! nlwp->l_md.md_pcb
!tst r6, r6 ! "full" switch?
mov.l r5, @r2 ! curlwp = nlwp;
!bt/s .L_prepare_switch
mov.l r10, @r3 ! curpcb = nlwp->l_md.md_pcb;
!mov r5, r8 ! preserve nlwp
!bra .L_restore_nlwp
! mov r4, r9 ! preserve olwp
.L_prepare_switch:
!! arguments to cpu_switch_prepare are already in the right registers
mov.l .L_cpu_switch_prepare, r0
mov r5, r8 ! preserve nlwp
jsr @r0
mov r4, r9 ! preserve olwp
.L_restore_nlwp:
!! restore new lwp's context from switchframe
!! r10 is nlwp->l_md.md_pcb == &nlwp->l_md.md_pcb->pcb_sf
!! setup nlwp's kernel stack first
mov.l @(SF_R7_BANK, r10), r0 ! kernel stack bottom
mov.l @(SF_R6_BANK, r10), r2 ! current trapframe
mov.l @(SF_R15, r10), r3 ! current kernel sp
!! while switching kernel stack, all exceptions must be disabled
__EXCEPTION_BLOCK(r1, r11) ! saves SR in r11
ldc r0, r7_bank
ldc r2, r6_bank
mov r3, r15
#if !defined(P1_STACK) && defined(SH4)
!! wire u-area in TLB
MOV (switch_resume, r0)
jsr @r0
mov r8, r4 ! nlwp
#endif
!! safe to use nlwp's kernel stack now
ldc r11, sr ! __EXCEPTION_UNBLOCK
!! finish restoring new lwp's context from switchframe
!! sf_r15, sf_r6_bank, sf_r7_bank are already restored
mov r10, r1 ! &nlwp->l_md.md_pcb->pcb_sf
mov r9, r0 ! return olwp (we are about to clobber r9)
ldc.l @r1+, gbr
mov.l @r1+, r8 ! r8 = new SR
mov #0x78, r9
shll r9 ! r9 = PSL_IMASK
not r9, r10 ! r10 = ~PSL_IMASK
and r9, r11 ! r11 = old SR & PSL_IMASK
and r10, r8
or r11, r8
ldc r8, sr
lds.l @r1+, pr
mov.l @r1+, r8
mov.l @r1+, r9
mov.l @r1+, r10
mov.l @r1+, r11
mov.l @r1+, r12
mov.l @r1+, r13
rts
mov.l @r1+, r14
.align 2
.L_curlwp: .long _C_LABEL(curlwp)
.L_curpcb: .long _C_LABEL(curpcb)
.L_cpu_switch_prepare: .long _C_LABEL(cpu_switch_prepare)
#ifdef SH4
FUNC_SYMBOL(switch_resume)
#endif
SET_ENTRY_SIZE(cpu_switchto)
#ifdef SH3
NENTRY(sh3_switch_resume)
rts
nop
SET_ENTRY_SIZE(sh3_switch_resume)
#endif
#ifdef SH4
NENTRY(sh4_switch_resume)
add #L_MD_UPTE, r4 ! l->l_md.md_upte
mov #UPAGES, r3
mov.l @r4, r0 ! if (l->l_md.md_upte[0].addr == 0) return;
tst r0, r0
bt 2f
mov #0, r0
mov.l .L_4_PTEH, r2
mov.l @r2, r7
mov.l r0, @r2
mov.l .L_VPN_MASK, r6
mov.l .L_4_UTLB_AA_A, r5
mova 1f, r0
mov.l .L_P2BASE, r1
or r1, r0
jmp @r0 ! run on P2
nop
.align 2 ! mova target must be 4byte aligned
1: mov.l @(4, r4), r0
and r6, r0
mov.l r0, @r5 ! clear D, V
mov.l @r4+, r0 ! addr
mov.l @r4+, r1 ! data
mov.l r1, @r0 ! *addr = data
mov.l @r4+, r0 ! addr
mov.l @r4+, r1 ! data
mov.l r1, @r0 ! *addr = data
dt r3
bf 1b
mov.l r7, @r2
2: rts ! to the caller in P1
nop
.align 2
.L_4_PTEH: .long SH4_PTEH
.L_4_UTLB_AA_A: .long (SH4_UTLB_AA | SH4_UTLB_A)
.L_VPN_MASK: .long 0xfffff000
.L_P2BASE: .long 0xa0000000
SET_ENTRY_SIZE(sh4_switch_resume)
#endif
NENTRY(_cpu_intr_raise)
stc sr, r2
mov #0x78, r1
mov r2, r0
shll r1
and r1, r0
cmp/ge r4, r0
bt/s 1f
not r1, r1
and r1, r2
or r2, r4
ldc r4, sr
1: rts
nop
SET_ENTRY_SIZE(_cpu_intr_raise)
NENTRY(_cpu_intr_suspend)
stc sr, r0
mov #0x78, r1
shll r1
mov r0, r2
or r1, r2
ldc r2, sr
rts
and r1, r0
SET_ENTRY_SIZE(_cpu_intr_suspend)
NENTRY(_cpu_intr_resume)
stc sr, r0
mov #0x78, r2
shll r2
not r2, r1
and r0, r1
or r1, r4
ldc r4, sr
rts
and r2, r0
SET_ENTRY_SIZE(_cpu_intr_resume)
NENTRY(_cpu_exception_suspend)
stc sr, r0
mov #0x10, r1
swap.b r1, r1
mov r0, r2
swap.w r1, r1
or r1, r2
ldc r2, sr
rts
nop
SET_ENTRY_SIZE(_cpu_exception_suspend)
NENTRY(_cpu_exception_resume)
stc sr, r0
mov #0x10, r1
swap.b r1, r1
swap.w r1, r1
not r1, r1
and r1, r0
or r4, r0
ldc r0, sr
rts
nop
SET_ENTRY_SIZE(_cpu_exception_resume)
.align 5
NENTRY(_cpu_spin)
1: nop
nop
nop
add #-1, r4
nop
cmp/pl r4
nop
bt 1b
rts
nop
SET_ENTRY_SIZE(_cpu_spin)
NENTRY(lwp_trampoline)
mov.l .L_lwp_startup, r1
mov r0, r4
jsr @r1
mov r10, r5
jsr @r12
mov r11, r4
__EXCEPTION_RETURN
.align 2
.L_lwp_startup: .long _C_LABEL(lwp_startup)
SET_ENTRY_SIZE(lwp_trampoline)
#if defined(COMPAT_16) || defined(MODULAR)
NENTRY(sigcode)
mov r15, r4
mov.l .L_SYS___sigreturn14, r0
trapa #0x80
mov.l .L_SYS_exit, r0
trapa #0x80
.align 2
.L_SYS___sigreturn14: .long SYS_compat_16___sigreturn14
.L_SYS_exit: .long SYS_exit
.globl _C_LABEL(esigcode)
_C_LABEL(esigcode):
SET_ENTRY_SIZE(sigcode)
#endif
ENTRY(savectx)
SAVEPCB_AND_JUMP(r4, rts)
SET_ENTRY_SIZE(savectx)
ENTRY(copyout)
mov.l r14, @-r15
sts.l pr, @-r15
mov r15, r14
mov r4, r3
mov r5, r2
mov r5, r4
add r6, r2
cmp/hs r5, r2
bf 3f
mov.l .L_copyout_VM_MAXUSER_ADDRESS, r1
cmp/hi r1, r2
bt 3f
mov.l .L_copyout_curpcb, r1
mov.l @r1, r2
mov.l .L_copyout_onfault, r1
mov.l r1, @(PCB_ONFAULT,r2)
mov.l .L_copyout_memcpy, r1
jsr @r1
mov r3, r5
mov #0, r0
1:
mov.l .L_copyout_curpcb, r1
mov.l @r1, r2
mov #0, r1
mov.l r1, @(PCB_ONFAULT,r2)
2:
mov r14, r15
lds.l @r15+, pr
rts
mov.l @r15+, r14
3:
bra 2b
mov #EFAULT, r0
.align 2
.L_copyout_onfault:
.long 1b
.L_copyout_VM_MAXUSER_ADDRESS:
.long VM_MAXUSER_ADDRESS
.L_copyout_curpcb:
.long _C_LABEL(curpcb)
.L_copyout_memcpy:
.long _C_LABEL(memcpy)
SET_ENTRY_SIZE(copyout)
ENTRY(copyin)
mov.l r14, @-r15
sts.l pr, @-r15
mov r15, r14
mov r4, r3
mov r5, r4
mov r3, r2
add r6, r2
cmp/hs r3, r2
bf 3f
mov.l .L_copyin_VM_MAXUSER_ADDRESS, r1
cmp/hi r1, r2
bt 3f
mov.l .L_copyin_curpcb, r1
mov.l @r1, r2
mov.l .L_copyin_onfault, r1
mov.l r1, @(PCB_ONFAULT,r2)
mov.l .L_copyin_memcpy, r1
jsr @r1
mov r3, r5
mov #0, r0
1:
mov.l .L_copyin_curpcb, r1
mov.l @r1, r2
mov #0, r1
mov.l r1, @(PCB_ONFAULT,r2)
2:
mov r14, r15
lds.l @r15+, pr
rts
mov.l @r15+, r14
3:
bra 2b
mov #EFAULT, r0
.align 2
.L_copyin_onfault:
.long 1b
.L_copyin_VM_MAXUSER_ADDRESS:
.long VM_MAXUSER_ADDRESS
.L_copyin_curpcb:
.long _C_LABEL(curpcb)
.L_copyin_memcpy:
.long _C_LABEL(memcpy)
SET_ENTRY_SIZE(copyin)
ENTRY(copyoutstr)
mov.l r8, @-r15
mov r4, r8
mov.l .L_copyoutstr_curpcb, r1
mov.l @r1, r2
mov.l .L_copyoutstr_onfault, r1
mov.l r1, @(PCB_ONFAULT,r2)
mov.l .L_copyoutstr_VM_MAXUSER_ADDRESS, r3
cmp/hi r3, r5
bt 5f
mov r3, r0
sub r5, r0
cmp/hi r6, r0
bf 2f
bra 2f
mov r6, r0
.align 2
1:
mov.b @r4+, r1
mov.b r1, @r5
extu.b r1, r1
add #1, r5
tst r1, r1
bf 2f
bra 3f
mov #0, r0
.align 2
2:
add #-1, r0
cmp/eq #-1, r0
bf 1b
cmp/hi r3, r5
bf 6f
mov #0, r0
3:
tst r7, r7
bt 4f
mov r4, r1
sub r8, r1
mov.l r1, @r7
4:
mov.l .L_copyoutstr_curpcb, r1
mov.l @r1, r2
mov #0, r1
mov.l r1, @(PCB_ONFAULT,r2)
rts
mov.l @r15+, r8
5:
bra 4b
mov #EFAULT, r0
6: bra 3b
mov #ENAMETOOLONG, r0
.align 2
.L_copyoutstr_onfault:
.long 4b
.L_copyoutstr_VM_MAXUSER_ADDRESS:
.long VM_MAXUSER_ADDRESS
.L_copyoutstr_curpcb:
.long _C_LABEL(curpcb)
SET_ENTRY_SIZE(copyoutstr)
ENTRY(copyinstr)
mov.l r8, @-r15
mov r4, r8
mov.l .L_copyinstr_curpcb, r1
mov.l @r1, r2
mov.l .L_copyinstr_onfault, r1
mov.l r1, @(PCB_ONFAULT,r2)
mov.l .L_copyinstr_VM_MAXUSER_ADDRESS, r3
cmp/hi r3, r4
bt 5f
mov r3, r0
sub r4, r0
cmp/hi r6, r0
bf 2f
bra 2f
mov r6, r0
.align 2
1:
mov.b @r4+, r1
mov.b r1, @r5
extu.b r1, r1
add #1, r5
tst r1, r1
bf 2f
bra 3f
mov #0, r0
.align 2
2:
add #-1, r0
cmp/eq #-1, r0
bf 1b
cmp/hi r3, r4
bf 6f
mov #0, r0
3:
tst r7, r7
bt 4f
mov r4, r1
sub r8, r1
mov.l r1, @r7
4:
mov.l .L_copyinstr_curpcb, r1
mov.l @r1, r2
mov #0, r1
mov.l r1, @(PCB_ONFAULT,r2)
rts
mov.l @r15+, r8
5:
bra 4b
mov #EFAULT, r0
6:
bra 3b
mov #ENAMETOOLONG, r0
.align 2
.L_copyinstr_onfault:
.long 4b
.L_copyinstr_VM_MAXUSER_ADDRESS:
.long VM_MAXUSER_ADDRESS
.L_copyinstr_curpcb:
.long _C_LABEL(curpcb)
SET_ENTRY_SIZE(copyinstr)
#define UFETCHSTORE_PROLOGUE(func) \
mov.l .L ## func ## _VM_MAXUSER_ADDRESS, r1 ;\
cmp/hi r1, r4 ;\
bt/s 2f ;\
mov #EFAULT,r0 ;\
mov.l .L ## func ## _curpcb, r1 ;\
mov.l @r1, r2 ;\
mov.l .L ## func ## _onfault, r1 ;\
mov.l r1, @(PCB_ONFAULT,r2)
#define UFETCHSTORE_EPILOGUE(func) \
mov #0, r0 ;\
1: ;\
mov.l .L ## func ## _curpcb, r1 ;\
mov.l @r1, r2 ;\
mov #0, r1 ;\
mov.l r1, @(PCB_ONFAULT,r2) ;\
2: ;\
rts ;\
nop ;\
\
.align 2 ;\
.L ## func ## _onfault: ;\
.long 1b ;\
.L ## func ## _VM_MAXUSER_ADDRESS: ;\
.long VM_MAXUSER_ADDRESS - 4 ;\
.L ## func ## _curpcb: ;\
.long _C_LABEL(curpcb)
ENTRY(_ufetch_8)
UFETCHSTORE_PROLOGUE(_ufetch_8)
mov.b @r4, r1
mov.b r1, @r5
UFETCHSTORE_EPILOGUE(_ufetch_8)
SET_ENTRY_SIZE(_ufetch_8)
ENTRY(_ufetch_16)
UFETCHSTORE_PROLOGUE(_ufetch_16)
mov.w @r4, r1
mov.w r1 @r5
UFETCHSTORE_EPILOGUE(_ufetch_16)
SET_ENTRY_SIZE(_ufetch_16)
ENTRY(_ufetch_32)
UFETCHSTORE_PROLOGUE(_ufetch_32)
mov.l @r4, r1
mov.l r1, @r5
UFETCHSTORE_EPILOGUE(_ufetch_32)
SET_ENTRY_SIZE(_ufetch_32)
ENTRY(_ustore_8)
UFETCHSTORE_PROLOGUE(_ustore_8)
mov.b r5, @r4
UFETCHSTORE_EPILOGUE(_ustore_8)
SET_ENTRY_SIZE(_ustore_8)
ENTRY(_ustore_16)
UFETCHSTORE_PROLOGUE(_ustore_16)
mov.w r5, @r4
UFETCHSTORE_EPILOGUE(_ustore_16)
SET_ENTRY_SIZE(_ustore_16)
ENTRY(_ustore_32)
UFETCHSTORE_PROLOGUE(_ustore_32)
mov.l r5, @r4
UFETCHSTORE_EPILOGUE(_ustore_32)
SET_ENTRY_SIZE(_ustore_32)
ENTRY(kcopy)
mov.l r8, @-r15
mov.l r14, @-r15
sts.l pr, @-r15
mov r15, r14
mov r4, r3
mov.l .L_kcopy_curpcb, r1
mov.l @r1, r2
mov.l @(PCB_ONFAULT,r2) ,r8
mov.l .L_kcopy_onfault, r1
mov.l r1, @(PCB_ONFAULT,r2)
mov.l .L_kcopy_memcpy, r1
mov r5, r4
jsr @r1
mov r3, r5
mov #0, r0
1:
mov.l .L_kcopy_curpcb, r1
mov.l @r1, r2
mov.l r8, @(PCB_ONFAULT,r2)
mov r14, r15
lds.l @r15+, pr
mov.l @r15+, r14
rts
mov.l @r15+, r8
.align 2
.L_kcopy_onfault:
.long 1b
.L_kcopy_curpcb:
.long _C_LABEL(curpcb)
.L_kcopy_memcpy:
.long _C_LABEL(memcpy)
SET_ENTRY_SIZE(kcopy)
#if defined(DDB) || defined(KGDB)
ENTRY(setjmp)
add #4*9, r4
mov.l r8, @-r4
mov.l r9, @-r4
mov.l r10, @-r4
mov.l r11, @-r4
mov.l r12, @-r4
mov.l r13, @-r4
mov.l r14, @-r4
mov.l r15, @-r4
sts.l pr, @-r4
rts
xor r0, r0
SET_ENTRY_SIZE(setjmp)
ENTRY(longjmp)
lds.l @r4+, pr
mov.l @r4+, r15
mov.l @r4+, r14
mov.l @r4+, r13
mov.l @r4+, r12
mov.l @r4+, r11
mov.l @r4+, r10
mov.l @r4+, r9
mov.l @r4+, r8
rts
mov #1, r0
SET_ENTRY_SIZE(longjmp)
#endif