linux/arch/sh/mm/clear_page.S
Paul Mundt 510c72ad2d sh: Fixup various PAGE_SIZE == 4096 assumptions.
There were a number of places that made evil PAGE_SIZE == 4k
assumptions that ended up breaking when trying to play with
8k and 64k page sizes, this fixes those up.

The most significant change is the way we load THREAD_SIZE,
previously this was done via:

	mov	#(THREAD_SIZE >> 8), reg
	shll8	reg

to avoid a memory access and allow the immediate load. With
a 64k PAGE_SIZE, we're out of range for the immediate load
size without resorting to special instructions available in
later ISAs (movi20s and so on). The "workaround" for this is
to bump up the shift to 10 and insert a shll2, which gives a
bit more flexibility while still being much cheaper than a
memory access.

Signed-off-by: Paul Mundt <lethal@linux-sh.org>
2006-12-06 10:45:39 +09:00

198 lines
2.9 KiB
ArmAsm

/*
* __clear_user_page, __clear_user, clear_page implementation of SuperH
*
* Copyright (C) 2001 Kaz Kojima
* Copyright (C) 2001, 2002 Niibe Yutaka
* Copyright (C) 2006 Paul Mundt
*/
#include <linux/linkage.h>
#include <asm/page.h>
/*
* clear_page_slow
* @to: P1 address
*
* void clear_page_slow(void *to)
*/
/*
* r0 --- scratch
* r4 --- to
* r5 --- to + PAGE_SIZE
*/
ENTRY(clear_page_slow)
mov r4,r5
mov.l .Llimit,r0
add r0,r5
mov #0,r0
!
1:
#if defined(CONFIG_CPU_SH3)
mov.l r0,@r4
#elif defined(CONFIG_CPU_SH4)
movca.l r0,@r4
mov r4,r1
#endif
add #32,r4
mov.l r0,@-r4
mov.l r0,@-r4
mov.l r0,@-r4
mov.l r0,@-r4
mov.l r0,@-r4
mov.l r0,@-r4
mov.l r0,@-r4
#if defined(CONFIG_CPU_SH4)
ocbwb @r1
#endif
cmp/eq r5,r4
bf/s 1b
add #28,r4
!
rts
nop
.Llimit: .long (PAGE_SIZE-28)
ENTRY(__clear_user)
!
mov #0, r0
mov #0xe0, r1 ! 0xffffffe0
!
! r4..(r4+31)&~32 -------- not aligned [ Area 0 ]
! (r4+31)&~32..(r4+r5)&~32 -------- aligned [ Area 1 ]
! (r4+r5)&~32..r4+r5 -------- not aligned [ Area 2 ]
!
! Clear area 0
mov r4, r2
!
tst r1, r5 ! length < 32
bt .Larea2 ! skip to remainder
!
add #31, r2
and r1, r2
cmp/eq r4, r2
bt .Larea1
mov r2, r3
sub r4, r3
mov r3, r7
mov r4, r2
!
.L0: dt r3
0: mov.b r0, @r2
bf/s .L0
add #1, r2
!
sub r7, r5
mov r2, r4
.Larea1:
mov r4, r3
add r5, r3
and r1, r3
cmp/hi r2, r3
bf .Larea2
!
! Clear area 1
#if defined(CONFIG_CPU_SH4)
1: movca.l r0, @r2
#else
1: mov.l r0, @r2
#endif
add #4, r2
2: mov.l r0, @r2
add #4, r2
3: mov.l r0, @r2
add #4, r2
4: mov.l r0, @r2
add #4, r2
5: mov.l r0, @r2
add #4, r2
6: mov.l r0, @r2
add #4, r2
7: mov.l r0, @r2
add #4, r2
8: mov.l r0, @r2
add #4, r2
cmp/hi r2, r3
bt/s 1b
nop
!
! Clear area 2
.Larea2:
mov r4, r3
add r5, r3
cmp/hs r3, r2
bt/s .Ldone
sub r2, r3
.L2: dt r3
9: mov.b r0, @r2
bf/s .L2
add #1, r2
!
.Ldone: rts
mov #0, r0 ! return 0 as normal return
! return the number of bytes remained
.Lbad_clear_user:
mov r4, r0
add r5, r0
rts
sub r2, r0
.section __ex_table,"a"
.align 2
.long 0b, .Lbad_clear_user
.long 1b, .Lbad_clear_user
.long 2b, .Lbad_clear_user
.long 3b, .Lbad_clear_user
.long 4b, .Lbad_clear_user
.long 5b, .Lbad_clear_user
.long 6b, .Lbad_clear_user
.long 7b, .Lbad_clear_user
.long 8b, .Lbad_clear_user
.long 9b, .Lbad_clear_user
.previous
#if defined(CONFIG_CPU_SH4)
/*
* __clear_user_page
* @to: P3 address (with same color)
* @orig_to: P1 address
*
* void __clear_user_page(void *to, void *orig_to)
*/
/*
* r0 --- scratch
* r4 --- to
* r5 --- orig_to
* r6 --- to + PAGE_SIZE
*/
ENTRY(__clear_user_page)
mov.l .Lpsz,r0
mov r4,r6
add r0,r6
mov #0,r0
!
1: ocbi @r5
add #32,r5
movca.l r0,@r4
mov r4,r1
add #32,r4
mov.l r0,@-r4
mov.l r0,@-r4
mov.l r0,@-r4
mov.l r0,@-r4
mov.l r0,@-r4
mov.l r0,@-r4
mov.l r0,@-r4
add #28,r4
cmp/eq r6,r4
bf/s 1b
ocbwb @r1
!
rts
nop
.Lpsz: .long PAGE_SIZE
#endif