106 lines
		
	
	
	
		
			2 KiB
			
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
		
		
			
		
	
	
			106 lines
		
	
	
	
		
			2 KiB
			
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
|   | /* | ||
|  |  * OpenRISC string.S | ||
|  |  * | ||
|  |  * Linux architectural port borrowing liberally from similar works of | ||
|  |  * others.  All original copyrights apply as per the original source | ||
|  |  * declaration. | ||
|  |  * | ||
|  |  * Modifications for the OpenRISC architecture: | ||
|  |  * Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
 | ||
|  |  * Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
 | ||
|  |  * | ||
|  |  *      This program is free software; you can redistribute it and/or
 | ||
|  |  *      modify it under the terms of the GNU General Public License | ||
|  |  *      as published by the Free Software Foundation; either version
 | ||
|  |  *      2 of the License, or (at your option) any later version. | ||
|  |  */ | ||
|  | 
 | ||
|  | #include <linux/linkage.h> | ||
|  | #include <asm/errno.h> | ||
|  | 
 | ||
|  | 	/* | ||
|  | 	 * this can be optimized by doing gcc inline assemlby with | ||
|  | 	 * proper constraints (no need to save args registers...) | ||
|  | 	 * | ||
|  | 	 */ | ||
|  | 
 | ||
|  | 
 | ||
|  | /* | ||
|  |  * | ||
|  |  * int __copy_tofrom_user(void *to, const void *from, unsigned long size);
 | ||
|  |  * | ||
|  |  * NOTE: it returns number of bytes NOT copied !!! | ||
|  |  * | ||
|  |  */ | ||
|  | 	.global	__copy_tofrom_user
 | ||
|  | __copy_tofrom_user: | ||
|  | 	l.addi  r1,r1,-12 | ||
|  | 	l.sw    0(r1),r6 | ||
|  | 	l.sw    4(r1),r4 | ||
|  | 	l.sw    8(r1),r3 | ||
|  | 
 | ||
|  | 	l.addi  r11,r5,0 | ||
|  | 2:  	l.sfeq  r11,r0 | ||
|  | 	l.bf    1f | ||
|  | 	l.addi  r11,r11,-1 | ||
|  | 8:    	l.lbz   r6,0(r4) | ||
|  | 9:    	l.sb    0(r3),r6 | ||
|  | 	l.addi  r3,r3,1 | ||
|  | 	l.j     2b | ||
|  | 	l.addi  r4,r4,1 | ||
|  | 1: | ||
|  | 	l.addi  r11,r11,1               // r11 holds the return value | ||
|  | 
 | ||
|  | 	l.lwz   r6,0(r1) | ||
|  | 	l.lwz   r4,4(r1) | ||
|  | 	l.lwz   r3,8(r1) | ||
|  | 	l.jr    r9 | ||
|  | 	l.addi  r1,r1,12 | ||
|  | 
 | ||
|  | 	.section .fixup, "ax" | ||
|  | 99: | ||
|  | 		l.j     1b | ||
|  | 		l.nop | ||
|  | 	.previous | ||
|  | 
 | ||
|  | 	.section __ex_table, "a" | ||
|  | 		.long 8b, 99b		// read fault | ||
|  | 		.long 9b, 99b		// write fault | ||
|  | 	.previous | ||
|  | 
 | ||
|  | /* | ||
|  |  * unsigned long clear_user(void *addr, unsigned long size) ;
 | ||
|  |  * | ||
|  |  * NOTE: it returns number of bytes NOT cleared !!! | ||
|  |  */ | ||
|  | 	.global	__clear_user
 | ||
|  | __clear_user: | ||
|  | 	l.addi  r1,r1,-8 | ||
|  | 	l.sw    0(r1),r4 | ||
|  | 	l.sw    4(r1),r3 | ||
|  | 
 | ||
|  | 2:	l.sfeq	r4,r0 | ||
|  | 	l.bf	1f | ||
|  | 	l.addi	r4,r4,-1 | ||
|  | 9:	l.sb	0(r3),r0 | ||
|  | 	l.j	2b | ||
|  | 	l.addi  r3,r3,1 | ||
|  | 
 | ||
|  | 1: | ||
|  | 	l.addi  r11,r4,1 | ||
|  | 
 | ||
|  | 	l.lwz	r4,0(r1) | ||
|  | 	l.lwz	r3,4(r1) | ||
|  | 	l.jr	r9 | ||
|  | 	l.addi	r1,r1,8 | ||
|  | 
 | ||
|  | 	.section .fixup, "ax" | ||
|  | 99: | ||
|  | 		l.j     1b | ||
|  | 		l.nop | ||
|  | 	.previous | ||
|  | 
 | ||
|  | 	.section __ex_table, "a" | ||
|  | 		.long 9b, 99b		// write fault | ||
|  | 	.previous |