diff options
Diffstat (limited to 'arch/unicore32/lib')
| -rw-r--r-- | arch/unicore32/lib/Makefile | 27 | ||||
| -rw-r--r-- | arch/unicore32/lib/backtrace.S | 163 | ||||
| -rw-r--r-- | arch/unicore32/lib/clear_user.S | 57 | ||||
| -rw-r--r-- | arch/unicore32/lib/copy_from_user.S | 108 | ||||
| -rw-r--r-- | arch/unicore32/lib/copy_page.S | 39 | ||||
| -rw-r--r-- | arch/unicore32/lib/copy_template.S | 214 | ||||
| -rw-r--r-- | arch/unicore32/lib/copy_to_user.S | 96 | ||||
| -rw-r--r-- | arch/unicore32/lib/delay.S | 51 | ||||
| -rw-r--r-- | arch/unicore32/lib/findbit.S | 100 | ||||
| -rw-r--r-- | arch/unicore32/lib/strncpy_from_user.S | 45 | ||||
| -rw-r--r-- | arch/unicore32/lib/strnlen_user.S | 42 | 
11 files changed, 942 insertions, 0 deletions
diff --git a/arch/unicore32/lib/Makefile b/arch/unicore32/lib/Makefile new file mode 100644 index 00000000000..87229a558b3 --- /dev/null +++ b/arch/unicore32/lib/Makefile @@ -0,0 +1,27 @@ +# +# linux/arch/unicore32/lib/Makefile +# +# Copyright (C) 2001-2010 GUAN Xue-tao +# + +lib-y	:= backtrace.o delay.o findbit.o +lib-y	+= strncpy_from_user.o strnlen_user.o +lib-y	+= clear_user.o copy_page.o +lib-y	+= copy_from_user.o copy_to_user.o + +GNU_LIBC_A		:= $(shell $(CC) $(KBUILD_CFLAGS) -print-file-name=libc.a) +GNU_LIBC_A_OBJS		:= memchr.o memcpy.o memmove.o memset.o +GNU_LIBC_A_OBJS		+= strchr.o strrchr.o +GNU_LIBC_A_OBJS		+= rawmemchr.o			# needed by strrchr.o + +GNU_LIBGCC_A		:= $(shell $(CC) $(KBUILD_CFLAGS) -print-file-name=libgcc.a) +GNU_LIBGCC_A_OBJS	:= _ashldi3.o _ashrdi3.o _lshrdi3.o +GNU_LIBGCC_A_OBJS	+= _divsi3.o _modsi3.o _ucmpdi2.o _umodsi3.o _udivsi3.o + +lib-y	+= $(GNU_LIBC_A_OBJS) $(GNU_LIBGCC_A_OBJS) + +$(addprefix $(obj)/, $(GNU_LIBC_A_OBJS)): +	$(Q)$(AR) p $(GNU_LIBC_A) $(notdir $@) > $@ + +$(addprefix $(obj)/, $(GNU_LIBGCC_A_OBJS)): +	$(Q)$(AR) p $(GNU_LIBGCC_A) $(notdir $@) > $@ diff --git a/arch/unicore32/lib/backtrace.S b/arch/unicore32/lib/backtrace.S new file mode 100644 index 00000000000..ef01d77f2f6 --- /dev/null +++ b/arch/unicore32/lib/backtrace.S @@ -0,0 +1,163 @@ +/* + * linux/arch/unicore32/lib/backtrace.S + * + * Code specific to PKUnity SoC and UniCore ISA + * + * Copyright (C) 2001-2010 GUAN Xue-tao + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/linkage.h> +#include <asm/assembler.h> +		.text + +@ fp is 0 or stack frame + +#define frame	v4 +#define sv_fp	v5 +#define sv_pc	v6 +#define offset	v8 + +ENTRY(__backtrace) +		mov	r0, fp + +ENTRY(c_backtrace) + +#if !defined(CONFIG_FRAME_POINTER) || !defined(CONFIG_PRINTK) +		mov	pc, lr +ENDPROC(__backtrace) +ENDPROC(c_backtrace) +#else +		stm.w	(v4 - v8, lr), [sp-]	@ Save an extra register +						@ so we have a location... +		mov.a	frame, r0		@ if frame pointer is zero +		beq	no_frame		@ we have no stack frames + +1:		stm.w	(pc), [sp-]		@ calculate offset of PC stored +		ldw.w	r0, [sp]+, #4		@ by stmfd for this CPU +		adr	r1, 1b +		sub	offset, r0, r1 + +/* + * Stack frame layout: + *             optionally saved caller registers (r4 - r10) + *             saved fp + *             saved sp + *             saved lr + *    frame => saved pc + *             optionally saved arguments (r0 - r3) + * saved sp => <next word> + * + * Functions start with the following code sequence: + *                  mov   ip, sp + *                  stm.w (r0 - r3), [sp-] (optional) + * corrected pc =>  stm.w sp, (..., fp, ip, lr, pc) + */ +for_each_frame: + +1001:		ldw	sv_pc, [frame+], #0	@ get saved pc +1002:		ldw	sv_fp, [frame+], #-12	@ get saved fp + +		sub	sv_pc, sv_pc, offset	@ Correct PC for prefetching + +1003:		ldw	r2, [sv_pc+], #-4	@ if stmfd sp, {args} exists, +		ldw	r3, .Ldsi+4		@ adjust saved 'pc' back one +		cxor.a	r3, r2 >> #14		@ instruction +		beq	201f +		sub	r0, sv_pc, #4		@ allow for mov +		b	202f +201: +		sub	r0, sv_pc, #8		@ allow for mov + stmia +202: +		ldw	r1, [frame+], #-4	@ get saved lr +		mov	r2, frame +		b.l	dump_backtrace_entry + +		ldw	r1, [sv_pc+], #-4	@ if stmfd sp, {args} exists, +		ldw	r3, .Ldsi+4 +		cxor.a	r3, r1 >> #14 +		bne	1004f +		ldw	r0, [frame+], #-8	@ get sp +		sub	r0, r0, #4		@ point at the last arg +		b.l	.Ldumpstm		@ dump saved registers + +1004:		ldw	r1, [sv_pc+], #0	@ if stmfd {, fp, ip, lr, pc} +		ldw	r3, .Ldsi		@ instruction exists, +		cxor.a	r3, r1 >> #14 +		bne	201f +		sub	r0, frame, #16 +		b.l	.Ldumpstm		@ dump saved registers +201: +		cxor.a	sv_fp, #0		@ zero saved fp means +		beq	no_frame		@ no further frames + +		csub.a	sv_fp, frame		@ next frame must be +		mov	frame, sv_fp		@ above the current frame +		bua	for_each_frame + +1006:		adr	r0, .Lbad +		mov	r1, frame +		b.l	printk +no_frame:	ldm.w	(v4 - v8, pc), [sp]+ +ENDPROC(__backtrace) +ENDPROC(c_backtrace) + +		.pushsection __ex_table,"a" +		.align	3 +		.long	1001b, 1006b +		.long	1002b, 1006b +		.long	1003b, 1006b +		.long	1004b, 1006b +		.popsection + +#define instr v4 +#define reg   v5 +#define stack v6 + +.Ldumpstm:	stm.w	(instr, reg, stack, v7, lr), [sp-] +		mov	stack, r0 +		mov	instr, r1 +		mov	reg, #14 +		mov	v7, #0 +1:		mov	r3, #1 +		csub.a	reg, #8 +		bne	201f +		sub	reg, reg, #3 +201: +		cand.a	instr, r3 << reg +		beq	2f +		add	v7, v7, #1 +		cxor.a	v7, #6 +		cmoveq	v7, #1 +		cmoveq	r1, #'\n' +		cmovne	r1, #' ' +		ldw.w	r3, [stack]+, #-4 +		mov	r2, reg +		csub.a	r2, #8 +		bsl	201f +		sub	r2, r2, #3 +201: +		cand.a	instr, #0x40		@ if H is 1, high 16 regs +		beq	201f +		add	r2, r2, #0x10		@ so r2 need add 16 +201: +		adr	r0, .Lfp +		b.l	printk +2:		sub.a	reg, reg, #1 +		bns	1b +		cxor.a	v7, #0 +		beq	201f +		adr	r0, .Lcr +		b.l	printk +201:		ldm.w	(instr, reg, stack, v7, pc), [sp]+ + +.Lfp:		.asciz	"%cr%d:%08x" +.Lcr:		.asciz	"\n" +.Lbad:		.asciz	"Backtrace aborted due to bad frame pointer <%p>\n" +		.align +.Ldsi:		.word	0x92eec000 >> 14	@ stm.w sp, (... fp, ip, lr, pc) +		.word	0x92e10000 >> 14	@ stm.w sp, () + +#endif diff --git a/arch/unicore32/lib/clear_user.S b/arch/unicore32/lib/clear_user.S new file mode 100644 index 00000000000..20047f7224f --- /dev/null +++ b/arch/unicore32/lib/clear_user.S @@ -0,0 +1,57 @@ +/* + * linux/arch/unicore32/lib/clear_user.S + * + * Code specific to PKUnity SoC and UniCore ISA + * + * Copyright (C) 2001-2010 GUAN Xue-tao + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/linkage.h> +#include <asm/assembler.h> + +		.text + +/* Prototype: int __clear_user(void *addr, size_t sz) + * Purpose  : clear some user memory + * Params   : addr - user memory address to clear + *          : sz   - number of bytes to clear + * Returns  : number of bytes NOT cleared + */ +WEAK(__clear_user) +		stm.w	(lr), [sp-] +		stm.w	(r1), [sp-] +		mov	r2, #0 +		csub.a	r1, #4 +		bsl	2f +		and.a	ip, r0, #3 +		beq	1f +		csub.a	ip, #2 +		strusr	r2, r0, 1 +		strusr	r2, r0, 1, el +		strusr	r2, r0, 1, sl +		rsub	ip, ip, #4 +		sub	r1, r1, ip		@  7  6  5  4  3  2  1 +1:		sub.a	r1, r1, #8		@ -1 -2 -3 -4 -5 -6 -7 +		strusr	r2, r0, 4, ns, rept=2 +		bns	1b +		add.a	r1, r1, #4		@  3  2  1  0 -1 -2 -3 +		strusr	r2, r0, 4, ns +2:		cand.a	r1, #2			@ 1x 1x 0x 0x 1x 1x 0x +		strusr	r2, r0, 1, ne, rept=2 +		cand.a	r1, #1			@ x1 x0 x1 x0 x1 x0 x1 +		beq	3f +USER(		stb.u	r2, [r0]) +3:		mov	r0, #0 +		ldm.w	(r1), [sp]+ +		ldm.w	(pc), [sp]+ +ENDPROC(__clear_user) + +		.pushsection .fixup,"ax" +		.align	0 +9001:		ldm.w	(r0), [sp]+ +		ldm.w	(pc), [sp]+ +		.popsection + diff --git a/arch/unicore32/lib/copy_from_user.S b/arch/unicore32/lib/copy_from_user.S new file mode 100644 index 00000000000..ab0767ea5db --- /dev/null +++ b/arch/unicore32/lib/copy_from_user.S @@ -0,0 +1,108 @@ +/* + * linux/arch/unicore32/lib/copy_from_user.S + * + * Code specific to PKUnity SoC and UniCore ISA + * + * Copyright (C) 2001-2010 GUAN Xue-tao + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/linkage.h> +#include <asm/assembler.h> + +/* + * Prototype: + * + *	size_t __copy_from_user(void *to, const void *from, size_t n) + * + * Purpose: + * + *	copy a block to kernel memory from user memory + * + * Params: + * + *	to = kernel memory + *	from = user memory + *	n = number of bytes to copy + * + * Return value: + * + *	Number of bytes NOT copied. + */ + +	.macro ldr1w ptr reg abort +	ldrusr	\reg, \ptr, 4, abort=\abort +	.endm + +	.macro ldr4w ptr reg1 reg2 reg3 reg4 abort +100:	ldm.w	(\reg1, \reg2, \reg3, \reg4), [\ptr]+ +	.pushsection __ex_table, "a" +	.align	3 +	.long 100b, \abort +	.popsection +	.endm + +	.macro ldr8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort +100:	ldm.w (\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8), [\ptr]+ +	.pushsection __ex_table, "a" +	.align	3 +	.long 100b, \abort +	.popsection +	.endm + +	.macro ldr1b ptr reg cond=al abort +	ldrusr	\reg, \ptr, 1, \cond, abort=\abort +	.endm + +	.macro str1w ptr reg abort +	stw.w \reg, [\ptr]+, #4 +	.endm + +	.macro str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort +	stm.w (\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8), [\ptr]+ +	.endm + +	.macro str1b ptr reg cond=al abort +	.ifnc	\cond, al +	b\cond	201f +	b	202f +	.endif +201:	stb.w \reg, [\ptr]+, #1 +202: +	.endm + +	.macro enter +	mov	r3, #0 +	stm.w	(r0, r2, r3), [sp-] +	.endm + +	.macro exit +	add	sp, sp, #8 +	ldm.w	(r0), [sp]+ +	mov	pc, lr +	.endm + +	.text + +ENTRY(__copy_from_user) + +#include "copy_template.S" + +ENDPROC(__copy_from_user) + +	.pushsection .fixup,"ax" +	.align 0 +	copy_abort_preamble +	ldm.w	(r1, r2), [sp]+ +	sub	r3, r0, r1 +	rsub	r2, r3, r2 +	stw	r2, [sp] +	mov	r1, #0 +	b.l	memset +	ldw.w	r0, [sp]+, #4 +	copy_abort_end +	.popsection + diff --git a/arch/unicore32/lib/copy_page.S b/arch/unicore32/lib/copy_page.S new file mode 100644 index 00000000000..3a448d755ad --- /dev/null +++ b/arch/unicore32/lib/copy_page.S @@ -0,0 +1,39 @@ +/* + * linux/arch/unicore32/lib/copy_page.S + * + * Code specific to PKUnity SoC and UniCore ISA + * + * Copyright (C) 2001-2010 GUAN Xue-tao + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + *  ASM optimised string functions + */ +#include <linux/linkage.h> +#include <asm/assembler.h> +#include <generated/asm-offsets.h> +#include <asm/cache.h> + +#define COPY_COUNT (PAGE_SZ/256) + +		.text +		.align	5 +/* + * UniCore optimised copy_page routine + */ +ENTRY(copy_page) +		stm.w	(r17 - r19, lr), [sp-] +		mov	r17, r0 +		mov	r18, r1 +		mov	r19, #COPY_COUNT +1: +	.rept	4 +		ldm.w	(r0 - r15), [r18]+ +		stm.w	(r0 - r15), [r17]+ +	.endr +		sub.a	r19, r19, #1 +		bne	1b +		ldm.w	(r17 - r19, pc), [sp]+ +ENDPROC(copy_page) diff --git a/arch/unicore32/lib/copy_template.S b/arch/unicore32/lib/copy_template.S new file mode 100644 index 00000000000..524287fc012 --- /dev/null +++ b/arch/unicore32/lib/copy_template.S @@ -0,0 +1,214 @@ +/* + * linux/arch/unicore32/lib/copy_template.S + * + * Code specific to PKUnity SoC and UniCore ISA + * + * Copyright (C) 2001-2010 GUAN Xue-tao + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * Theory of operation + * ------------------- + * + * This file provides the core code for a forward memory copy used in + * the implementation of memcopy(), copy_to_user() and copy_from_user(). + * + * The including file must define the following accessor macros + * according to the need of the given function: + * + * ldr1w ptr reg abort + * + *	This loads one word from 'ptr', stores it in 'reg' and increments + *	'ptr' to the next word. The 'abort' argument is used for fixup tables. + * + * ldr4w ptr reg1 reg2 reg3 reg4 abort + * ldr8w ptr, reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort + * + *	This loads four or eight words starting from 'ptr', stores them + *	in provided registers and increments 'ptr' past those words. + *	The'abort' argument is used for fixup tables. + * + * ldr1b ptr reg cond abort + * + *	Similar to ldr1w, but it loads a byte and increments 'ptr' one byte. + *	It also must apply the condition code if provided, otherwise the + *	"al" condition is assumed by default. + * + * str1w ptr reg abort + * str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort + * str1b ptr reg cond abort + * + *	Same as their ldr* counterparts, but data is stored to 'ptr' location + *	rather than being loaded. + * + * enter + * + *	Preserve the provided registers on the stack plus any additional + *	data as needed by the implementation including this code. Called + *	upon code entry. + * + * exit + * + *	Restore registers with the values previously saved with the + *	'preserv' macro. Called upon code termination. + */ + + +		enter + +		sub.a	r2, r2, #4 +		bsl	8f +		and.a	ip, r0, #3 +		bne	9f +		and.a	ip, r1, #3 +		bne	10f + +1:		sub.a	r2, r2, #(28) +		stm.w	(r5 - r8), [sp-] +		bsl	5f + +3: +4:		ldr8w	r1, r3, r4, r5, r6, r7, r8, r10, r11, abort=20f +		sub.a	r2, r2, #32 +		str8w	r0, r3, r4, r5, r6, r7, r8, r10, r11, abort=20f +		beg	3b + +5:		and.a	ip, r2, #28 +		rsub	ip, ip, #32 +		beq	7f +		add	pc, pc, ip		@ C is always clear here +		nop + +		ldr1w	r1, r3, abort=20f +		ldr1w	r1, r4, abort=20f +		ldr1w	r1, r5, abort=20f +		ldr1w	r1, r6, abort=20f +		ldr1w	r1, r7, abort=20f +		ldr1w	r1, r8, abort=20f +		ldr1w	r1, r11, abort=20f + +		add	pc, pc, ip +		nop + +		str1w	r0, r3, abort=20f +		str1w	r0, r4, abort=20f +		str1w	r0, r5, abort=20f +		str1w	r0, r6, abort=20f +		str1w	r0, r7, abort=20f +		str1w	r0, r8, abort=20f +		str1w	r0, r11, abort=20f + +7:		ldm.w	(r5 - r8), [sp]+ + +8:		mov.a	r2, r2 << #31 +		ldr1b	r1, r3, ne, abort=21f +		ldr1b	r1, r4, ea, abort=21f +		ldr1b	r1, r10, ea, abort=21f +		str1b	r0, r3, ne, abort=21f +		str1b	r0, r4, ea, abort=21f +		str1b	r0, r10, ea, abort=21f + +		exit + +9:		rsub	ip, ip, #4 +		csub.a	ip, #2 +		ldr1b	r1, r3, sg, abort=21f +		ldr1b	r1, r4, eg, abort=21f +		ldr1b	r1, r11, abort=21f +		str1b	r0, r3, sg, abort=21f +		str1b	r0, r4, eg, abort=21f +		sub.a	r2, r2, ip +		str1b	r0, r11, abort=21f +		bsl	8b +		and.a	ip, r1, #3 +		beq	1b + +10:		andn	r1, r1, #3 +		csub.a	ip, #2 +		ldr1w	r1, r11, abort=21f +		beq	17f +		bsg	18f + + +		.macro	forward_copy_shift a b + +		sub.a	r2, r2, #28 +		bsl	14f + +11:		stm.w	(r5 - r9), [sp-] + +12: +		ldr4w	r1, r4, r5, r6, r7, abort=19f +		mov	r3, r11 pull #\a +		sub.a	r2, r2, #32 +		ldr4w	r1, r8, r9, r10, r11, abort=19f +		or	r3, r3, r4 push #\b +		mov	r4, r4 pull #\a +		or	r4, r4, r5 push #\b +		mov	r5, r5 pull #\a +		or	r5, r5, r6 push #\b +		mov	r6, r6 pull #\a +		or	r6, r6, r7 push #\b +		mov	r7, r7 pull #\a +		or	r7, r7, r8 push #\b +		mov	r8, r8 pull #\a +		or	r8, r8, r9 push #\b +		mov	r9, r9 pull #\a +		or	r9, r9, r10 push #\b +		mov	r10, r10 pull #\a +		or	r10, r10, r11 push #\b +		str8w	r0, r3, r4, r5, r6, r7, r8, r9, r10, , abort=19f +		beg	12b + +		ldm.w	(r5 - r9), [sp]+ + +14:		and.a	ip, r2, #28 +		beq	16f + +15:		mov	r3, r11 pull #\a +		ldr1w	r1, r11, abort=21f +		sub.a	ip, ip, #4 +		or	r3, r3, r11 push #\b +		str1w	r0, r3, abort=21f +		bsg	15b + +16:		sub	r1, r1, #(\b / 8) +		b	8b + +		.endm + + +		forward_copy_shift	a=8	b=24 + +17:		forward_copy_shift	a=16	b=16 + +18:		forward_copy_shift	a=24	b=8 + + +/* + * Abort preamble and completion macros. + * If a fixup handler is required then those macros must surround it. + * It is assumed that the fixup code will handle the private part of + * the exit macro. + */ + +	.macro	copy_abort_preamble +19:	ldm.w	(r5 - r9), [sp]+ +	b	21f +299:	.word	0			@ store lr +					@ to avoid function call in fixup +20:	ldm.w	(r5 - r8), [sp]+ +21: +	adr	r1, 299b +	stw	lr, [r1] +	.endm + +	.macro	copy_abort_end +	adr	lr, 299b +	ldw	pc, [lr] +	.endm + diff --git a/arch/unicore32/lib/copy_to_user.S b/arch/unicore32/lib/copy_to_user.S new file mode 100644 index 00000000000..6e22151c840 --- /dev/null +++ b/arch/unicore32/lib/copy_to_user.S @@ -0,0 +1,96 @@ +/* + * linux/arch/unicore32/lib/copy_to_user.S + * + * Code specific to PKUnity SoC and UniCore ISA + * + * Copyright (C) 2001-2010 GUAN Xue-tao + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/linkage.h> +#include <asm/assembler.h> + +/* + * Prototype: + * + *	size_t __copy_to_user(void *to, const void *from, size_t n) + * + * Purpose: + * + *	copy a block to user memory from kernel memory + * + * Params: + * + *	to = user memory + *	from = kernel memory + *	n = number of bytes to copy + * + * Return value: + * + *	Number of bytes NOT copied. + */ + +	.macro ldr1w ptr reg abort +	ldw.w \reg, [\ptr]+, #4 +	.endm + +	.macro ldr4w ptr reg1 reg2 reg3 reg4 abort +	ldm.w	(\reg1, \reg2, \reg3, \reg4), [\ptr]+ +	.endm + +	.macro ldr8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort +	ldm.w (\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8), [\ptr]+ +	.endm + +	.macro ldr1b ptr reg cond=al abort +	notcond	\cond, .+8 +	ldb.w \reg, [\ptr]+, #1 +	.endm + +	.macro str1w ptr reg abort +	strusr	\reg, \ptr, 4, abort=\abort +	.endm + +	.macro str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort +100:	stm.w (\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8), [\ptr]+ + +	.pushsection __ex_table, "a" +	.long 100b, \abort +	.popsection +	.endm + +	.macro str1b ptr reg cond=al abort +	strusr	\reg, \ptr, 1, \cond, abort=\abort +	.endm + +	.macro enter +	mov	r3, #0 +	stm.w	(r0, r2, r3), [sp-] +	.endm + +	.macro exit +	add	sp, sp, #8 +	ldm.w	(r0), [sp]+ +	mov	pc, lr +	.endm + +	.text + +WEAK(__copy_to_user) + +#include "copy_template.S" + +ENDPROC(__copy_to_user) + +	.pushsection .fixup,"ax" +	.align 0 +	copy_abort_preamble +	ldm.w	(r1, r2, r3), [sp]+ +	sub	r0, r0, r1 +	rsub	r0, r0, r2 +	copy_abort_end +	.popsection + diff --git a/arch/unicore32/lib/delay.S b/arch/unicore32/lib/delay.S new file mode 100644 index 00000000000..24664c009e7 --- /dev/null +++ b/arch/unicore32/lib/delay.S @@ -0,0 +1,51 @@ +/* + * linux/arch/unicore32/lib/delay.S + * + * Code specific to PKUnity SoC and UniCore ISA + * + * Copyright (C) 2001-2010 GUAN Xue-tao + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/linkage.h> +#include <asm/assembler.h> +#include <asm/param.h> +		.text + +.LC0:		.word	loops_per_jiffy +.LC1:		.word	(2199023*HZ)>>11 + +/* + * r0  <= 2000 + * lpj <= 0x01ffffff (max. 3355 bogomips) + * HZ  <= 1000 + */ + +ENTRY(__udelay) +		ldw	r2, .LC1 +		mul	r0, r2, r0 +ENTRY(__const_udelay)				@ 0 <= r0 <= 0x7fffff06 +		ldw	r2, .LC0 +		ldw	r2, [r2]		@ max = 0x01ffffff +		mov	r0, r0 >> #14		@ max = 0x0001ffff +		mov	r2, r2 >> #10		@ max = 0x00007fff +		mul	r0, r2, r0		@ max = 2^32-1 +		mov.a	r0, r0 >> #6 +		cmoveq	pc, lr + +/* + * loops = r0 * HZ * loops_per_jiffy / 1000000 + * + * Oh, if only we had a cycle counter... + */ + +@ Delay routine +ENTRY(__delay) +		sub.a	r0, r0, #2 +		bua	__delay +		mov	pc, lr +ENDPROC(__udelay) +ENDPROC(__const_udelay) +ENDPROC(__delay) diff --git a/arch/unicore32/lib/findbit.S b/arch/unicore32/lib/findbit.S new file mode 100644 index 00000000000..c77746247d3 --- /dev/null +++ b/arch/unicore32/lib/findbit.S @@ -0,0 +1,100 @@ +/* + * linux/arch/unicore32/lib/findbit.S + * + * Code specific to PKUnity SoC and UniCore ISA + * + * Copyright (C) 2001-2010 GUAN Xue-tao + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/linkage.h> +#include <asm/assembler.h> +                .text + +/* + * Purpose  : Find a 'zero' bit + * Prototype: int find_first_zero_bit(void *addr, unsigned int maxbit); + */ +ENTRY(find_first_zero_bit) +		cxor.a	r1, #0 +		beq	3f +		mov	r2, #0 +1:		ldb	r3, [r0+], r2 >> #3 +		xor.a	r3, r3, #0xff		@ invert bits +		bne	.L_found		@ any now set - found zero bit +		add	r2, r2, #8		@ next bit pointer +2:		csub.a	r2, r1			@ any more? +		bub	1b +3:		mov	r0, r1			@ no free bits +		mov	pc, lr +ENDPROC(find_first_zero_bit) + +/* + * Purpose  : Find next 'zero' bit + * Prototype: int find_next_zero_bit + *		(void *addr, unsigned int maxbit, int offset) + */ +ENTRY(find_next_zero_bit) +		cxor.a	r1, #0 +		beq	3b +		and.a	ip, r2, #7 +		beq	1b			@ If new byte, goto old routine +		ldb	r3, [r0+], r2 >> #3 +		xor	r3, r3, #0xff		@ now looking for a 1 bit +		mov.a	r3, r3 >> ip		@ shift off unused bits +		bne	.L_found +		or	r2, r2, #7		@ if zero, then no bits here +		add	r2, r2, #1		@ align bit pointer +		b	2b			@ loop for next bit +ENDPROC(find_next_zero_bit) + +/* + * Purpose  : Find a 'one' bit + * Prototype: int find_first_bit + *		(const unsigned long *addr, unsigned int maxbit); + */ +ENTRY(find_first_bit) +		cxor.a	r1, #0 +		beq	3f +		mov	r2, #0 +1:		ldb	r3, [r0+], r2 >> #3 +		mov.a	r3, r3 +		bne	.L_found		@ any now set - found zero bit +		add	r2, r2, #8		@ next bit pointer +2:		csub.a	r2, r1			@ any more? +		bub	1b +3:		mov	r0, r1			@ no free bits +		mov	pc, lr +ENDPROC(find_first_bit) + +/* + * Purpose  : Find next 'one' bit + * Prototype: int find_next_zero_bit + *		(void *addr, unsigned int maxbit, int offset) + */ +ENTRY(find_next_bit) +		cxor.a	r1, #0 +		beq	3b +		and.a	ip, r2, #7 +		beq	1b			@ If new byte, goto old routine +		ldb	r3, [r0+], r2 >> #3 +		mov.a	r3, r3 >> ip		@ shift off unused bits +		bne	.L_found +		or	r2, r2, #7		@ if zero, then no bits here +		add	r2, r2, #1		@ align bit pointer +		b	2b			@ loop for next bit +ENDPROC(find_next_bit) + +/* + * One or more bits in the LSB of r3 are assumed to be set. + */ +.L_found: +		rsub	r1, r3, #0 +		and	r3, r3, r1 +		cntlz	r3, r3 +		rsub	r3, r3, #31 +		add	r0, r2, r3 +		mov	pc, lr + diff --git a/arch/unicore32/lib/strncpy_from_user.S b/arch/unicore32/lib/strncpy_from_user.S new file mode 100644 index 00000000000..ff6c304d5c7 --- /dev/null +++ b/arch/unicore32/lib/strncpy_from_user.S @@ -0,0 +1,45 @@ +/* + * linux/arch/unicore32/lib/strncpy_from_user.S + * + * Code specific to PKUnity SoC and UniCore ISA + * + * Copyright (C) 2001-2010 GUAN Xue-tao + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/linkage.h> +#include <asm/assembler.h> +#include <asm/errno.h> + +	.text +	.align	5 + +/* + * Copy a string from user space to kernel space. + *  r0 = dst, r1 = src, r2 = byte length + * returns the number of characters copied (strlen of copied string), + *  -EFAULT on exception, or "len" if we fill the whole buffer + */ +ENTRY(__strncpy_from_user) +	mov	ip, r1 +1:	sub.a	r2, r2, #1 +	ldrusr	r3, r1, 1, ns +	bfs	2f +	stb.w	r3, [r0]+, #1 +	cxor.a	r3, #0 +	bne	1b +	sub	r1, r1, #1	@ take NUL character out of count +2:	sub	r0, r1, ip +	mov	pc, lr +ENDPROC(__strncpy_from_user) + +	.pushsection .fixup,"ax" +	.align	0 +9001:	mov	r3, #0 +	stb	r3, [r0+], #0	@ null terminate +	mov	r0, #-EFAULT +	mov	pc, lr +	.popsection + diff --git a/arch/unicore32/lib/strnlen_user.S b/arch/unicore32/lib/strnlen_user.S new file mode 100644 index 00000000000..75863030f21 --- /dev/null +++ b/arch/unicore32/lib/strnlen_user.S @@ -0,0 +1,42 @@ +/* + * linux/arch/unicore32/lib/strnlen_user.S + * + * Code specific to PKUnity SoC and UniCore ISA + * + * Copyright (C) 2001-2010 GUAN Xue-tao + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/linkage.h> +#include <asm/assembler.h> +#include <asm/errno.h> + +	.text +	.align	5 + +/* Prototype: unsigned long __strnlen_user(const char *str, long n) + * Purpose  : get length of a string in user memory + * Params   : str - address of string in user memory + * Returns  : length of string *including terminator* + *	      or zero on exception, or n + 1 if too long + */ +ENTRY(__strnlen_user) +	mov	r2, r0 +1: +	ldrusr	r3, r0, 1 +	cxor.a	r3, #0 +	beq	2f +	sub.a	r1, r1, #1 +	bne	1b +	add	r0, r0, #1 +2:	sub	r0, r0, r2 +	mov	pc, lr +ENDPROC(__strnlen_user) + +	.pushsection .fixup,"ax" +	.align	0 +9001:	mov	r0, #0 +	mov	pc, lr +	.popsection  | 
