root/arch/csky/kernel/entry.S
/* 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/page.h>
#include <asm/thread_info.h>

.macro  zero_fp
#ifdef CONFIG_STACKTRACE
        movi    r8, 0
#endif
.endm

.macro  context_tracking
#ifdef CONFIG_CONTEXT_TRACKING_USER
        mfcr    a0, epsr
        btsti   a0, 31
        bt      1f
        jbsr    user_exit_callable
        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

.text
ENTRY(csky_pagefault)
        SAVE_ALL 0
        zero_fp
        context_tracking
        psrset  ee
        mov     a0, sp
        jbsr    do_page_fault
        jmpi    ret_from_exception

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      ret_from_exception

        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 */
        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:
        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_USER
        jbsr    user_enter_callable
#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

        RD_MEH  a0
        WR_MEH  a0

        /* 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    generic_handle_arch_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)