summaryrefslogtreecommitdiffstats
path: root/arch/csky/abiv2
diff options
context:
space:
mode:
Diffstat (limited to 'arch/csky/abiv2')
-rw-r--r--arch/csky/abiv2/Makefile10
-rw-r--r--arch/csky/abiv2/cacheflush.c60
-rw-r--r--arch/csky/abiv2/fpu.c275
-rw-r--r--arch/csky/abiv2/inc/abi/cacheflush.h46
-rw-r--r--arch/csky/abiv2/inc/abi/ckmmu.h87
-rw-r--r--arch/csky/abiv2/inc/abi/elf.h43
-rw-r--r--arch/csky/abiv2/inc/abi/entry.h156
-rw-r--r--arch/csky/abiv2/inc/abi/fpu.h66
-rw-r--r--arch/csky/abiv2/inc/abi/page.h14
-rw-r--r--arch/csky/abiv2/inc/abi/pgtable-bits.h37
-rw-r--r--arch/csky/abiv2/inc/abi/reg_ops.h17
-rw-r--r--arch/csky/abiv2/inc/abi/regdef.h26
-rw-r--r--arch/csky/abiv2/inc/abi/string.h27
-rw-r--r--arch/csky/abiv2/inc/abi/vdso.h23
-rw-r--r--arch/csky/abiv2/memcmp.S152
-rw-r--r--arch/csky/abiv2/memcpy.S110
-rw-r--r--arch/csky/abiv2/memmove.S108
-rw-r--r--arch/csky/abiv2/memset.S83
-rw-r--r--arch/csky/abiv2/strcmp.S168
-rw-r--r--arch/csky/abiv2/strcpy.S123
-rw-r--r--arch/csky/abiv2/strksyms.c12
-rw-r--r--arch/csky/abiv2/strlen.S97
-rw-r--r--arch/csky/abiv2/sysdep.h30
23 files changed, 1770 insertions, 0 deletions
diff --git a/arch/csky/abiv2/Makefile b/arch/csky/abiv2/Makefile
new file mode 100644
index 0000000000000..069ca7276b99a
--- /dev/null
+++ b/arch/csky/abiv2/Makefile
@@ -0,0 +1,10 @@
+obj-y += cacheflush.o
+obj-$(CONFIG_CPU_HAS_FPU) += fpu.o
+obj-y += memcmp.o
+obj-y += memcpy.o
+obj-y += memmove.o
+obj-y += memset.o
+obj-y += strcmp.o
+obj-y += strcpy.o
+obj-y += strlen.o
+obj-y += strksyms.o
diff --git a/arch/csky/abiv2/cacheflush.c b/arch/csky/abiv2/cacheflush.c
new file mode 100644
index 0000000000000..d22c95ffc74dc
--- /dev/null
+++ b/arch/csky/abiv2/cacheflush.c
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
+
+#include <linux/cache.h>
+#include <linux/highmem.h>
+#include <linux/mm.h>
+#include <asm/cache.h>
+
+void flush_icache_page(struct vm_area_struct *vma, struct page *page)
+{
+ unsigned long start;
+
+ start = (unsigned long) kmap_atomic(page);
+
+ cache_wbinv_range(start, start + PAGE_SIZE);
+
+ kunmap_atomic((void *)start);
+}
+
+void flush_icache_user_range(struct vm_area_struct *vma, struct page *page,
+ unsigned long vaddr, int len)
+{
+ unsigned long kaddr;
+
+ kaddr = (unsigned long) kmap_atomic(page) + (vaddr & ~PAGE_MASK);
+
+ cache_wbinv_range(kaddr, kaddr + len);
+
+ kunmap_atomic((void *)kaddr);
+}
+
+void update_mmu_cache(struct vm_area_struct *vma, unsigned long address,
+ pte_t *pte)
+{
+ unsigned long addr, pfn;
+ struct page *page;
+ void *va;
+
+ if (!(vma->vm_flags & VM_EXEC))
+ return;
+
+ pfn = pte_pfn(*pte);
+ if (unlikely(!pfn_valid(pfn)))
+ return;
+
+ page = pfn_to_page(pfn);
+ if (page == ZERO_PAGE(0))
+ return;
+
+ va = page_address(page);
+ addr = (unsigned long) va;
+
+ if (va == NULL && PageHighMem(page))
+ addr = (unsigned long) kmap_atomic(page);
+
+ cache_wbinv_range(addr, addr + PAGE_SIZE);
+
+ if (va == NULL && PageHighMem(page))
+ kunmap_atomic((void *) addr);
+}
diff --git a/arch/csky/abiv2/fpu.c b/arch/csky/abiv2/fpu.c
new file mode 100644
index 0000000000000..e7e11344005af
--- /dev/null
+++ b/arch/csky/abiv2/fpu.c
@@ -0,0 +1,275 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
+
+#include <linux/ptrace.h>
+#include <linux/uaccess.h>
+#include <abi/reg_ops.h>
+
+#define MTCR_MASK 0xFC00FFE0
+#define MFCR_MASK 0xFC00FFE0
+#define MTCR_DIST 0xC0006420
+#define MFCR_DIST 0xC0006020
+
+void __init init_fpu(void)
+{
+ mtcr("cr<1, 2>", 0);
+}
+
+/*
+ * fpu_libc_helper() is to help libc to excute:
+ * - mfcr %a, cr<1, 2>
+ * - mfcr %a, cr<2, 2>
+ * - mtcr %a, cr<1, 2>
+ * - mtcr %a, cr<2, 2>
+ */
+int fpu_libc_helper(struct pt_regs *regs)
+{
+ int fault;
+ unsigned long instrptr, regx = 0;
+ unsigned long index = 0, tmp = 0;
+ unsigned long tinstr = 0;
+ u16 instr_hi, instr_low;
+
+ instrptr = instruction_pointer(regs);
+ if (instrptr & 1)
+ return 0;
+
+ fault = __get_user(instr_low, (u16 *)instrptr);
+ if (fault)
+ return 0;
+
+ fault = __get_user(instr_hi, (u16 *)(instrptr + 2));
+ if (fault)
+ return 0;
+
+ tinstr = instr_hi | ((unsigned long)instr_low << 16);
+
+ if (((tinstr >> 21) & 0x1F) != 2)
+ return 0;
+
+ if ((tinstr & MTCR_MASK) == MTCR_DIST) {
+ index = (tinstr >> 16) & 0x1F;
+ if (index > 13)
+ return 0;
+
+ tmp = tinstr & 0x1F;
+ if (tmp > 2)
+ return 0;
+
+ regx = *(&regs->a0 + index);
+
+ if (tmp == 1)
+ mtcr("cr<1, 2>", regx);
+ else if (tmp == 2)
+ mtcr("cr<2, 2>", regx);
+ else
+ return 0;
+
+ regs->pc += 4;
+ return 1;
+ }
+
+ if ((tinstr & MFCR_MASK) == MFCR_DIST) {
+ index = tinstr & 0x1F;
+ if (index > 13)
+ return 0;
+
+ tmp = ((tinstr >> 16) & 0x1F);
+ if (tmp > 2)
+ return 0;
+
+ if (tmp == 1)
+ regx = mfcr("cr<1, 2>");
+ else if (tmp == 2)
+ regx = mfcr("cr<2, 2>");
+ else
+ return 0;
+
+ *(&regs->a0 + index) = regx;
+
+ regs->pc += 4;
+ return 1;
+ }
+
+ return 0;
+}
+
+void fpu_fpe(struct pt_regs *regs)
+{
+ int sig, code;
+ unsigned int fesr;
+
+ fesr = mfcr("cr<2, 2>");
+
+ sig = SIGFPE;
+ code = FPE_FLTUNK;
+
+ if (fesr & FPE_ILLE) {
+ sig = SIGILL;
+ code = ILL_ILLOPC;
+ } else if (fesr & FPE_IDC) {
+ sig = SIGILL;
+ code = ILL_ILLOPN;
+ } else if (fesr & FPE_FEC) {
+ sig = SIGFPE;
+ if (fesr & FPE_IOC)
+ code = FPE_FLTINV;
+ else if (fesr & FPE_DZC)
+ code = FPE_FLTDIV;
+ else if (fesr & FPE_UFC)
+ code = FPE_FLTUND;
+ else if (fesr & FPE_OFC)
+ code = FPE_FLTOVF;
+ else if (fesr & FPE_IXC)
+ code = FPE_FLTRES;
+ }
+
+ force_sig_fault(sig, code, (void __user *)regs->pc, current);
+}
+
+#define FMFVR_FPU_REGS(vrx, vry) \
+ "fmfvrl %0, "#vrx"\n" \
+ "fmfvrh %1, "#vrx"\n" \
+ "fmfvrl %2, "#vry"\n" \
+ "fmfvrh %3, "#vry"\n"
+
+#define FMTVR_FPU_REGS(vrx, vry) \
+ "fmtvrl "#vrx", %0\n" \
+ "fmtvrh "#vrx", %1\n" \
+ "fmtvrl "#vry", %2\n" \
+ "fmtvrh "#vry", %3\n"
+
+#define STW_FPU_REGS(a, b, c, d) \
+ "stw %0, (%4, "#a")\n" \
+ "stw %1, (%4, "#b")\n" \
+ "stw %2, (%4, "#c")\n" \
+ "stw %3, (%4, "#d")\n"
+
+#define LDW_FPU_REGS(a, b, c, d) \
+ "ldw %0, (%4, "#a")\n" \
+ "ldw %1, (%4, "#b")\n" \
+ "ldw %2, (%4, "#c")\n" \
+ "ldw %3, (%4, "#d")\n"
+
+void save_to_user_fp(struct user_fp *user_fp)
+{
+ unsigned long flg;
+ unsigned long tmp1, tmp2;
+ unsigned long *fpregs;
+
+ local_irq_save(flg);
+
+ tmp1 = mfcr("cr<1, 2>");
+ tmp2 = mfcr("cr<2, 2>");
+
+ user_fp->fcr = tmp1;
+ user_fp->fesr = tmp2;
+
+ fpregs = &user_fp->vr[0];
+#ifdef CONFIG_CPU_HAS_FPUV2
+#ifdef CONFIG_CPU_HAS_VDSP
+ asm volatile(
+ "vstmu.32 vr0-vr3, (%0)\n"
+ "vstmu.32 vr4-vr7, (%0)\n"
+ "vstmu.32 vr8-vr11, (%0)\n"
+ "vstmu.32 vr12-vr15, (%0)\n"
+ "fstmu.64 vr16-vr31, (%0)\n"
+ : "+a"(fpregs)
+ ::"memory");
+#else
+ asm volatile(
+ "fstmu.64 vr0-vr31, (%0)\n"
+ : "+a"(fpregs)
+ ::"memory");
+#endif
+#else
+ {
+ unsigned long tmp3, tmp4;
+
+ asm volatile(
+ FMFVR_FPU_REGS(vr0, vr1)
+ STW_FPU_REGS(0, 4, 16, 20)
+ FMFVR_FPU_REGS(vr2, vr3)
+ STW_FPU_REGS(32, 36, 48, 52)
+ FMFVR_FPU_REGS(vr4, vr5)
+ STW_FPU_REGS(64, 68, 80, 84)
+ FMFVR_FPU_REGS(vr6, vr7)
+ STW_FPU_REGS(96, 100, 112, 116)
+ "addi %4, 128\n"
+ FMFVR_FPU_REGS(vr8, vr9)
+ STW_FPU_REGS(0, 4, 16, 20)
+ FMFVR_FPU_REGS(vr10, vr11)
+ STW_FPU_REGS(32, 36, 48, 52)
+ FMFVR_FPU_REGS(vr12, vr13)
+ STW_FPU_REGS(64, 68, 80, 84)
+ FMFVR_FPU_REGS(vr14, vr15)
+ STW_FPU_REGS(96, 100, 112, 116)
+ : "=a"(tmp1), "=a"(tmp2), "=a"(tmp3),
+ "=a"(tmp4), "+a"(fpregs)
+ ::"memory");
+ }
+#endif
+
+ local_irq_restore(flg);
+}
+
+void restore_from_user_fp(struct user_fp *user_fp)
+{
+ unsigned long flg;
+ unsigned long tmp1, tmp2;
+ unsigned long *fpregs;
+
+ local_irq_save(flg);
+
+ tmp1 = user_fp->fcr;
+ tmp2 = user_fp->fesr;
+
+ mtcr("cr<1, 2>", tmp1);
+ mtcr("cr<2, 2>", tmp2);
+
+ fpregs = &user_fp->vr[0];
+#ifdef CONFIG_CPU_HAS_FPUV2
+#ifdef CONFIG_CPU_HAS_VDSP
+ asm volatile(
+ "vldmu.32 vr0-vr3, (%0)\n"
+ "vldmu.32 vr4-vr7, (%0)\n"
+ "vldmu.32 vr8-vr11, (%0)\n"
+ "vldmu.32 vr12-vr15, (%0)\n"
+ "fldmu.64 vr16-vr31, (%0)\n"
+ : "+a"(fpregs)
+ ::"memory");
+#else
+ asm volatile(
+ "fldmu.64 vr0-vr31, (%0)\n"
+ : "+a"(fpregs)
+ ::"memory");
+#endif
+#else
+ {
+ unsigned long tmp3, tmp4;
+
+ asm volatile(
+ LDW_FPU_REGS(0, 4, 16, 20)
+ FMTVR_FPU_REGS(vr0, vr1)
+ LDW_FPU_REGS(32, 36, 48, 52)
+ FMTVR_FPU_REGS(vr2, vr3)
+ LDW_FPU_REGS(64, 68, 80, 84)
+ FMTVR_FPU_REGS(vr4, vr5)
+ LDW_FPU_REGS(96, 100, 112, 116)
+ FMTVR_FPU_REGS(vr6, vr7)
+ "addi %4, 128\n"
+ LDW_FPU_REGS(0, 4, 16, 20)
+ FMTVR_FPU_REGS(vr8, vr9)
+ LDW_FPU_REGS(32, 36, 48, 52)
+ FMTVR_FPU_REGS(vr10, vr11)
+ LDW_FPU_REGS(64, 68, 80, 84)
+ FMTVR_FPU_REGS(vr12, vr13)
+ LDW_FPU_REGS(96, 100, 112, 116)
+ FMTVR_FPU_REGS(vr14, vr15)
+ : "=a"(tmp1), "=a"(tmp2), "=a"(tmp3),
+ "=a"(tmp4), "+a"(fpregs)
+ ::"memory");
+ }
+#endif
+ local_irq_restore(flg);
+}
diff --git a/arch/csky/abiv2/inc/abi/cacheflush.h b/arch/csky/abiv2/inc/abi/cacheflush.h
new file mode 100644
index 0000000000000..b8db5e0b2fe3c
--- /dev/null
+++ b/arch/csky/abiv2/inc/abi/cacheflush.h
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __ABI_CSKY_CACHEFLUSH_H
+#define __ABI_CSKY_CACHEFLUSH_H
+
+/* Keep includes the same across arches. */
+#include <linux/mm.h>
+
+/*
+ * The cache doesn't need to be flushed when TLB entries change when
+ * the cache is mapped to physical memory, not virtual memory
+ */
+#define flush_cache_all() do { } while (0)
+#define flush_cache_mm(mm) do { } while (0)
+#define flush_cache_dup_mm(mm) do { } while (0)
+
+#define flush_cache_range(vma, start, end) \
+ do { \
+ if (vma->vm_flags & VM_EXEC) \
+ icache_inv_all(); \
+ } while (0)
+
+#define flush_cache_page(vma, vmaddr, pfn) do { } while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
+#define flush_dcache_page(page) do { } while (0)
+#define flush_dcache_mmap_lock(mapping) do { } while (0)
+#define flush_dcache_mmap_unlock(mapping) do { } while (0)
+
+#define flush_icache_range(start, end) cache_wbinv_range(start, end)
+
+void flush_icache_page(struct vm_area_struct *vma, struct page *page);
+void flush_icache_user_range(struct vm_area_struct *vma, struct page *page,
+ unsigned long vaddr, int len);
+
+#define flush_cache_vmap(start, end) do { } while (0)
+#define flush_cache_vunmap(start, end) do { } while (0)
+
+#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
+do { \
+ memcpy(dst, src, len); \
+ cache_wbinv_range((unsigned long)dst, (unsigned long)dst + len); \
+} while (0)
+#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
+ memcpy(dst, src, len)
+
+#endif /* __ABI_CSKY_CACHEFLUSH_H */
diff --git a/arch/csky/abiv2/inc/abi/ckmmu.h b/arch/csky/abiv2/inc/abi/ckmmu.h
new file mode 100644
index 0000000000000..97230ad9427c3
--- /dev/null
+++ b/arch/csky/abiv2/inc/abi/ckmmu.h
@@ -0,0 +1,87 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
+
+#ifndef __ASM_CSKY_CKMMUV2_H
+#define __ASM_CSKY_CKMMUV2_H
+
+#include <abi/reg_ops.h>
+#include <asm/barrier.h>
+
+static inline int read_mmu_index(void)
+{
+ return mfcr("cr<0, 15>");
+}
+
+static inline void write_mmu_index(int value)
+{
+ mtcr("cr<0, 15>", value);
+}
+
+static inline int read_mmu_entrylo0(void)
+{
+ return mfcr("cr<2, 15>");
+}
+
+static inline int read_mmu_entrylo1(void)
+{
+ return mfcr("cr<3, 15>");
+}
+
+static inline void write_mmu_pagemask(int value)
+{
+ mtcr("cr<6, 15>", value);
+}
+
+static inline int read_mmu_entryhi(void)
+{
+ return mfcr("cr<4, 15>");
+}
+
+static inline void write_mmu_entryhi(int value)
+{
+ mtcr("cr<4, 15>", value);
+}
+
+/*
+ * TLB operations.
+ */
+static inline void tlb_probe(void)
+{
+ mtcr("cr<8, 15>", 0x80000000);
+}
+
+static inline void tlb_read(void)
+{
+ mtcr("cr<8, 15>", 0x40000000);
+}
+
+static inline void tlb_invalid_all(void)
+{
+#ifdef CONFIG_CPU_HAS_TLBI
+ asm volatile("tlbi.alls\n":::"memory");
+ sync_is();
+#else
+ mtcr("cr<8, 15>", 0x04000000);
+#endif
+}
+
+static inline void tlb_invalid_indexed(void)
+{
+ mtcr("cr<8, 15>", 0x02000000);
+}
+
+/* setup hardrefil pgd */
+static inline unsigned long get_pgd(void)
+{
+ return mfcr("cr<29, 15>");
+}
+
+static inline void setup_pgd(unsigned long pgd, bool kernel)
+{
+ if (kernel)
+ mtcr("cr<28, 15>", pgd);
+ else
+ mtcr("cr<29, 15>", pgd);
+}
+
+#endif /* __ASM_CSKY_CKMMUV2_H */
diff --git a/arch/csky/abiv2/inc/abi/elf.h b/arch/csky/abiv2/inc/abi/elf.h
new file mode 100644
index 0000000000000..290f49ef4c485
--- /dev/null
+++ b/arch/csky/abiv2/inc/abi/elf.h
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __ABI_CSKY_ELF_H
+#define __ABI_CSKY_ELF_H
+
+/* The member sort in array pr_reg[x] is defined by GDB. */
+#define ELF_CORE_COPY_REGS(pr_reg, regs) do { \
+ pr_reg[0] = regs->pc; \
+ pr_reg[1] = regs->a1; \
+ pr_reg[2] = regs->a0; \
+ pr_reg[3] = regs->sr; \
+ pr_reg[4] = regs->a2; \
+ pr_reg[5] = regs->a3; \
+ pr_reg[6] = regs->regs[0]; \
+ pr_reg[7] = regs->regs[1]; \
+ pr_reg[8] = regs->regs[2]; \
+ pr_reg[9] = regs->regs[3]; \
+ pr_reg[10] = regs->regs[4]; \
+ pr_reg[11] = regs->regs[5]; \
+ pr_reg[12] = regs->regs[6]; \
+ pr_reg[13] = regs->regs[7]; \
+ pr_reg[14] = regs->regs[8]; \
+ pr_reg[15] = regs->regs[9]; \
+ pr_reg[16] = regs->usp; \
+ pr_reg[17] = regs->lr; \
+ pr_reg[18] = regs->exregs[0]; \
+ pr_reg[19] = regs->exregs[1]; \
+ pr_reg[20] = regs->exregs[2]; \
+ pr_reg[21] = regs->exregs[3]; \
+ pr_reg[22] = regs->exregs[4]; \
+ pr_reg[23] = regs->exregs[5]; \
+ pr_reg[24] = regs->exregs[6]; \
+ pr_reg[25] = regs->exregs[7]; \
+ pr_reg[26] = regs->exregs[8]; \
+ pr_reg[27] = regs->exregs[9]; \
+ pr_reg[28] = regs->exregs[10]; \
+ pr_reg[29] = regs->exregs[11]; \
+ pr_reg[30] = regs->exregs[12]; \
+ pr_reg[31] = regs->exregs[13]; \
+ pr_reg[32] = regs->exregs[14]; \
+ pr_reg[33] = regs->tls; \
+} while (0);
+#endif /* __ABI_CSKY_ELF_H */
diff --git a/arch/csky/abiv2/inc/abi/entry.h b/arch/csky/abiv2/inc/abi/entry.h
new file mode 100644
index 0000000000000..acd05214d4e3a
--- /dev/null
+++ b/arch/csky/abiv2/inc/abi/entry.h
@@ -0,0 +1,156 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
+
+#ifndef __ASM_CSKY_ENTRY_H
+#define __ASM_CSKY_ENTRY_H
+
+#include <asm/setup.h>
+#include <abi/regdef.h>
+
+#define LSAVE_PC 8
+#define LSAVE_PSR 12
+#define LSAVE_A0 24
+#define LSAVE_A1 28
+#define LSAVE_A2 32
+#define LSAVE_A3 36
+
+#define EPC_INCREASE 4
+#define EPC_KEEP 0
+
+#define KSPTOUSP
+#define USPTOKSP
+
+#define usp cr<14, 1>
+
+.macro INCTRAP rx
+ addi \rx, EPC_INCREASE
+.endm
+
+.macro SAVE_ALL epc_inc
+ subi sp, 152
+ stw tls, (sp, 0)
+ stw lr, (sp, 4)
+
+ mfcr lr, epc
+ movi tls, \epc_inc
+ add lr, tls
+ stw lr, (sp, 8)
+
+ mfcr lr, epsr
+ stw lr, (sp, 12)
+ mfcr lr, usp
+ stw lr, (sp, 16)
+
+ stw a0, (sp, 20)
+ stw a0, (sp, 24)
+ stw a1, (sp, 28)
+ stw a2, (sp, 32)
+ stw a3, (sp, 36)
+
+ addi sp, 40
+ stm r4-r13, (sp)
+
+ addi sp, 40
+ stm r16-r30, (sp)
+#ifdef CONFIG_CPU_HAS_HILO
+ mfhi lr
+ stw lr, (sp, 60)
+ mflo lr
+ stw lr, (sp, 64)
+#endif
+ subi sp, 80
+.endm
+
+.macro RESTORE_ALL
+ psrclr ie
+ ldw tls, (sp, 0)
+ ldw lr, (sp, 4)
+ ldw a0, (sp, 8)
+ mtcr a0, epc
+ ldw a0, (sp, 12)
+ mtcr a0, epsr
+ ldw a0, (sp, 16)
+ mtcr a0, usp
+
+#ifdef CONFIG_CPU_HAS_HILO
+ ldw a0, (sp, 140)
+ mthi a0
+ ldw a0, (sp, 144)
+ mtlo a0
+#endif
+
+ ldw a0, (sp, 24)
+ ldw a1, (sp, 28)
+ ldw a2, (sp, 32)
+ ldw a3, (sp, 36)
+
+ addi sp, 40
+ ldm r4-r13, (sp)
+ addi sp, 40
+ ldm r16-r30, (sp)
+ addi sp, 72
+ rte
+.endm
+
+.macro SAVE_SWITCH_STACK
+ subi sp, 64
+ stm r4-r11, (sp)
+ stw r15, (sp, 32)
+ stw r16, (sp, 36)
+ stw r17, (sp, 40)
+ stw r26, (sp, 44)
+ stw r27, (sp, 48)
+ stw r28, (sp, 52)
+ stw r29, (sp, 56)
+ stw r30, (sp, 60)
+.endm
+
+.macro RESTORE_SWITCH_STACK
+ ldm r4-r11, (sp)
+ ldw r15, (sp, 32)
+ ldw r16, (sp, 36)
+ ldw r17, (sp, 40)
+ ldw r26, (sp, 44)
+ ldw r27, (sp, 48)
+ ldw r28, (sp, 52)
+ ldw r29, (sp, 56)
+ ldw r30, (sp, 60)
+ addi sp, 64
+.endm
+
+/* MMU registers operators. */
+.macro RD_MIR rx
+ mfcr \rx, cr<0, 15>
+.endm
+
+.macro RD_MEH rx
+ mfcr \rx, cr<4, 15>
+.endm
+
+.macro RD_MCIR rx
+ mfcr \rx, cr<8, 15>
+.endm
+
+.macro RD_PGDR rx
+ mfcr \rx, cr<29, 15>
+.endm
+
+.macro RD_PGDR_K rx
+ mfcr \rx, cr<28, 15>
+.endm
+
+.macro WR_MEH rx
+ mtcr \rx, cr<4, 15>
+.endm
+
+.macro WR_MCIR rx
+ mtcr \rx, cr<8, 15>
+.endm
+
+.macro SETUP_MMU rx
+ lrw \rx, PHYS_OFFSET | 0xe
+ mtcr \rx, cr<30, 15>
+ lrw \rx, (PHYS_OFFSET + 0x20000000) | 0xe
+ mtcr \rx, cr<31, 15>
+.endm
+#endif /* __ASM_CSKY_ENTRY_H */
diff --git a/arch/csky/abiv2/inc/abi/fpu.h b/arch/csky/abiv2/inc/abi/fpu.h
new file mode 100644
index 0000000000000..22ca3cf2794a1
--- /dev/null
+++ b/arch/csky/abiv2/inc/abi/fpu.h
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
+
+#ifndef __ASM_CSKY_FPU_H
+#define __ASM_CSKY_FPU_H
+
+#include <asm/sigcontext.h>
+#include <asm/ptrace.h>
+
+int fpu_libc_helper(struct pt_regs *regs);
+void fpu_fpe(struct pt_regs *regs);
+void __init init_fpu(void);
+
+void save_to_user_fp(struct user_fp *user_fp);
+void restore_from_user_fp(struct user_fp *user_fp);
+
+/*
+ * Define the fesr bit for fpe handle.
+ */
+#define FPE_ILLE (1 << 16) /* Illegal instruction */
+#define FPE_FEC (1 << 7) /* Input float-point arithmetic exception */
+#define FPE_IDC (1 << 5) /* Input denormalized exception */
+#define FPE_IXC (1 << 4) /* Inexact exception */
+#define FPE_UFC (1 << 3) /* Underflow exception */
+#define FPE_OFC (1 << 2) /* Overflow exception */
+#define FPE_DZC (1 << 1) /* Divide by zero exception */
+#define FPE_IOC (1 << 0) /* Invalid operation exception */
+#define FPE_REGULAR_EXCEPTION (FPE_IXC | FPE_UFC | FPE_OFC | FPE_DZC | FPE_IOC)
+
+#ifdef CONFIG_OPEN_FPU_IDE
+#define IDE_STAT (1 << 5)
+#else
+#define IDE_STAT 0
+#endif
+
+#ifdef CONFIG_OPEN_FPU_IXE
+#define IXE_STAT (1 << 4)
+#else
+#define IXE_STAT 0
+#endif
+
+#ifdef CONFIG_OPEN_FPU_UFE
+#define UFE_STAT (1 << 3)
+#else
+#define UFE_STAT 0
+#endif
+
+#ifdef CONFIG_OPEN_FPU_OFE
+#define OFE_STAT (1 << 2)
+#else
+#define OFE_STAT 0
+#endif
+
+#ifdef CONFIG_OPEN_FPU_DZE
+#define DZE_STAT (1 << 1)
+#else
+#define DZE_STAT 0
+#endif
+
+#ifdef CONFIG_OPEN_FPU_IOE
+#define IOE_STAT (1 << 0)
+#else
+#define IOE_STAT 0
+#endif
+
+#endif /* __ASM_CSKY_FPU_H */
diff --git a/arch/csky/abiv2/inc/abi/page.h b/arch/csky/abiv2/inc/abi/page.h
new file mode 100644
index 0000000000000..0a70cb553dca9
--- /dev/null
+++ b/arch/csky/abiv2/inc/abi/page.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
+
+static inline void clear_user_page(void *addr, unsigned long vaddr,
+ struct page *page)
+{
+ clear_page(addr);
+}
+
+static inline void copy_user_page(void *to, void *from, unsigned long vaddr,
+ struct page *page)
+{
+ copy_page(to, from);
+}
diff --git a/arch/csky/abiv2/inc/abi/pgtable-bits.h b/arch/csky/abiv2/inc/abi/pgtable-bits.h
new file mode 100644
index 0000000000000..b20ae19702e3c
--- /dev/null
+++ b/arch/csky/abiv2/inc/abi/pgtable-bits.h
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
+
+#ifndef __ASM_CSKY_PGTABLE_BITS_H
+#define __ASM_CSKY_PGTABLE_BITS_H
+
+/* implemented in software */
+#define _PAGE_ACCESSED (1<<7)
+#define PAGE_ACCESSED_BIT (7)
+
+#define _PAGE_READ (1<<8)
+#define _PAGE_WRITE (1<<9)
+#define _PAGE_PRESENT (1<<10)
+
+#define _PAGE_MODIFIED (1<<11)
+#define PAGE_MODIFIED_BIT (11)
+
+/* implemented in hardware */
+#define _PAGE_GLOBAL (1<<0)
+
+#define _PAGE_VALID (1<<1)
+#define PAGE_VALID_BIT (1)
+
+#define _PAGE_DIRTY (1<<2)
+#define PAGE_DIRTY_BIT (2)
+
+#define _PAGE_SO (1<<5)
+#define _PAGE_BUF (1<<6)
+
+#define _PAGE_CACHE (1<<3)
+
+#define _CACHE_MASK _PAGE_CACHE
+
+#define _CACHE_CACHED (_PAGE_VALID | _PAGE_CACHE | _PAGE_BUF)
+#define _CACHE_UNCACHED (_PAGE_VALID | _PAGE_SO)
+
+#endif /* __ASM_CSKY_PGTABLE_BITS_H */
diff --git a/arch/csky/abiv2/inc/abi/reg_ops.h b/arch/csky/abiv2/inc/abi/reg_ops.h
new file mode 100644
index 0000000000000..ae82c3f26a6b8
--- /dev/null
+++ b/arch/csky/abiv2/inc/abi/reg_ops.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
+
+#ifndef __ABI_REG_OPS_H
+#define __ABI_REG_OPS_H
+#include <asm/reg_ops.h>
+
+static inline unsigned int mfcr_hint(void)
+{
+ return mfcr("cr31");
+}
+
+static inline unsigned int mfcr_ccr2(void)
+{
+ return mfcr("cr23");
+}
+#endif /* __ABI_REG_OPS_H */
diff --git a/arch/csky/abiv2/inc/abi/regdef.h b/arch/csky/abiv2/inc/abi/regdef.h
new file mode 100644
index 0000000000000..c72abb781bdc4
--- /dev/null
+++ b/arch/csky/abiv2/inc/abi/regdef.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
+
+#ifndef __ASM_CSKY_REGDEF_H
+#define __ASM_CSKY_REGDEF_H
+
+#define syscallid r7
+#define r11_sig r11
+
+#define regs_syscallid(regs) regs->regs[3]
+
+/*
+ * PSR format:
+ * | 31 | 30-24 | 23-16 | 15 14 | 13-10 | 9 | 8-0 |
+ * S VEC TM MM
+ *
+ * S: Super Mode
+ * VEC: Exception Number
+ * TM: Trace Mode
+ * MM: Memory unaligned addr access
+ */
+#define DEFAULT_PSR_VALUE 0x80000200
+
+#define SYSTRACE_SAVENUM 5
+
+#endif /* __ASM_CSKY_REGDEF_H */
diff --git a/arch/csky/abiv2/inc/abi/string.h b/arch/csky/abiv2/inc/abi/string.h
new file mode 100644
index 0000000000000..f01bad2ac4fba
--- /dev/null
+++ b/arch/csky/abiv2/inc/abi/string.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __ABI_CSKY_STRING_H
+#define __ABI_CSKY_STRING_H
+
+#define __HAVE_ARCH_MEMCMP
+extern int memcmp(const void *, const void *, __kernel_size_t);
+
+#define __HAVE_ARCH_MEMCPY
+extern void *memcpy(void *, const void *, __kernel_size_t);
+
+#define __HAVE_ARCH_MEMMOVE
+extern void *memmove(void *, const void *, __kernel_size_t);
+
+#define __HAVE_ARCH_MEMSET
+extern void *memset(void *, int, __kernel_size_t);
+
+#define __HAVE_ARCH_STRCMP
+extern int strcmp(const char *, const char *);
+
+#define __HAVE_ARCH_STRCPY
+extern char *strcpy(char *, const char *);
+
+#define __HAVE_ARCH_STRLEN
+extern __kernel_size_t strlen(const char *);
+
+#endif /* __ABI_CSKY_STRING_H */
diff --git a/arch/csky/abiv2/inc/abi/vdso.h b/arch/csky/abiv2/inc/abi/vdso.h
new file mode 100644
index 0000000000000..b60d4a0703263
--- /dev/null
+++ b/arch/csky/abiv2/inc/abi/vdso.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __ABI_CSKY_VDSO_H
+#define __ABI_CSKY_VDSO_H
+
+#include <linux/uaccess.h>
+
+static inline int setup_vdso_page(unsigned short *ptr)
+{
+ int err = 0;
+
+ /* movi r7, 173 */
+ err |= __put_user(0xea07, ptr);
+ err |= __put_user(0x008b, ptr+1);
+
+ /* trap 0 */
+ err |= __put_user(0xc000, ptr+2);
+ err |= __put_user(0x2020, ptr+3);
+
+ return err;
+}
+
+#endif /* __ABI_CSKY_STRING_H */
diff --git a/arch/csky/abiv2/memcmp.S b/arch/csky/abiv2/memcmp.S
new file mode 100644
index 0000000000000..bf0d809f09e22
--- /dev/null
+++ b/arch/csky/abiv2/memcmp.S
@@ -0,0 +1,152 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
+
+#include <linux/linkage.h>
+#include "sysdep.h"
+
+ENTRY(memcmp)
+ /* Test if len less than 4 bytes. */
+ mov r3, r0
+ movi r0, 0
+ mov r12, r4
+ cmplti r2, 4
+ bt .L_compare_by_byte
+
+ andi r13, r0, 3
+ movi r19, 4
+
+ /* Test if s1 is not 4 bytes aligned. */
+ bnez r13, .L_s1_not_aligned
+
+ LABLE_ALIGN
+.L_s1_aligned:
+ /* If dest is aligned, then copy. */
+ zext r18, r2, 31, 4
+ /* Test if len less than 16 bytes. */
+ bez r18, .L_compare_by_word
+
+.L_compare_by_4word:
+ /* If aligned, load word each time. */
+ ldw r20, (r3, 0)
+ ldw r21, (r1, 0)
+ /* If s1[i] != s2[i], goto .L_byte_check. */
+ cmpne r20, r21
+ bt .L_byte_check
+
+ ldw r20, (r3, 4)
+ ldw r21, (r1, 4)
+ cmpne r20, r21
+ bt .L_byte_check
+
+ ldw r20, (r3, 8)
+ ldw r21, (r1, 8)
+ cmpne r20, r21
+ bt .L_byte_check
+
+ ldw r20, (r3, 12)
+ ldw r21, (r1, 12)
+ cmpne r20, r21
+ bt .L_byte_check
+
+ PRE_BNEZAD (r18)
+ addi a3, 16
+ addi a1, 16
+
+ BNEZAD (r18, .L_compare_by_4word)
+
+.L_compare_by_word:
+ zext r18, r2, 3, 2
+ bez r18, .L_compare_by_byte
+.L_compare_by_word_loop:
+ ldw r20, (r3, 0)
+ ldw r21, (r1, 0)
+ addi r3, 4
+ PRE_BNEZAD (r18)
+ cmpne r20, r21
+ addi r1, 4
+ bt .L_byte_check
+ BNEZAD (r18, .L_compare_by_word_loop)
+
+.L_compare_by_byte:
+ zext r18, r2, 1, 0
+ bez r18, .L_return
+.L_compare_by_byte_loop:
+ ldb r0, (r3, 0)
+ ldb r4, (r1, 0)
+ addi r3, 1
+ subu r0, r4
+ PRE_BNEZAD (r18)
+ addi r1, 1
+ bnez r0, .L_return
+ BNEZAD (r18, .L_compare_by_byte_loop)
+
+.L_return:
+ mov r4, r12
+ rts
+
+# ifdef __CSKYBE__
+/* d[i] != s[i] in word, so we check byte 0. */
+.L_byte_check:
+ xtrb0 r0, r20
+ xtrb0 r2, r21
+ subu r0, r2
+ bnez r0, .L_return
+
+ /* check byte 1 */
+ xtrb1 r0, r20
+ xtrb1 r2, r21
+ subu r0, r2
+ bnez r0, .L_return
+
+ /* check byte 2 */
+ xtrb2 r0, r20
+ xtrb2 r2, r21
+ subu r0, r2
+ bnez r0, .L_return
+
+ /* check byte 3 */
+ xtrb3 r0, r20
+ xtrb3 r2, r21
+ subu r0, r2
+# else
+/* s1[i] != s2[i] in word, so we check byte 3. */
+.L_byte_check:
+ xtrb3 r0, r20
+ xtrb3 r2, r21
+ subu r0, r2
+ bnez r0, .L_return
+
+ /* check byte 2 */
+ xtrb2 r0, r20
+ xtrb2 r2, r21
+ subu r0, r2
+ bnez r0, .L_return
+
+ /* check byte 1 */
+ xtrb1 r0, r20
+ xtrb1 r2, r21
+ subu r0, r2
+ bnez r0, .L_return
+
+ /* check byte 0 */
+ xtrb0 r0, r20
+ xtrb0 r2, r21
+ subu r0, r2
+ br .L_return
+# endif /* !__CSKYBE__ */
+
+/* Compare when s1 is not aligned. */
+.L_s1_not_aligned:
+ sub r13, r19, r13
+ sub r2, r13
+.L_s1_not_aligned_loop:
+ ldb r0, (r3, 0)
+ ldb r4, (r1, 0)
+ addi r3, 1
+ subu r0, r4
+ PRE_BNEZAD (r13)
+ addi r1, 1
+ bnez r0, .L_return
+ BNEZAD (r13, .L_s1_not_aligned_loop)
+ br .L_s1_aligned
+ENDPROC(memcmp)
diff --git a/arch/csky/abiv2/memcpy.S b/arch/csky/abiv2/memcpy.S
new file mode 100644
index 0000000000000..987fec60ab97d
--- /dev/null
+++ b/arch/csky/abiv2/memcpy.S
@@ -0,0 +1,110 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
+
+#include <linux/linkage.h>
+#include "sysdep.h"
+
+ENTRY(__memcpy)
+ENTRY(memcpy)
+ /* Test if len less than 4 bytes. */
+ mov r12, r0
+ cmplti r2, 4
+ bt .L_copy_by_byte
+
+ andi r13, r0, 3
+ movi r19, 4
+ /* Test if dest is not 4 bytes aligned. */
+ bnez r13, .L_dest_not_aligned
+
+/* Hardware can handle unaligned access directly. */
+.L_dest_aligned:
+ /* If dest is aligned, then copy. */
+ zext r18, r2, 31, 4
+
+ /* Test if len less than 16 bytes. */
+ bez r18, .L_len_less_16bytes
+ movi r19, 0
+
+ LABLE_ALIGN
+.L_len_larger_16bytes:
+#if defined(__CSKY_VDSPV2__)
+ vldx.8 vr0, (r1), r19
+ PRE_BNEZAD (r18)
+ addi r1, 16
+ vstx.8 vr0, (r0), r19
+ addi r0, 16
+#elif defined(__CK860__)
+ ldw r3, (r1, 0)
+ stw r3, (r0, 0)
+ ldw r3, (r1, 4)
+ stw r3, (r0, 4)
+ ldw r3, (r1, 8)
+ stw r3, (r0, 8)
+ ldw r3, (r1, 12)
+ addi r1, 16
+ stw r3, (r0, 12)
+ addi r0, 16
+#else
+ ldw r20, (r1, 0)
+ ldw r21, (r1, 4)
+ ldw r22, (r1, 8)
+ ldw r23, (r1, 12)
+ stw r20, (r0, 0)
+ stw r21, (r0, 4)
+ stw r22, (r0, 8)
+ stw r23, (r0, 12)
+ PRE_BNEZAD (r18)
+ addi r1, 16
+ addi r0, 16
+#endif
+ BNEZAD (r18, .L_len_larger_16bytes)
+
+.L_len_less_16bytes:
+ zext r18, r2, 3, 2
+ bez r18, .L_copy_by_byte
+.L_len_less_16bytes_loop:
+ ldw r3, (r1, 0)
+ PRE_BNEZAD (r18)
+ addi r1, 4
+ stw r3, (r0, 0)
+ addi r0, 4
+ BNEZAD (r18, .L_len_less_16bytes_loop)
+
+/* Test if len less than 4 bytes. */
+.L_copy_by_byte:
+ zext r18, r2, 1, 0
+ bez r18, .L_return
+.L_copy_by_byte_loop:
+ ldb r3, (r1, 0)
+ PRE_BNEZAD (r18)
+ addi r1, 1
+ stb r3, (r0, 0)
+ addi r0, 1
+ BNEZAD (r18, .L_copy_by_byte_loop)
+
+.L_return:
+ mov r0, r12
+ rts
+
+/*
+ * If dest is not aligned, just copying some bytes makes the
+ * dest align.
+ */
+.L_dest_not_aligned:
+ sub r13, r19, r13
+ sub r2, r13
+
+/* Makes the dest align. */
+.L_dest_not_aligned_loop:
+ ldb r3, (r1, 0)
+ PRE_BNEZAD (r13)
+ addi r1, 1
+ stb r3, (r0, 0)
+ addi r0, 1
+ BNEZAD (r13, .L_dest_not_aligned_loop)
+ cmplti r2, 4
+ bt .L_copy_by_byte
+
+ /* Check whether the src is aligned. */
+ jbr .L_dest_aligned
+ENDPROC(__memcpy)
diff --git a/arch/csky/abiv2/memmove.S b/arch/csky/abiv2/memmove.S
new file mode 100644
index 0000000000000..b0c42ecf18896
--- /dev/null
+++ b/arch/csky/abiv2/memmove.S
@@ -0,0 +1,108 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
+
+#include <linux/linkage.h>
+#include "sysdep.h"
+
+ .weak memmove
+ENTRY(__memmove)
+ENTRY(memmove)
+ subu r3, r0, r1
+ cmphs r3, r2
+ bt memcpy
+
+ mov r12, r0
+ addu r0, r0, r2
+ addu r1, r1, r2
+
+ /* Test if len less than 4 bytes. */
+ cmplti r2, 4
+ bt .L_copy_by_byte
+
+ andi r13, r0, 3
+ /* Test if dest is not 4 bytes aligned. */
+ bnez r13, .L_dest_not_aligned
+ /* Hardware can handle unaligned access directly. */
+.L_dest_aligned:
+ /* If dest is aligned, then copy. */
+ zext r18, r2, 31, 4
+ /* Test if len less than 16 bytes. */
+ bez r18, .L_len_less_16bytes
+ movi r19, 0
+
+ /* len > 16 bytes */
+ LABLE_ALIGN
+.L_len_larger_16bytes:
+ subi r1, 16
+ subi r0, 16
+#if defined(__CSKY_VDSPV2__)
+ vldx.8 vr0, (r1), r19
+ PRE_BNEZAD (r18)
+ vstx.8 vr0, (r0), r19
+#elif defined(__CK860__)
+ ldw r3, (r1, 12)
+ stw r3, (r0, 12)
+ ldw r3, (r1, 8)
+ stw r3, (r0, 8)
+ ldw r3, (r1, 4)
+ stw r3, (r0, 4)
+ ldw r3, (r1, 0)
+ stw r3, (r0, 0)
+#else
+ ldw r20, (r1, 0)
+ ldw r21, (r1, 4)
+ ldw r22, (r1, 8)
+ ldw r23, (r1, 12)
+ stw r20, (r0, 0)
+ stw r21, (r0, 4)
+ stw r22, (r0, 8)
+ stw r23, (r0, 12)
+ PRE_BNEZAD (r18)
+#endif
+ BNEZAD (r18, .L_len_larger_16bytes)
+
+.L_len_less_16bytes:
+ zext r18, r2, 3, 2
+ bez r18, .L_copy_by_byte
+.L_len_less_16bytes_loop:
+ subi r1, 4
+ subi r0, 4
+ ldw r3, (r1, 0)
+ PRE_BNEZAD (r18)
+ stw r3, (r0, 0)
+ BNEZAD (r18, .L_len_less_16bytes_loop)
+
+ /* Test if len less than 4 bytes. */
+.L_copy_by_byte:
+ zext r18, r2, 1, 0
+ bez r18, .L_return
+.L_copy_by_byte_loop:
+ subi r1, 1
+ subi r0, 1
+ ldb r3, (r1, 0)
+ PRE_BNEZAD (r18)
+ stb r3, (r0, 0)
+ BNEZAD (r18, .L_copy_by_byte_loop)
+
+.L_return:
+ mov r0, r12
+ rts
+
+ /* If dest is not aligned, just copy some bytes makes the dest
+ align. */
+.L_dest_not_aligned:
+ sub r2, r13
+.L_dest_not_aligned_loop:
+ subi r1, 1
+ subi r0, 1
+ /* Makes the dest align. */
+ ldb r3, (r1, 0)
+ PRE_BNEZAD (r13)
+ stb r3, (r0, 0)
+ BNEZAD (r13, .L_dest_not_aligned_loop)
+ cmplti r2, 4
+ bt .L_copy_by_byte
+ /* Check whether the src is aligned. */
+ jbr .L_dest_aligned
+ENDPROC(memmove)
+ENDPROC(__memmove)
diff --git a/arch/csky/abiv2/memset.S b/arch/csky/abiv2/memset.S
new file mode 100644
index 0000000000000..a7e7d994b667d
--- /dev/null
+++ b/arch/csky/abiv2/memset.S
@@ -0,0 +1,83 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
+
+#include <linux/linkage.h>
+#include "sysdep.h"
+
+ .weak memset
+ENTRY(__memset)
+ENTRY(memset)
+ /* Test if len less than 4 bytes. */
+ mov r12, r0
+ cmplti r2, 8
+ bt .L_set_by_byte
+
+ andi r13, r0, 3
+ movi r19, 4
+ /* Test if dest is not 4 bytes aligned. */
+ bnez r13, .L_dest_not_aligned
+ /* Hardware can handle unaligned access directly. */
+.L_dest_aligned:
+ zextb r3, r1
+ lsli r1, 8
+ or r1, r3
+ lsli r3, r1, 16
+ or r3, r1
+
+ /* If dest is aligned, then copy. */
+ zext r18, r2, 31, 4
+ /* Test if len less than 16 bytes. */
+ bez r18, .L_len_less_16bytes
+
+ LABLE_ALIGN
+.L_len_larger_16bytes:
+ stw r3, (r0, 0)
+ stw r3, (r0, 4)
+ stw r3, (r0, 8)
+ stw r3, (r0, 12)
+ PRE_BNEZAD (r18)
+ addi r0, 16
+ BNEZAD (r18, .L_len_larger_16bytes)
+
+.L_len_less_16bytes:
+ zext r18, r2, 3, 2
+ andi r2, 3
+ bez r18, .L_set_by_byte
+.L_len_less_16bytes_loop:
+ stw r3, (r0, 0)
+ PRE_BNEZAD (r18)
+ addi r0, 4
+ BNEZAD (r18, .L_len_less_16bytes_loop)
+
+ /* Test if len less than 4 bytes. */
+.L_set_by_byte:
+ zext r18, r2, 2, 0
+ bez r18, .L_return
+.L_set_by_byte_loop:
+ stb r1, (r0, 0)
+ PRE_BNEZAD (r18)
+ addi r0, 1
+ BNEZAD (r18, .L_set_by_byte_loop)
+
+.L_return:
+ mov r0, r12
+ rts
+
+ /* If dest is not aligned, just set some bytes makes the dest
+ align. */
+
+.L_dest_not_aligned:
+ sub r13, r19, r13
+ sub r2, r13
+.L_dest_not_aligned_loop:
+ /* Makes the dest align. */
+ stb r1, (r0, 0)
+ PRE_BNEZAD (r13)
+ addi r0, 1
+ BNEZAD (r13, .L_dest_not_aligned_loop)
+ cmplti r2, 8
+ bt .L_set_by_byte
+ /* Check whether the src is aligned. */
+ jbr .L_dest_aligned
+ENDPROC(memset)
+ENDPROC(__memset)
diff --git a/arch/csky/abiv2/strcmp.S b/arch/csky/abiv2/strcmp.S
new file mode 100644
index 0000000000000..f8403f4d8c2be
--- /dev/null
+++ b/arch/csky/abiv2/strcmp.S
@@ -0,0 +1,168 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
+
+#include <linux/linkage.h>
+#include "sysdep.h"
+
+ENTRY(strcmp)
+ mov a3, a0
+ /* Check if the s1 addr is aligned. */
+ xor a2, a3, a1
+ andi a2, 0x3
+ bnez a2, 7f
+ andi t1, a0, 0x3
+ bnez t1, 5f
+
+1:
+ /* If aligned, load word each time. */
+ ldw t0, (a3, 0)
+ ldw t1, (a1, 0)
+ /* If s1[i] != s2[i], goto 2f. */
+ cmpne t0, t1
+ bt 2f
+ /* If s1[i] == s2[i], check if s1 or s2 is at the end. */
+ tstnbz t0
+ /* If at the end, goto 3f (finish comparing). */
+ bf 3f
+
+ ldw t0, (a3, 4)
+ ldw t1, (a1, 4)
+ cmpne t0, t1
+ bt 2f
+ tstnbz t0
+ bf 3f
+
+ ldw t0, (a3, 8)
+ ldw t1, (a1, 8)
+ cmpne t0, t1
+ bt 2f
+ tstnbz t0
+ bf 3f
+
+ ldw t0, (a3, 12)
+ ldw t1, (a1, 12)
+ cmpne t0, t1
+ bt 2f
+ tstnbz t0
+ bf 3f
+
+ ldw t0, (a3, 16)
+ ldw t1, (a1, 16)
+ cmpne t0, t1
+ bt 2f
+ tstnbz t0
+ bf 3f
+
+ ldw t0, (a3, 20)
+ ldw t1, (a1, 20)
+ cmpne t0, t1
+ bt 2f
+ tstnbz t0
+ bf 3f
+
+ ldw t0, (a3, 24)
+ ldw t1, (a1, 24)
+ cmpne t0, t1
+ bt 2f
+ tstnbz t0
+ bf 3f
+
+ ldw t0, (a3, 28)
+ ldw t1, (a1, 28)
+ cmpne t0, t1
+ bt 2f
+ tstnbz t0
+ bf 3f
+
+ addi a3, 32
+ addi a1, 32
+
+ br 1b
+
+# ifdef __CSKYBE__
+ /* d[i] != s[i] in word, so we check byte 0. */
+2:
+ xtrb0 a0, t0
+ xtrb0 a2, t1
+ subu a0, a2
+ bez a2, 4f
+ bnez a0, 4f
+
+ /* check byte 1 */
+ xtrb1 a0, t0
+ xtrb1 a2, t1
+ subu a0, a2
+ bez a2, 4f
+ bnez a0, 4f
+
+ /* check byte 2 */
+ xtrb2 a0, t0
+ xtrb2 a2, t1
+ subu a0, a2
+ bez a2, 4f
+ bnez a0, 4f
+
+ /* check byte 3 */
+ xtrb3 a0, t0
+ xtrb3 a2, t1
+ subu a0, a2
+# else
+ /* s1[i] != s2[i] in word, so we check byte 3. */
+2:
+ xtrb3 a0, t0
+ xtrb3 a2, t1
+ subu a0, a2
+ bez a2, 4f
+ bnez a0, 4f
+
+ /* check byte 2 */
+ xtrb2 a0, t0
+ xtrb2 a2, t1
+ subu a0, a2
+ bez a2, 4f
+ bnez a0, 4f
+
+ /* check byte 1 */
+ xtrb1 a0, t0
+ xtrb1 a2, t1
+ subu a0, a2
+ bez a2, 4f
+ bnez a0, 4f
+
+ /* check byte 0 */
+ xtrb0 a0, t0
+ xtrb0 a2, t1
+ subu a0, a2
+
+# endif /* !__CSKYBE__ */
+ jmp lr
+3:
+ movi a0, 0
+4:
+ jmp lr
+
+ /* Compare when s1 or s2 is not aligned. */
+5:
+ subi t1, 4
+6:
+ ldb a0, (a3, 0)
+ ldb a2, (a1, 0)
+ subu a0, a2
+ bez a2, 4b
+ bnez a0, 4b
+ addi t1, 1
+ addi a1, 1
+ addi a3, 1
+ bnez t1, 6b
+ br 1b
+
+7:
+ ldb a0, (a3, 0)
+ addi a3, 1
+ ldb a2, (a1, 0)
+ addi a1, 1
+ subu a0, a2
+ bnez a0, 4b
+ bnez a2, 7b
+ jmp r15
+ENDPROC(strcmp)
diff --git a/arch/csky/abiv2/strcpy.S b/arch/csky/abiv2/strcpy.S
new file mode 100644
index 0000000000000..3c6d3f6a573a1
--- /dev/null
+++ b/arch/csky/abiv2/strcpy.S
@@ -0,0 +1,123 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
+
+#include <linux/linkage.h>
+#include "sysdep.h"
+
+ENTRY(strcpy)
+ mov a3, a0
+ /* Check if the src addr is aligned. */
+ andi t0, a1, 3
+ bnez t0, 11f
+1:
+ /* Check if all the bytes in the word are not zero. */
+ ldw a2, (a1)
+ tstnbz a2
+ bf 9f
+ stw a2, (a3)
+
+ ldw a2, (a1, 4)
+ tstnbz a2
+ bf 2f
+ stw a2, (a3, 4)
+
+ ldw a2, (a1, 8)
+ tstnbz a2
+ bf 3f
+ stw a2, (a3, 8)
+
+ ldw a2, (a1, 12)
+ tstnbz a2
+ bf 4f
+ stw a2, (a3, 12)
+
+ ldw a2, (a1, 16)
+ tstnbz a2
+ bf 5f
+ stw a2, (a3, 16)
+
+ ldw a2, (a1, 20)
+ tstnbz a2
+ bf 6f
+ stw a2, (a3, 20)
+
+ ldw a2, (a1, 24)
+ tstnbz a2
+ bf 7f
+ stw a2, (a3, 24)
+
+ ldw a2, (a1, 28)
+ tstnbz a2
+ bf 8f
+ stw a2, (a3, 28)
+
+ addi a3, 32
+ addi a1, 32
+ br 1b
+
+
+2:
+ addi a3, 4
+ br 9f
+
+3:
+ addi a3, 8
+ br 9f
+
+4:
+ addi a3, 12
+ br 9f
+
+5:
+ addi a3, 16
+ br 9f
+
+6:
+ addi a3, 20
+ br 9f
+
+7:
+ addi a3, 24
+ br 9f
+
+8:
+ addi a3, 28
+9:
+# ifdef __CSKYBE__
+ xtrb0 t0, a2
+ st.b t0, (a3)
+ bez t0, 10f
+ xtrb1 t0, a2
+ st.b t0, (a3, 1)
+ bez t0, 10f
+ xtrb2 t0, a2
+ st.b t0, (a3, 2)
+ bez t0, 10f
+ stw a2, (a3)
+# else
+ xtrb3 t0, a2
+ st.b t0, (a3)
+ bez t0, 10f
+ xtrb2 t0, a2
+ st.b t0, (a3, 1)
+ bez t0, 10f
+ xtrb1 t0, a2
+ st.b t0, (a3, 2)
+ bez t0, 10f
+ stw a2, (a3)
+# endif /* !__CSKYBE__ */
+10:
+ jmp lr
+
+11:
+ subi t0, 4
+12:
+ ld.b a2, (a1)
+ st.b a2, (a3)
+ bez a2, 10b
+ addi t0, 1
+ addi a1, a1, 1
+ addi a3, a3, 1
+ bnez t0, 12b
+ jbr 1b
+ENDPROC(strcpy)
diff --git a/arch/csky/abiv2/strksyms.c b/arch/csky/abiv2/strksyms.c
new file mode 100644
index 0000000000000..06da723d82024
--- /dev/null
+++ b/arch/csky/abiv2/strksyms.c
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
+
+#include <linux/module.h>
+
+EXPORT_SYMBOL(memcpy);
+EXPORT_SYMBOL(memset);
+EXPORT_SYMBOL(memcmp);
+EXPORT_SYMBOL(memmove);
+EXPORT_SYMBOL(strcmp);
+EXPORT_SYMBOL(strcpy);
+EXPORT_SYMBOL(strlen);
diff --git a/arch/csky/abiv2/strlen.S b/arch/csky/abiv2/strlen.S
new file mode 100644
index 0000000000000..bcdd70764d086
--- /dev/null
+++ b/arch/csky/abiv2/strlen.S
@@ -0,0 +1,97 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
+
+#include <linux/linkage.h>
+#include "sysdep.h"
+
+ENTRY(strlen)
+ /* Check if the start addr is aligned. */
+ mov r3, r0
+ andi r1, r0, 3
+ movi r2, 4
+ movi r0, 0
+ bnez r1, .L_start_not_aligned
+
+ LABLE_ALIGN
+.L_start_addr_aligned:
+ /* Check if all the bytes in the word are not zero. */
+ ldw r1, (r3)
+ tstnbz r1
+ bf .L_string_tail
+
+ ldw r1, (r3, 4)
+ addi r0, 4
+ tstnbz r1
+ bf .L_string_tail
+
+ ldw r1, (r3, 8)
+ addi r0, 4
+ tstnbz r1
+ bf .L_string_tail
+
+ ldw r1, (r3, 12)
+ addi r0, 4
+ tstnbz r1
+ bf .L_string_tail
+
+ ldw r1, (r3, 16)
+ addi r0, 4
+ tstnbz r1
+ bf .L_string_tail
+
+ ldw r1, (r3, 20)
+ addi r0, 4
+ tstnbz r1
+ bf .L_string_tail
+
+ ldw r1, (r3, 24)
+ addi r0, 4
+ tstnbz r1
+ bf .L_string_tail
+
+ ldw r1, (r3, 28)
+ addi r0, 4
+ tstnbz r1
+ bf .L_string_tail
+
+ addi r0, 4
+ addi r3, 32
+ br .L_start_addr_aligned
+
+.L_string_tail:
+# ifdef __CSKYBE__
+ xtrb0 r3, r1
+ bez r3, .L_return
+ addi r0, 1
+ xtrb1 r3, r1
+ bez r3, .L_return
+ addi r0, 1
+ xtrb2 r3, r1
+ bez r3, .L_return
+ addi r0, 1
+# else
+ xtrb3 r3, r1
+ bez r3, .L_return
+ addi r0, 1
+ xtrb2 r3, r1
+ bez r3, .L_return
+ addi r0, 1
+ xtrb1 r3, r1
+ bez r3, .L_return
+ addi r0, 1
+# endif /* !__CSKYBE__ */
+
+.L_return:
+ rts
+
+.L_start_not_aligned:
+ sub r2, r2, r1
+.L_start_not_aligned_loop:
+ ldb r1, (r3)
+ PRE_BNEZAD (r2)
+ addi r3, 1
+ bez r1, .L_return
+ addi r0, 1
+ BNEZAD (r2, .L_start_not_aligned_loop)
+ br .L_start_addr_aligned
+ENDPROC(strlen)
diff --git a/arch/csky/abiv2/sysdep.h b/arch/csky/abiv2/sysdep.h
new file mode 100644
index 0000000000000..bbbedfd347774
--- /dev/null
+++ b/arch/csky/abiv2/sysdep.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
+
+#ifndef __SYSDEP_H
+#define __SYSDEP_H
+
+#ifdef __ASSEMBLER__
+
+#if defined(__CK860__)
+#define LABLE_ALIGN \
+ .balignw 16, 0x6c03
+
+#define PRE_BNEZAD(R)
+
+#define BNEZAD(R, L) \
+ bnezad R, L
+#else
+#define LABLE_ALIGN \
+ .balignw 8, 0x6c03
+
+#define PRE_BNEZAD(R) \
+ subi R, 1
+
+#define BNEZAD(R, L) \
+ bnez R, L
+#endif
+
+#endif
+
+#endif