/* SPDX-License-Identifier: GPL-2.0 */// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd. #include <linux/linkage.h>#include <abi/entry.h>#include <abi/pgtable-bits.h>#include <asm/errno.h>#include <asm/setup.h>#include <asm/unistd.h>#include <asm/asm-offsets.h>#include <linux/threads.h>#include <asm/setup.h>#include <asm/page.h>#include <asm/thread_info.h> #define PTE_INDX_MSK 0xffc#define PTE_INDX_SHIFT 10#define _PGDIR_SHIFT 22 .macro zero_fp#ifdef CONFIG_STACKTRACE movi r8, 0#endif.endm .macro context_tracking#ifdef CONFIG_CONTEXT_TRACKING mfcr a0, epsr btsti a0, 31 bt 1f jbsr context_tracking_user_exit ldw a0, (sp, LSAVE_A0) ldw a1, (sp, LSAVE_A1) ldw a2, (sp, LSAVE_A2) ldw a3, (sp, LSAVE_A3)#if defined(__CSKYABIV1__) ldw r6, (sp, LSAVE_A4) ldw r7, (sp, LSAVE_A5)#endif1:#endif.endm .macro tlbop_begin name, val0, val1, val2ENTRY(csky_\name) mtcr a3, ss2 mtcr r6, ss3 mtcr a2, ss4 RD_PGDR r6 RD_MEH a3#ifdef CONFIG_CPU_HAS_TLBI tlbi.vaas a3 sync.is btsti a3, 31 bf 1f RD_PGDR_K r61:#else bgeni a2, 31 WR_MCIR a2 bgeni a2, 25 WR_MCIR a2#endif bclri r6, 0 lrw a2, va_pa_offset ld.w a2, (a2, 0) subu r6, a2 bseti r6, 31 mov a2, a3 lsri a2, _PGDIR_SHIFT lsli a2, 2 addu r6, a2 ldw r6, (r6) lrw a2, va_pa_offset ld.w a2, (a2, 0) subu r6, a2 bseti r6, 31 lsri a3, PTE_INDX_SHIFT lrw a2, PTE_INDX_MSK and a3, a2 addu r6, a3 ldw a3, (r6) movi a2, (_PAGE_PRESENT | \val0) and a3, a2 cmpne a3, a2 bt \name /* First read/write the page, just update the flags */ ldw a3, (r6) bgeni a2, PAGE_VALID_BIT bseti a2, PAGE_ACCESSED_BIT bseti a2, \val1 bseti a2, \val2 or a3, a2 stw a3, (r6) /* Some cpu tlb-hardrefill bypass the cache */#ifdef CONFIG_CPU_NEED_TLBSYNC movi a2, 0x22 bseti a2, 6 mtcr r6, cr22 mtcr a2, cr17 sync#endif mfcr a3, ss2 mfcr r6, ss3 mfcr a2, ss4 rte\name: mfcr a3, ss2 mfcr r6, ss3 mfcr a2, ss4 SAVE_ALL 0.endm.macro tlbop_end is_write zero_fp context_tracking RD_MEH a2 psrset ee, ie mov a0, sp movi a1, \is_write jbsr do_page_fault jmpi ret_from_exception.endm .text tlbop_begin tlbinvalidl, _PAGE_READ, PAGE_VALID_BIT, PAGE_ACCESSED_BITtlbop_end 0 tlbop_begin tlbinvalids, _PAGE_WRITE, PAGE_DIRTY_BIT, PAGE_MODIFIED_BITtlbop_end 1 tlbop_begin tlbmodified, _PAGE_WRITE, PAGE_DIRTY_BIT, PAGE_MODIFIED_BIT#ifndef CONFIG_CPU_HAS_LDSTEXjbsr csky_cmpxchg_fixup#endiftlbop_end 1 ENTRY(csky_systemcall) SAVE_ALL TRAP0_SIZE zero_fp context_tracking psrset ee, ie lrw r9, __NR_syscalls cmphs syscallid, r9 /* Check nr of syscall */ bt 1f lrw r9, sys_call_table ixw r9, syscallid ldw syscallid, (r9) cmpnei syscallid, 0 bf ret_from_exception mov r9, sp bmaski r10, THREAD_SHIFT andn r9, r10 ldw r10, (r9, TINFO_FLAGS) lrw r9, _TIF_SYSCALL_WORK and r10, r9 cmpnei r10, 0 bt csky_syscall_trace#if defined(__CSKYABIV2__) subi sp, 8 stw r5, (sp, 0x4) stw r4, (sp, 0x0) jsr syscallid /* Do system call */ addi sp, 8#else jsr syscallid#endif stw a0, (sp, LSAVE_A0) /* Save return value */1:#ifdef CONFIG_DEBUG_RSEQ mov a0, sp jbsr rseq_syscall#endif jmpi ret_from_exception csky_syscall_trace: mov a0, sp /* sp = pt_regs pointer */ jbsr syscall_trace_enter cmpnei a0, 0 bt 1f /* Prepare args before do system call */ ldw a0, (sp, LSAVE_A0) ldw a1, (sp, LSAVE_A1) ldw a2, (sp, LSAVE_A2) ldw a3, (sp, LSAVE_A3)#if defined(__CSKYABIV2__) subi sp, 8 ldw r9, (sp, LSAVE_A4) stw r9, (sp, 0x0) ldw r9, (sp, LSAVE_A5) stw r9, (sp, 0x4) jsr syscallid /* Do system call */ addi sp, 8#else ldw r6, (sp, LSAVE_A4) ldw r7, (sp, LSAVE_A5) jsr syscallid /* Do system call */#endif stw a0, (sp, LSAVE_A0) /* Save return value */ 1:#ifdef CONFIG_DEBUG_RSEQ mov a0, sp jbsr rseq_syscall#endif mov a0, sp /* right now, sp --> pt_regs */ jbsr syscall_trace_exit br ret_from_exception ENTRY(ret_from_kernel_thread) jbsr schedule_tail mov a0, r10 jsr r9 jbsr ret_from_exception ENTRY(ret_from_fork) jbsr schedule_tail mov r9, sp bmaski r10, THREAD_SHIFT andn r9, r10 ldw r10, (r9, TINFO_FLAGS) lrw r9, _TIF_SYSCALL_WORK and r10, r9 cmpnei r10, 0 bf ret_from_exception mov a0, sp /* sp = pt_regs pointer */ jbsr syscall_trace_exit ret_from_exception: psrclr ie ld r9, (sp, LSAVE_PSR) btsti r9, 31 bt 1f /* * Load address of current->thread_info, Then get address of task_struct * Get task_needreshed in task_struct */ mov r9, sp bmaski r10, THREAD_SHIFT andn r9, r10 ldw r10, (r9, TINFO_FLAGS) lrw r9, _TIF_WORK_MASK and r10, r9 cmpnei r10, 0 bt exit_work#ifdef CONFIG_CONTEXT_TRACKING jbsr context_tracking_user_enter#endif1:#ifdef CONFIG_PREEMPTION mov r9, sp bmaski r10, THREAD_SHIFT andn r9, r10 ldw r10, (r9, TINFO_PREEMPT) cmpnei r10, 0 bt 2f jbsr preempt_schedule_irq /* irq en/disable is done inside */2:#endif #ifdef CONFIG_TRACE_IRQFLAGS ld r10, (sp, LSAVE_PSR) btsti r10, 6 bf 2f jbsr trace_hardirqs_on2:#endif RESTORE_ALL exit_work: lrw r9, ret_from_exception mov lr, r9 btsti r10, TIF_NEED_RESCHED bt work_resched psrset ie mov a0, sp mov a1, r10 jmpi do_notify_resume work_resched: jmpi schedule ENTRY(csky_trap) SAVE_ALL 0 zero_fp context_tracking psrset ee mov a0, sp /* Push Stack pointer arg */ jbsr trap_c /* Call C-level trap handler */ jmpi ret_from_exception /* * Prototype from libc for abiv1: * register unsigned int __result asm("a0"); * asm( "trap 3" :"=r"(__result)::); */ENTRY(csky_get_tls) USPTOKSP /* increase epc for continue */ mfcr a0, epc addi a0, TRAP0_SIZE mtcr a0, epc /* get current task thread_info with kernel 8K stack */ bmaski a0, THREAD_SHIFT not a0 subi sp, 1 and a0, sp addi sp, 1 /* get tls */ ldw a0, (a0, TINFO_TP_VALUE) KSPTOUSP rte ENTRY(csky_irq) SAVE_ALL 0 zero_fp context_tracking psrset ee #ifdef CONFIG_TRACE_IRQFLAGS jbsr trace_hardirqs_off#endif mov a0, sp jbsr csky_do_IRQ jmpi ret_from_exception /* * a0 = prev task_struct * * a1 = next task_struct * * a0 = return next */ENTRY(__switch_to) lrw a3, TASK_THREAD addu a3, a0 SAVE_SWITCH_STACK stw sp, (a3, THREAD_KSP) /* Set up next process to run */ lrw a3, TASK_THREAD addu a3, a1 ldw sp, (a3, THREAD_KSP) /* Set next kernel sp */ #if defined(__CSKYABIV2__) addi a3, a1, TASK_THREAD_INFO ldw tls, (a3, TINFO_TP_VALUE)#endif RESTORE_SWITCH_STACK rtsENDPROC(__switch_to)
/* SPDX-License-Identifier: GPL-2.0 */
// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
#include <linux/linkage.h>
#include <abi/entry.h>
#include <abi/pgtable-bits.h>
#include <asm/errno.h>
#include <asm/setup.h>
#include <asm/unistd.h>
#include <asm/asm-offsets.h>
#include <linux/threads.h>
#include <asm/setup.h>
#include <asm/page.h>
#include <asm/thread_info.h>
#define PTE_INDX_MSK 0xffc
#define PTE_INDX_SHIFT 10
#define _PGDIR_SHIFT 22
.macro zero_fp
#ifdef CONFIG_STACKTRACE
movi r8, 0
#endif
.endm
.macro context_tracking
#ifdef CONFIG_CONTEXT_TRACKING
mfcr a0, epsr
btsti a0, 31
bt 1f
jbsr context_tracking_user_exit
ldw a0, (sp, LSAVE_A0)
ldw a1, (sp, LSAVE_A1)
ldw a2, (sp, LSAVE_A2)
ldw a3, (sp, LSAVE_A3)
#if defined(__CSKYABIV1__)
ldw r6, (sp, LSAVE_A4)
ldw r7, (sp, LSAVE_A5)
#endif
1:
#endif
.endm
.macro tlbop_begin name, val0, val1, val2
ENTRY(csky_\name)
mtcr a3, ss2
mtcr r6, ss3
mtcr a2, ss4
RD_PGDR r6
RD_MEH a3
#ifdef CONFIG_CPU_HAS_TLBI
tlbi.vaas a3
sync.is
btsti a3, 31
bf 1f
RD_PGDR_K r6
1:
#else
bgeni a2, 31
WR_MCIR a2
bgeni a2, 25
WR_MCIR a2
#endif
bclri r6, 0
lrw a2, va_pa_offset
ld.w a2, (a2, 0)
subu r6, a2
bseti r6, 31
mov a2, a3
lsri a2, _PGDIR_SHIFT
lsli a2, 2
addu r6, a2
ldw r6, (r6)
lrw a2, va_pa_offset
ld.w a2, (a2, 0)
subu r6, a2
bseti r6, 31
lsri a3, PTE_INDX_SHIFT
lrw a2, PTE_INDX_MSK
and a3, a2
addu r6, a3
ldw a3, (r6)
movi a2, (_PAGE_PRESENT | \val0)
and a3, a2
cmpne a3, a2
bt \name
/* First read/write the page, just update the flags */
ldw a3, (r6)
bgeni a2, PAGE_VALID_BIT
bseti a2, PAGE_ACCESSED_BIT
bseti a2, \val1
bseti a2, \val2
or a3, a2
stw a3, (r6)
/* Some cpu tlb-hardrefill bypass the cache */
#ifdef CONFIG_CPU_NEED_TLBSYNC
movi a2, 0x22
bseti a2, 6
mtcr r6, cr22
mtcr a2, cr17
sync
#endif
mfcr a3, ss2
mfcr r6, ss3
mfcr a2, ss4
rte
\name:
mfcr a3, ss2
mfcr r6, ss3
mfcr a2, ss4
SAVE_ALL 0
.endm
.macro tlbop_end is_write
zero_fp
context_tracking
RD_MEH a2
psrset ee, ie
mov a0, sp
movi a1, \is_write
jbsr do_page_fault
jmpi ret_from_exception
.endm
.text
tlbop_begin tlbinvalidl, _PAGE_READ, PAGE_VALID_BIT, PAGE_ACCESSED_BIT
tlbop_end 0
tlbop_begin tlbinvalids, _PAGE_WRITE, PAGE_DIRTY_BIT, PAGE_MODIFIED_BIT
tlbop_end 1
tlbop_begin tlbmodified, _PAGE_WRITE, PAGE_DIRTY_BIT, PAGE_MODIFIED_BIT
#ifndef CONFIG_CPU_HAS_LDSTEX
jbsr csky_cmpxchg_fixup
#endif
tlbop_end 1
ENTRY(csky_systemcall)
SAVE_ALL TRAP0_SIZE
zero_fp
context_tracking
psrset ee, ie
lrw r9, __NR_syscalls
cmphs syscallid, r9 /* Check nr of syscall */
bt 1f
lrw r9, sys_call_table
ixw r9, syscallid
ldw syscallid, (r9)
cmpnei syscallid, 0
bf ret_from_exception
mov r9, sp
bmaski r10, THREAD_SHIFT
andn r9, r10
ldw r10, (r9, TINFO_FLAGS)
lrw r9, _TIF_SYSCALL_WORK
and r10, r9
cmpnei r10, 0
bt csky_syscall_trace
#if defined(__CSKYABIV2__)
subi sp, 8
stw r5, (sp, 0x4)
stw r4, (sp, 0x0)
jsr syscallid /* Do system call */
addi sp, 8
#else
jsr syscallid
#endif
stw a0, (sp, LSAVE_A0) /* Save return value */
1:
#ifdef CONFIG_DEBUG_RSEQ
mov a0, sp
jbsr rseq_syscall
#endif
jmpi ret_from_exception
csky_syscall_trace:
mov a0, sp /* sp = pt_regs pointer */
jbsr syscall_trace_enter
cmpnei a0, 0
bt 1f
/* Prepare args before do system call */
ldw a0, (sp, LSAVE_A0)
ldw a1, (sp, LSAVE_A1)
ldw a2, (sp, LSAVE_A2)
ldw a3, (sp, LSAVE_A3)
#if defined(__CSKYABIV2__)
subi sp, 8
ldw r9, (sp, LSAVE_A4)
stw r9, (sp, 0x0)
ldw r9, (sp, LSAVE_A5)
stw r9, (sp, 0x4)
jsr syscallid /* Do system call */
addi sp, 8
#else
ldw r6, (sp, LSAVE_A4)
ldw r7, (sp, LSAVE_A5)
jsr syscallid /* Do system call */
#endif
stw a0, (sp, LSAVE_A0) /* Save return value */
1:
#ifdef CONFIG_DEBUG_RSEQ
mov a0, sp
jbsr rseq_syscall
#endif
mov a0, sp /* right now, sp --> pt_regs */
jbsr syscall_trace_exit
br ret_from_exception
ENTRY(ret_from_kernel_thread)
jbsr schedule_tail
mov a0, r10
jsr r9
jbsr ret_from_exception
ENTRY(ret_from_fork)
jbsr schedule_tail
mov r9, sp
bmaski r10, THREAD_SHIFT
andn r9, r10
ldw r10, (r9, TINFO_FLAGS)
lrw r9, _TIF_SYSCALL_WORK
and r10, r9
cmpnei r10, 0
bf ret_from_exception
mov a0, sp /* sp = pt_regs pointer */
jbsr syscall_trace_exit
ret_from_exception:
psrclr ie
ld r9, (sp, LSAVE_PSR)
btsti r9, 31
bt 1f
/*
* Load address of current->thread_info, Then get address of task_struct
* Get task_needreshed in task_struct
*/
mov r9, sp
bmaski r10, THREAD_SHIFT
andn r9, r10
ldw r10, (r9, TINFO_FLAGS)
lrw r9, _TIF_WORK_MASK
and r10, r9
cmpnei r10, 0
bt exit_work
#ifdef CONFIG_CONTEXT_TRACKING
jbsr context_tracking_user_enter
#endif
1:
#ifdef CONFIG_PREEMPTION
mov r9, sp
bmaski r10, THREAD_SHIFT
andn r9, r10
ldw r10, (r9, TINFO_PREEMPT)
cmpnei r10, 0
bt 2f
jbsr preempt_schedule_irq /* irq en/disable is done inside */
2:
#endif
#ifdef CONFIG_TRACE_IRQFLAGS
ld r10, (sp, LSAVE_PSR)
btsti r10, 6
bf 2f
jbsr trace_hardirqs_on
2:
#endif
RESTORE_ALL
exit_work:
lrw r9, ret_from_exception
mov lr, r9
btsti r10, TIF_NEED_RESCHED
bt work_resched
psrset ie
mov a0, sp
mov a1, r10
jmpi do_notify_resume
work_resched:
jmpi schedule
ENTRY(csky_trap)
SAVE_ALL 0
zero_fp
context_tracking
psrset ee
mov a0, sp /* Push Stack pointer arg */
jbsr trap_c /* Call C-level trap handler */
jmpi ret_from_exception
/*
* Prototype from libc for abiv1:
* register unsigned int __result asm("a0");
* asm( "trap 3" :"=r"(__result)::);
*/
ENTRY(csky_get_tls)
USPTOKSP
/* increase epc for continue */
mfcr a0, epc
addi a0, TRAP0_SIZE
mtcr a0, epc
/* get current task thread_info with kernel 8K stack */
bmaski a0, THREAD_SHIFT
not a0
subi sp, 1
and a0, sp
addi sp, 1
/* get tls */
ldw a0, (a0, TINFO_TP_VALUE)
KSPTOUSP
rte
ENTRY(csky_irq)
SAVE_ALL 0
zero_fp
context_tracking
psrset ee
#ifdef CONFIG_TRACE_IRQFLAGS
jbsr trace_hardirqs_off
#endif
mov a0, sp
jbsr csky_do_IRQ
jmpi ret_from_exception
/*
* a0 = prev task_struct *
* a1 = next task_struct *
* a0 = return next
*/
ENTRY(__switch_to)
lrw a3, TASK_THREAD
addu a3, a0
SAVE_SWITCH_STACK
stw sp, (a3, THREAD_KSP)
/* Set up next process to run */
lrw a3, TASK_THREAD
addu a3, a1
ldw sp, (a3, THREAD_KSP) /* Set next kernel sp */
#if defined(__CSKYABIV2__)
addi a3, a1, TASK_THREAD_INFO
ldw tls, (a3, TINFO_TP_VALUE)
#endif
RESTORE_SWITCH_STACK
rts
ENDPROC(__switch_to)