| /* 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 |