/*======================================================

FILE:      bridle_arm.c

SERVICES:  common functions for MPU and MMU

GENERAL DESCRIPTION:

  @@@TODO: fill me in!

PUBLIC CLASSES AND STATIC FUNCTIONS:

    @@@TODO: fill me in!

INITIALIZATION & SEQUENCING REQUIREMENTS:

	See Exported Routines

        Copyright © 2004 QUALCOMM Incorporated.
               All Rights Reserved.
            QUALCOMM Proprietary/GTDR
=====================================================*/
#include "rextls.h"
#include "AEEBridle.h"
#include "AEECriticalSection.h"

/* in switable.c */
extern PFNSWIHANDLER g_bridle_SubSystems[];

/* in bridle_asmutils.s */
extern uint32 bridle_get_cpsr(void);
extern void   bridle_access_abort(void);

/* in swihandler.s */
extern uint32 bridle_SwitchToUser(uint32 arg1, uint32 arg2, uint32 arg3, uint32 arg4, void (*fn)(void));
extern uint32 bridle_SwitchToSystem(uint32 arg1, uint32 arg2, uint32 arg3, uint32 arg4, uint32 swino);


#if __ARMCC_VERSION >= 120000 // ADS 1.2
#pragma arm section zidata = "bridle_svc_zi_usr_ro"
#endif // __ARMCC_VERSION >= 120000 // ADS 1.2

boolean bridle_on;

#if __ARMCC_VERSION >= 120000 // ADS 1.2
#pragma arm section zidata
#endif // __ARMCC_VERSION >= 120000 // ADS 1.2


static int gnInUserCallKey = 0;

/*===========================================================================

FUNCTION   

DESCRIPTION
  
DEPENDENCIES

RETURN VALUE

SIDE EFFECTS

===========================================================================*/
int bridle_self_init(void *p)
{
   (void)p;
   return rex_tls_create(&gnInUserCallKey);
}

/*===========================================================================

FUNCTION   

DESCRIPTION
  
DEPENDENCIES

RETURN VALUE

SIDE EFFECTS

===========================================================================*/
boolean bridle_IsInUserCall(void)
{
   if (BRIDLE_IS_ENABLED()) {
      return BRIDLE_IS_IN_USR_MODE();
   } else {
      boolean *pbInUser = (boolean *)rex_tls_ptr(gnInUserCallKey);
      
      return *pbInUser;
   }
}

/*===========================================================================

FUNCTION   

DESCRIPTION
  
DEPENDENCIES

RETURN VALUE

SIDE EFFECTS

===========================================================================*/
uint32 bridle_SystemCall(uint32 arg1, uint32 arg2, uint32 arg3, uint32 arg4, uint32 swi_no)
{   
   int     subsys_no = BRIDLE_GET_SUBSYSNO(swi_no);
   uint32  uRet;

   if (subsys_no < 0) {
      subsys_no = 0;
   }

   if (BRIDLE_IS_ENABLED()) {
      if (BRIDLE_IS_IN_USR_MODE()) {
         uRet = bridle_SwitchToSystem(arg1, arg2, arg3, arg4, swi_no); /* swino is last, and so on stack! */
      } else {
         /* force the mode to FROM_PRIV, we're already in supervisor */
         swi_no |= BRIDLE_FROM_PRIV;
         uRet = g_bridle_SubSystems[subsys_no](swi_no, arg1, arg2, arg3, arg4);
      }
   } else {
      boolean bInUserSave, *pbInUser;
      
      pbInUser = (boolean *)rex_tls_ptr(gnInUserCallKey);
      bInUserSave = *pbInUser;
      *pbInUser = FALSE;

      /* force the mode to FROM_PRIV, bridle is not enabled. */
      swi_no |= BRIDLE_FROM_PRIV;
      uRet = g_bridle_SubSystems[subsys_no](swi_no, arg1, arg2, arg3, arg4);

      *pbInUser = bInUserSave;
   }

   return uRet;
}

/*===========================================================================

FUNCTION   

DESCRIPTION
  
DEPENDENCIES

RETURN VALUE

SIDE EFFECTS

===========================================================================*/
uint32 bridle_UserCall(uint32 arg1, uint32 arg2, uint32 arg3, uint32 arg4, void (*fn)(void))
{
   uint32 retVal;

   //This is the Critical Section used by bridle_SwitchToUser
   //to ensure that only one task is using the User stack
   #if __ARMCC_VERSION >= 120000 // ADS 1.2
   #pragma arm section zidata = "bridle_critical_section_zi"
   #endif // __ARMCC_VERSION >= 120000 // ADS 1.2

   static AEECriticalSection bridleUserStackCritSect;

   #if __ARMCC_VERSION >= 120000 // ADS 1.2
   #pragma arm section zidata
   #endif // __ARMCC_VERSION >= 120000 // ADS 1.2

   AEECriticalSection_Enter(&bridleUserStackCritSect);

   if (BRIDLE_IS_ENABLED()) {
      if (BRIDLE_IS_IN_SVC_MODE()) {
         retVal = bridle_SwitchToUser(arg1, arg2, arg3, arg4, fn);
      } else {
         retVal = ((uint32 (*)(uint32,uint32,uint32,uint32))fn)(arg1, arg2, arg3, arg4);         
      }
   } else {
      boolean bInUserSave, *pbInUser;
      
      pbInUser = (boolean *)rex_tls_ptr(gnInUserCallKey);
      bInUserSave = *pbInUser;
      *pbInUser = TRUE;

      retVal = ((uint32 (*)(uint32,uint32,uint32,uint32))fn)(arg1, arg2, arg3, arg4);         

      *pbInUser = bInUserSave;
   }

   AEECriticalSection_Leave(&bridleUserStackCritSect);

   return retVal;
}

/*===========================================================================

FUNCTION   

DESCRIPTION
  
DEPENDENCIES

RETURN VALUE

SIDE EFFECTS

===========================================================================*/
boolean bridle_CheckMode(int mode)
{
   return (boolean)(mode == (bridle_get_cpsr() & 0x0f));
}

/*===========================================================================

FUNCTION   

DESCRIPTION
  
DEPENDENCIES

RETURN VALUE

SIDE EFFECTS

===========================================================================*/
boolean bridle_IsEnabled(void)
{
   return bridle_on;
}
