summaryrefslogtreecommitdiff
path: root/libc/sysdeps/linux/arm/mmap64.S
blob: 7071541247e342e5b3c4bbad59875d452d870972 (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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/* Copyright (C) 2000 Free Software Foundation, Inc.
   This file is part of the GNU C Library.

   The GNU C Library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   The GNU C Library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with the GNU C Library; if not, write to the Free
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   02111-1307 USA.  */

#include <features.h>
#define _ERRNO_H
#include <bits/errno.h>
#include <sys/syscall.h>
#include <bits/arm_asm.h>

#if defined __UCLIBC_HAS_LFS__ && defined __NR_mmap2

/* The mmap2 system call takes six arguments, all in registers.  */
.text
.global mmap64
.type mmap64,%function
.align 2

#ifdef __ARM_EABI__
#if defined(THUMB1_ONLY)
.thumb_func
mmap64:
#ifdef __ARMEB__
/* Offsets are after pushing 3 words.  */
# define LOW_OFFSET  12 + 8 + 4
# define HIGH_OFFSET 12 + 8 + 0
#else
# define LOW_OFFSET  12 + 8 + 0
# define HIGH_OFFSET 12 + 8 + 4
#endif
	push	{r4, r5, r6}
	ldr	r6, [sp, $LOW_OFFSET]
	ldr	r5, [sp, $HIGH_OFFSET]
	lsl	r4, r6, #20		@ check that offset is page-aligned
	bne	.Linval
	lsr	r4, r5, #12		@ check for overflow
	bne	.Linval
	@ compose page offset
	lsr	r6, r6, #12
	lsl	r5, r5, #20
	orr	r5, r5, r6
	ldr	r4, [sp, #8]		@ load fd
	DO_CALL (mmap2)
	ldr	r1, =0xfffff000
	cmp	r0, r1
	bcs	.Lerror
	bx	lr
.Linval:
	ldr	r0, =-EINVAL
	pop	{r4, r5, r6}
.Lerror:
	push	{r3, lr}
	bl	__syscall_error
	POP_RET
.pool
#else /* !THUMB1_ONLY */
mmap64:
#ifdef __ARMEB__
# define LOW_OFFSET      8 + 4
/* The initial + 4 is for the stack postdecrement.  */
# define HIGH_OFFSET 4 + 8 + 0
#else
# define LOW_OFFSET      8 + 0
# define HIGH_OFFSET 4 + 8 + 4
#endif
	ldr	ip, [sp, $LOW_OFFSET]
	str	r5, [sp, #-4]!
	ldr	r5, [sp, $HIGH_OFFSET]
	str	r4, [sp, #-4]!
	movs	r4, ip, lsl $20		@ check that offset is page-aligned
	mov	ip, ip, lsr $12
	IT(t, eq)
	moveqs	r4, r5, lsr $12		@ check for overflow
	bne	.Linval
	ldr	r4, [sp, $8]		@ load fd
	orr	r5, ip, r5, lsl $20	@ compose page offset
	DO_CALL (mmap2)
	cmn	r0, $4096
	ldmfd	sp!, {r4, r5}
	IT(t, cc)
#if defined(__USE_BX__)
	bxcc	lr
#else
	movcc	pc, lr
#endif
	b	__syscall_error
.Linval:
	mov	r0, $-EINVAL
	ldmfd	sp!, {r4, r5}
	b	__syscall_error
#endif
#else /* !__ARM_EABI__ */
mmap64:
	stmfd	sp!, {r4, r5, lr}
	ldr	r5, [sp, $16]
	ldr	r4, [sp, $12]
	movs	ip, r5, lsl $20		@ check that offset is page-aligned
	bne	.Linval
	ldr	ip, [sp, $20]
	mov	r5, r5, lsr $12
	orr	r5, r5, ip, lsl $20	@ compose page offset
	movs	ip, ip, lsr $12
	bne	.Linval			@ check for overflow
	mov	ip, r0
	DO_CALL (mmap2)
	cmn	r0, $4096
	ldmccfd	sp!, {r4, r5, pc}
	cmn	r0, $ENOSYS
	ldmnefd	sp!, {r4, r5, lr}
	bne	__error
	/* The current kernel does not support mmap2.  Fall back to plain
	   mmap if the offset is small enough.  */
	ldr	r5, [sp, $20]
	mov	r0, ip			@ first arg was clobbered
	teq	r5, $0
	ldmeqfd	sp!, {r4, r5, lr}
	beq	HIDDEN_JUMPTARGET(mmap)
.Linval:
	mov	r0, $-EINVAL
	ldmfd	sp!, {r4, r5, lr}
	b	__error

__error:
	b	__syscall_error
#endif
.size mmap64,.-mmap64

#endif