/*
 * Copyright (c) 2013-2019 TRUSTONIC LIMITED
 * All rights reserved
 *
 * The present software is the confidential and proprietary information of
 * TRUSTONIC LIMITED. You shall not disclose the present software and shall
 * use it only in accordance with the terms of the license agreement you
 * entered into with TRUSTONIC LIMITED. This software may be subject to
 * export or import laws in certain countries.
 */
/**
 * This is a wrapper to include standard header files.
 */

#ifndef __TASTD_H__
#define __TASTD_H__

#if TBASE_API_LEVEL >= 3

//==============================================================================
// Standard include files
//==============================================================================


#if defined(__cplusplus)

    #include <cstdint>
    #include <cstdlib>
    #include <cstdio>
    #include <cstring>
    #include <string>
    #include <cstdarg>
    #include <exception>
    using namespace std;

    extern "C" {
        // nothing here
    }

#else

    #include <stdint.h>
    #include <stdbool.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <stdarg.h>

#endif // defined(__cplusplus)


//==============================================================================
// Compiler specific definitions
//==============================================================================

#if defined(__GNUC__)
    #define _INLINE             __inline__
    #define _SECTION(x)         __attribute__((section(x)))
    #define _USED               __attribute__((used))
    #define _NORETURN           __attribute__((noreturn))
    #define _WEAK               __attribute__((weak))
    #define _ZEROINIT
#else
    #error "unknown compiler"
#endif


//==============================================================================
// C/C++ compatibility
//==============================================================================

#if defined(__cplusplus)

    #define _EXTERN_C                extern "C"
    #define _BEGIN_EXTERN_C          extern "C" {
    #define _END_EXTERN_C            }

#else

    #define _EXTERN_C
    #define _BEGIN_EXTERN_C
    #define _END_EXTERN_C

#endif // defined(__cplusplus)


// Thread entry function
#define _THREAD_ENTRY       _EXTERN_C _NORETURN


//==============================================================================
// TLAPI settings
//==============================================================================
#define _TLAPI_EXTERN_C     _EXTERN_C
#define _TLAPI_NORETURN     _NORETURN


//==============================================================================
// Basic types
//==============================================================================

#if !defined(TRUE)
    #define TRUE    (1==1)
#endif // !defined(TRUE)

#if !defined(FALSE)
    #define FALSE   (1!=1)
#endif // !defined(TRUE)


#define DUMMY_FUNCTION()       do{}while(FALSE)


typedef void        *void_ptr;  /**< a pointer to anything. */
typedef void_ptr    addr_t;     /**< an address, can be physical or virtual */
typedef uint32_t    bool_t;     /**< boolean data type. */

//==============================================================================
// Trusted application entry function
//==============================================================================

#define _TLAPI_ENTRY        _TLAPI_EXTERN_C _TLAPI_NORETURN

_TLAPI_ENTRY void tlMain(
    void* const tciBuffer,
    const uint32_t  tciBufferLen
);



//==============================================================================
// Stack utilities
//==============================================================================

typedef uint32_t        stackEntry_t, *stackEntry_ptr;

// calculate the size in byte for the given number of stack entries
#define STACK_ENTRY_COUNT_TO_BYTE_SIZE(e)    (e * sizeof(stackEntry_t))
// calculate the number of stack entries require to hold given number of bytes
#define BYTE_SIZE_TO_STACK_ENTRY_COUNT(b)    ((b + sizeof(stackEntry_t) - 1) / sizeof(stackEntry_t))

// internal macros to get variable names from given name. Don't try using the
// variable names directly.
#define _STACK_ARRAY_VAR(_name_)    (__attribute__((aligned(8))) _stack_##_name_##_array)
#define _STACK_ENTRIES_VAR(_name_)  _stack_##_name_##_entries

