Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

nds32: Library functions

This patch add support for various library functions.

Signed-off-by: Vincent Chen <vincentc@andestech.com>
Signed-off-by: Greentime Hu <greentime@andestech.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>

+721
+17
arch/nds32/include/asm/string.h
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // Copyright (C) 2005-2017 Andes Technology Corporation 3 + 4 + #ifndef __ASM_NDS32_STRING_H 5 + #define __ASM_NDS32_STRING_H 6 + 7 + #define __HAVE_ARCH_MEMCPY 8 + extern void *memcpy(void *, const void *, __kernel_size_t); 9 + 10 + #define __HAVE_ARCH_MEMMOVE 11 + extern void *memmove(void *, const void *, __kernel_size_t); 12 + 13 + #define __HAVE_ARCH_MEMSET 14 + extern void *memset(void *, int, __kernel_size_t); 15 + 16 + extern void *memzero(void *ptr, __kernel_size_t n); 17 + #endif
+35
arch/nds32/include/asm/swab.h
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // Copyright (C) 2005-2017 Andes Technology Corporation 3 + 4 + #ifndef __NDS32_SWAB_H__ 5 + #define __NDS32_SWAB_H__ 6 + 7 + #include <linux/types.h> 8 + #include <linux/compiler.h> 9 + 10 + static __inline__ __attribute_const__ __u32 ___arch__swab32(__u32 x) 11 + { 12 + __asm__("wsbh %0, %0\n\t" /* word swap byte within halfword */ 13 + "rotri %0, %0, #16\n" 14 + :"=r"(x) 15 + :"0"(x)); 16 + return x; 17 + } 18 + 19 + static __inline__ __attribute_const__ __u16 ___arch__swab16(__u16 x) 20 + { 21 + __asm__("wsbh %0, %0\n" /* word swap byte within halfword */ 22 + :"=r"(x) 23 + :"0"(x)); 24 + return x; 25 + } 26 + 27 + #define __arch_swab32(x) ___arch__swab32(x) 28 + #define __arch_swab16(x) ___arch__swab16(x) 29 + 30 + #if !defined(__STRICT_ANSI__) || defined(__KERNEL__) 31 + #define __BYTEORDER_HAS_U64__ 32 + #define __SWAB_64_THRU_32__ 33 + #endif 34 + 35 + #endif /* __NDS32_SWAB_H__ */
+283
arch/nds32/include/asm/uaccess.h
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // Copyright (C) 2005-2017 Andes Technology Corporation 3 + 4 + #ifndef _ASMANDES_UACCESS_H 5 + #define _ASMANDES_UACCESS_H 6 + 7 + /* 8 + * User space memory access functions 9 + */ 10 + #include <linux/sched.h> 11 + #include <asm/errno.h> 12 + #include <asm/memory.h> 13 + #include <asm/types.h> 14 + #include <linux/mm.h> 15 + 16 + #define VERIFY_READ 0 17 + #define VERIFY_WRITE 1 18 + 19 + #define __asmeq(x, y) ".ifnc " x "," y " ; .err ; .endif\n\t" 20 + 21 + /* 22 + * The exception table consists of pairs of addresses: the first is the 23 + * address of an instruction that is allowed to fault, and the second is 24 + * the address at which the program should continue. No registers are 25 + * modified, so it is entirely up to the continuation code to figure out 26 + * what to do. 27 + * 28 + * All the routines below use bits of fixup code that are out of line 29 + * with the main instruction path. This means when everything is well, 30 + * we don't even have to jump over them. Further, they do not intrude 31 + * on our cache or tlb entries. 32 + */ 33 + 34 + struct exception_table_entry { 35 + unsigned long insn, fixup; 36 + }; 37 + 38 + extern int fixup_exception(struct pt_regs *regs); 39 + 40 + #define KERNEL_DS ((mm_segment_t) { ~0UL }) 41 + #define USER_DS ((mm_segment_t) {TASK_SIZE - 1}) 42 + 43 + #define get_ds() (KERNEL_DS) 44 + #define get_fs() (current_thread_info()->addr_limit) 45 + #define user_addr_max get_fs 46 + 47 + static inline void set_fs(mm_segment_t fs) 48 + { 49 + current_thread_info()->addr_limit = fs; 50 + } 51 + 52 + #define segment_eq(a, b) ((a) == (b)) 53 + 54 + #define __range_ok(addr, size) (size <= get_fs() && addr <= (get_fs() -size)) 55 + 56 + #define access_ok(type, addr, size) \ 57 + __range_ok((unsigned long)addr, (unsigned long)size) 58 + /* 59 + * Single-value transfer routines. They automatically use the right 60 + * size if we just have the right pointer type. Note that the functions 61 + * which read from user space (*get_*) need to take care not to leak 62 + * kernel data even if the calling code is buggy and fails to check 63 + * the return value. This means zeroing out the destination variable 64 + * or buffer on error. Normally this is done out of line by the 65 + * fixup code, but there are a few places where it intrudes on the 66 + * main code path. When we only write to user space, there is no 67 + * problem. 68 + * 69 + * The "__xxx" versions of the user access functions do not verify the 70 + * address space - it must have been done previously with a separate 71 + * "access_ok()" call. 72 + * 73 + * The "xxx_error" versions set the third argument to EFAULT if an 74 + * error occurs, and leave it unchanged on success. Note that these 75 + * versions are void (ie, don't return a value as such). 76 + */ 77 + 78 + #define get_user(x,p) \ 79 + ({ \ 80 + long __e = -EFAULT; \ 81 + if(likely(access_ok(VERIFY_READ, p, sizeof(*p)))) { \ 82 + __e = __get_user(x,p); \ 83 + } else \ 84 + x = 0; \ 85 + __e; \ 86 + }) 87 + #define __get_user(x,ptr) \ 88 + ({ \ 89 + long __gu_err = 0; \ 90 + __get_user_err((x),(ptr),__gu_err); \ 91 + __gu_err; \ 92 + }) 93 + 94 + #define __get_user_error(x,ptr,err) \ 95 + ({ \ 96 + __get_user_err((x),(ptr),err); \ 97 + (void) 0; \ 98 + }) 99 + 100 + #define __get_user_err(x,ptr,err) \ 101 + do { \ 102 + unsigned long __gu_addr = (unsigned long)(ptr); \ 103 + unsigned long __gu_val; \ 104 + __chk_user_ptr(ptr); \ 105 + switch (sizeof(*(ptr))) { \ 106 + case 1: \ 107 + __get_user_asm("lbi",__gu_val,__gu_addr,err); \ 108 + break; \ 109 + case 2: \ 110 + __get_user_asm("lhi",__gu_val,__gu_addr,err); \ 111 + break; \ 112 + case 4: \ 113 + __get_user_asm("lwi",__gu_val,__gu_addr,err); \ 114 + break; \ 115 + case 8: \ 116 + __get_user_asm_dword(__gu_val,__gu_addr,err); \ 117 + break; \ 118 + default: \ 119 + BUILD_BUG(); \ 120 + break; \ 121 + } \ 122 + (x) = (__typeof__(*(ptr)))__gu_val; \ 123 + } while (0) 124 + 125 + #define __get_user_asm(inst,x,addr,err) \ 126 + asm volatile( \ 127 + "1: "inst" %1,[%2]\n" \ 128 + "2:\n" \ 129 + " .section .fixup,\"ax\"\n" \ 130 + " .align 2\n" \ 131 + "3: move %0, %3\n" \ 132 + " move %1, #0\n" \ 133 + " b 2b\n" \ 134 + " .previous\n" \ 135 + " .section __ex_table,\"a\"\n" \ 136 + " .align 3\n" \ 137 + " .long 1b, 3b\n" \ 138 + " .previous" \ 139 + : "+r" (err), "=&r" (x) \ 140 + : "r" (addr), "i" (-EFAULT) \ 141 + : "cc") 142 + 143 + #ifdef __NDS32_EB__ 144 + #define __gu_reg_oper0 "%H1" 145 + #define __gu_reg_oper1 "%L1" 146 + #else 147 + #define __gu_reg_oper0 "%L1" 148 + #define __gu_reg_oper1 "%H1" 149 + #endif 150 + 151 + #define __get_user_asm_dword(x, addr, err) \ 152 + asm volatile( \ 153 + "\n1:\tlwi " __gu_reg_oper0 ",[%2]\n" \ 154 + "\n2:\tlwi " __gu_reg_oper1 ",[%2+4]\n" \ 155 + "3:\n" \ 156 + " .section .fixup,\"ax\"\n" \ 157 + " .align 2\n" \ 158 + "4: move %0, %3\n" \ 159 + " b 3b\n" \ 160 + " .previous\n" \ 161 + " .section __ex_table,\"a\"\n" \ 162 + " .align 3\n" \ 163 + " .long 1b, 4b\n" \ 164 + " .long 2b, 4b\n" \ 165 + " .previous" \ 166 + : "+r"(err), "=&r"(x) \ 167 + : "r"(addr), "i"(-EFAULT) \ 168 + : "cc") 169 + #define put_user(x,p) \ 170 + ({ \ 171 + long __e = -EFAULT; \ 172 + if(likely(access_ok(VERIFY_WRITE, p, sizeof(*p)))) { \ 173 + __e = __put_user(x,p); \ 174 + } \ 175 + __e; \ 176 + }) 177 + #define __put_user(x,ptr) \ 178 + ({ \ 179 + long __pu_err = 0; \ 180 + __put_user_err((x),(ptr),__pu_err); \ 181 + __pu_err; \ 182 + }) 183 + 184 + #define __put_user_error(x,ptr,err) \ 185 + ({ \ 186 + __put_user_err((x),(ptr),err); \ 187 + (void) 0; \ 188 + }) 189 + 190 + #define __put_user_err(x,ptr,err) \ 191 + do { \ 192 + unsigned long __pu_addr = (unsigned long)(ptr); \ 193 + __typeof__(*(ptr)) __pu_val = (x); \ 194 + __chk_user_ptr(ptr); \ 195 + switch (sizeof(*(ptr))) { \ 196 + case 1: \ 197 + __put_user_asm("sbi",__pu_val,__pu_addr,err); \ 198 + break; \ 199 + case 2: \ 200 + __put_user_asm("shi",__pu_val,__pu_addr,err); \ 201 + break; \ 202 + case 4: \ 203 + __put_user_asm("swi",__pu_val,__pu_addr,err); \ 204 + break; \ 205 + case 8: \ 206 + __put_user_asm_dword(__pu_val,__pu_addr,err); \ 207 + break; \ 208 + default: \ 209 + BUILD_BUG(); \ 210 + break; \ 211 + } \ 212 + } while (0) 213 + 214 + #define __put_user_asm(inst,x,addr,err) \ 215 + asm volatile( \ 216 + "1: "inst" %1,[%2]\n" \ 217 + "2:\n" \ 218 + " .section .fixup,\"ax\"\n" \ 219 + " .align 2\n" \ 220 + "3: move %0, %3\n" \ 221 + " b 2b\n" \ 222 + " .previous\n" \ 223 + " .section __ex_table,\"a\"\n" \ 224 + " .align 3\n" \ 225 + " .long 1b, 3b\n" \ 226 + " .previous" \ 227 + : "+r" (err) \ 228 + : "r" (x), "r" (addr), "i" (-EFAULT) \ 229 + : "cc") 230 + 231 + #ifdef __NDS32_EB__ 232 + #define __pu_reg_oper0 "%H2" 233 + #define __pu_reg_oper1 "%L2" 234 + #else 235 + #define __pu_reg_oper0 "%L2" 236 + #define __pu_reg_oper1 "%H2" 237 + #endif 238 + 239 + #define __put_user_asm_dword(x, addr, err) \ 240 + asm volatile( \ 241 + "\n1:\tswi " __pu_reg_oper0 ",[%1]\n" \ 242 + "\n2:\tswi " __pu_reg_oper1 ",[%1+4]\n" \ 243 + "3:\n" \ 244 + " .section .fixup,\"ax\"\n" \ 245 + " .align 2\n" \ 246 + "4: move %0, %3\n" \ 247 + " b 3b\n" \ 248 + " .previous\n" \ 249 + " .section __ex_table,\"a\"\n" \ 250 + " .align 3\n" \ 251 + " .long 1b, 4b\n" \ 252 + " .long 2b, 4b\n" \ 253 + " .previous" \ 254 + : "+r"(err) \ 255 + : "r"(addr), "r"(x), "i"(-EFAULT) \ 256 + : "cc") 257 + extern unsigned long __arch_clear_user(void __user * addr, unsigned long n); 258 + extern long strncpy_from_user(char *dest, const char __user * src, long count); 259 + extern __must_check long strlen_user(const char __user * str); 260 + extern __must_check long strnlen_user(const char __user * str, long n); 261 + extern unsigned long __arch_copy_from_user(void *to, const void __user * from, 262 + unsigned long n); 263 + extern unsigned long __arch_copy_to_user(void __user * to, const void *from, 264 + unsigned long n); 265 + 266 + #define raw_copy_from_user __arch_copy_from_user 267 + #define raw_copy_to_user __arch_copy_to_user 268 + 269 + #define INLINE_COPY_FROM_USER 270 + #define INLINE_COPY_TO_USER 271 + static inline unsigned long clear_user(void __user * to, unsigned long n) 272 + { 273 + if (access_ok(VERIFY_WRITE, to, n)) 274 + n = __arch_clear_user(to, n); 275 + return n; 276 + } 277 + 278 + static inline unsigned long __clear_user(void __user * to, unsigned long n) 279 + { 280 + return __arch_clear_user(to, n); 281 + } 282 + 283 + #endif /* _ASMNDS32_UACCESS_H */
+31
arch/nds32/kernel/nds32_ksyms.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // Copyright (C) 2005-2017 Andes Technology Corporation 3 + 4 + #include <linux/module.h> 5 + #include <linux/string.h> 6 + #include <linux/delay.h> 7 + #include <linux/in6.h> 8 + #include <linux/syscalls.h> 9 + #include <linux/uaccess.h> 10 + 11 + #include <asm/checksum.h> 12 + #include <asm/io.h> 13 + #include <asm/ftrace.h> 14 + #include <asm/proc-fns.h> 15 + 16 + /* mem functions */ 17 + EXPORT_SYMBOL(memset); 18 + EXPORT_SYMBOL(memcpy); 19 + EXPORT_SYMBOL(memmove); 20 + EXPORT_SYMBOL(memzero); 21 + 22 + /* user mem (segment) */ 23 + EXPORT_SYMBOL(__arch_copy_from_user); 24 + EXPORT_SYMBOL(__arch_copy_to_user); 25 + EXPORT_SYMBOL(__arch_clear_user); 26 + 27 + /* cache handling */ 28 + EXPORT_SYMBOL(cpu_icache_inval_all); 29 + EXPORT_SYMBOL(cpu_dcache_wbinval_all); 30 + EXPORT_SYMBOL(cpu_dma_inval_range); 31 + EXPORT_SYMBOL(cpu_dma_wb_range);
+3
arch/nds32/lib/Makefile
··· 1 + lib-y := copy_page.o memcpy.o memmove.o \ 2 + memset.o memzero.o \ 3 + copy_from_user.o copy_to_user.o clear_user.o
+42
arch/nds32/lib/clear_user.S
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // Copyright (C) 2005-2017 Andes Technology Corporation 3 + 4 + #include <linux/linkage.h> 5 + #include <asm/assembler.h> 6 + #include <asm/errno.h> 7 + 8 + /* Prototype: int __arch_clear_user(void *addr, size_t sz) 9 + * Purpose : clear some user memory 10 + * Params : addr - user memory address to clear 11 + * : sz - number of bytes to clear 12 + * Returns : number of bytes NOT cleared 13 + */ 14 + .text 15 + .align 5 16 + ENTRY(__arch_clear_user) 17 + add $r5, $r0, $r1 18 + beqz $r1, clear_exit 19 + xor $p1, $p1, $p1 ! Use $p1=0 to clear mem 20 + srli $p0, $r1, #2 ! $p0 = number of word to clear 21 + andi $r1, $r1, #3 ! Bytes less than a word to copy 22 + beqz $p0, byte_clear ! Only less than a word to clear 23 + word_clear: 24 + USER( smw.bim,$p1, [$r0], $p1) ! Clear the word 25 + addi $p0, $p0, #-1 ! Decrease word count 26 + bnez $p0, word_clear ! Continue looping to clear all words 27 + beqz $r1, clear_exit ! No left bytes to copy 28 + byte_clear: 29 + USER( sbi.bi, $p1, [$r0], #1) ! Clear the byte 30 + addi $r1, $r1, #-1 ! Decrease byte count 31 + bnez $r1, byte_clear ! Continue looping to clear all left bytes 32 + clear_exit: 33 + move $r0, $r1 ! Set return value 34 + ret 35 + 36 + .section .fixup,"ax" 37 + .align 0 38 + 9001: 39 + sub $r0, $r5, $r0 ! Bytes left to copy 40 + ret 41 + .previous 42 + ENDPROC(__arch_clear_user)
+45
arch/nds32/lib/copy_from_user.S
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // Copyright (C) 2005-2017 Andes Technology Corporation 3 + 4 + #include <linux/linkage.h> 5 + #include <asm/assembler.h> 6 + #include <asm/errno.h> 7 + 8 + .macro lbi1 dst, addr, adj 9 + USER( lbi.bi, \dst, [\addr], \adj) 10 + .endm 11 + 12 + .macro sbi1 src, addr, adj 13 + sbi.bi \src, [\addr], \adj 14 + .endm 15 + 16 + .macro lmw1 start_reg, addr, end_reg 17 + USER( lmw.bim, \start_reg, [\addr], \end_reg) 18 + .endm 19 + 20 + .macro smw1 start_reg, addr, end_reg 21 + smw.bim \start_reg, [\addr], \end_reg 22 + .endm 23 + 24 + 25 + /* Prototype: int __arch_copy_from_user(void *to, const char *from, size_t n) 26 + * Purpose : copy a block from user memory to kernel memory 27 + * Params : to - kernel memory 28 + * : from - user memory 29 + * : n - number of bytes to copy 30 + * Returns : Number of bytes NOT copied. 31 + */ 32 + 33 + .text 34 + ENTRY(__arch_copy_from_user) 35 + add $r5, $r0, $r2 36 + #include "copy_template.S" 37 + move $r0, $r2 38 + ret 39 + .section .fixup,"ax" 40 + .align 2 41 + 9001: 42 + sub $r0, $r5, $r0 43 + ret 44 + .previous 45 + ENDPROC(__arch_copy_from_user)
+69
arch/nds32/lib/copy_template.S
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // Copyright (C) 2005-2017 Andes Technology Corporation 3 + 4 + 5 + beq $r1, $r0, quit_memcpy 6 + beqz $r2, quit_memcpy 7 + srli $r3, $r2, #5 ! check if len < cache-line size 32 8 + beqz $r3, word_copy_entry 9 + andi $r4, $r0, #0x3 ! check byte-align 10 + beqz $r4, unalign_word_copy_entry 11 + 12 + addi $r4, $r4,#-4 13 + abs $r4, $r4 ! check how many un-align byte to copy 14 + sub $r2, $r2, $r4 ! update $R2 15 + 16 + unalign_byte_copy: 17 + lbi1 $r3, $r1, #1 18 + addi $r4, $r4, #-1 19 + sbi1 $r3, $r0, #1 20 + bnez $r4, unalign_byte_copy 21 + beqz $r2, quit_memcpy 22 + 23 + unalign_word_copy_entry: 24 + andi $r3, $r0, 0x1f ! check cache-line unaligncount 25 + beqz $r3, cache_copy 26 + 27 + addi $r3, $r3, #-32 28 + abs $r3, $r3 29 + sub $r2, $r2, $r3 ! update $R2 30 + 31 + unalign_word_copy: 32 + lmw1 $r4, $r1, $r4 33 + addi $r3, $r3, #-4 34 + smw1 $r4, $r0, $r4 35 + bnez $r3, unalign_word_copy 36 + beqz $r2, quit_memcpy 37 + 38 + addi $r3, $r2, #-32 ! to check $r2< cache_line , than go to word_copy 39 + bltz $r3, word_copy_entry 40 + cache_copy: 41 + srli $r3, $r2, #5 42 + beqz $r3, word_copy_entry 43 + 3: 44 + lmw1 $r17, $r1, $r24 45 + addi $r3, $r3, #-1 46 + smw1 $r17, $r0, $r24 47 + bnez $r3, 3b 48 + 49 + word_copy_entry: 50 + andi $r2, $r2, #31 51 + 52 + beqz $r2, quit_memcpy 53 + 5: 54 + srli $r3, $r2, #2 55 + beqz $r3, byte_copy 56 + word_copy: 57 + lmw1 $r4, $r1, $r4 58 + addi $r3, $r3, #-1 59 + smw1 $r4, $r0, $r4 60 + bnez $r3, word_copy 61 + andi $r2, $r2, #3 62 + beqz $r2, quit_memcpy 63 + byte_copy: 64 + lbi1 $r3, $r1, #1 65 + addi $r2, $r2, #-1 66 + 67 + sbi1 $r3, $r0, #1 68 + bnez $r2, byte_copy 69 + quit_memcpy:
+45
arch/nds32/lib/copy_to_user.S
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // Copyright (C) 2005-2017 Andes Technology Corporation 3 + 4 + #include <linux/linkage.h> 5 + #include <asm/assembler.h> 6 + #include <asm/errno.h> 7 + 8 + .macro lbi1 dst, addr, adj 9 + lbi.bi \dst, [\addr], \adj 10 + .endm 11 + 12 + .macro sbi1 src, addr, adj 13 + USER( sbi.bi, \src, [\addr], \adj) 14 + .endm 15 + 16 + .macro lmw1 start_reg, addr, end_reg 17 + lmw.bim \start_reg, [\addr], \end_reg 18 + .endm 19 + 20 + .macro smw1 start_reg, addr, end_reg 21 + USER( smw.bim, \start_reg, [\addr], \end_reg) 22 + .endm 23 + 24 + 25 + /* Prototype: int __arch_copy_to_user(void *to, const char *from, size_t n) 26 + * Purpose : copy a block to user memory from kernel memory 27 + * Params : to - user memory 28 + * : from - kernel memory 29 + * : n - number of bytes to copy 30 + * Returns : Number of bytes NOT copied. 31 + */ 32 + 33 + .text 34 + ENTRY(__arch_copy_to_user) 35 + add $r5, $r0, $r2 36 + #include "copy_template.S" 37 + move $r0, $r2 38 + ret 39 + .section .fixup,"ax" 40 + .align 2 41 + 9001: 42 + sub $r0, $r5, $r0 43 + ret 44 + .previous 45 + ENDPROC(__arch_copy_to_user)
+30
arch/nds32/lib/memcpy.S
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // Copyright (C) 2005-2017 Andes Technology Corporation 3 + 4 + #include <linux/linkage.h> 5 + 6 + 7 + .macro lbi1 dst, addr, adj 8 + lbi.bi \dst, [\addr], \adj 9 + .endm 10 + 11 + .macro sbi1 src, addr, adj 12 + sbi.bi \src, [\addr], \adj 13 + .endm 14 + 15 + .macro lmw1 start_reg, addr, end_reg 16 + lmw.bim \start_reg, [\addr], \end_reg 17 + .endm 18 + 19 + .macro smw1 start_reg, addr, end_reg 20 + smw.bim \start_reg, [\addr], \end_reg 21 + .endm 22 + 23 + .text 24 + ENTRY(memcpy) 25 + move $r5, $r0 26 + #include "copy_template.S" 27 + move $r0, $r5 28 + ret 29 + 30 + ENDPROC(memcpy)
+70
arch/nds32/lib/memmove.S
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // Copyright (C) 2005-2017 Andes Technology Corporation 3 + 4 + #include <linux/linkage.h> 5 + 6 + /* 7 + void *memmove(void *dst, const void *src, int n); 8 + 9 + dst: $r0 10 + src: $r1 11 + n : $r2 12 + ret: $r0 - pointer to the memory area dst. 13 + */ 14 + .text 15 + 16 + ENTRY(memmove) 17 + move $r5, $r0 ! Set return value = det 18 + beq $r0, $r1, exit_memcpy ! Exit when det = src 19 + beqz $r2, exit_memcpy ! Exit when n = 0 20 + pushm $t0, $t1 ! Save reg 21 + srli $p1, $r2, #2 ! $p1 is how many words to copy 22 + 23 + ! Avoid data lost when memory overlap 24 + ! Copy data reversely when src < dst 25 + slt $p0, $r0, $r1 ! check if $r0 < $r1 26 + beqz $p0, do_reverse ! branch if dst > src 27 + 28 + ! No reverse, dst < src 29 + andi $r2, $r2, #3 ! How many bytes are less than a word 30 + li $t0, #1 ! Determining copy direction in byte_cpy 31 + beqz $p1, byte_cpy ! When n is less than a word 32 + 33 + word_cpy: 34 + lmw.bim $p0, [$r1], $p0 ! Read a word from src 35 + addi $p1, $p1, #-1 ! How many words left to copy 36 + smw.bim $p0, [$r0], $p0 ! Copy the word to det 37 + bnez $p1, word_cpy ! If remained words > 0 38 + beqz $r2, end_memcpy ! No left bytes to copy 39 + b byte_cpy 40 + 41 + do_reverse: 42 + add $r0, $r0, $r2 ! Start with the end of $r0 43 + add $r1, $r1, $r2 ! Start with the end of $r1 44 + andi $r2, $r2, #3 ! How many bytes are less than a word 45 + li $t0, #-1 ! Determining copy direction in byte_cpy 46 + beqz $p1, reverse_byte_cpy ! When n is less than a word 47 + 48 + reverse_word_cpy: 49 + lmw.adm $p0, [$r1], $p0 ! Read a word from src 50 + addi $p1, $p1, #-1 ! How many words left to copy 51 + smw.adm $p0, [$r0], $p0 ! Copy the word to det 52 + bnez $p1, reverse_word_cpy ! If remained words > 0 53 + beqz $r2, end_memcpy ! No left bytes to copy 54 + 55 + reverse_byte_cpy: 56 + addi $r0, $r0, #-1 57 + addi $r1, $r1, #-1 58 + byte_cpy: ! Less than 4 bytes to copy now 59 + lb.bi $p0, [$r1], $t0 ! Read a byte from src 60 + addi $r2, $r2, #-1 ! How many bytes left to copy 61 + sb.bi $p0, [$r0], $t0 ! copy the byte to det 62 + bnez $r2, byte_cpy ! If remained bytes > 0 63 + 64 + end_memcpy: 65 + popm $t0, $t1 66 + exit_memcpy: 67 + move $r0, $r5 68 + ret 69 + 70 + ENDPROC(memmove)
+33
arch/nds32/lib/memset.S
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // Copyright (C) 2005-2017 Andes Technology Corporation 3 + 4 + #include <linux/linkage.h> 5 + 6 + .text 7 + ENTRY(memset) 8 + move $r5, $r0 ! Return value 9 + beqz $r2, end_memset ! Exit when len = 0 10 + srli $p1, $r2, 2 ! $p1 is how many words to copy 11 + andi $r2, $r2, 3 ! How many bytes are less than a word 12 + beqz $p1, byte_set ! When n is less than a word 13 + 14 + ! set $r1 from ??????ab to abababab 15 + andi $r1, $r1, #0x00ff ! $r1 = 000000ab 16 + slli $p0, $r1, #8 ! $p0 = 0000ab00 17 + or $r1, $r1, $p0 ! $r1 = 0000abab 18 + slli $p0, $r1, #16 ! $p0 = abab0000 19 + or $r1, $r1, $p0 ! $r1 = abababab 20 + word_set: 21 + addi $p1, $p1, #-1 ! How many words left to copy 22 + smw.bim $r1, [$r0], $r1 ! Copy the word to det 23 + bnez $p1, word_set ! Still words to set, continue looping 24 + beqz $r2, end_memset ! No left byte to set 25 + byte_set: ! Less than 4 bytes left to set 26 + addi $r2, $r2, #-1 ! Decrease len by 1 27 + sbi.bi $r1, [$r0], #1 ! Set data of the next byte to $r1 28 + bnez $r2, byte_set ! Still bytes left to set 29 + end_memset: 30 + move $r0, $r5 31 + ret 32 + 33 + ENDPROC(memset)
+18
arch/nds32/lib/memzero.S
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // Copyright (C) 2005-2017 Andes Technology Corporation 3 + 4 + #include <linux/linkage.h> 5 + 6 + .text 7 + ENTRY(memzero) 8 + beqz $r1, 1f 9 + push $lp 10 + move $r2, $r1 11 + move $r1, #0 12 + push $r0 13 + bal memset 14 + pop $r0 15 + pop $lp 16 + 1: 17 + ret 18 + ENDPROC(memzero)