/*
 *
 * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
 *
 * Syscall helpers
 */

#ifndef __SYSCALL_SL_H__
#define __SYSCALL_SL_H__

#ifdef __cplusplus
extern "C" {
#endif

#include "core/syscall_sw.h"
#include "errno.h"

#ifndef _X86_TST_

#if !defined(__aarch64__)

#define MAX_ERRNO       4095

#define INLINE_SYSCALL(name, nr, args...)                               \
({                                                                      \
        unsigned long syscall_result = INTERNAL_SYSCALL(name, nr, args);\
        if (syscall_result >= (unsigned long)-MAX_ERRNO) {              \
                errno = -syscall_result;                                \
                syscall_result = -1;                                    \
        }                                                               \
(long) syscall_result;                                                  \
})

#define INLINE_SYSCALL_NORETURN(name, nr, args...)                      \
do {                                                                    \
        (void) INTERNAL_SYSCALL(name, nr, args);                                  \
        __builtin_unreachable();                                        \
} while (0)

#define INTERNAL_SYSCALL(name, nr, args...)             \
({                                                      \
        register int _a1 asm ("r0"), _nr asm ("r7");    \
        LOAD_ARGS_##nr (args)                           \
        _nr = SYSCALL_SW_##name;                        \
        asm volatile ("svc 0x0"                         \
                : "=r" (_a1)                            \
                : "r" (_nr) ASM_ARGS_##nr               \
                : "memory");                            \
_a1;                                                    \
})

#define LOAD_ARGS_0()
#define ASM_ARGS_0

#define LOAD_ARGS_1(a1) \
  LOAD_ARGS_0() \
  _a1 = (int) (a1);
#define ASM_ARGS_1  ASM_ARGS_0, "r" (_a1)

#define LOAD_ARGS_2(a1, a2) \
  LOAD_ARGS_1 (a1)              \
  register int _a2 asm ("r1") = (int) (a2);
#define ASM_ARGS_2  ASM_ARGS_0, "r" (_a1), "r" (_a2)

#define LOAD_ARGS_3(a1, a2, a3) \
  LOAD_ARGS_2 (a1, a2)          \
  register int _a3 asm ("r2") = (int) (a3);
#define ASM_ARGS_3  ASM_ARGS_0, "r" (_a1), "r" (_a2), "r" (_a3)

#define LOAD_ARGS_4(a1, a2, a3, a4)     \
  LOAD_ARGS_3 (a1, a2, a3)              \
  register int _a4 asm ("r3") = (int) (a4);
#define ASM_ARGS_4  ASM_ARGS_0, "r" (_a1), "r" (_a2), \
                                "r" (_a3), "r" (_a4)

#define LOAD_ARGS_5(a1, a2, a3, a4, a5) \
  LOAD_ARGS_4 (a1, a2, a3, a4)          \
  register int _v1 asm ("r4") = (int) (a5);
#define ASM_ARGS_5  ASM_ARGS_0, "r" (_a1), "r" (_a2), "r" (_a3), \
                                "r" (_a4), "r" (_v1)

#define LOAD_ARGS_6(a1, a2, a3, a4, a5, a6)     \
  LOAD_ARGS_5 (a1, a2, a3, a4, a5)              \
  register int _v2 asm ("r5") = (int) (a6);
#define ASM_ARGS_6  ASM_ARGS_0, "r" (_a1), "r" (_a2), "r" (_a3), \
                                "r" (_a4), "r" (_v1), "r" (_v2)

/* AARCH64 FIXME: */
/* Code for aarch64 is just compilable now, but not runable. */
#elif defined(__aarch64__)
#define MAX_ERRNO       4095

#define INLINE_SYSCALL(name, nr, args...)                               \
({                                                                      \
        unsigned long syscall_result = INTERNAL_SYSCALL(name, nr, args);\
        if (syscall_result >= (unsigned long)-MAX_ERRNO) {              \
                errno = -syscall_result;                                \
                syscall_result = -1;                                    \
        }                                                               \
(unsigned long) syscall_result;                                                 \
})

#define INLINE_SYSCALL_NORETURN(name, nr, args...)                      \
do {                                                                    \
        (void) INTERNAL_SYSCALL(name, nr, args);                                   \
        __builtin_unreachable();                                        \
} while (0)

#define INTERNAL_SYSCALL(name, nr, args...)             \
({                                                      \
        register long _a1 asm ("x0"), _nr asm ("x7");   \
        LOAD_ARGS_##nr (args)                           \
        _nr = SYSCALL_SW_##name;                        \
        asm volatile ("svc 0x0"                         \
                : "=r" (_a1)                            \
                : "r" (_nr) ASM_ARGS_##nr               \
                : "memory");                            \
_a1;                                                    \
})

#define LOAD_ARGS_0()
#define ASM_ARGS_0

#define LOAD_ARGS_1(a1) \
  LOAD_ARGS_0() \
  _a1 = (long) (a1);
#define ASM_ARGS_1  ASM_ARGS_0, "r" (_a1)

#define LOAD_ARGS_2(a1, a2) \
  LOAD_ARGS_1 (a1)              \
  register long _a2 asm ("x1") = (long)(a2);
#define ASM_ARGS_2  ASM_ARGS_0, "r" (_a1), "r" (_a2)

#define LOAD_ARGS_3(a1, a2, a3) \
  LOAD_ARGS_2 (a1, a2)          \
  register long _a3 asm ("x2") = (long)(a3);
#define ASM_ARGS_3  ASM_ARGS_0, "r" (_a1), "r" (_a2), "r" (_a3)

#define LOAD_ARGS_4(a1, a2, a3, a4)     \
  LOAD_ARGS_3 (a1, a2, a3)              \
  register long _a4 asm ("x3") = (long)(a4);
#define ASM_ARGS_4  ASM_ARGS_0, "r" (_a1), "r" (_a2), \
                                "r" (_a3), "r" (_a4)

#define LOAD_ARGS_5(a1, a2, a3, a4, a5) \
  LOAD_ARGS_4 (a1, a2, a3, a4)          \
  register long _v1 asm ("x4") = (long)(a5);
#define ASM_ARGS_5  ASM_ARGS_0, "r" (_a1), "r" (_a2), "r" (_a3), \
                                "r" (_a4), "r" (_v1)

#define LOAD_ARGS_6(a1, a2, a3, a4, a5, a6)     \
  LOAD_ARGS_5 (a1, a2, a3, a4, a5)              \
  register long _v2 asm ("x5") = (long)(a6);
#define ASM_ARGS_6  ASM_ARGS_0, "r" (_a1), "r" (_a2), "r" (_a3), \
                                "r" (_a4), "r" (_v1), "r" (_v2)

#endif /* __aarch64__ */

#else /*_X86_TST_*/

#define INLINE_SYSCALL(name, nr, args...) (0);


#endif /*_X86_TST_*/

#ifdef __cplusplus
}
#endif

#endif /* !__SYSCALL_SL_H__ */