// declare a stack. Basically, this is an array in RAM. However, no assumptions
// must be make about how a stack is defined internally. Access functions and
// macros must be used. The actual implementation may change anytime
// Note about the "extern const" declaration, that in C++ variables declared
// "const" have internal linkage. To enforce external linkage, "extern" must be
// given, too. Actually, it is given by _EXTERN_C, but we keep the additional
// "extern" here to remember why we need it.
// _STACK_ARRAY_VAR() has "_USED", because compiler/liker shall never remove
// it. If a stack is declared, it must exist, even if no code references it. It
// may still be needed by a wrapper that set up our binary externally.
// _STACK_ENTRIES_VAR() has "_UNSED" because it my not be referenced at all. It
// is just an internal helper variable.
#if defined(__GNUC__)
    #define DECLARE_STACK(_name_,_size_) \
        _BEGIN_EXTERN_C \
            _USED stackEntry_t      _STACK_ARRAY_VAR(_name_)[BYTE_SIZE_TO_STACK_ENTRY_COUNT(_size_)]; \
            _USED const uint32_t    _STACK_ENTRIES_VAR(_name_) = BYTE_SIZE_TO_STACK_ENTRY_COUNT(_size_); \
        _END_EXTERN_C
#else
    #error "unknown compiler"
#endif

#if TBASE_API_LEVEL < 8
    #define DECLARE_TRUSTLET_MAIN_STACK(_size_) DECLARE_STACK(tlMain, _size_)
#else
    #define DECLARE_TRUSTLET_MAIN_STACK(_size_) \
        _BEGIN_EXTERN_C \
            _USED const uint32_t _ta_main_stack_size = _size_; \
        _END_EXTERN_C
#endif
#define DECLARE_TRUSTED_APPLICATION_MAIN_STACK  \
        _EXTERN_C _USED const uint32_t _TBASE_API_LEVEL = TBASE_API_LEVEL;\
        DECLARE_TRUSTLET_MAIN_STACK

//==============================================================================
// Heap utilities
//==============================================================================

typedef uint32_t        heapEntry_t, *heapEntry_ptr;
// calculate the size in byte for the given number of heap entries
#define HEAP_ENTRY_COUNT_TO_BYTE_SIZE(e)    (e * sizeof(heapEntry_t))

//==============================================================================
// Debugging output
//==============================================================================

#ifndef EOL
    #define EOL "\n"
#endif


// enable debugging output if DEBUG is set. We use __INCLUDE_DEBUG so avoid
// having debug output directly glued to DEBUG. This allows some hack to have
// debug output for release builds.
#if defined(DEBUG)

    #define __INCLUDE_DEBUG

#endif

// assert message function.
_EXTERN_C void dbgAssertMsg(
    const char      *exp,
    const char      *file,
    const uint32_t  line);

#if defined(__INCLUDE_DEBUG)

    //------------------------------------------------------------------------
    // debug a da data blob
    _EXTERN_C void __dbgBlob(
                        const char    *szDescriptor,
                        const void    *blob,
                        uint32_t      sizeOfBlob);

    //------------------------------------------------------------------------
    _TLAPI_EXTERN_C void DbgPrintf(
                const char *fmt,
                ...) __attribute__ ((__format__(__printf__, 1, 2)));

    #define dbgBlob(...)        __dbgBlob(__VA_ARGS__)
    #define dbgAssertMsg(...)   __dbgAssertMsg(__VA_ARGS__)
#else


    #define dbgBlob(...)        DUMMY_FUNCTION()
    #define dbgAssertMsg(...)   DUMMY_FUNCTION()

    #define DbgPrintf(...)      DUMMY_FUNCTION()
#endif // __INCLUDE_DEBUG


//==============================================================================
// Assert
//==============================================================================

#if defined(DEBUG)

    #define __INCLUDE_ASSERT

#elif defined(NDEBUG) && defined(NDEBUG_WITH_ASSERT)

    #define __INCLUDE_ASSERT

#endif


#if defined(__INCLUDE_ASSERT)

    _EXTERN_C _NORETURN void _doAssert(
        const char      *expr,
        const char      *file,
        const uint32_t  line
    );

    #define assert(cond) \
        do{if (!(cond)){_doAssert(#cond,__FILE__,__LINE__);}} while(FALSE)

#else // not __INCLUDE_ASSERT

    #define assert(cond)                DUMMY_FUNCTION()

#endif // [not] __INCLUDE_ASSERT

#endif /* TBASE_API_LEVEL */

void _init(void);
extern const uint32_t _tlEntryVersion;

#endif //__TASTD_H__
