162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 362306a36Sopenharmony_ci * License. See the file "COPYING" in the main directory of this archive 462306a36Sopenharmony_ci * for more details. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 1998, 1999, 2000 by Ralf Baechle 762306a36Sopenharmony_ci * Copyright (C) 1999, 2000 Silicon Graphics, Inc. 862306a36Sopenharmony_ci * Copyright (C) 2007 by Maciej W. Rozycki 962306a36Sopenharmony_ci * Copyright (C) 2011, 2012 MIPS Technologies, Inc. 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci#include <linux/export.h> 1262306a36Sopenharmony_ci#include <asm/asm.h> 1362306a36Sopenharmony_ci#include <asm/asm-offsets.h> 1462306a36Sopenharmony_ci#include <asm/regdef.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#if LONGSIZE == 4 1762306a36Sopenharmony_ci#define LONG_S_L swl 1862306a36Sopenharmony_ci#define LONG_S_R swr 1962306a36Sopenharmony_ci#else 2062306a36Sopenharmony_ci#define LONG_S_L sdl 2162306a36Sopenharmony_ci#define LONG_S_R sdr 2262306a36Sopenharmony_ci#endif 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#ifdef CONFIG_CPU_MICROMIPS 2562306a36Sopenharmony_ci#define STORSIZE (LONGSIZE * 2) 2662306a36Sopenharmony_ci#define STORMASK (STORSIZE - 1) 2762306a36Sopenharmony_ci#define FILL64RG t8 2862306a36Sopenharmony_ci#define FILLPTRG t7 2962306a36Sopenharmony_ci#undef LONG_S 3062306a36Sopenharmony_ci#define LONG_S LONG_SP 3162306a36Sopenharmony_ci#else 3262306a36Sopenharmony_ci#define STORSIZE LONGSIZE 3362306a36Sopenharmony_ci#define STORMASK LONGMASK 3462306a36Sopenharmony_ci#define FILL64RG a1 3562306a36Sopenharmony_ci#define FILLPTRG t0 3662306a36Sopenharmony_ci#endif 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#define LEGACY_MODE 1 3962306a36Sopenharmony_ci#define EVA_MODE 2 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci/* 4262306a36Sopenharmony_ci * No need to protect it with EVA #ifdefery. The generated block of code 4362306a36Sopenharmony_ci * will never be assembled if EVA is not enabled. 4462306a36Sopenharmony_ci */ 4562306a36Sopenharmony_ci#define __EVAFY(insn, reg, addr) __BUILD_EVA_INSN(insn##e, reg, addr) 4662306a36Sopenharmony_ci#define ___BUILD_EVA_INSN(insn, reg, addr) __EVAFY(insn, reg, addr) 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci#define EX(insn,reg,addr,handler) \ 4962306a36Sopenharmony_ci .if \mode == LEGACY_MODE; \ 5062306a36Sopenharmony_ci9: insn reg, addr; \ 5162306a36Sopenharmony_ci .else; \ 5262306a36Sopenharmony_ci9: ___BUILD_EVA_INSN(insn, reg, addr); \ 5362306a36Sopenharmony_ci .endif; \ 5462306a36Sopenharmony_ci .section __ex_table,"a"; \ 5562306a36Sopenharmony_ci PTR_WD 9b, handler; \ 5662306a36Sopenharmony_ci .previous 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci .macro f_fill64 dst, offset, val, fixup, mode 5962306a36Sopenharmony_ci EX(LONG_S, \val, (\offset + 0 * STORSIZE)(\dst), \fixup) 6062306a36Sopenharmony_ci EX(LONG_S, \val, (\offset + 1 * STORSIZE)(\dst), \fixup) 6162306a36Sopenharmony_ci EX(LONG_S, \val, (\offset + 2 * STORSIZE)(\dst), \fixup) 6262306a36Sopenharmony_ci EX(LONG_S, \val, (\offset + 3 * STORSIZE)(\dst), \fixup) 6362306a36Sopenharmony_ci#if ((defined(CONFIG_CPU_MICROMIPS) && (LONGSIZE == 4)) || !defined(CONFIG_CPU_MICROMIPS)) 6462306a36Sopenharmony_ci EX(LONG_S, \val, (\offset + 4 * STORSIZE)(\dst), \fixup) 6562306a36Sopenharmony_ci EX(LONG_S, \val, (\offset + 5 * STORSIZE)(\dst), \fixup) 6662306a36Sopenharmony_ci EX(LONG_S, \val, (\offset + 6 * STORSIZE)(\dst), \fixup) 6762306a36Sopenharmony_ci EX(LONG_S, \val, (\offset + 7 * STORSIZE)(\dst), \fixup) 6862306a36Sopenharmony_ci#endif 6962306a36Sopenharmony_ci#if (!defined(CONFIG_CPU_MICROMIPS) && (LONGSIZE == 4)) 7062306a36Sopenharmony_ci EX(LONG_S, \val, (\offset + 8 * STORSIZE)(\dst), \fixup) 7162306a36Sopenharmony_ci EX(LONG_S, \val, (\offset + 9 * STORSIZE)(\dst), \fixup) 7262306a36Sopenharmony_ci EX(LONG_S, \val, (\offset + 10 * STORSIZE)(\dst), \fixup) 7362306a36Sopenharmony_ci EX(LONG_S, \val, (\offset + 11 * STORSIZE)(\dst), \fixup) 7462306a36Sopenharmony_ci EX(LONG_S, \val, (\offset + 12 * STORSIZE)(\dst), \fixup) 7562306a36Sopenharmony_ci EX(LONG_S, \val, (\offset + 13 * STORSIZE)(\dst), \fixup) 7662306a36Sopenharmony_ci EX(LONG_S, \val, (\offset + 14 * STORSIZE)(\dst), \fixup) 7762306a36Sopenharmony_ci EX(LONG_S, \val, (\offset + 15 * STORSIZE)(\dst), \fixup) 7862306a36Sopenharmony_ci#endif 7962306a36Sopenharmony_ci .endm 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci .align 5 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci /* 8462306a36Sopenharmony_ci * Macro to generate the __bzero{,_user} symbol 8562306a36Sopenharmony_ci * Arguments: 8662306a36Sopenharmony_ci * mode: LEGACY_MODE or EVA_MODE 8762306a36Sopenharmony_ci */ 8862306a36Sopenharmony_ci .macro __BUILD_BZERO mode 8962306a36Sopenharmony_ci /* Initialize __memset if this is the first time we call this macro */ 9062306a36Sopenharmony_ci .ifnotdef __memset 9162306a36Sopenharmony_ci .set __memset, 1 9262306a36Sopenharmony_ci .hidden __memset /* Make sure it does not leak */ 9362306a36Sopenharmony_ci .endif 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci sltiu t0, a2, STORSIZE /* very small region? */ 9662306a36Sopenharmony_ci .set noreorder 9762306a36Sopenharmony_ci bnez t0, .Lsmall_memset\@ 9862306a36Sopenharmony_ci andi t0, a0, STORMASK /* aligned? */ 9962306a36Sopenharmony_ci .set reorder 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci#ifdef CONFIG_CPU_MICROMIPS 10262306a36Sopenharmony_ci move t8, a1 /* used by 'swp' instruction */ 10362306a36Sopenharmony_ci move t9, a1 10462306a36Sopenharmony_ci#endif 10562306a36Sopenharmony_ci .set noreorder 10662306a36Sopenharmony_ci#ifndef CONFIG_CPU_DADDI_WORKAROUNDS 10762306a36Sopenharmony_ci beqz t0, 1f 10862306a36Sopenharmony_ci PTR_SUBU t0, STORSIZE /* alignment in bytes */ 10962306a36Sopenharmony_ci#else 11062306a36Sopenharmony_ci .set noat 11162306a36Sopenharmony_ci li AT, STORSIZE 11262306a36Sopenharmony_ci beqz t0, 1f 11362306a36Sopenharmony_ci PTR_SUBU t0, AT /* alignment in bytes */ 11462306a36Sopenharmony_ci .set at 11562306a36Sopenharmony_ci#endif 11662306a36Sopenharmony_ci .set reorder 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci#ifndef CONFIG_CPU_NO_LOAD_STORE_LR 11962306a36Sopenharmony_ci R10KCBARRIER(0(ra)) 12062306a36Sopenharmony_ci#ifdef __MIPSEB__ 12162306a36Sopenharmony_ci EX(LONG_S_L, a1, (a0), .Lfirst_fixup\@) /* make word/dword aligned */ 12262306a36Sopenharmony_ci#else 12362306a36Sopenharmony_ci EX(LONG_S_R, a1, (a0), .Lfirst_fixup\@) /* make word/dword aligned */ 12462306a36Sopenharmony_ci#endif 12562306a36Sopenharmony_ci PTR_SUBU a0, t0 /* long align ptr */ 12662306a36Sopenharmony_ci PTR_ADDU a2, t0 /* correct size */ 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci#else /* CONFIG_CPU_NO_LOAD_STORE_LR */ 12962306a36Sopenharmony_ci#define STORE_BYTE(N) \ 13062306a36Sopenharmony_ci EX(sb, a1, N(a0), .Lbyte_fixup\@); \ 13162306a36Sopenharmony_ci .set noreorder; \ 13262306a36Sopenharmony_ci beqz t0, 0f; \ 13362306a36Sopenharmony_ci PTR_ADDU t0, 1; \ 13462306a36Sopenharmony_ci .set reorder; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci PTR_ADDU a2, t0 /* correct size */ 13762306a36Sopenharmony_ci PTR_ADDU t0, 1 13862306a36Sopenharmony_ci STORE_BYTE(0) 13962306a36Sopenharmony_ci STORE_BYTE(1) 14062306a36Sopenharmony_ci#if LONGSIZE == 4 14162306a36Sopenharmony_ci EX(sb, a1, 2(a0), .Lbyte_fixup\@) 14262306a36Sopenharmony_ci#else 14362306a36Sopenharmony_ci STORE_BYTE(2) 14462306a36Sopenharmony_ci STORE_BYTE(3) 14562306a36Sopenharmony_ci STORE_BYTE(4) 14662306a36Sopenharmony_ci STORE_BYTE(5) 14762306a36Sopenharmony_ci EX(sb, a1, 6(a0), .Lbyte_fixup\@) 14862306a36Sopenharmony_ci#endif 14962306a36Sopenharmony_ci0: 15062306a36Sopenharmony_ci ori a0, STORMASK 15162306a36Sopenharmony_ci xori a0, STORMASK 15262306a36Sopenharmony_ci PTR_ADDIU a0, STORSIZE 15362306a36Sopenharmony_ci#endif /* CONFIG_CPU_NO_LOAD_STORE_LR */ 15462306a36Sopenharmony_ci1: ori t1, a2, 0x3f /* # of full blocks */ 15562306a36Sopenharmony_ci xori t1, 0x3f 15662306a36Sopenharmony_ci andi t0, a2, 0x40-STORSIZE 15762306a36Sopenharmony_ci beqz t1, .Lmemset_partial\@ /* no block to fill */ 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci PTR_ADDU t1, a0 /* end address */ 16062306a36Sopenharmony_ci1: PTR_ADDIU a0, 64 16162306a36Sopenharmony_ci R10KCBARRIER(0(ra)) 16262306a36Sopenharmony_ci f_fill64 a0, -64, FILL64RG, .Lfwd_fixup\@, \mode 16362306a36Sopenharmony_ci bne t1, a0, 1b 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci.Lmemset_partial\@: 16662306a36Sopenharmony_ci R10KCBARRIER(0(ra)) 16762306a36Sopenharmony_ci PTR_LA t1, 2f /* where to start */ 16862306a36Sopenharmony_ci#ifdef CONFIG_CPU_MICROMIPS 16962306a36Sopenharmony_ci LONG_SRL t7, t0, 1 17062306a36Sopenharmony_ci#endif 17162306a36Sopenharmony_ci#if LONGSIZE == 4 17262306a36Sopenharmony_ci PTR_SUBU t1, FILLPTRG 17362306a36Sopenharmony_ci#else 17462306a36Sopenharmony_ci .set noat 17562306a36Sopenharmony_ci LONG_SRL AT, FILLPTRG, 1 17662306a36Sopenharmony_ci PTR_SUBU t1, AT 17762306a36Sopenharmony_ci .set at 17862306a36Sopenharmony_ci#endif 17962306a36Sopenharmony_ci PTR_ADDU a0, t0 /* dest ptr */ 18062306a36Sopenharmony_ci jr t1 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci /* ... but first do longs ... */ 18362306a36Sopenharmony_ci f_fill64 a0, -64, FILL64RG, .Lpartial_fixup\@, \mode 18462306a36Sopenharmony_ci2: andi a2, STORMASK /* At most one long to go */ 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci .set noreorder 18762306a36Sopenharmony_ci beqz a2, 1f 18862306a36Sopenharmony_ci#ifndef CONFIG_CPU_NO_LOAD_STORE_LR 18962306a36Sopenharmony_ci PTR_ADDU a0, a2 /* What's left */ 19062306a36Sopenharmony_ci .set reorder 19162306a36Sopenharmony_ci R10KCBARRIER(0(ra)) 19262306a36Sopenharmony_ci#ifdef __MIPSEB__ 19362306a36Sopenharmony_ci EX(LONG_S_R, a1, -1(a0), .Llast_fixup\@) 19462306a36Sopenharmony_ci#else 19562306a36Sopenharmony_ci EX(LONG_S_L, a1, -1(a0), .Llast_fixup\@) 19662306a36Sopenharmony_ci#endif 19762306a36Sopenharmony_ci#else /* CONFIG_CPU_NO_LOAD_STORE_LR */ 19862306a36Sopenharmony_ci PTR_SUBU t0, $0, a2 19962306a36Sopenharmony_ci .set reorder 20062306a36Sopenharmony_ci move a2, zero /* No remaining longs */ 20162306a36Sopenharmony_ci PTR_ADDIU t0, 1 20262306a36Sopenharmony_ci STORE_BYTE(0) 20362306a36Sopenharmony_ci STORE_BYTE(1) 20462306a36Sopenharmony_ci#if LONGSIZE == 4 20562306a36Sopenharmony_ci EX(sb, a1, 2(a0), .Lbyte_fixup\@) 20662306a36Sopenharmony_ci#else 20762306a36Sopenharmony_ci STORE_BYTE(2) 20862306a36Sopenharmony_ci STORE_BYTE(3) 20962306a36Sopenharmony_ci STORE_BYTE(4) 21062306a36Sopenharmony_ci STORE_BYTE(5) 21162306a36Sopenharmony_ci EX(sb, a1, 6(a0), .Lbyte_fixup\@) 21262306a36Sopenharmony_ci#endif 21362306a36Sopenharmony_ci0: 21462306a36Sopenharmony_ci#endif /* CONFIG_CPU_NO_LOAD_STORE_LR */ 21562306a36Sopenharmony_ci1: move a2, zero 21662306a36Sopenharmony_ci jr ra 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci.Lsmall_memset\@: 21962306a36Sopenharmony_ci PTR_ADDU t1, a0, a2 22062306a36Sopenharmony_ci beqz a2, 2f 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci1: PTR_ADDIU a0, 1 /* fill bytewise */ 22362306a36Sopenharmony_ci R10KCBARRIER(0(ra)) 22462306a36Sopenharmony_ci .set noreorder 22562306a36Sopenharmony_ci bne t1, a0, 1b 22662306a36Sopenharmony_ci EX(sb, a1, -1(a0), .Lsmall_fixup\@) 22762306a36Sopenharmony_ci .set reorder 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci2: move a2, zero 23062306a36Sopenharmony_ci jr ra /* done */ 23162306a36Sopenharmony_ci .if __memset == 1 23262306a36Sopenharmony_ci END(memset) 23362306a36Sopenharmony_ci .set __memset, 0 23462306a36Sopenharmony_ci .hidden __memset 23562306a36Sopenharmony_ci .endif 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci#ifdef CONFIG_CPU_NO_LOAD_STORE_LR 23862306a36Sopenharmony_ci.Lbyte_fixup\@: 23962306a36Sopenharmony_ci /* 24062306a36Sopenharmony_ci * unset_bytes = (#bytes - (#unaligned bytes)) - (-#unaligned bytes remaining + 1) + 1 24162306a36Sopenharmony_ci * a2 = a2 - t0 + 1 24262306a36Sopenharmony_ci */ 24362306a36Sopenharmony_ci PTR_SUBU a2, t0 24462306a36Sopenharmony_ci PTR_ADDIU a2, 1 24562306a36Sopenharmony_ci jr ra 24662306a36Sopenharmony_ci#endif /* CONFIG_CPU_NO_LOAD_STORE_LR */ 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci.Lfirst_fixup\@: 24962306a36Sopenharmony_ci /* unset_bytes already in a2 */ 25062306a36Sopenharmony_ci jr ra 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci.Lfwd_fixup\@: 25362306a36Sopenharmony_ci /* 25462306a36Sopenharmony_ci * unset_bytes = partial_start_addr + #bytes - fault_addr 25562306a36Sopenharmony_ci * a2 = t1 + (a2 & 3f) - $28->task->BUADDR 25662306a36Sopenharmony_ci */ 25762306a36Sopenharmony_ci PTR_L t0, TI_TASK($28) 25862306a36Sopenharmony_ci andi a2, 0x3f 25962306a36Sopenharmony_ci LONG_L t0, THREAD_BUADDR(t0) 26062306a36Sopenharmony_ci LONG_ADDU a2, t1 26162306a36Sopenharmony_ci LONG_SUBU a2, t0 26262306a36Sopenharmony_ci jr ra 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci.Lpartial_fixup\@: 26562306a36Sopenharmony_ci /* 26662306a36Sopenharmony_ci * unset_bytes = partial_end_addr + #bytes - fault_addr 26762306a36Sopenharmony_ci * a2 = a0 + (a2 & STORMASK) - $28->task->BUADDR 26862306a36Sopenharmony_ci */ 26962306a36Sopenharmony_ci PTR_L t0, TI_TASK($28) 27062306a36Sopenharmony_ci andi a2, STORMASK 27162306a36Sopenharmony_ci LONG_L t0, THREAD_BUADDR(t0) 27262306a36Sopenharmony_ci LONG_ADDU a2, a0 27362306a36Sopenharmony_ci LONG_SUBU a2, t0 27462306a36Sopenharmony_ci jr ra 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci.Llast_fixup\@: 27762306a36Sopenharmony_ci /* unset_bytes already in a2 */ 27862306a36Sopenharmony_ci jr ra 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci.Lsmall_fixup\@: 28162306a36Sopenharmony_ci /* 28262306a36Sopenharmony_ci * unset_bytes = end_addr - current_addr + 1 28362306a36Sopenharmony_ci * a2 = t1 - a0 + 1 28462306a36Sopenharmony_ci */ 28562306a36Sopenharmony_ci PTR_SUBU a2, t1, a0 28662306a36Sopenharmony_ci PTR_ADDIU a2, 1 28762306a36Sopenharmony_ci jr ra 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci .endm 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci/* 29262306a36Sopenharmony_ci * memset(void *s, int c, size_t n) 29362306a36Sopenharmony_ci * 29462306a36Sopenharmony_ci * a0: start of area to clear 29562306a36Sopenharmony_ci * a1: char to fill with 29662306a36Sopenharmony_ci * a2: size of area to clear 29762306a36Sopenharmony_ci */ 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ciLEAF(memset) 30062306a36Sopenharmony_ciEXPORT_SYMBOL(memset) 30162306a36Sopenharmony_ci move v0, a0 /* result */ 30262306a36Sopenharmony_ci beqz a1, 1f 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci andi a1, 0xff /* spread fillword */ 30562306a36Sopenharmony_ci LONG_SLL t1, a1, 8 30662306a36Sopenharmony_ci or a1, t1 30762306a36Sopenharmony_ci LONG_SLL t1, a1, 16 30862306a36Sopenharmony_ci#if LONGSIZE == 8 30962306a36Sopenharmony_ci or a1, t1 31062306a36Sopenharmony_ci LONG_SLL t1, a1, 32 31162306a36Sopenharmony_ci#endif 31262306a36Sopenharmony_ci or a1, t1 31362306a36Sopenharmony_ci1: 31462306a36Sopenharmony_ci#ifndef CONFIG_EVA 31562306a36Sopenharmony_ciFEXPORT(__bzero) 31662306a36Sopenharmony_ciEXPORT_SYMBOL(__bzero) 31762306a36Sopenharmony_ci#endif 31862306a36Sopenharmony_ci __BUILD_BZERO LEGACY_MODE 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci#ifdef CONFIG_EVA 32162306a36Sopenharmony_ciLEAF(__bzero) 32262306a36Sopenharmony_ciEXPORT_SYMBOL(__bzero) 32362306a36Sopenharmony_ci __BUILD_BZERO EVA_MODE 32462306a36Sopenharmony_ciEND(__bzero) 32562306a36Sopenharmony_ci#endif 326