Back to index

glibc  2.9
sysdep.h
Go to the documentation of this file.
00001 /* Copyright (C) 1992, 93, 1995-2000, 2002, 2003, 2005, 2006
00002    Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004    Contributed by Ulrich Drepper, <drepper@gnu.ai.mit.edu>, August 1995.
00005    ARM changes by Philip Blundell, <pjb27@cam.ac.uk>, May 1997.
00006 
00007    The GNU C Library is free software; you can redistribute it and/or
00008    modify it under the terms of the GNU Lesser General Public
00009    License as published by the Free Software Foundation; either
00010    version 2.1 of the License, or (at your option) any later version.
00011 
00012    The GNU C Library is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015    Lesser General Public License for more details.
00016 
00017    You should have received a copy of the GNU Lesser General Public
00018    License along with the GNU C Library; if not, write to the Free
00019    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00020    02111-1307 USA.  */
00021 
00022 #ifndef _LINUX_ARM_SYSDEP_H
00023 #define _LINUX_ARM_SYSDEP_H 1
00024 
00025 /* There is some commonality.  */
00026 #include <sysdeps/unix/arm/sysdep.h>
00027 
00028 /* Defines RTLD_PRIVATE_ERRNO and USE_DL_SYSINFO.  */
00029 #include <dl-sysdep.h>
00030 
00031 /* For Linux we can use the system call table in the header file
00032        /usr/include/asm/unistd.h
00033    of the kernel.  But these symbols do not follow the SYS_* syntax
00034    so we have to redefine the `SYS_ify' macro here.  */
00035 #undef SYS_ify
00036 #define SWI_BASE  (0x900000)
00037 #define SYS_ify(syscall_name)      (__NR_##syscall_name)
00038 
00039 
00040 /* The following must match the kernel's <asm/procinfo.h>.  */
00041 #define HWCAP_ARM_SWP              1
00042 #define HWCAP_ARM_HALF             2
00043 #define HWCAP_ARM_THUMB            4
00044 #define HWCAP_ARM_26BIT            8
00045 #define HWCAP_ARM_FAST_MULT 16
00046 #define HWCAP_ARM_FPA              32
00047 #define HWCAP_ARM_VFP              64
00048 #define HWCAP_ARM_EDSP             128
00049 #define HWCAP_ARM_JAVA             256
00050 #define HWCAP_ARM_IWMMXT    512
00051 
00052 #ifdef __ASSEMBLER__
00053 
00054 /* Linux uses a negative return value to indicate syscall errors,
00055    unlike most Unices, which use the condition codes' carry flag.
00056 
00057    Since version 2.1 the return value of a system call might be
00058    negative even if the call succeeded.  E.g., the `lseek' system call
00059    might return a large offset.  Therefore we must not anymore test
00060    for < 0, but test for a real error by making sure the value in R0
00061    is a real error number.  Linus said he will make sure the no syscall
00062    returns a value in -1 .. -4095 as a valid result so we can safely
00063    test with -4095.  */
00064 
00065 #undef PSEUDO
00066 #define       PSEUDO(name, syscall_name, args)                              \
00067   .text;                                                             \
00068   ENTRY (name);                                                             \
00069     DO_CALL (syscall_name, args);                                    \
00070     cmn r0, $4096;
00071 
00072 #define PSEUDO_RET                                                   \
00073     RETINSTR(cc, lr);                                                       \
00074     b PLTJMP(SYSCALL_ERROR)
00075 #undef ret
00076 #define ret PSEUDO_RET
00077 
00078 #undef PSEUDO_END
00079 #define       PSEUDO_END(name)                                              \
00080   SYSCALL_ERROR_HANDLER                                                     \
00081   END (name)
00082 
00083 #undef PSEUDO_NOERRNO
00084 #define       PSEUDO_NOERRNO(name, syscall_name, args)                      \
00085   .text;                                                             \
00086   ENTRY (name);                                                             \
00087     DO_CALL (syscall_name, args);
00088 
00089 #define PSEUDO_RET_NOERRNO                                           \
00090     DO_RET (lr);
00091 
00092 #undef ret_NOERRNO
00093 #define ret_NOERRNO PSEUDO_RET_NOERRNO
00094 
00095 #undef PSEUDO_END_NOERRNO
00096 #define       PSEUDO_END_NOERRNO(name)                                      \
00097   END (name)
00098 
00099 /* The function has to return the error code.  */
00100 #undef PSEUDO_ERRVAL
00101 #define       PSEUDO_ERRVAL(name, syscall_name, args) \
00102   .text;                                                             \
00103   ENTRY (name)                                                              \
00104     DO_CALL (syscall_name, args);                                    \
00105     rsb r0, r0, #0
00106 
00107 #undef PSEUDO_END_ERRVAL
00108 #define       PSEUDO_END_ERRVAL(name) \
00109   END (name)
00110 
00111 #define ret_ERRVAL PSEUDO_RET_NOERRNO
00112 
00113 #if NOT_IN_libc
00114 # define SYSCALL_ERROR __local_syscall_error
00115 # if RTLD_PRIVATE_ERRNO
00116 #  define SYSCALL_ERROR_HANDLER                                \
00117 __local_syscall_error:                                         \
00118        ldr     r1, 1f;                                         \
00119        rsb     r0, r0, #0;                              \
00120 0:     str     r0, [pc, r1];                                   \
00121        mvn     r0, #0;                                         \
00122        DO_RET(lr);                                      \
00123 1:     .word C_SYMBOL_NAME(rtld_errno) - 0b - 8;
00124 # else
00125 #  define SYSCALL_ERROR_HANDLER                                \
00126 __local_syscall_error:                                         \
00127        str    lr, [sp, #-4]!;                                  \
00128        str    r0, [sp, #-4]!;                                  \
00129        bl     PLTJMP(C_SYMBOL_NAME(__errno_location));  \
00130        ldr    r1, [sp], #4;                             \
00131        rsb    r1, r1, #0;                               \
00132        str    r1, [r0];                                 \
00133        mvn    r0, #0;                                          \
00134        ldr    pc, [sp], #4;
00135 # endif
00136 #else
00137 # define SYSCALL_ERROR_HANDLER     /* Nothing here; code in sysdep.S is used.  */
00138 # define SYSCALL_ERROR __syscall_error
00139 #endif
00140 
00141 /* Linux takes system call args in registers:
00142        syscall number       in the SWI instruction
00143        arg 1         r0
00144        arg 2         r1
00145        arg 3         r2
00146        arg 4         r3
00147        arg 5         r4     (this is different from the APCS convention)
00148        arg 6         r5
00149        arg 7         r6
00150 
00151    The compiler is going to form a call by coming here, through PSEUDO, with
00152    arguments
00153        syscall number       in the DO_CALL macro
00154        arg 1         r0
00155        arg 2         r1
00156        arg 3         r2
00157        arg 4         r3
00158        arg 5         [sp]
00159        arg 6         [sp+4]
00160        arg 7         [sp+8]
00161 
00162    We need to shuffle values between R4..R6 and the stack so that the
00163    caller's v1..v3 and stack frame are not corrupted, and the kernel
00164    sees the right arguments.
00165 
00166 */
00167 
00168 #undef DO_CALL
00169 #define DO_CALL(syscall_name, args)              \
00170     DOARGS_##args                         \
00171     swi SYS_ify (syscall_name);           \
00172     UNDOARGS_##args
00173 
00174 #define DOARGS_0 /* nothing */
00175 #define DOARGS_1 /* nothing */
00176 #define DOARGS_2 /* nothing */
00177 #define DOARGS_3 /* nothing */
00178 #define DOARGS_4 /* nothing */
00179 #define DOARGS_5 str r4, [sp, $-4]!; ldr r4, [sp, $4];
00180 #define DOARGS_6 mov ip, sp; stmfd sp!, {r4, r5}; ldmia ip, {r4, r5};
00181 #define DOARGS_7 mov ip, sp; stmfd sp!, {r4, r5, r6}; ldmia ip, {r4, r5, r6};
00182 
00183 #define UNDOARGS_0 /* nothing */
00184 #define UNDOARGS_1 /* nothing */
00185 #define UNDOARGS_2 /* nothing */
00186 #define UNDOARGS_3 /* nothing */
00187 #define UNDOARGS_4 /* nothing */
00188 #define UNDOARGS_5 ldr r4, [sp], $4;
00189 #define UNDOARGS_6 ldmfd sp!, {r4, r5};
00190 #define UNDOARGS_7 ldmfd sp!, {r4, r5, r6};
00191 
00192 #else /* not __ASSEMBLER__ */
00193 
00194 /* Define a macro which expands into the inline wrapper code for a system
00195    call.  */
00196 #undef INLINE_SYSCALL
00197 #define INLINE_SYSCALL(name, nr, args...)                      \
00198   ({ unsigned int _sys_result = INTERNAL_SYSCALL (name, , nr, args);  \
00199      if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (_sys_result, ), 0))     \
00200        {                                                       \
00201         __set_errno (INTERNAL_SYSCALL_ERRNO (_sys_result, ));         \
00202         _sys_result = (unsigned int) -1;                       \
00203        }                                                       \
00204      (int) _sys_result; })
00205 
00206 #undef INTERNAL_SYSCALL_DECL
00207 #define INTERNAL_SYSCALL_DECL(err) do { } while (0)
00208 
00209 #undef INTERNAL_SYSCALL_RAW
00210 #define INTERNAL_SYSCALL_RAW(name, err, nr, args...)           \
00211   ({ unsigned int _sys_result;                                 \
00212      {                                                  \
00213        register int _a1 asm ("a1");                            \
00214        LOAD_ARGS_##nr (args)                                   \
00215        asm volatile ("swi   %1     @ syscall " #name    \
00216                    : "=r" (_a1)                         \
00217                    : "i" (name) ASM_ARGS_##nr                  \
00218                    : "memory");                         \
00219        _sys_result = _a1;                               \
00220      }                                                  \
00221      (int) _sys_result; })
00222 
00223 #undef INTERNAL_SYSCALL
00224 #define INTERNAL_SYSCALL(name, err, nr, args...)        \
00225        INTERNAL_SYSCALL_RAW(SYS_ify(name), err, nr, args)
00226 
00227 #undef INTERNAL_SYSCALL_ARM
00228 #define INTERNAL_SYSCALL_ARM(name, err, nr, args...)           \
00229        INTERNAL_SYSCALL_RAW(__ARM_NR_##name, err, nr, args)
00230 
00231 #undef INTERNAL_SYSCALL_ERROR_P
00232 #define INTERNAL_SYSCALL_ERROR_P(val, err) \
00233   ((unsigned int) (val) >= 0xfffff001u)
00234 
00235 #undef INTERNAL_SYSCALL_ERRNO
00236 #define INTERNAL_SYSCALL_ERRNO(val, err)  (-(val))
00237 
00238 #define LOAD_ARGS_0()
00239 #define ASM_ARGS_0
00240 #define LOAD_ARGS_1(a1)                          \
00241   _a1 = (int) (a1);                       \
00242   LOAD_ARGS_0 ()
00243 #define ASM_ARGS_1   ASM_ARGS_0, "r" (_a1)
00244 #define LOAD_ARGS_2(a1, a2)               \
00245   register int _a2 asm ("a2") = (int) (a2);      \
00246   LOAD_ARGS_1 (a1)
00247 #define ASM_ARGS_2   ASM_ARGS_1, "r" (_a2)
00248 #define LOAD_ARGS_3(a1, a2, a3)                  \
00249   register int _a3 asm ("a3") = (int) (a3);      \
00250   LOAD_ARGS_2 (a1, a2)
00251 #define ASM_ARGS_3   ASM_ARGS_2, "r" (_a3)
00252 #define LOAD_ARGS_4(a1, a2, a3, a4)              \
00253   register int _a4 asm ("a4") = (int) (a4);      \
00254   LOAD_ARGS_3 (a1, a2, a3)
00255 #define ASM_ARGS_4   ASM_ARGS_3, "r" (_a4)
00256 #define LOAD_ARGS_5(a1, a2, a3, a4, a5)          \
00257   register int _v1 asm ("v1") = (int) (a5);      \
00258   LOAD_ARGS_4 (a1, a2, a3, a4)
00259 #define ASM_ARGS_5   ASM_ARGS_4, "r" (_v1)
00260 #define LOAD_ARGS_6(a1, a2, a3, a4, a5, a6)      \
00261   register int _v2 asm ("v2") = (int) (a6);      \
00262   LOAD_ARGS_5 (a1, a2, a3, a4, a5)
00263 #define ASM_ARGS_6   ASM_ARGS_5, "r" (_v2)
00264 #define LOAD_ARGS_7(a1, a2, a3, a4, a5, a6, a7)  \
00265   register int _v3 asm ("v3") = (int) (a7);      \
00266   LOAD_ARGS_6 (a1, a2, a3, a4, a5, a6)
00267 #define ASM_ARGS_7   ASM_ARGS_6, "r" (_v3)
00268 
00269 /* We can't implement non-constant syscalls directly since the syscall
00270    number is normally encoded in the instruction.  So use SYS_syscall.  */
00271 #define INTERNAL_SYSCALL_NCS(number, err, nr, args...)         \
00272        INTERNAL_SYSCALL_NCS_##nr (number, err, args)
00273 
00274 #define INTERNAL_SYSCALL_NCS_0(number, err, args...)           \
00275        INTERNAL_SYSCALL (syscall, err, 1, number, args)
00276 #define INTERNAL_SYSCALL_NCS_1(number, err, args...)           \
00277        INTERNAL_SYSCALL (syscall, err, 2, number, args)
00278 #define INTERNAL_SYSCALL_NCS_2(number, err, args...)           \
00279        INTERNAL_SYSCALL (syscall, err, 3, number, args)
00280 #define INTERNAL_SYSCALL_NCS_3(number, err, args...)           \
00281        INTERNAL_SYSCALL (syscall, err, 4, number, args)
00282 #define INTERNAL_SYSCALL_NCS_4(number, err, args...)           \
00283        INTERNAL_SYSCALL (syscall, err, 5, number, args)
00284 #define INTERNAL_SYSCALL_NCS_5(number, err, args...)           \
00285        INTERNAL_SYSCALL (syscall, err, 6, number, args)
00286 
00287 #endif /* __ASSEMBLER__ */
00288 
00289 /* Pointer mangling is not yet supported for ARM.  */
00290 #define PTR_MANGLE(var) (void) (var)
00291 #define PTR_DEMANGLE(var) (void) (var)
00292 
00293 #endif /* linux/arm/sysdep.h */