/*
Copyright (c) 2007-2013, John Ryland
*/
#include <oslayer.h>
char **environ;
int errno;
/*
XXX - Performance issue, potentially could be faster not using the int 0x80 sys call gate method
The modern and faster way is using the vDSO entry which needs to be looked up on program
initialization. It is in the AT_SYSINFO elf parameter. #include <elf.h>
See article here:
http://articles.manugarg.com/aboutelfauxiliaryvectors.html
*/
#define SYS_sysExit 0x01
#define SYS_sysFork 0x02
#define SYS_fsRead 0x03
#define SYS_fsWrite 0x04
#define SYS_fsOpen 0x05
#define SYS_fsClose 0x06
#define SYS_sysGetPid 0x14
#define SYS_sysIoctl 0x36
#if defined(ARCH_MacOSX64)
# define SYS_sysCall 0 // probably doesn't exist on Mac
# define SYS_sysBrk 69 // sbrk was 69 on Mac, but looks deprecated and can't see replacement
# define SYS_sysExecve 59
# define SYS_sysGetTimeOfDay 116
# define SYS_sysSelect 407 // 93
# define SYS_fsStat 188 // 338 for stat64
# define SYS_fsSeek 199
# define SYS_fsMmap 197
# define SYS_fsMunmap 73
#else
# define SYS_sysCall 0x71 // probably doesn't exist on Mac
# define SYS_sysBrk 0x2D // sbrk was 69 on Mac, but looks deprecated and can't see replacement
# define SYS_sysExecve 0x0B // old execv on Mac - should be 59 on Mac
# define SYS_sysGetTimeOfDay 0x4E // Looks wrong - should be 116 on Mac
# define SYS_sysSelect 0x52 // Looks wrong - should be 93 on Mac
# define SYS_fsStat 0x6A // 188, 338 for stat64
# define SYS_fsSeek 0x13 // old lseek on Mac - 199 on Mac
# define SYS_fsMmap 0xC0 // This is actually mmap2 (not tested on ARM) // 0x5A is mmap_old
# define SYS_fsMunmap 0x5B // 73 on Mac
#endif
typedef unsigned long ulong;
//#define __NR_vm86old 113
//#define __NR_vm86 166
//#define __NR_mmap2 192
#define SYS_BASE 0x900000
#define _EVAL(x) #x
#define EVAL(x) _EVAL(x)
#define CHECK_RESULT_RETURN(r) \
if ((ulong)(res) >= (ulong)(-125)) { \
errno = -(res); \
return (r)-1; \
} \
return (r)res
#if defined(ARCH_ARM)
# define SYS_CALL_ASM(a,a1,a2,a3,a4) \
"mov\tr0,%1\n\tmov\tr1,%2\n\tmov\tr2,%3\n\tmov\tr3,%4\n\t" \
"swi\t(" EVAL(SYS_BASE) "+" EVAL(a) ")\n\tmov %0,r0" \
: "=r"(res) \
: "r"((ulong)(a1)),"r"((ulong)(a2)),"r"((ulong)(a3)),"r"((ulong)(a4)) \
: "r0","r1","r2","r3","lr"
# define SYS_CALL_EXT_MACRO(r,a,a1,a2,a3,a4,a5,a6) \
long res; \
unsigned buf[6] = {(unsigned)a1,(unsigned)a2,(unsigned)a3,(unsigned)a4,(unsigned)a5,(unsigned)a6}; \
__asm__ __volatile__ ( \
SYS_CALL_ASM(a,buf,0,0,0) \
); \
CHECK_RESULT_RETURN(r);
#elif defined(ARCH_X86)
# define SYS_CALL_ASM(a,a1,a2,a3,a4) \
/* "sysenter" */ "int $0x80" \
: "=a"(res) \
: "0"(a),"b"((ulong)(a1)),"c"((ulong)(a2)),"d"((ulong)(a3)),"S"((ulong)(a4))
# define SYS_CALL_EXT_MACRO(r,a,a1,a2,a3,a4,a5,a6) \
long res; \
__asm__ __volatile__ ( \
"push %%ebp ; movl %%eax,%%ebp ; movl %1,%%eax\n" \
/* "sysenter\n" */ "int $0x80\n" \
"pop %%ebp\n" \
: "=a"(res) \
: "i"(a),"b"((ulong)(a1)),"c"((ulong)(a2)),"d"((ulong)(a3)),\
"S"((ulong)(a4)),"D"((ulong)(a5)),"0"((ulong)(a6)) \
); \
CHECK_RESULT_RETURN(r);
#elif defined(ARCH_X64)
# define SYS_CALL_ASM(a,a1,a2,a3,a4) \
/* "sysenter" */ "int $0x80" \
: "=a"(res) \
: "0"(a),"b"((ulong)(a1)),"c"((ulong)(a2)),"d"((ulong)(a3)),"S"((ulong)(a4))
# define SYS_CALL_EXT_MACRO(r,a,a1,a2,a3,a4,a5,a6) \
long res; \
__asm__ __volatile__ ( \
"push %%rbp ; movl %%eax,%%ebp ; movl %1,%%eax\n" \
/* "sysenter\n" */ "int $0x80\n" \
"pop %%rbp\n" \
: "=a"(res) \
: "i"(a),"b"((ulong)(a1)),"c"((ulong)(a2)),"d"((ulong)(a3)),\
"S"((ulong)(a4)),"D"((ulong)(a5)),"0"((ulong)(a6)) \
); \
CHECK_RESULT_RETURN(r);
#elif defined(ARCH_MacOSX64)
# define UNIX_SYSCALL_BASE 0x2000000
# define SYS_CALL_ASM(a,a1,a2,a3,a4) \
"syscall" \
: "=a"(res) \
: "a"(a+UNIX_SYSCALL_BASE),"D"((ulong)(a1)),"S"((ulong)(a2)),"d"((ulong)(a3)),"r"(r10)
# define SYS_CALL_EXT_MACRO(r,a,a1,a2,a3,a4,a5,a6) \
long res; \
register long r10 asm("r10") = a4; \
register long r8 asm("r8") = a5; \
register long r9 asm("r9") = a6; \
__asm__ __volatile__ ( \
/*"push %%rbp ; movl %%eax,%%ebp ; movl %1,%%eax\n"*/ \
"syscall\n" \
/*"pop %%rbp\n"*/ \
: "=a"(res) \
: "a"(a+UNIX_SYSCALL_BASE),"D"((ulong)(a1)),"S"((ulong)(a2)),"d"((ulong)(a3)),\
"r"(r10),"r"(r8),"r"(r9) \
); \
CHECK_RESULT_RETURN(r);
#define SYS_CALL_MACRO(r,a,a1,a2,a3,a4) \
long res; \
register long r10 asm("r10") = a4; \
__asm__ __volatile__ ( \
SYS_CALL_ASM(a,a1,a2,a3,a4) \
); \
CHECK_RESULT_RETURN(r);
#else
# error Unknown architecture!
#endif
#if !defined(ARCH_MacOSX64)
#define SYS_CALL_MACRO(r,a,a1,a2,a3,a4) \
long res; \
__asm__ __volatile__ ( \
SYS_CALL_ASM(a,a1,a2,a3,a4) \
); \
CHECK_RESULT_RETURN(r);
#endif
#ifdef USE_VM86_STYLE_SYSCALL
#define SYS_CALL(r,a,a1,a2,a3) long res = sysCall(SYS_BASE+a, (ulong)a1, (ulong)a2, (ulong)a3); \
CHECK_RESULT_RETURN(r);
#else
#define SYS_CALL(r,a,a1,a2,a3) SYS_CALL_MACRO(r,a,a1,a2,a3,0)
#endif
#define SYS_CALL6(r,n,t1,t2,t3,t4,t5,t6) r n(t1 a1, t2 a2, t3 a3, t4 a4, t5 a5, t6 a6) { \
SYS_CALL_EXT_MACRO(r,SYS_##n,a1,a2,a3,a4,a5,a6); }
#define SYS_CALL5(r,n,t1,t2,t3,t4,t5) r n(t1 a1, t2 a2, t3 a3, t4 a4, t5 a5) { \
SYS_CALL_EXT_MACRO(r,SYS_##n,a1,(ulong)a2,(ulong)a3,(ulong)a4,(ulong)a5,0); }
#define SYS_CALL4(r,n,t1,t2,t3,t4) r n(t1 a1, t2 a2, t3 a3, t4 a4) { \
SYS_CALL_MACRO(r,SYS_##n,a1,a2,a3,a4); }
#define SYS_CALL3(r,n,t1,t2,t3) r n(t1 a1, t2 a2, t3 a3) { \
SYS_CALL(r,SYS_##n,a1,a2,a3); }
#define SYS_CALL2(r,n,t1,t2) r n(t1 a1, t2 a2) { \
SYS_CALL(r,SYS_##n,a1,a2, 0); }
#define SYS_CALL1(r,n,t1) r n(t1 a1) { \
SYS_CALL(r,SYS_##n,a1, 0, 0); }
#define SYS_CALL0(r,n) r n(void) { \
SYS_CALL(r,SYS_##n, 0, 0, 0); }
SYS_CALL4(long,sysCall,int,long,long,long)
SYS_CALL5(int,sysSelect,int,fd_set*,fd_set*,fd_set*,timeval*)
SYS_CALL6(void*,fsMmap,void*,int,int,int,int,int)
SYS_CALL1(void,sysExit,int)
SYS_CALL1(int,sysBrk,void*) // XXX not tested
SYS_CALL0(int,sysFork) // XXX not tested
SYS_CALL0(int,sysGetPid) // XXX not tested
SYS_CALL2(int,sysGetTimeOfDay,timeval*,timezone*)
SYS_CALL3(int,sysIoctl,int,unsigned long,void*)
SYS_CALL2(int,fsOpen,const char*,int)
SYS_CALL1(int,fsClose,int)
SYS_CALL2(int,fsStat,const char*,stat*)
SYS_CALL3(int,fsSeek,int,unsigned,int) // XXX not tested
SYS_CALL3(int,fsRead,int,void*,int)
SYS_CALL3(int,fsWrite,int,const void*,int)
SYS_CALL2(int,fsMunmap,void*,int)
SYS_CALL3(int,sysExecve,const char *, char *const *, char *const *) // XXX not tested
/*
int sysExecve(const char *prog, char *const argv[], char *const envp[]) // XXX not tested
{
SYS_CALL(int, SYS_sysExecve, prog, argv, envp);
}
*/