aboutsummaryrefslogtreecommitdiff
path: root/src/pkg/sync/atomic/asm_linux_arm.s
blob: 72f8d746bb269e2aba73eac3fe35f4f34c3624e4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
// Copyright 2011 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Linux/ARM atomic operations.

// Because there is so much variation in ARM devices,
// the Linux kernel provides an appropriate compare-and-swap
// implementation at address 0xffff0fc0.  Caller sets:
//	R0 = old value
//	R1 = new value
//	R2 = valptr
//	LR = return address
// The function returns with CS true if the swap happened.
// http://lxr.linux.no/linux+v2.6.37.2/arch/arm/kernel/entry-armv.S#L850
// On older kernels (before 2.6.24) the function can incorrectly
// report a conflict, so we have to double-check the compare ourselves
// and retry if necessary.
//
// http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=b49c0f24cf6744a3f4fd09289fe7cade349dead5
//
TEXT cas<>(SB),7,$0
	MOVW	$0xffff0fc0, PC

TEXT ·CompareAndSwapInt32(SB),7,$0
	B	·CompareAndSwapUint32(SB)

// Implement using kernel cas for portability.
TEXT ·CompareAndSwapUint32(SB),7,$0
	MOVW	valptr+0(FP), R2
	MOVW	old+4(FP), R0
casagain:
	MOVW	new+8(FP), R1
	BL cas<>(SB)
	BCC	cascheck
	MOVW	$1, R0
casret:
	MOVW	R0, ret+12(FP)
	RET
cascheck:
	// Kernel lies; double-check.
	MOVW	valptr+0(FP), R2
	MOVW	old+4(FP), R0
	MOVW	0(R2), R3
	CMP	R0, R3
	BEQ	casagain
	MOVW	$0, R0
	B	casret

TEXT ·CompareAndSwapUintptr(SB),7,$0
	B	·CompareAndSwapUint32(SB)

TEXT ·AddInt32(SB),7,$0
	B	·AddUint32(SB)

// Implement using kernel cas for portability.
TEXT ·AddUint32(SB),7,$0
	MOVW	valptr+0(FP), R2
	MOVW	delta+4(FP), R4
addloop1:
	MOVW	0(R2), R0
	MOVW	R0, R1
	ADD	R4, R1
	BL	cas<>(SB)
	BCC	addloop1
	MOVW	R1, ret+8(FP)
	RET

TEXT ·AddUintptr(SB),7,$0
	B	·AddUint32(SB)

// The kernel provides no 64-bit compare-and-swap,
// so use native ARM instructions, which will only work on
// ARM 11 and later devices.
TEXT ·CompareAndSwapInt64(SB),7,$0
	B	·armCompareAndSwapUint64(SB)

TEXT ·CompareAndSwapUint64(SB),7,$0
	B	·armCompareAndSwapUint64(SB)

TEXT ·AddInt64(SB),7,$0
	B	·armAddUint64(SB)

TEXT ·AddUint64(SB),7,$0
	B	·armAddUint64(SB)