/* SPDX-License-Identifier: LGPL-2.1-only OR BSD-3-Clause */
/******************************************************************************
 *
 * This file is provided under a dual license.  When you use or
 * distribute this software, you may choose to be licensed under
 * version 2.1 of the GNU Lesser General Public License
 * ("LGPLv2.1 License") or BSD License.
 *
 * LGPLv2.1 License
 *
 * Copyright(C) 2019 MediaTek Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of version 2.1 of the GNU Lesser General Public
 * License as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html for more
 * details.
 *
 * BSD LICENSE
 *
 * Copyright(C) 2019 MediaTek Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *  * Neither the name of the copyright holder nor the names of its
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *****************************************************************************/

/*-----------------------------------------------------------------------------
 * $RCSfile: io_mtci.c,v $
 $Revision: #5 $
 * $Date: 2015/11/26 $
 * $Author: dongmei.cen $
 *
 * Description: Peripherals, such as NOR/NAND/SIF/RTC/PWM/GPIO (and others), are centralized in
 *                   this file
 *---------------------------------------------------------------------------*/

//-----------------------------------------------------------------------------
// Include files
//-----------------------------------------------------------------------------
#include "mtdrm.h"
#include <linux/mtal_ioctl.h>
#include "mtdrm_wv.h"
#include "tz_if.h"
#include "x_bim.h"


//-----------------------------------------------------------------------------
// Constant definitions
//-----------------------------------------------------------------------------


#define USR_SPACE_ACCESS_VALIDATE_ARG_K(arg,size)         \
    if (!access_ok(VERIFY_READ, (void __user *)arg,       \
                size))                                 \
{                                                     \
    ret =  MTR_ERR_INV;                               \
    goto final;                                       \
}                                                     \

#define COPY_TO_USER_ARG_K(ArgUsr, ArgKernel,size)        \
    if (copy_to_user((void __user *)ArgUsr, &ArgKernel,   \
                size))                             \
{                                                     \
    ret =  MTR_ERR_INV;                               \
    goto final;                                       \
}
#define COPY_FROM_USER_ARG_K(ArgUsr, ArgKernel,size)      \
    if (copy_from_user(&(ArgKernel), (void __user *)(ArgUsr), \
                (size)))                             \
{                                                     \
    ret =  MTR_ERR_INV;                               \
    goto final;                                       \
}
#define USR_SPACE_ACCESS_VALIDATE_ARG_SIZE(arg,size)      \
    if (!access_ok(VERIFY_READ, (void __user *)arg,       \
                size))                                 \
{                                                     \
    ret =  MTR_ERR_INV;                               \
    goto final;                                       \
}                                                     \

#define COPY_FROM_USER_ARG_SIZE(ArgUsr, ArgKernel, size)  \
    if (copy_from_user(ArgKernel, (void __user *)ArgUsr,  \
                (size)))                           \
{                                                     \
    ret =  MTR_ERR_INV;                               \
    goto final;                                       \
}                                                     \

#define COPY_TO_USER_ARG_SIZE(ArgUsr, ArgKernel,size)     \
    if (copy_to_user((void __user *)ArgUsr, ArgKernel,    \
                size))                             \
{                                                     \
    ret =  MTR_ERR_INV;                               \
    goto final;                                       \
}                                                     \


//-----------------------------------------------------------------------------
// Type definitions
//-----------------------------------------------------------------------------
#define  KEY_CONTROL_SIZE   16
#define  KEY_IV_SIZE        16
#define  KEY_PAD_SIZE       16
#define  KEY_SIZE           16
#define  MAC_KEY_SIZE       32

#define CC_WIDEVINE_TZ_ENABLE

#if !defined (_TYPEDEF_UPTR_) && !defined(UPTR)
/* typedef uintptr_t  UPTR; */
typedef unsigned long  UPTR;
#define _TYPEDEF_UPTR_
#endif

#ifdef CC_WIDEVINE_TZ_ENABLE
#define x_mem_alloc(size) (void*)VIRTUAL(BSP_AllocAlignedDmaMemory(((size)+TZ_CACHE_LINE_SIZE_MSK)&~(TZ_CACHE_LINE_SIZE_MSK), TZ_CACHE_LINE_SIZE))
#define x_mem_free(addr)  BSP_FreeAlignedDmaMemory(PHYSICAL((UPTR)(addr)))
#endif

#define CHECK_ALLOC(x,size, retval,togo) \
    (x) = x_mem_alloc(size); \
    if((x) ==NULL){           \
        (retval) = MTR_BUFFER_FULL; \
        goto togo;          \
    }

#define CHECK_FREE(x) do{if((x)!=NULL) x_mem_free((x));}while(0)

#define VDEC_ALIGN 0x8000

#define MAX_BSP_ALLOC_SIZE (64*1024 - 256)
#define MAX_BSP_ALLOC_SIZE_GEN (64)

static inline void TZ_CACHE_STR(void* u4VAddr, UINT32 u4Size)
{
    if(u4VAddr == 0) return ;
    TZ_NWD_BufferStart((UPTR)u4VAddr, TZ_CACHE_ALIGN(u4Size));
}

static inline void TZ_CACHE_END(void* u4VAddr, UINT32 u4Size)
{
    if(u4VAddr == 0) return ;
    TZ_NWD_BufferEnd((UPTR)u4VAddr, TZ_CACHE_ALIGN(u4Size));
}

//-----------------------------------------------------------------------------
// Static Variables
//-----------------------------------------------------------------------------

static HANDLE_T _hWidevineSema;
static uint8_t *input_data_addr                   = NULL;
static uint8_t *output_data_addr                  = NULL;

#if defined(CC_WIDEVINE_SUPPORT_USAGE_REPORT)
static HANDLE_T _hRpmbSema;
static char rpmbSemaInit;

#define RPMB_LOCK() do{\
        if(rpmbSemaInit==0) {\
            x_sema_create(&_hRpmbSema, X_SEMA_TYPE_BINARY, X_SEMA_STATE_UNLOCK);\
            rpmbSemaInit =1;\
        }\
        x_sema_lock(_hRpmbSema, X_SEMA_OPTION_WAIT) ;\
    }while(0);

#define RPMB_UNLOCK() x_sema_unlock(_hRpmbSema);

#else

#define RPMB_LOCK()
#define RPMB_UNLOCK()

#endif


//-----------------------------------------------------------------------------
// Secure Buffer Allocation
//-----------------------------------------------------------------------------


// Must Match to TZ Definition Manually

#define SEC_BUF_ANONYMOUS_SESSION		0x0
#define SEC_BUF_ANONYMOUS_HANDLE		0x0

#define SEC_BUF_FLAG_IS_CYCLIC_BUFFER	0x1

typedef struct
{
    UINT32 u4Session;
    UINT32 u4Size;        //Size to be alloc
    UINT32 u4Flag;        //Ctrl flag
	UINT32 *u4Handle;     //return handle of the secure buf
} TZ_DRM_SEC_BUF_ALLOC_T;

typedef struct
{
    UINT32 u4Session;
	UINT32 u4Handle;
	UINT32 *u4Fragment;
	UINT32 u4Size;
} TZ_DRM_SEC_BUF_FRAGMENT_ALLOC_T;

typedef struct
{
    UINT32 u4Session;
	UINT32 u4Handle;
	UINT32 u4Fragment;
	UINT32 u4Size;
} TZ_DRM_SEC_BUF_FRAGMENT_FREE_T;


//-----------------------------------------------------------------------------
// Public functions
//-----------------------------------------------------------------------------

static inline bool RangeCheck(const uint8_t* message,
        uint32_t message_length,
        const uint8_t* field,
        uint32_t field_length,
        bool allow_null) {
    if (field == NULL) return allow_null;
    if (field < message) return false;
    if (((field + field_length) < field) || ((message + message_length) < message)) // when integer overflow
        return false;
    if ((field + field_length) > (message + message_length)) return false;
    return true;
}

//===================================
// Secure Buffer Allocation
//===================================

MT_RESULT_T _MTDRM_RPMB_LOAD_MAC_KEY(unsigned long arg)
{
    RpmbLoadKeyArg rArg, *tzArg = NULL;

    MT_RESULT_T ret     = MTR_OK;
    uint32_t *result    = NULL;
    uint8_t *key        = NULL;

	MTDMX_PRINT("MTAL: %s entry \n",__FUNCTION__);

    CHECK_ALLOC(result,sizeof(uint32_t),ret,final);

    USR_SPACE_ACCESS_VALIDATE_ARG_K(arg, sizeof(RpmbLoadKeyArg));
    COPY_FROM_USER_ARG_K(arg, rArg, sizeof(RpmbLoadKeyArg));

    USR_SPACE_ACCESS_VALIDATE_ARG_K(rArg.result,sizeof(uint32_t));

    CHECK_ALLOC(key,rArg.keySize,ret,final);
    USR_SPACE_ACCESS_VALIDATE_ARG_K(rArg.key,rArg.keySize);
    COPY_FROM_USER_ARG_K(rArg.key, *key, rArg.keySize);

    CHECK_ALLOC(tzArg,sizeof(rArg),ret,final);

    x_memcpy(tzArg,&rArg,sizeof(rArg));
    tzArg->result  = (uint32_t* )PHYSICAL((UINT32)result);
    tzArg->key = (uint8_t* )PHYSICAL((UINT32)key);

    TZ_CACHE_STR(result  , sizeof(uint32_t));
    TZ_CACHE_STR(key , rArg.keySize);
    TZ_RPMB_LOAD_MAC_KEY(tzArg , sizeof(rArg));
    TZ_CACHE_END(result  , sizeof(uint32_t));
    TZ_CACHE_END(key , rArg.keySize);

    COPY_TO_USER_ARG_K(rArg.result,  *result ,sizeof(uint32_t));

final:
	if(result!=NULL)
		MTDMX_PRINT("MTAL: %s exit, *result=%d \n",__FUNCTION__,*result);

    CHECK_FREE(tzArg);
    CHECK_FREE(result);
    CHECK_FREE(key);

    return ret;
}

MT_RESULT_T _MTDRM_RPMB_GET_WCNT_REQ(unsigned long arg)
{
    RpmGetWriteCntReqArg rArg, *tzArg = NULL;

    MT_RESULT_T ret     = MTR_OK;
    uint32_t *result    = NULL;
    RPMB_DATAFRAM *dFrm        = NULL;

	MTDMX_PRINT("MTAL: %s entry \n",__FUNCTION__);

    CHECK_ALLOC(result,sizeof(uint32_t),ret,final);
    CHECK_ALLOC(dFrm,sizeof(RPMB_DATAFRAM),ret,final);

    USR_SPACE_ACCESS_VALIDATE_ARG_K(arg, sizeof(RpmGetWriteCntReqArg));
    COPY_FROM_USER_ARG_K(arg, rArg, sizeof(RpmGetWriteCntReqArg));

    USR_SPACE_ACCESS_VALIDATE_ARG_K(rArg.result,sizeof(uint32_t));
    USR_SPACE_ACCESS_VALIDATE_ARG_K(rArg.dFrm,sizeof(RPMB_DATAFRAM));

    CHECK_ALLOC(tzArg,sizeof(rArg),ret,final);

    x_memcpy(tzArg,&rArg,sizeof(rArg));
    tzArg->result  = (uint32_t* )PHYSICAL((UINT32)result);
    tzArg->dFrm = (RPMB_DATAFRAM* )PHYSICAL((UINT32)dFrm);

    TZ_CACHE_STR(result  , sizeof(uint32_t));
    TZ_CACHE_STR(dFrm , sizeof(RPMB_DATAFRAM));
    TZ_RPMB_GET_WCNT_REQ(tzArg , sizeof(rArg));
    TZ_CACHE_END(result  , sizeof(uint32_t));
    TZ_CACHE_END(dFrm , sizeof(RPMB_DATAFRAM));

    COPY_TO_USER_ARG_K(rArg.result,  *result ,sizeof(uint32_t));
    COPY_TO_USER_ARG_K(rArg.dFrm,  *dFrm ,sizeof(RPMB_DATAFRAM));

final:
	if(result!=NULL)
		MTDMX_PRINT("MTAL: %s exit, *result=%d \n",__FUNCTION__,*result);

    CHECK_FREE(tzArg);
    CHECK_FREE(result);
    CHECK_FREE(dFrm);

    return ret;
}

MT_RESULT_T _MTDRM_RPMB_SET_WCNT_RESP(unsigned long arg)
{
    RpmSetWriteCntRespArg rArg, *tzArg = NULL;

    MT_RESULT_T ret     = MTR_OK;
    uint32_t *result    = NULL;
    RPMB_DATAFRAM *dFrm        = NULL;

	MTDMX_PRINT("MTAL: %s entry \n",__FUNCTION__);

    CHECK_ALLOC(result,sizeof(uint32_t),ret,final);
    CHECK_ALLOC(dFrm,sizeof(RPMB_DATAFRAM),ret,final);

    USR_SPACE_ACCESS_VALIDATE_ARG_K(arg, sizeof(RpmSetWriteCntRespArg));
    COPY_FROM_USER_ARG_K(arg, rArg, sizeof(RpmSetWriteCntRespArg));

    USR_SPACE_ACCESS_VALIDATE_ARG_K(rArg.result,sizeof(uint32_t));
    USR_SPACE_ACCESS_VALIDATE_ARG_K(rArg.dFrm,sizeof(RPMB_DATAFRAM));

    COPY_FROM_USER_ARG_K(rArg.dFrm, *dFrm, sizeof(RPMB_DATAFRAM));

    CHECK_ALLOC(tzArg,sizeof(rArg),ret,final);

    x_memcpy(tzArg,&rArg,sizeof(rArg));
    tzArg->result  = (uint32_t* )PHYSICAL((UINT32)result);
    tzArg->dFrm = (RPMB_DATAFRAM* )PHYSICAL((UINT32)dFrm);

    TZ_CACHE_STR(result  , sizeof(uint32_t));
    TZ_CACHE_STR(dFrm , sizeof(RPMB_DATAFRAM));
    TZ_RPMB_SET_WCNT_RESP(tzArg , sizeof(rArg));
    TZ_CACHE_END(result  , sizeof(uint32_t));
    TZ_CACHE_END(dFrm , sizeof(RPMB_DATAFRAM));

    COPY_TO_USER_ARG_K(rArg.result,  *result ,sizeof(uint32_t));

final:
	if(result!=NULL)
		MTDMX_PRINT("MTAL: %s exit, *result=%d \n",__FUNCTION__,*result);

    CHECK_FREE(tzArg);
    CHECK_FREE(result);
    CHECK_FREE(dFrm);

    return ret;
}

UINT32 u4SecureBufferAlloc(size_t size)
{
#if 0
    return (UINT32)BSP_AllocAlignedDmaMemory(size, VDEC_ALIGN );
#else

    TZ_DRM_SEC_BUF_ALLOC_T *arg;
    UINT32 u4Handle;
    UINT32 *pu4Handle;

    arg = x_mem_alloc(sizeof(TZ_DRM_SEC_BUF_ALLOC_T));
    pu4Handle = x_mem_alloc(sizeof(TZ_DRM_SEC_BUF_ALLOC_T));

    arg->u4Session = 0;
    arg->u4Size    = size;
    arg->u4Flag    = 0;
    arg->u4Handle  = (UINT32*)PHYSICAL((UINT32)pu4Handle);

    TZ_CACHE_STR(pu4Handle , sizeof(UINT32));
    TZ_SEC_BUF_ALLOC(arg , sizeof(TZ_DRM_SEC_BUF_ALLOC_T));
    TZ_CACHE_END(pu4Handle , sizeof(UINT32));

    u4Handle = *pu4Handle;

    x_mem_free(arg);
    x_mem_free(pu4Handle);

    return u4Handle;

#endif

}

MT_RESULT_T _MTDRM_SECURE_ALLOC(unsigned long arg)
{
    SecureAllocArg rArg;
    void *addr=NULL;
    MT_RESULT_T ret = MTR_OK;

    USR_SPACE_ACCESS_VALIDATE_ARG_K(arg, sizeof(SecureAllocArg));
    COPY_FROM_USER_ARG_K(arg, rArg, sizeof(SecureAllocArg));

    USR_SPACE_ACCESS_VALIDATE_ARG_K(rArg.handle,sizeof(SECURE_BUF_HANDLE));

    //addr = (void *)PHYSICAL((UINT32)x_mem_alloc(rArg.size));
    //addr = (void *)BSP_AllocAlignedDmaMemory(rArg.size, VDEC_ALIGN );
    addr = (void *)u4SecureBufferAlloc(rArg.size);

    COPY_TO_USER_ARG_K(rArg.handle, addr,sizeof(SECURE_BUF_HANDLE));

final:
    return ret;
}

BOOL bSecureBufferFree(UINT32 u4Handle)
{
#if 0
    return BSP_FreeAlignedDmaMemory(u4Handle);
#else
    UINT32 *rel;

    rel = x_mem_alloc(sizeof(UINT32));
    *rel = u4Handle;
    TZ_SEC_BUF_FREE(rel , sizeof(UINT32));
    x_mem_free(rel);

    return 0;
#endif
}

MT_RESULT_T _MTDRM_SECURE_FREE(unsigned long arg)
{
    MT_RESULT_T ret = MTR_OK;
    if(arg !=(unsigned long) NULL)
    {
        //x_mem_free((void *)VIRTUAL(arg));
        //BSP_FreeAlignedDmaMemory(arg);
        bSecureBufferFree(arg);
    }
    return ret;
}

MT_RESULT_T _MTDRM_SECURE_FREE_ALL(void)
{
    MT_RESULT_T ret = MTR_OK;
    UINT32 *rel;

    rel = x_mem_alloc(sizeof(UINT32));
    TZ_SEC_BUF_FLUSH(rel , sizeof(UINT32));
    x_mem_free(rel);

    return ret;
}

BOOL bSecureBufferFragmentAlloc(UINT32 u4Session , UINT32 u4Handle, UINT32 *u4Fragment, UINT32 u4Size)
{
	TZ_DRM_SEC_BUF_FRAGMENT_ALLOC_T *rArg=NULL;

    MT_RESULT_T ret         = MTR_OK;
    UINT32 *rFrg = NULL;

    CHECK_ALLOC(rArg,sizeof(rArg),ret,final);
    CHECK_ALLOC(rFrg,sizeof(UINT32),ret,final);

	rArg->u4Session = u4Session;
	rArg->u4Handle = u4Handle;
	rArg->u4Fragment = rFrg;
	rArg->u4Size = u4Size;

	TZ_CACHE_STR(rArg->u4Fragment , sizeof(UINT32));
	ret =  TZ_SEC_BUF_FRAGMENT_ALLOC(&rArg , sizeof(TZ_DRM_SEC_BUF_FRAGMENT_ALLOC_T));
	TZ_CACHE_END(rArg->u4Fragment , sizeof(UINT32));

final:

	if(ret == MTR_OK)
	{
		*u4Fragment = *rFrg;
	}

    CHECK_FREE(rArg);
    CHECK_FREE(rFrg);

    return ret;
}

BOOL bSecureBufferFragmentFree(UINT32 u4Session , UINT32 u4Handle, UINT32 u4Fragment, UINT32 u4Size)
{
	TZ_DRM_SEC_BUF_FRAGMENT_FREE_T *rArg=NULL;

    MT_RESULT_T ret         = MTR_OK;
    CHECK_ALLOC(rArg,sizeof(rArg),ret,final);

	rArg->u4Session = u4Session;
	rArg->u4Handle = u4Handle;
	rArg->u4Fragment = u4Fragment;
	rArg->u4Size = u4Size;

	ret =  TZ_SEC_BUF_FRAGMENT_FREE(&rArg , sizeof(TZ_DRM_SEC_BUF_FRAGMENT_FREE_T));
final:

    CHECK_FREE(rArg);

    return ret;
}

//===================================
// WV Level 1 Wrapper
//===================================

static char u1Initialized = 0;

MT_RESULT_T _MTDRM_WV_OEMCrypto_Initialize(unsigned long arg)
{
    MT_RESULT_T ret         = MTR_OK;
    OEMCryptoResult *result = NULL;

	MTDMX_PRINT("MTAL: %s entry \n",__FUNCTION__);

    if (!u1Initialized)
    {
        x_sema_create(&_hWidevineSema, X_SEMA_TYPE_BINARY, X_SEMA_STATE_UNLOCK);
        u1Initialized = 1 ;
    }


    if(input_data_addr ==NULL){
        input_data_addr = x_mem_alloc(MAX_BSP_ALLOC_SIZE);
    }

    if(output_data_addr ==NULL){
        output_data_addr = x_mem_alloc(MAX_BSP_ALLOC_SIZE);
    }

    x_sema_lock(_hWidevineSema, X_SEMA_OPTION_WAIT) ;
    RPMB_LOCK();

    CHECK_ALLOC(result,sizeof(OEMCryptoResult),ret,final);
    *result = OEMCrypto_ERROR_UNKNOWN_FAILURE;

    USR_SPACE_ACCESS_VALIDATE_ARG_K(arg , sizeof(OEMCryptoResult));

#ifdef CC_WIDEVINE_TZ_ENABLE
    TZ_OEMCrypto_Initialize(result, sizeof(OEMCryptoResult));
#else
    *result = OEMCrypto_Initialize();
#endif

    COPY_TO_USER_ARG_K(arg, *result, sizeof(OEMCryptoResult));
final:
	if(result!=NULL)
		MTDMX_PRINT("MTAL: %s exit, *result=%d \n",__FUNCTION__,*result);

    CHECK_FREE(result);

    x_sema_unlock(_hWidevineSema);
    return ret;
}

MT_RESULT_T _MTDRM_WV_OEMCrypto_Terminate(unsigned long arg)
{
    MT_RESULT_T ret         = MTR_OK;
    OEMCryptoResult *result = NULL;

	MTDMX_PRINT("MTAL: %s entry \n",__FUNCTION__);

    if (!u1Initialized)
    {
        x_sema_create(&_hWidevineSema, X_SEMA_TYPE_BINARY, X_SEMA_STATE_UNLOCK);
        u1Initialized = 1 ;
    }

    x_sema_lock(_hWidevineSema, X_SEMA_OPTION_WAIT) ;
    RPMB_LOCK();

    CHECK_ALLOC(result,sizeof(OEMCryptoResult),ret,final);

    *result = OEMCrypto_ERROR_UNKNOWN_FAILURE;
#ifdef CC_WIDEVINE_TZ_ENABLE
    TZ_OEMCrypto_Terminate(result,sizeof(OEMCryptoResult));
#else
    *result = OEMCrypto_Terminate();
#endif

    USR_SPACE_ACCESS_VALIDATE_ARG_K(arg , sizeof(OEMCryptoResult));
    COPY_TO_USER_ARG_K(arg, *result,sizeof(OEMCryptoResult));
final:
	if(result!=NULL)
		MTDMX_PRINT("MTAL: %s exit, *result=%d \n",__FUNCTION__,*result);

    CHECK_FREE(result);

    x_sema_unlock(_hWidevineSema);
    return ret;
}

MT_RESULT_T _MTDRM_WV_OEMCrypto_OpenSession(unsigned long arg)
{
    MT_RESULT_T ret             = MTR_OK;
    OEMCryptoResult *result=NULL, *presult     = NULL;
    OEMCrypto_SESSION *session=NULL, *psession  = NULL;
    OpenSessionArg_64BIT rArg = {{0},{0}};
	OpenSessionArg_64BIT *tzArg = NULL;

	MTDMX_PRINT("MTAL: %s entry \n",__FUNCTION__);

    if (!u1Initialized)
    {
        x_sema_create(&_hWidevineSema, X_SEMA_TYPE_BINARY, X_SEMA_STATE_UNLOCK);
        u1Initialized = 1 ;
    }

    x_sema_lock(_hWidevineSema, X_SEMA_OPTION_WAIT) ;

    CHECK_ALLOC(result,sizeof(OEMCryptoResult),ret,final);
    *result = OEMCrypto_ERROR_UNKNOWN_FAILURE;

    CHECK_ALLOC(session,sizeof(OEMCrypto_SESSION),ret,final);

    USR_SPACE_ACCESS_VALIDATE_ARG_K(arg, sizeof(OpenSessionArg_64BIT));
    COPY_FROM_USER_ARG_K(arg, rArg, sizeof(OpenSessionArg_64BIT));

#ifdef CONFIG_COMPAT
	if (is_compat_task())
	{
		presult = (OEMCryptoResult*)(compat_ptr(rArg.addr_r));
		psession = (OEMCrypto_SESSION*)(compat_ptr(rArg.addr_s));
	}
	else
#endif
	{
		presult = (OEMCryptoResult*)rArg.result;
		psession = (OEMCrypto_SESSION*)rArg.session;
	}

    USR_SPACE_ACCESS_VALIDATE_ARG_K(presult,sizeof(OEMCryptoResult));
    USR_SPACE_ACCESS_VALIDATE_ARG_K(psession,sizeof(OEMCrypto_SESSION));

#ifdef CC_WIDEVINE_TZ_ENABLE
    CHECK_ALLOC(tzArg,sizeof(rArg),ret,final);
    x_memcpy(tzArg,&rArg,sizeof(rArg));
    tzArg->result  = (OEMCryptoResult* )PHYSICAL((UPTR)result);
    tzArg->session = (OEMCrypto_SESSION* )PHYSICAL((UPTR)session);

    TZ_CACHE_STR(result  , sizeof(OEMCryptoResult));
    TZ_CACHE_STR(session , sizeof(OEMCrypto_SESSION));
    TZ_OEMCrypto_OpenSession(tzArg , sizeof(rArg));
    TZ_CACHE_END(result  , sizeof(OEMCryptoResult));
    TZ_CACHE_END(session , sizeof(OEMCrypto_SESSION));

#else
    *result = OEMCrypto_OpenSession(session);
#endif

    COPY_TO_USER_ARG_K(presult,  *result ,sizeof(OEMCryptoResult));
    COPY_TO_USER_ARG_K(psession, *session,sizeof(OEMCrypto_SESSION));
final:

#ifdef CC_WIDEVINE_TZ_ENABLE
    CHECK_FREE(tzArg);
#endif
	if(result!=NULL)
		MTDMX_PRINT("MTAL: %s exit, *result=%d \n",__FUNCTION__,*result);

    CHECK_FREE(result);
    CHECK_FREE(session);

    x_sema_unlock(_hWidevineSema);

    return ret;
}


MT_RESULT_T _MTDRM_WV_OEMCrypto_CloseSession(unsigned long arg)
{
    MT_RESULT_T ret = MTR_OK;
    OEMCryptoResult *result=NULL, *presult      = NULL;
    CloseSessionArg_64BIT rArg = {{0},0};
	CloseSessionArg_64BIT  *tzArg = NULL;

	MTDMX_PRINT("MTAL: %s entry \n",__FUNCTION__);

    if (!u1Initialized)
    {
        x_sema_create(&_hWidevineSema, X_SEMA_TYPE_BINARY, X_SEMA_STATE_UNLOCK);
        u1Initialized = 1 ;
    }

    x_sema_lock(_hWidevineSema, X_SEMA_OPTION_WAIT) ;

    CHECK_ALLOC(result,sizeof(OEMCryptoResult),ret,final);
    *result = OEMCrypto_ERROR_UNKNOWN_FAILURE;

    USR_SPACE_ACCESS_VALIDATE_ARG_K(arg,sizeof(CloseSessionArg_64BIT));
    COPY_FROM_USER_ARG_K(arg, rArg, sizeof(CloseSessionArg_64BIT));

#ifdef CONFIG_COMPAT
	if (is_compat_task())
	{
		presult = (OEMCryptoResult*)(compat_ptr(rArg.addr_r));
	}
	else
#endif
	{
		presult = (OEMCryptoResult*)rArg.result;
	}

    USR_SPACE_ACCESS_VALIDATE_ARG_K(presult,sizeof(OEMCryptoResult));

#ifdef CC_WIDEVINE_TZ_ENABLE
    CHECK_ALLOC(tzArg,sizeof(rArg),ret,final);
    x_memcpy(tzArg,&rArg,sizeof(rArg));
    tzArg->result = (OEMCryptoResult* )PHYSICAL((UPTR)result);

    TZ_CACHE_STR(result , sizeof(OEMCryptoResult));
    TZ_OEMCrypto_CloseSession(tzArg , sizeof(rArg));
    TZ_CACHE_END(result , sizeof(OEMCryptoResult));
#else
    *result = OEMCrypto_CloseSession(rArg.session);
#endif

    COPY_TO_USER_ARG_K(presult, *result,sizeof(OEMCryptoResult));
final:

#ifdef CC_WIDEVINE_TZ_ENABLE
    CHECK_FREE(tzArg);
#endif
	if(result!=NULL)
		MTDMX_PRINT("MTAL: %s exit, *result=%d \n",__FUNCTION__,*result);

    CHECK_FREE(result);

    x_sema_unlock(_hWidevineSema);
    return ret;
}

MT_RESULT_T _MTDRM_WV_OEMCrypto_GenerateDerivedKeys(unsigned long arg)
{
    MT_RESULT_T ret                     = MTR_OK;
    GenerateDerivedKeysArg_64BIT rArg = {{0},0,{0},0,{0},0};
	GenerateDerivedKeysArg_64BIT *tzArg = NULL;
    OEMCryptoResult *result=NULL, *presult             = NULL;
    uint8_t *mac_key_context=NULL, *pmac_key_context   = NULL;
    uint8_t *enc_key_context=NULL, *penc_key_context   = NULL;

	MTDMX_PRINT("MTAL: %s entry \n",__FUNCTION__);

    if (!u1Initialized)
    {
        x_sema_create(&_hWidevineSema, X_SEMA_TYPE_BINARY, X_SEMA_STATE_UNLOCK);
        u1Initialized = 1 ;
    }

    x_sema_lock(_hWidevineSema, X_SEMA_OPTION_WAIT) ;

    CHECK_ALLOC(result,sizeof(OEMCryptoResult),ret,final);
    *result = OEMCrypto_ERROR_UNKNOWN_FAILURE;

    USR_SPACE_ACCESS_VALIDATE_ARG_K(arg, sizeof(GenerateDerivedKeysArg_64BIT));
    COPY_FROM_USER_ARG_K(arg , rArg , sizeof(GenerateDerivedKeysArg_64BIT));

#ifdef CONFIG_COMPAT
	if (is_compat_task())
	{
		presult = (OEMCryptoResult*)(compat_ptr(rArg.addr_r));
		pmac_key_context = (uint8_t*)(compat_ptr(rArg.addr_m));
		penc_key_context = (uint8_t*)(compat_ptr(rArg.addr_e));
	}
	else
#endif
	{
		presult = (OEMCryptoResult*)rArg.result;
		pmac_key_context = (uint8_t*)rArg.mac_key_context;
		penc_key_context = (uint8_t*)rArg.enc_key_context;
	}

    USR_SPACE_ACCESS_VALIDATE_ARG_K(presult, sizeof(OEMCryptoResult));
    USR_SPACE_ACCESS_VALIDATE_ARG_K(pmac_key_context, rArg.mac_key_context_length);
    USR_SPACE_ACCESS_VALIDATE_ARG_K(penc_key_context, rArg.enc_key_context_length);

    CHECK_ALLOC(mac_key_context ,rArg.mac_key_context_length, ret, final);
    COPY_FROM_USER_ARG_K(pmac_key_context , *mac_key_context , rArg.mac_key_context_length);

    CHECK_ALLOC(enc_key_context ,rArg.enc_key_context_length, ret, final);
    COPY_FROM_USER_ARG_K(penc_key_context , *enc_key_context , rArg.enc_key_context_length);

#ifdef CC_WIDEVINE_TZ_ENABLE
    CHECK_ALLOC(tzArg,sizeof(rArg),ret,final);

    x_memcpy(tzArg,&rArg,sizeof(rArg));
    tzArg->result          = (OEMCryptoResult* )PHYSICAL((UPTR)result);
    tzArg->mac_key_context = (uint8_t *)PHYSICAL((UPTR)mac_key_context);
    tzArg->enc_key_context = (uint8_t *)PHYSICAL((UPTR)enc_key_context);

    TZ_CACHE_STR(result , sizeof(OEMCryptoResult));
    TZ_CACHE_STR(mac_key_context, rArg.mac_key_context_length);;
    TZ_CACHE_STR(enc_key_context, rArg.enc_key_context_length);;

    TZ_OEMCrypto_GenerateDerivedKeys(tzArg , sizeof(rArg));

    TZ_CACHE_END(result , sizeof(OEMCryptoResult));
    TZ_CACHE_END(mac_key_context, rArg.mac_key_context_length);;
    TZ_CACHE_END(enc_key_context, rArg.enc_key_context_length);;
#else
    *result = OEMCrypto_GenerateDerivedKeys(rArg.session,
            mac_key_context, rArg.mac_key_context_length,
            enc_key_context, rArg.enc_key_context_length);
#endif

    COPY_TO_USER_ARG_K(presult, *result,sizeof(OEMCryptoResult));

final :

#ifdef CC_WIDEVINE_TZ_ENABLE
    CHECK_FREE(tzArg);
#endif
	if(result!=NULL)
		MTDMX_PRINT("MTAL: %s exit, *result=%d \n",__FUNCTION__,*result);

    CHECK_FREE(result);
    CHECK_FREE(mac_key_context);
    CHECK_FREE(enc_key_context);

    x_sema_unlock(_hWidevineSema);
    return ret;
}

MT_RESULT_T _MTDRM_WV_OEMCrypto_GenerateNonce(unsigned long arg)
{
    MT_RESULT_T ret = MTR_OK;
    GenerateNonceArg_64BIT rArg = {{0},0,{0}};
	GenerateNonceArg_64BIT *tzArg = NULL;
    OEMCryptoResult *result=NULL, *presult      = NULL;
    uint32_t *nonce=NULL, *pnonce               = NULL;

	MTDMX_PRINT("MTAL: %s entry \n",__FUNCTION__);

    if (!u1Initialized)
    {
        x_sema_create(&_hWidevineSema, X_SEMA_TYPE_BINARY, X_SEMA_STATE_UNLOCK);
        u1Initialized = 1 ;
    }

    x_sema_lock(_hWidevineSema, X_SEMA_OPTION_WAIT) ;

    CHECK_ALLOC(result,sizeof(OEMCryptoResult),ret,final);
    *result = OEMCrypto_ERROR_UNKNOWN_FAILURE;
    CHECK_ALLOC(nonce,sizeof(uint32_t),ret,final);

    USR_SPACE_ACCESS_VALIDATE_ARG_K(arg, sizeof(GenerateNonceArg_64BIT));
    COPY_FROM_USER_ARG_K(arg , rArg , sizeof(GenerateNonceArg_64BIT));

#ifdef CONFIG_COMPAT
	if (is_compat_task())
	{
		presult = (OEMCryptoResult*)(compat_ptr(rArg.addr_r));
		pnonce = (uint32_t*)(compat_ptr(rArg.addr_n));
	}
	else
#endif
	{
		presult = (OEMCryptoResult*)rArg.result;
		pnonce = (uint32_t*)rArg.nonce;
	}

    USR_SPACE_ACCESS_VALIDATE_ARG_K(presult, sizeof(OEMCryptoResult));
    USR_SPACE_ACCESS_VALIDATE_ARG_K(pnonce, sizeof(uint32_t));

#ifdef CC_WIDEVINE_TZ_ENABLE
    CHECK_ALLOC(tzArg,sizeof(rArg),ret,final);
    x_memcpy(tzArg,&rArg,sizeof(rArg));
    tzArg->result = (OEMCryptoResult* )PHYSICAL((UPTR)result);
    tzArg->nonce  = (uint32_t *)PHYSICAL((UPTR)nonce);

    TZ_CACHE_STR(nonce  , sizeof(uint32_t));
    TZ_CACHE_STR(result , sizeof(OEMCryptoResult));
    TZ_OEMCrypto_GenerateNonce(tzArg, sizeof(rArg));
    TZ_CACHE_END(nonce  , sizeof(uint32_t));
    TZ_CACHE_END(result , sizeof(OEMCryptoResult));
#else
    *result =  OEMCrypto_GenerateNonce(rArg.session,nonce);
#endif

    COPY_TO_USER_ARG_K(presult, *result , sizeof(OEMCryptoResult));
    COPY_TO_USER_ARG_K(pnonce , *nonce  , sizeof(uint32_t));

final:

#ifdef CC_WIDEVINE_TZ_ENABLE
    CHECK_FREE(tzArg);
#endif
	if(result!=NULL)
		MTDMX_PRINT("MTAL: %s exit, *result=%d \n",__FUNCTION__,*result);

    CHECK_FREE(result);
    CHECK_FREE(nonce);

    x_sema_unlock(_hWidevineSema);
    return ret;
}

MT_RESULT_T _MTDRM_WV_OEMCrypto_GenerateSignature(unsigned long arg)
{
    MT_RESULT_T ret = MTR_OK;
	GenerateSignatureArg_64BIT rArg  = {{0},0,{0},0,{0},{0}};
    GenerateSignatureArg_64BIT  *tzArg = NULL;
    OEMCryptoResult *result=NULL, *presult  = NULL;
	uint8_t *pmessage = NULL;
	uint8_t *psignature = NULL;
    UINT32 *signature_length=NULL, *psignature_length = NULL;
    UINT32 invDataLen;

	MTDMX_PRINT("MTAL: %s entry \n",__FUNCTION__);

    if (!u1Initialized)
    {
        x_sema_create(&_hWidevineSema, X_SEMA_TYPE_BINARY, X_SEMA_STATE_UNLOCK);
        u1Initialized = 1 ;
    }

    x_sema_lock(_hWidevineSema, X_SEMA_OPTION_WAIT) ;

    USR_SPACE_ACCESS_VALIDATE_ARG_K(arg, sizeof(GenerateSignatureArg_64BIT));
    COPY_FROM_USER_ARG_K(arg,rArg, sizeof(GenerateSignatureArg_64BIT));


#ifdef CONFIG_COMPAT
	if (is_compat_task())
	{
		presult = (OEMCryptoResult*)(compat_ptr(rArg.addr_r));
		pmessage = (uint8_t*)(compat_ptr(rArg.addr_m));
		psignature = (uint8_t*)(compat_ptr(rArg.addr_s));
		psignature_length = (UINT32*)(compat_ptr(rArg.addr_sl));
	}
	else
#endif
	{
		presult = (OEMCryptoResult*)rArg.result;
		pmessage = (uint8_t*)rArg.message;
		psignature = (uint8_t*)rArg.signature;
		psignature_length = (UINT32*)rArg.signature_length;
	}

    USR_SPACE_ACCESS_VALIDATE_ARG_K(presult, sizeof(OEMCryptoResult));
    CHECK_ALLOC(result,sizeof(OEMCryptoResult),ret,final);
    *result = OEMCrypto_ERROR_UNKNOWN_FAILURE;

    CHECK_ALLOC(signature_length,sizeof(UINT32),ret,final);
    USR_SPACE_ACCESS_VALIDATE_ARG_K(psignature_length, sizeof(UINT32));
    COPY_FROM_USER_ARG_K(psignature_length,*signature_length, sizeof(UINT32));

    if (*signature_length < SHA256_DIGEST_LENGTH) {
        *result = OEMCrypto_ERROR_SHORT_BUFFER;
        *signature_length = SHA256_DIGEST_LENGTH;
        goto result;
    }

    USR_SPACE_ACCESS_VALIDATE_ARG_K(pmessage, rArg.message_length);
    USR_SPACE_ACCESS_VALIDATE_ARG_K(psignature, *signature_length);

    if(rArg.message_length>MAX_BSP_ALLOC_SIZE)
        goto final;
    if(input_data_addr ==NULL)
        goto final;
    COPY_FROM_USER_ARG_K(pmessage , *input_data_addr , rArg.message_length);

    if(*signature_length>MAX_BSP_ALLOC_SIZE)
        goto final;
    if(output_data_addr ==NULL)
        goto final;

    CHECK_ALLOC(tzArg,sizeof(rArg),ret,final);
    x_memcpy(tzArg,&rArg,sizeof(rArg));
    tzArg->result           = (OEMCryptoResult* )PHYSICAL((UPTR)result );
    tzArg->message          = (uint8_t *)PHYSICAL((UPTR)input_data_addr);
    tzArg->signature        = (uint8_t *)PHYSICAL((UPTR)output_data_addr);
    tzArg->signature_length = (UINT32 *)PHYSICAL((UPTR)signature_length);


    invDataLen = *signature_length;

    TZ_CACHE_STR(input_data_addr          , rArg.message_length);
    TZ_CACHE_STR(signature_length , sizeof(UINT32));
    TZ_CACHE_STR(result           , sizeof(OEMCryptoResult));
    TZ_CACHE_STR(output_data_addr         , *signature_length);

    TZ_OEMCrypto_GenerateSignature(tzArg, sizeof(rArg));

    TZ_CACHE_END(input_data_addr          , rArg.message_length);
    TZ_CACHE_END(signature_length , sizeof(UINT32));
    TZ_CACHE_END(result           , sizeof(OEMCryptoResult));
    TZ_CACHE_END(output_data_addr         , invDataLen);

    if(*result == OEMCrypto_SUCCESS)
    {
        COPY_TO_USER_ARG_K(psignature, *output_data_addr , *signature_length);
    }

result:
    COPY_TO_USER_ARG_K(presult, *result, sizeof(OEMCryptoResult));
    COPY_TO_USER_ARG_K(psignature_length, *signature_length , sizeof(UINT32));

final:

#ifdef CC_WIDEVINE_TZ_ENABLE
    CHECK_FREE(tzArg);
#endif
	if(result!=NULL)
		MTDMX_PRINT("MTAL: %s exit, *result=%d \n",__FUNCTION__,*result);

    CHECK_FREE(result);
    CHECK_FREE(signature_length);

    x_sema_unlock(_hWidevineSema);

    return ret;
}

MT_RESULT_T _MTDRM_WV_OEMCrypto_LoadKeys(unsigned long arg)
{
    MT_RESULT_T ret = MTR_OK;
	LoadKeysArg_64BIT rArg		   = {{0},0,{0},0,{0},0,{0},{0},0,{0},{0},0};
    LoadKeysArg_64BIT *tzArg       = NULL;
    OEMCryptoResult *result=NULL, *presult           = NULL;
    uint8_t *message=NULL, *pmessage                 = NULL;
    uint8_t *signature=NULL, *psignature             = NULL;
    uint8_t *enc_mac_keys_iv=NULL, *penc_mac_keys_iv = NULL;
    uint8_t *enc_mac_keys=NULL, *penc_mac_keys       = NULL;
    OEMCrypto_KeyObject_64BIT *key_array=NULL, *pkey_array = NULL;
    uint8_t *pst=NULL, *ppst = NULL;
    uint32_t i;
    uint64_t key_array_length = 0;

	MTDMX_PRINT("MTAL: %s entry \n",__FUNCTION__);

    if (!u1Initialized)
    {
        x_sema_create(&_hWidevineSema, X_SEMA_TYPE_BINARY, X_SEMA_STATE_UNLOCK);
        u1Initialized = 1 ;
    }

    x_sema_lock(_hWidevineSema, X_SEMA_OPTION_WAIT) ;

    CHECK_ALLOC(result,sizeof(OEMCryptoResult),ret,final);
    *result = OEMCrypto_ERROR_UNKNOWN_FAILURE;

    USR_SPACE_ACCESS_VALIDATE_ARG_K(arg, sizeof(LoadKeysArg_64BIT));
    COPY_FROM_USER_ARG_K(arg,rArg , sizeof(LoadKeysArg_64BIT));

#ifdef CONFIG_COMPAT
	if (is_compat_task())
	{
		presult = (OEMCryptoResult*)(compat_ptr(rArg.addr_r));
		pmessage = (uint8_t*)(compat_ptr(rArg.addr_m));
		psignature = (uint8_t*)(compat_ptr(rArg.addr_s));
		penc_mac_keys_iv = (uint8_t*)(compat_ptr(rArg.addr_ei));
		penc_mac_keys = (uint8_t*)(compat_ptr(rArg.addr_e));
		pkey_array = (OEMCrypto_KeyObject_64BIT*)(compat_ptr(rArg.addr_ka));
		ppst = (uint8_t*)(compat_ptr(rArg.addr_p));

		for(i=0;i<rArg.num_keys;++i)
		{
			pkey_array[i].key_id = (uint8_t*)(compat_ptr(pkey_array[i].addr_ki));
			pkey_array[i].key_data_iv = (uint8_t*)(compat_ptr(pkey_array[i].addr_kdi));
			pkey_array[i].key_data = (uint8_t*)(compat_ptr(pkey_array[i].addr_kd));
			pkey_array[i].key_control_iv = (uint8_t*)(compat_ptr(pkey_array[i].addr_kci));
			pkey_array[i].key_control = (uint8_t*)(compat_ptr(pkey_array[i].addr_kc));

		}
	}
	else
#endif
	{
		presult = (OEMCryptoResult*)rArg.result;
		pmessage = (uint8_t*)rArg.message;
		psignature = (uint8_t*)rArg.signature;
		penc_mac_keys_iv = (uint8_t*)rArg.enc_mac_keys_iv;
		penc_mac_keys = (uint8_t*)rArg.enc_mac_keys;
		pkey_array = (OEMCrypto_KeyObject_64BIT*)rArg.key_array;
		ppst = (uint8_t*)rArg.pst;
	}


    USR_SPACE_ACCESS_VALIDATE_ARG_K(presult, sizeof(OEMCryptoResult));
    USR_SPACE_ACCESS_VALIDATE_ARG_K(pmessage, rArg.message_length);
    CHECK_ALLOC(message ,rArg.message_length, ret, final);
    COPY_FROM_USER_ARG_K(pmessage , *message, rArg.message_length);


    USR_SPACE_ACCESS_VALIDATE_ARG_K(psignature, rArg.signature_length);
    CHECK_ALLOC(signature ,rArg.signature_length, ret, final);
    COPY_FROM_USER_ARG_K(psignature , *signature , rArg.signature_length);

    key_array_length = sizeof(OEMCrypto_KeyObject_64BIT)*rArg.num_keys;
    if(key_array_length > 0xffffffff)
    {
        MTDMX_PRINT("_MTDRM_WV_OEMCrypto_LoadKeys  key_array_length overflow  \n");
        *result = OEMCrypto_ERROR_UNKNOWN_FAILURE;
        goto result;
    }

    USR_SPACE_ACCESS_VALIDATE_ARG_K(pkey_array, sizeof(OEMCrypto_KeyObject_64BIT)*rArg.num_keys);
    CHECK_ALLOC(key_array ,sizeof(OEMCrypto_KeyObject_64BIT)*rArg.num_keys, ret, final);


    // Range check
    if (!RangeCheck(pmessage, rArg.message_length, penc_mac_keys, 2*MAC_KEY_SIZE, true) ||
            !RangeCheck(pmessage, rArg.message_length, penc_mac_keys_iv,  KEY_IV_SIZE, true) ||
            !RangeCheck(pmessage, rArg.message_length, ppst, rArg.pst_length, true)
       )
    {
    	MTDMX_PRINT("_MTDRM_WV_OEMCrypto_LoadKeys RangeCheck fail  \n");
        *result = OEMCrypto_ERROR_INVALID_CONTEXT;
        goto result;
    }

    for(i=0;i<rArg.num_keys;++i)
    {
        if (!RangeCheck(pmessage, rArg.message_length, pkey_array[i].key_id, pkey_array[i].key_id_length, false)
                ||!RangeCheck(pmessage, rArg.message_length, pkey_array[i].key_data, pkey_array[i].key_data_length, false)
                ||!RangeCheck(pmessage, rArg.message_length, pkey_array[i].key_data_iv,   KEY_IV_SIZE, false)
                ||!RangeCheck(pmessage, rArg.message_length, pkey_array[i].key_control,   KEY_CONTROL_SIZE, false)
                ||!RangeCheck(pmessage, rArg.message_length, pkey_array[i].key_control_iv, KEY_IV_SIZE, false)) {
			MTDMX_PRINT("_MTDRM_WV_OEMCrypto_LoadKeys RangeCheck key_array fail 	\n");
            *result = OEMCrypto_ERROR_INVALID_CONTEXT;
            goto result;
        }

        key_array[i].key_id          = pkey_array[i].key_id             - pmessage + message;
        key_array[i].key_id_length   = pkey_array[i].key_id_length ;
        key_array[i].key_data_iv     = pkey_array[i].key_data_iv        - pmessage + message;
        key_array[i].key_data        = pkey_array[i].key_data           - pmessage + message;
        key_array[i].key_data_length = pkey_array[i].key_data_length ;;
        key_array[i].key_control_iv  = pkey_array[i].key_control_iv     - pmessage + message;
        key_array[i].key_control     = pkey_array[i].key_control        - pmessage + message;
        key_array[i].cipher_mode     = pkey_array[i].cipher_mode;
    }

    pst = (ppst ==NULL)? NULL : ppst - pmessage + message;

    enc_mac_keys_iv  = (penc_mac_keys_iv == NULL ) ? NULL : penc_mac_keys_iv - pmessage + message;
    enc_mac_keys     = (penc_mac_keys==NULL) ? NULL :penc_mac_keys - pmessage + message;

#ifdef CC_WIDEVINE_TZ_ENABLE

    for(i=0;i<rArg.num_keys;++i)
    {
        key_array[i].key_id           = (uint8_t*)PHYSICAL((UPTR)key_array[i].key_id          );
        key_array[i].key_data_iv      = (uint8_t*)PHYSICAL((UPTR)key_array[i].key_data_iv     );
        key_array[i].key_data         = (uint8_t*)PHYSICAL((UPTR)key_array[i].key_data        );
        key_array[i].key_control_iv   = (uint8_t*)PHYSICAL((UPTR)key_array[i].key_control_iv  );
        key_array[i].key_control      = (uint8_t*)PHYSICAL((UPTR)key_array[i].key_control     );
    }

    CHECK_ALLOC(tzArg,sizeof(rArg),ret,final);
    x_memcpy(tzArg,&rArg,sizeof(rArg));

    tzArg->result          = (OEMCryptoResult* )PHYSICAL((UPTR)result);;
    tzArg->message         = (uint8_t *)PHYSICAL((UPTR)message);
    tzArg->signature       = (uint8_t *)PHYSICAL((UPTR)signature);
    tzArg->pst             = (uint8_t *)PHYSICAL((UPTR)pst);
    tzArg->enc_mac_keys_iv = (uint8_t *)PHYSICAL((UPTR)enc_mac_keys_iv);
    tzArg->enc_mac_keys    = (uint8_t *)PHYSICAL((UPTR)enc_mac_keys);
    tzArg->key_array       = (OEMCrypto_KeyObject_64BIT*)PHYSICAL((UPTR)key_array);

    TZ_CACHE_STR(message   , rArg.message_length);
    TZ_CACHE_STR(signature , rArg.signature_length);
    TZ_CACHE_STR(key_array , sizeof(OEMCrypto_KeyObject_64BIT)*rArg.num_keys);
    TZ_CACHE_STR(result , sizeof(OEMCryptoResult));
    TZ_OEMCrypto_LoadKeys(tzArg, sizeof(rArg));
    TZ_CACHE_END(message   , rArg.message_length);
    TZ_CACHE_END(signature , rArg.signature_length);
    TZ_CACHE_END(key_array , sizeof(OEMCrypto_KeyObject_64BIT)*rArg.num_keys);
    TZ_CACHE_END(result , sizeof(OEMCryptoResult));

#else
    *result =  OEMCrypto_LoadKeys(rArg.session,
            message, rArg.message_length,
            signature, rArg.signature_length,
            enc_mac_keys_iv, enc_mac_keys,
            rArg.num_keys, key_array);
#endif

result:
    COPY_TO_USER_ARG_K(presult, *result, sizeof(OEMCryptoResult));

final:

#ifdef CC_WIDEVINE_TZ_ENABLE
    CHECK_FREE(tzArg);
#endif
	if(result!=NULL)
		MTDMX_PRINT("MTAL: %s exit, *result=%d \n",__FUNCTION__,*result);

    CHECK_FREE(result);
    CHECK_FREE(message);
    CHECK_FREE(signature);
    CHECK_FREE(key_array);

    x_sema_unlock(_hWidevineSema);
    return ret;
}

MT_RESULT_T _MTDRM_WV_OEMCrypto_RefreshKeys(unsigned long arg)
{
    MT_RESULT_T ret = MTR_OK;
	RefreshKeysArg_64BIT rArg			  = {{0},0,{0},0,{0},0,0,{0}};
    RefreshKeysArg_64BIT *tzArg           = NULL;
    OEMCryptoResult *result=NULL, *presult     = NULL ;
    uint8_t *message=NULL, *pmessage           = NULL;
    uint8_t *signature=NULL, *psignature       = NULL;
    OEMCrypto_KeyRefreshObject_64BIT *key_array=NULL, *pkey_array = NULL;
    uint32_t i;
    uint64_t key_array_length = 0;

	MTDMX_PRINT("MTAL: %s entry \n",__FUNCTION__);

    if (!u1Initialized)
    {
        x_sema_create(&_hWidevineSema, X_SEMA_TYPE_BINARY, X_SEMA_STATE_UNLOCK);
        u1Initialized = 1 ;
    }

    x_sema_lock(_hWidevineSema, X_SEMA_OPTION_WAIT) ;

    CHECK_ALLOC(result,sizeof(OEMCryptoResult),ret,final);
    *result = OEMCrypto_ERROR_UNKNOWN_FAILURE;

    USR_SPACE_ACCESS_VALIDATE_ARG_K(arg, sizeof(RefreshKeysArg_64BIT));
    COPY_FROM_USER_ARG_K(arg,rArg ,sizeof( RefreshKeysArg_64BIT));

#ifdef CONFIG_COMPAT
	if (is_compat_task())
	{
		presult = (OEMCryptoResult*)(compat_ptr(rArg.addr_r));
		pmessage = (uint8_t*)(compat_ptr(rArg.addr_m));
		psignature = (uint8_t*)(compat_ptr(rArg.addr_s));
		pkey_array = (OEMCrypto_KeyRefreshObject_64BIT*)(compat_ptr(rArg.addr_ka));

		for(i=0;i<rArg.num_keys;++i)
		{
			pkey_array[i].key_id = (uint8_t*)(compat_ptr(pkey_array[i].addr_ki));
			pkey_array[i].key_control_iv = (uint8_t*)(compat_ptr(pkey_array[i].addr_kci));
			pkey_array[i].key_control = (uint8_t*)(compat_ptr(pkey_array[i].addr_kc));
		}
	}
	else
#endif
	{
		presult = (OEMCryptoResult*)rArg.result;
		pmessage = (uint8_t*)rArg.message;
		psignature = (uint8_t*)rArg.signature;
		pkey_array = (OEMCrypto_KeyRefreshObject_64BIT*)rArg.key_array;
	}

    USR_SPACE_ACCESS_VALIDATE_ARG_K(presult, sizeof(OEMCryptoResult));
    USR_SPACE_ACCESS_VALIDATE_ARG_K(pmessage, rArg.message_length);
    USR_SPACE_ACCESS_VALIDATE_ARG_K(psignature, rArg.signature_length);
    USR_SPACE_ACCESS_VALIDATE_ARG_K(pkey_array, sizeof(OEMCrypto_KeyRefreshObject_64BIT)*rArg.num_keys);

    CHECK_ALLOC(message , rArg.message_length,ret, final);
    COPY_FROM_USER_ARG_K(pmessage , *message, rArg.message_length);

    CHECK_ALLOC(signature ,rArg.signature_length, ret, final);
    COPY_FROM_USER_ARG_K(psignature , *signature , rArg.signature_length);

    key_array_length = sizeof(OEMCrypto_KeyRefreshObject_64BIT)*rArg.num_keys;
    if(key_array_length > 0xffffffff)
    {
        MTDMX_PRINT("_MTDRM_WV_OEMCrypto_RefreshKeys  key_array_length overflow  \n");
        *result = OEMCrypto_ERROR_UNKNOWN_FAILURE;
        goto result;
    }

    CHECK_ALLOC(key_array ,sizeof(OEMCrypto_KeyRefreshObject_64BIT)*rArg.num_keys, ret, final);

    for(i=0;i<rArg.num_keys;++i)
    {
        if (!RangeCheck(pmessage, rArg.message_length, pkey_array[i].key_id,    pkey_array[i].key_id_length, true) ||
                !RangeCheck(pmessage, rArg.message_length, pkey_array[i].key_control, KEY_CONTROL_SIZE, false) ||
                !RangeCheck(pmessage, rArg.message_length, pkey_array[i].key_control_iv, KEY_IV_SIZE, true)) {
			 MTDMX_PRINT("_MTDRM_WV_OEMCrypto_RefreshKeys RangeCheck key_array fail \n");
            *result = OEMCrypto_ERROR_INVALID_CONTEXT;
            goto result;
        }

        key_array[i].key_id         = (pkey_array[i].key_id == NULL) ?
            NULL :pkey_array[i].key_id - pmessage + message;
        key_array[i].key_control_iv = pkey_array[i].key_control_iv == NULL ?
            NULL : pkey_array[i].key_control_iv - pmessage + message;
        key_array[i].key_control    = pkey_array[i].key_control == NULL ?
            NULL : pkey_array[i].key_control - pmessage + message;

        key_array[i].key_id_length  =pkey_array[i].key_id_length;
    }

#ifdef CC_WIDEVINE_TZ_ENABLE
    for(i=0;i<rArg.num_keys;++i)
    {
		key_array[i].key_id         = (key_array[i].key_id == NULL) ?  NULL :
            (uint8_t*)PHYSICAL((UPTR)key_array[i].key_id);
        key_array[i].key_control_iv = key_array[i].key_control_iv == NULL ?  NULL :
            (uint8_t*)PHYSICAL((UPTR)key_array[i].key_control_iv);
        key_array[i].key_control    = key_array[i].key_control == NULL ?  NULL :
            (uint8_t*)PHYSICAL((UPTR)key_array[i].key_control);
    }

    CHECK_ALLOC(tzArg,sizeof(rArg),ret,final);
    x_memcpy(tzArg,&rArg,sizeof(rArg));
    tzArg->result    = (OEMCryptoResult* )PHYSICAL((UPTR)result);
    tzArg->message   = (uint8_t *)PHYSICAL((UPTR)message);
    tzArg->signature = (uint8_t *)PHYSICAL((UPTR)signature);
    tzArg->key_array = (OEMCrypto_KeyRefreshObject_64BIT* )PHYSICAL((UPTR)key_array);

    TZ_CACHE_STR(message   , rArg.message_length);
    TZ_CACHE_STR(signature , rArg.signature_length);
    TZ_CACHE_STR(key_array , sizeof(OEMCrypto_KeyRefreshObject_64BIT)*rArg.num_keys);
    TZ_CACHE_STR(result , sizeof(OEMCryptoResult));
    TZ_OEMCrypto_RefreshKeys(tzArg, sizeof(rArg));
    TZ_CACHE_END(message   , rArg.message_length);
    TZ_CACHE_END(signature , rArg.signature_length);
    TZ_CACHE_END(key_array , sizeof(OEMCrypto_KeyRefreshObject_64BIT)*rArg.num_keys);
    TZ_CACHE_END(result , sizeof(OEMCryptoResult));

#else
    *result = OEMCrypto_RefreshKeys(rArg.session, message, rArg.message_length,
            signature, rArg.signature_length, rArg.num_keys, key_array);
#endif

result:
    COPY_TO_USER_ARG_K(presult, *result, sizeof(OEMCryptoResult));

final:
#ifdef CC_WIDEVINE_TZ_ENABLE
    if(tzArg !=NULL){
        x_mem_free(tzArg);
    }
#endif
	if(result!=NULL)
		MTDMX_PRINT("MTAL: %s exit, *result=%d \n",__FUNCTION__,*result);

    CHECK_FREE(result);
    CHECK_FREE(message);
    CHECK_FREE(signature);
    CHECK_FREE(key_array);

    x_sema_unlock(_hWidevineSema);
    return MTR_OK;
}

MT_RESULT_T _MTDRM_WV_OEMCrypto_SelectKey(unsigned long arg)
{
    OEMCryptoResult *result, *presult   = NULL;
    SelectKeyArg_64BIT rArg   = {{0},0,{0},0};
	SelectKeyArg_64BIT *tzArg = NULL;
    uint8_t *key_id=NULL, *pkey_id = NULL;
    MT_RESULT_T ret           = MTR_OK;

	MTDMX_PRINT("MTAL: %s entry \n",__FUNCTION__);

    if (!u1Initialized)
    {
        x_sema_create(&_hWidevineSema, X_SEMA_TYPE_BINARY, X_SEMA_STATE_UNLOCK);
        u1Initialized = 1 ;
    }

    x_sema_lock(_hWidevineSema, X_SEMA_OPTION_WAIT) ;

    CHECK_ALLOC(result,sizeof(OEMCryptoResult),ret,final);
    *result = OEMCrypto_ERROR_UNKNOWN_FAILURE;

    USR_SPACE_ACCESS_VALIDATE_ARG_K(arg, sizeof(SelectKeyArg_64BIT));
    COPY_FROM_USER_ARG_K(arg , rArg ,sizeof(SelectKeyArg_64BIT));

#ifdef CONFIG_COMPAT
		if (is_compat_task())
		{
			presult = (OEMCryptoResult*)(compat_ptr(rArg.addr_r));
			pkey_id = (uint8_t*)(compat_ptr(rArg.addr_k));
		}
		else
#endif
		{
			presult = (OEMCryptoResult*)rArg.result;
			pkey_id = (uint8_t*)rArg.key_id;
		}

    USR_SPACE_ACCESS_VALIDATE_ARG_K(presult, sizeof(OEMCryptoResult));
    USR_SPACE_ACCESS_VALIDATE_ARG_K(pkey_id, rArg.key_id_length);

    CHECK_ALLOC(key_id ,rArg.key_id_length, ret, final);
    COPY_FROM_USER_ARG_K(pkey_id , *key_id ,rArg.key_id_length);

#ifdef CC_WIDEVINE_TZ_ENABLE
    CHECK_ALLOC(tzArg,sizeof(rArg),ret,final);
    x_memcpy(tzArg,&rArg,sizeof(rArg));
    tzArg->result = (OEMCryptoResult* )PHYSICAL((UPTR)result);;
    tzArg->key_id = (uint8_t *)PHYSICAL((UPTR)key_id);

    TZ_CACHE_STR(key_id , rArg.key_id_length);
    TZ_CACHE_STR(result , sizeof(OEMCryptoResult));
    TZ_OEMCrypto_SelectKey(tzArg, sizeof(rArg));
    TZ_CACHE_END(key_id , rArg.key_id_length);
    TZ_CACHE_END(result , sizeof(OEMCryptoResult));
#else
    *result =  OEMCrypto_SelectKey(rArg.session, key_id, rArg.key_id_length);
#endif

    COPY_TO_USER_ARG_K(presult, *result, sizeof(OEMCryptoResult));

final:

#ifdef CC_WIDEVINE_TZ_ENABLE
    CHECK_FREE(tzArg);
#endif
	if(result!=NULL)
		MTDMX_PRINT("MTAL: %s exit, *result=%d \n",__FUNCTION__,*result);

    CHECK_FREE(result);
	CHECK_FREE(key_id);

    x_sema_unlock(_hWidevineSema);
    return ret;
}

MT_RESULT_T _MTDRM_WV_OEMCrypto_DecryptCTR(unsigned long arg)
{
    MT_RESULT_T ret                      = MTR_OK;
    OEMCryptoResult *result=NULL, *presult    = NULL;
    DecryptCTRArg_64BIT rArg             = {{0},0,{0},0,0,{0},0,{0},0};
	DecryptCTRArg_64BIT *tzArg           = NULL;
    uint8_t *iv=NULL, *piv                    = NULL;
    uint8_t *usr_out_buf_addr            = NULL;
    OEMCrypto_DestBufferDesc_64BIT *out_buffer=NULL, *pout_buffer = NULL;

    UINT32 max_length ;
    UINT32 remain_length=0;
    const uint8_t *data_addr_cur=NULL;
    UINT32 cpy_length;
    UINT32 cpy_ofst=0;

	//MTDMX_PRINT("MTAL: %s entry \n",__FUNCTION__);

    if (!u1Initialized)
    {
        x_sema_create(&_hWidevineSema, X_SEMA_TYPE_BINARY, X_SEMA_STATE_UNLOCK);
        u1Initialized = 1 ;
    }

    x_sema_lock(_hWidevineSema, X_SEMA_OPTION_WAIT) ;

    CHECK_ALLOC(result,sizeof(OEMCryptoResult),ret,final);
    *result = OEMCrypto_ERROR_UNKNOWN_FAILURE;

    CHECK_ALLOC(out_buffer,sizeof(OEMCrypto_DestBufferDesc_64BIT),ret,final);

    USR_SPACE_ACCESS_VALIDATE_ARG_K(arg, sizeof(DecryptCTRArg_64BIT));
    COPY_FROM_USER_ARG_K(arg , rArg, sizeof(DecryptCTRArg_64BIT));

#ifdef CONFIG_COMPAT
	if (is_compat_task())
	{
		presult = (OEMCryptoResult*)(compat_ptr(rArg.addr_r));
		piv = (uint8_t*)(compat_ptr(rArg.addr_iv));
		data_addr_cur = (uint8_t*)(compat_ptr(rArg.addr_d));
		pout_buffer = (OEMCrypto_DestBufferDesc_64BIT*)(compat_ptr(rArg.addr_o));

		if(pout_buffer->type ==OEMCrypto_BufferType_Clear)
		{
			pout_buffer->buffer.clear.address = (uint8_t*)(compat_ptr(pout_buffer->buffer.clear.addr_a));
		}
		if(pout_buffer->type ==OEMCrypto_BufferType_Secure)
		{
			pout_buffer->buffer.secure.handle =  (void*)( (UPTR)(pout_buffer->buffer.secure.handle) & (UPTR)0xFFFFFFFF );
			//MTDMX_PRINT("_MTDRM_WV_OEMCrypto_DecryptCTR pout_buffer->buffer.secure.handle =%p \n",pout_buffer->buffer.secure.handle);
		}
	}
	else
#endif
	{
		presult = (OEMCryptoResult*)rArg.result;
		piv = (uint8_t*)rArg.iv;
		data_addr_cur = (uint8_t*)rArg.data_addr;
		pout_buffer = (OEMCrypto_DestBufferDesc_64BIT*)rArg.out_buffer;
	}

    USR_SPACE_ACCESS_VALIDATE_ARG_K(presult     , sizeof(OEMCryptoResult));
    USR_SPACE_ACCESS_VALIDATE_ARG_K(data_addr_cur  , rArg.data_length);

    USR_SPACE_ACCESS_VALIDATE_ARG_K(piv         , KEY_IV_SIZE);
    USR_SPACE_ACCESS_VALIDATE_ARG_K(pout_buffer , sizeof(OEMCrypto_DestBufferDesc_64BIT));

    COPY_FROM_USER_ARG_K(pout_buffer , *out_buffer , sizeof(OEMCrypto_DestBufferDesc_64BIT));

    switch (out_buffer->type) {
        case OEMCrypto_BufferType_Clear:
            max_length =  out_buffer->buffer.clear.max_length;
            break;
        case OEMCrypto_BufferType_Secure:
            max_length = out_buffer->buffer.secure.max_length;
            break;
        default:
            max_length = 0xFFFFFFFF;
    }

    if (max_length < rArg.data_length) {
        *result =  OEMCrypto_ERROR_SHORT_BUFFER;
        goto result;
    }

    if(out_buffer->type ==OEMCrypto_BufferType_Clear){
        usr_out_buf_addr = out_buffer->buffer.clear.address ;
        USR_SPACE_ACCESS_VALIDATE_ARG_K(usr_out_buf_addr , out_buffer->buffer.clear.max_length);
        if(output_data_addr==NULL){
            goto final;
        }
    }

    if(input_data_addr == NULL){
        goto final;
    }

    remain_length = rArg.data_length;

    CHECK_ALLOC(iv,KEY_IV_SIZE, ret, final);
    COPY_FROM_USER_ARG_K(piv, *iv, KEY_IV_SIZE);

    if(out_buffer->type == OEMCrypto_BufferType_Clear)
    {
        out_buffer->buffer.clear.address = (uint8_t *)PHYSICAL((UPTR)output_data_addr);
    }

    CHECK_ALLOC(tzArg,sizeof(rArg),ret,final);
    x_memcpy(tzArg,&rArg,sizeof(rArg));
    tzArg->result     = (OEMCryptoResult* )PHYSICAL((UPTR)result );
    tzArg->data_addr  = (uint8_t *)PHYSICAL((UPTR)input_data_addr);
    tzArg->iv         = (uint8_t *)PHYSICAL((UPTR)iv);
    tzArg->out_buffer = (OEMCrypto_DestBufferDesc_64BIT *)PHYSICAL((UPTR)out_buffer);


    while(remain_length !=0){
        if(remain_length > MAX_BSP_ALLOC_SIZE){
            if((tzArg->block_offset !=0)&&(tzArg->block_offset < 16)){
                cpy_length = MAX_BSP_ALLOC_SIZE - tzArg->block_offset;
            }
            else
            {
                cpy_length = MAX_BSP_ALLOC_SIZE;
            }
        }else{
            cpy_length = remain_length ;
        }

        COPY_FROM_USER_ARG_K(data_addr_cur, *input_data_addr , cpy_length);

        remain_length -= cpy_length;
        data_addr_cur += cpy_length;

        tzArg->data_length  = cpy_length;

        switch (out_buffer->type) {
            case OEMCrypto_BufferType_Clear:
                    out_buffer->buffer.clear.max_length = cpy_length;
                break;
            case OEMCrypto_BufferType_Secure:
                    out_buffer->buffer.secure.max_length = cpy_length;
                break;
            default:
                break;
        }


	    if(out_buffer->type == OEMCrypto_BufferType_Clear)
	    {
	    	TZ_CACHE_STR((void *)VIRTUAL((UPTR)out_buffer->buffer.clear.address), cpy_length);
	    }

	    TZ_CACHE_STR(input_data_addr   , cpy_length);
	    TZ_CACHE_STR(iv          , KEY_IV_SIZE);
	    TZ_CACHE_STR(out_buffer , sizeof(OEMCrypto_DestBufferDesc_64BIT));
	    TZ_CACHE_STR(result , sizeof(OEMCryptoResult));


	    TZ_OEMCrypto_DecryptCTR(tzArg, sizeof(rArg));

	    TZ_CACHE_END(input_data_addr   , cpy_length);
	    TZ_CACHE_END(iv          , KEY_IV_SIZE);
	    TZ_CACHE_END(out_buffer , sizeof(OEMCrypto_DestBufferDesc_64BIT));
	    TZ_CACHE_END(result , sizeof(OEMCryptoResult));

	    if(out_buffer->type == OEMCrypto_BufferType_Clear)
	    {
	    	TZ_CACHE_END((void *)VIRTUAL((UPTR)out_buffer->buffer.clear.address), cpy_length);
	    }

        switch (out_buffer->type) {
            //case OEMCrypto_BufferType_Clear:
            //    out_buffer->buffer.clear.address += cpy_length;
            case OEMCrypto_BufferType_Secure:
                out_buffer->buffer.secure.offset += cpy_length;
            default:
                break;
        }

        tzArg->block_offset = 0;

        if(*result == OEMCrypto_SUCCESS)
        {
            if(out_buffer->type ==OEMCrypto_BufferType_Clear){
                COPY_TO_USER_ARG_K(usr_out_buf_addr+cpy_ofst, *output_data_addr , cpy_length);
                cpy_ofst += cpy_length;
        	}
    	}
        else
    	{
            break;
        }
    }

result:
    COPY_TO_USER_ARG_K(presult, *result, sizeof(OEMCryptoResult));

final:

#ifdef CC_WIDEVINE_TZ_ENABLE
    CHECK_FREE(tzArg);
#endif
	//if(result!=NULL)
	//	MTDMX_PRINT("MTAL: %s exit, *result=%d \n",__FUNCTION__,*result);

    CHECK_FREE(result);
    CHECK_FREE(iv);
    CHECK_FREE(out_buffer);

    x_sema_unlock(_hWidevineSema);
    return ret;
}

MT_RESULT_T _MTDRM_WV_OEMCrypto_DecryptCENC(unsigned long arg)
{
    MT_RESULT_T ret                      = MTR_OK;
    OEMCryptoResult *result=NULL, *presult    = NULL;
    DecryptCENCArg_64BIT rArg             = {{0},0,{0},0,0,{0},0,{0},{0},0};
	  DecryptCENCArg_64BIT *tzArg           = NULL;
    uint8_t *iv=NULL, *piv                = NULL;
    uint8_t *usr_out_buf_addr            = NULL;
    OEMCrypto_DestBufferDesc_64BIT *out_buffer=NULL, *pout_buffer = NULL;
	  OEMCrypto_CENCEncryptPatternDesc *pattern=NULL, *ppattern=NULL;

    UINT32 max_length ;
    UINT32 remain_length=0;
    const uint8_t *data_addr_cur=NULL;
    UINT32 cpy_length;
    UINT32 cpy_ofst=0;
    uint32_t REAL_MAX_LEN = MAX_BSP_ALLOC_SIZE;

	////MTDMX_PRINT("MTAL: %s entry \n",__FUNCTION__);

    if (!u1Initialized)
    {
        x_sema_create(&_hWidevineSema, X_SEMA_TYPE_BINARY, X_SEMA_STATE_UNLOCK);
        u1Initialized = 1 ;
    }

    x_sema_lock(_hWidevineSema, X_SEMA_OPTION_WAIT) ;

    CHECK_ALLOC(result,sizeof(OEMCryptoResult),ret,final);
    *result = OEMCrypto_ERROR_UNKNOWN_FAILURE;

    CHECK_ALLOC(out_buffer,sizeof(OEMCrypto_DestBufferDesc_64BIT),ret,final);

    USR_SPACE_ACCESS_VALIDATE_ARG_K(arg, sizeof(DecryptCENCArg_64BIT));
    COPY_FROM_USER_ARG_K(arg , rArg, sizeof(DecryptCENCArg_64BIT));

#ifdef CONFIG_COMPAT
	if (is_compat_task())
	{
		presult = (OEMCryptoResult*)(compat_ptr(rArg.addr_r));
		piv = (uint8_t*)(compat_ptr(rArg.addr_iv));
		data_addr_cur = (uint8_t*)(compat_ptr(rArg.addr_d));
		pout_buffer = (OEMCrypto_DestBufferDesc_64BIT*)(compat_ptr(rArg.addr_o));
		ppattern = (OEMCrypto_CENCEncryptPatternDesc *)(compat_ptr(rArg.addr_pattern));

		if(pout_buffer->type ==OEMCrypto_BufferType_Clear)
		{
			pout_buffer->buffer.clear.address = (uint8_t*)(compat_ptr(pout_buffer->buffer.clear.address));
		}
		if(pout_buffer->type ==OEMCrypto_BufferType_Secure)
		{
			pout_buffer->buffer.secure.handle =  (void*)( (UPTR)(pout_buffer->buffer.secure.handle) & (UPTR)0xFFFFFFFF );
		}
	}
	else
#endif
	{
		presult = (OEMCryptoResult*)rArg.result;
		piv = (uint8_t*)rArg.iv;
		data_addr_cur = (uint8_t*)rArg.data_addr;
		pout_buffer = (OEMCrypto_DestBufferDesc_64BIT*)rArg.out_buffer;
		ppattern = (OEMCrypto_CENCEncryptPatternDesc *)rArg.pattern;
	}

    USR_SPACE_ACCESS_VALIDATE_ARG_K(presult     , sizeof(OEMCryptoResult));
    USR_SPACE_ACCESS_VALIDATE_ARG_K(data_addr_cur  , rArg.data_length);

    USR_SPACE_ACCESS_VALIDATE_ARG_K(piv         , KEY_IV_SIZE);
    USR_SPACE_ACCESS_VALIDATE_ARG_K(pout_buffer , sizeof(OEMCrypto_DestBufferDesc_64BIT));

    COPY_FROM_USER_ARG_K(pout_buffer , *out_buffer , sizeof(OEMCrypto_DestBufferDesc_64BIT));

	if(NULL != ppattern)
	{
		CHECK_ALLOC(pattern,sizeof(OEMCrypto_CENCEncryptPatternDesc),ret,final);
		USR_SPACE_ACCESS_VALIDATE_ARG_K(ppattern , sizeof(OEMCrypto_CENCEncryptPatternDesc));
		COPY_FROM_USER_ARG_K(ppattern , *pattern , sizeof(OEMCrypto_CENCEncryptPatternDesc));
	}

    switch (out_buffer->type) {
        case OEMCrypto_BufferType_Clear:
            max_length =  out_buffer->buffer.clear.max_length;
            break;
        case OEMCrypto_BufferType_Secure:
            max_length = out_buffer->buffer.secure.max_length;
            break;
        default:
            max_length = 0xFFFFFFFF;
    }

    if (max_length < rArg.data_length) {
        *result =  OEMCrypto_ERROR_SHORT_BUFFER;
        goto result;
    }

    if(out_buffer->type ==OEMCrypto_BufferType_Clear){
        usr_out_buf_addr = out_buffer->buffer.clear.address ;
        USR_SPACE_ACCESS_VALIDATE_ARG_K(usr_out_buf_addr , out_buffer->buffer.clear.max_length);
        if(output_data_addr==NULL){
            goto final;
        }
    }

    if(input_data_addr == NULL){
        goto final;
    }

    remain_length = rArg.data_length;

    CHECK_ALLOC(iv,KEY_IV_SIZE, ret, final);
    COPY_FROM_USER_ARG_K(piv, *iv, KEY_IV_SIZE);

    if(out_buffer->type == OEMCrypto_BufferType_Clear)
    {
        out_buffer->buffer.clear.address = (uint8_t *)PHYSICAL((UPTR)output_data_addr);
    }

    CHECK_ALLOC(tzArg,sizeof(rArg),ret,final);
    x_memcpy(tzArg,&rArg,sizeof(rArg));
    tzArg->result     = (OEMCryptoResult* )PHYSICAL((UPTR)result );
    tzArg->data_addr  = (uint8_t *)PHYSICAL((UPTR)input_data_addr);
    tzArg->iv         = (uint8_t *)PHYSICAL((UPTR)iv);
    tzArg->out_buffer = (OEMCrypto_DestBufferDesc_64BIT *)PHYSICAL((UPTR)out_buffer);
    tzArg->pattern = (NULL==pattern)? NULL : (OEMCrypto_CENCEncryptPatternDesc *)PHYSICAL((UPTR)pattern);

    if (pattern != NULL && (pattern->encrypt + pattern->skip > 0) && tzArg->is_encrypted)
    {
        REAL_MAX_LEN = (MAX_BSP_ALLOC_SIZE / ((pattern->encrypt + pattern->skip) * 16)) * ((pattern->encrypt + pattern->skip) * 16);
    }
    while(remain_length !=0){
        if(remain_length > REAL_MAX_LEN){
            if((tzArg->block_offset !=0)&&(tzArg->block_offset < 16)){
                cpy_length = REAL_MAX_LEN - tzArg->block_offset;
            }
            else
            {
                cpy_length = REAL_MAX_LEN;
            }
        }else{
            cpy_length = remain_length ;
        }

        COPY_FROM_USER_ARG_K(data_addr_cur, *input_data_addr , cpy_length);

        remain_length -= cpy_length;
        data_addr_cur += cpy_length;

        tzArg->data_length  = cpy_length;

        switch (out_buffer->type) {
            case OEMCrypto_BufferType_Clear:
                    out_buffer->buffer.clear.max_length = cpy_length;
                break;
            case OEMCrypto_BufferType_Secure:
                    out_buffer->buffer.secure.max_length = cpy_length;
                break;
            default:
                break;
        }


	    if(out_buffer->type == OEMCrypto_BufferType_Clear)
	    {
	        TZ_CACHE_STR((void *)VIRTUAL((UPTR)out_buffer->buffer.clear.address), cpy_length);
	    }

	    TZ_CACHE_STR(input_data_addr   , cpy_length);
	    TZ_CACHE_STR(iv          , KEY_IV_SIZE);
	    TZ_CACHE_STR(out_buffer , sizeof(OEMCrypto_DestBufferDesc_64BIT));
	    TZ_CACHE_STR(result , sizeof(OEMCryptoResult));
		  TZ_CACHE_STR(pattern , sizeof(OEMCrypto_CENCEncryptPatternDesc));


	    TZ_OEMCrypto_DecryptCENC(tzArg, sizeof(rArg));

	    TZ_CACHE_END(input_data_addr   , cpy_length);
	    TZ_CACHE_END(iv          , KEY_IV_SIZE);
	    TZ_CACHE_END(out_buffer , sizeof(OEMCrypto_DestBufferDesc_64BIT));
	    TZ_CACHE_END(result , sizeof(OEMCryptoResult));
		  TZ_CACHE_END(pattern , sizeof(OEMCrypto_CENCEncryptPatternDesc));

	    if(out_buffer->type == OEMCrypto_BufferType_Clear)
	    {
	            TZ_CACHE_END((void *)VIRTUAL((UPTR)out_buffer->buffer.clear.address), cpy_length);
	    }

        switch (out_buffer->type) {
            case OEMCrypto_BufferType_Secure:
                out_buffer->buffer.secure.offset += cpy_length;
            default:
                break;
        }

        tzArg->block_offset = 0;

        if(*result == OEMCrypto_SUCCESS)
        {
            if(out_buffer->type ==OEMCrypto_BufferType_Clear){
                COPY_TO_USER_ARG_K(usr_out_buf_addr+cpy_ofst, *output_data_addr , cpy_length);
                cpy_ofst += cpy_length;
        		}
    		}
        else
    		{
            break;
        }
    }

result:
    COPY_TO_USER_ARG_K(presult, *result, sizeof(OEMCryptoResult));

final:

#ifdef CC_WIDEVINE_TZ_ENABLE
    CHECK_FREE(tzArg);
#endif
		if(result!=NULL &&  *result !=OEMCrypto_SUCCESS )
				MTDMX_PRINT("MTAL: %s exit, *result=%d \n",__FUNCTION__,*result);
    CHECK_FREE(result);
    CHECK_FREE(iv);
    CHECK_FREE(out_buffer);
	  CHECK_FREE(pattern);

    x_sema_unlock(_hWidevineSema);
    return ret;
}

MT_RESULT_T _MTDRM_WV_OEMCrypto_InstallKeybox(unsigned long arg)
{
    MT_RESULT_T ret = MTR_OK;
    InstallKeyboxArg_64BIT rArg   = {{0},{0},0};
	InstallKeyboxArg_64BIT *tzArg = NULL;
    OEMCryptoResult *result=NULL, *presult       = NULL;
    uint8_t *keybox=NULL, *pkeybox               = NULL;

	MTDMX_PRINT("MTAL: %s entry \n",__FUNCTION__);

    if (!u1Initialized)
    {
        x_sema_create(&_hWidevineSema, X_SEMA_TYPE_BINARY, X_SEMA_STATE_UNLOCK);
        u1Initialized = 1 ;
    }

    x_sema_lock(_hWidevineSema, X_SEMA_OPTION_WAIT) ;

    CHECK_ALLOC(result,sizeof(OEMCryptoResult),ret,final);
    *result = OEMCrypto_ERROR_UNKNOWN_FAILURE;

    USR_SPACE_ACCESS_VALIDATE_ARG_K(arg ,sizeof(InstallKeyboxArg_64BIT));
    COPY_FROM_USER_ARG_K(arg, rArg , sizeof(InstallKeyboxArg_64BIT));

#ifdef CONFIG_COMPAT
	if (is_compat_task())
	{
		presult = (OEMCryptoResult*)(compat_ptr(rArg.addr_r));
		pkeybox = (uint8_t*)(compat_ptr(rArg.addr_k));
	}
	else
#endif
	{
		presult = (OEMCryptoResult*)rArg.result;
		pkeybox = (uint8_t*)rArg.keybox;
	}

    USR_SPACE_ACCESS_VALIDATE_ARG_K(presult,sizeof(OEMCryptoResult));


    USR_SPACE_ACCESS_VALIDATE_ARG_K(pkeybox,rArg.keyBoxLength);
    CHECK_ALLOC(keybox ,rArg.keyBoxLength, ret, final);
    COPY_FROM_USER_ARG_K(pkeybox, *keybox , rArg.keyBoxLength);

#ifdef CC_WIDEVINE_TZ_ENABLE
    CHECK_ALLOC(tzArg,sizeof(rArg),ret,final);
    x_memcpy(tzArg,&rArg,sizeof(rArg));

    tzArg->result = (OEMCryptoResult* )PHYSICAL((UPTR)result);
    tzArg->keybox = (uint8_t *)PHYSICAL((UPTR)keybox);

    TZ_CACHE_STR(keybox             , rArg.keyBoxLength);
    TZ_CACHE_STR(result , sizeof(OEMCryptoResult));
    TZ_OEMCrypto_InstallKeybox(tzArg , sizeof(rArg));
    TZ_CACHE_END(keybox             , rArg.keyBoxLength);
    TZ_CACHE_END(result , sizeof(OEMCryptoResult));

#else
    *result = OEMCrypto_InstallKeybox(keybox,rArg.keyBoxLength);
#endif

    COPY_TO_USER_ARG_K(presult, *result, sizeof(OEMCryptoResult));

final:

#ifdef CC_WIDEVINE_TZ_ENABLE
    CHECK_FREE(tzArg);
#endif
	if(result!=NULL)
		MTDMX_PRINT("MTAL: %s exit, *result=%d \n",__FUNCTION__,*result);

    CHECK_FREE(result);
    CHECK_FREE(keybox);

    x_sema_unlock(_hWidevineSema);
    return ret;
}

MT_RESULT_T _MTDRM_WV_OEMCrypto_IsKeyboxValid(unsigned long arg)
{
    MT_RESULT_T ret = MTR_OK;
    OEMCryptoResult *result = NULL;

	MTDMX_PRINT("MTAL: %s entry \n",__FUNCTION__);

    if (!u1Initialized)
    {
        x_sema_create(&_hWidevineSema, X_SEMA_TYPE_BINARY, X_SEMA_STATE_UNLOCK);
        u1Initialized = 1 ;
    }

    x_sema_lock(_hWidevineSema, X_SEMA_OPTION_WAIT) ;

    CHECK_ALLOC(result,sizeof(OEMCryptoResult),ret,final);
    *result = OEMCrypto_ERROR_UNKNOWN_FAILURE;

#ifdef CC_WIDEVINE_TZ_ENABLE
    TZ_OEMCrypto_IsKeyboxValid(result , sizeof(OEMCryptoResult));
#else
    *result= OEMCrypto_IsKeyboxValid();
#endif
    USR_SPACE_ACCESS_VALIDATE_ARG_K(arg , sizeof(OEMCryptoResult));
    COPY_TO_USER_ARG_K(arg , *result , sizeof(OEMCryptoResult));
final:
	if(result!=NULL)
		MTDMX_PRINT("MTAL: %s exit, *result=%d \n",__FUNCTION__,*result);

    CHECK_FREE(result);

    x_sema_unlock(_hWidevineSema);
    return ret;
}

MT_RESULT_T _MTDRM_WV_OEMCrypto_GetDeviceID(unsigned long arg)
{
    MT_RESULT_T ret = MTR_OK;
    GetDeviceIDArg_64BIT rArg   = {{0},{0},{0}};
	GetDeviceIDArg_64BIT *tzArg = NULL;
    OEMCryptoResult *result=NULL, *presult     = NULL;
    uint8_t *deviceID=NULL, *pdeviceID         = NULL;
    UINT32 *dlen=NULL, *pdlen                  = NULL;
    UINT32 invDataLen;

	MTDMX_PRINT("MTAL: %s entry \n",__FUNCTION__);

    if (!u1Initialized)
    {
        x_sema_create(&_hWidevineSema, X_SEMA_TYPE_BINARY, X_SEMA_STATE_UNLOCK);
        u1Initialized = 1 ;
    }

    x_sema_lock(_hWidevineSema, X_SEMA_OPTION_WAIT) ;

    CHECK_ALLOC(result , sizeof(OEMCryptoResult) , ret , final);
    CHECK_ALLOC(dlen   , sizeof(UINT32)          , ret , final);

    *result = OEMCrypto_ERROR_UNKNOWN_FAILURE;
    USR_SPACE_ACCESS_VALIDATE_ARG_K(arg           , sizeof(GetDeviceIDArg_64BIT));
    COPY_FROM_USER_ARG_K(arg                      , rArg, sizeof(GetDeviceIDArg_64BIT));

#ifdef CONFIG_COMPAT
	if (is_compat_task())
	{
		presult = (OEMCryptoResult*)(compat_ptr(rArg.addr_r));
		pdeviceID = (uint8_t*)(compat_ptr(rArg.addr_d));
		pdlen = (UINT32*)(compat_ptr(rArg.addr_dl));
	}
	else
#endif
	{
		presult = (OEMCryptoResult*)rArg.result;
		pdeviceID = (uint8_t*)rArg.deviceID;
		pdlen = (UINT32*)rArg.idLength;
	}

	USR_SPACE_ACCESS_VALIDATE_ARG_K(presult   , sizeof(OEMCryptoResult));
    USR_SPACE_ACCESS_VALIDATE_ARG_K(pdlen , sizeof(UINT32));
    COPY_FROM_USER_ARG_K(pdlen            , *dlen, sizeof(UINT32));
    USR_SPACE_ACCESS_VALIDATE_ARG_K(pdeviceID , *dlen);

    CHECK_ALLOC(deviceID , *dlen , ret , final);

#ifdef CC_WIDEVINE_TZ_ENABLE
    CHECK_ALLOC(tzArg , sizeof(rArg) , ret , final);
    x_memcpy(tzArg,&rArg,sizeof(rArg));
    tzArg->result   = (OEMCryptoResult* )PHYSICAL((UPTR)result );
    tzArg->deviceID = (uint8_t *)PHYSICAL((UPTR)deviceID);
    tzArg->idLength = (UINT32  *)PHYSICAL((UPTR)dlen);

    invDataLen = *dlen;

    TZ_CACHE_STR(result , sizeof(OEMCryptoResult));
    TZ_CACHE_STR(deviceID, *dlen);
    TZ_CACHE_STR(dlen   , sizeof(UINT32));

    TZ_OEMCrypto_GetDeviceID(tzArg, sizeof(rArg));

    TZ_CACHE_END(result , sizeof(OEMCryptoResult));
    TZ_CACHE_END(dlen   , sizeof(UINT32));
    TZ_CACHE_END(deviceID, invDataLen);

#else
    *result =   OEMCrypto_GetDeviceID(deviceID, dlen);
#endif

    if(*result == OEMCrypto_SUCCESS)
    {
        COPY_TO_USER_ARG_K(pdeviceID , *deviceID, *dlen);
    }
    COPY_TO_USER_ARG_K(presult, *result, sizeof(OEMCryptoResult));
    COPY_TO_USER_ARG_K(pdlen , *dlen , sizeof(UINT32));

final:
#ifdef CC_WIDEVINE_TZ_ENABLE
    CHECK_FREE(tzArg);
#endif
	if(result!=NULL)
		MTDMX_PRINT("MTAL: %s exit, *result=%d \n",__FUNCTION__,*result);

    CHECK_FREE(result);
    CHECK_FREE(deviceID);
    CHECK_FREE(dlen);

    x_sema_unlock(_hWidevineSema);
    return ret;

}

MT_RESULT_T _MTDRM_WV_OEMCrypto_GetKeyData(unsigned long arg)
{
    MT_RESULT_T ret = MTR_OK;
	GetKeyDataArg_64BIT rArg    = {{0},{0},{0}};
    GetKeyDataArg_64BIT *tzArg  = NULL;
    OEMCryptoResult     *result=NULL, *presult = NULL;
    UINT32 *dlen=NULL, *pdlen = NULL;
    uint8_t *keyData=NULL, *pkeyData = NULL;

    UINT32 invDataLen;

	MTDMX_PRINT("MTAL: %s entry \n",__FUNCTION__);

    if (!u1Initialized)
    {
        x_sema_create(&_hWidevineSema, X_SEMA_TYPE_BINARY, X_SEMA_STATE_UNLOCK);
        u1Initialized = 1 ;
    }

    x_sema_lock(_hWidevineSema, X_SEMA_OPTION_WAIT) ;

    CHECK_ALLOC(result,sizeof(OEMCryptoResult),ret,final);
    *result = OEMCrypto_ERROR_UNKNOWN_FAILURE;

    CHECK_ALLOC(dlen,sizeof(UINT32),ret,final);

    USR_SPACE_ACCESS_VALIDATE_ARG_K(arg ,sizeof(GetKeyDataArg_64BIT));
    COPY_FROM_USER_ARG_K(arg, rArg , sizeof(GetKeyDataArg_64BIT));

#ifdef CONFIG_COMPAT
	if (is_compat_task())
	{
		presult = (OEMCryptoResult*)(compat_ptr(rArg.addr_r));
		pkeyData = (uint8_t*)(compat_ptr(rArg.addr_k));
		pdlen = (UINT32*)(compat_ptr(rArg.addr_kl));
	}
	else
#endif
	{
		presult = (OEMCryptoResult*)rArg.result;
		pkeyData = (uint8_t*)rArg.keyData;
		pdlen = (UINT32*)rArg.keyDataLength;
	}

    USR_SPACE_ACCESS_VALIDATE_ARG_K(presult, sizeof(OEMCryptoResult));
    USR_SPACE_ACCESS_VALIDATE_ARG_K(pdlen, sizeof(UINT32));
    COPY_FROM_USER_ARG_K(pdlen,*dlen , sizeof(UINT32));
    USR_SPACE_ACCESS_VALIDATE_ARG_K(pkeyData, *dlen );

    if(*dlen != 0 ){
        CHECK_ALLOC(keyData ,*dlen, ret, final);
    }

#ifdef CC_WIDEVINE_TZ_ENABLE
    CHECK_ALLOC(tzArg,sizeof(rArg),ret,final);
    x_memcpy(tzArg,&rArg,sizeof(rArg));
    tzArg->result     = (OEMCryptoResult* )PHYSICAL((UPTR)result );
    tzArg->keyData     = (uint8_t * )PHYSICAL((UPTR)keyData );
    tzArg->keyDataLength = (UINT32 *)PHYSICAL((UPTR)dlen);

    invDataLen = *dlen;

    TZ_CACHE_STR(result , sizeof(OEMCryptoResult));
    TZ_CACHE_STR(keyData , *dlen);
    TZ_CACHE_STR(dlen , sizeof(UINT32));

    TZ_OEMCrypto_GetKeyData(tzArg, sizeof(rArg));

    TZ_CACHE_END(result , sizeof(OEMCryptoResult));
    TZ_CACHE_END(dlen   , sizeof(UINT32));
    TZ_CACHE_END(keyData , invDataLen);
#else
    *result =   OEMCrypto_GetKeyData(keyData, dlen);
#endif

    if(*result == OEMCrypto_SUCCESS)
    {
        COPY_TO_USER_ARG_K(pkeyData       , *keyData , *dlen);
    }

    COPY_TO_USER_ARG_K(presult, *result, sizeof(OEMCryptoResult));
    COPY_TO_USER_ARG_K(pdlen, *dlen , sizeof(UINT32));

final:

#ifdef CC_WIDEVINE_TZ_ENABLE
    CHECK_FREE(tzArg);
#endif
	if(result!=NULL)
		MTDMX_PRINT("MTAL: %s exit, *result=%d \n",__FUNCTION__,*result);

    CHECK_FREE(result);
    CHECK_FREE(dlen);
    CHECK_FREE(keyData);

    x_sema_unlock(_hWidevineSema);

    return ret;
}

MT_RESULT_T _MTDRM_WV_OEMCrypto_GetRandom(unsigned long arg)
{
    MT_RESULT_T ret = MTR_OK;
    GetRandomArg_64BIT rArg   = {{0},{0},0};
	GetRandomArg_64BIT *tzArg = NULL;
    OEMCryptoResult *result=NULL, *presult   = NULL;
    uint8_t *randomData=NULL, *prandomData   = NULL;

	MTDMX_PRINT("MTAL: %s entry \n",__FUNCTION__);

    if (!u1Initialized)
    {
        x_sema_create(&_hWidevineSema, X_SEMA_TYPE_BINARY, X_SEMA_STATE_UNLOCK);
        u1Initialized = 1 ;
    }

    x_sema_lock(_hWidevineSema, X_SEMA_OPTION_WAIT) ;

    CHECK_ALLOC(result,sizeof(OEMCryptoResult),ret,final);
    *result = OEMCrypto_ERROR_UNKNOWN_FAILURE;

    USR_SPACE_ACCESS_VALIDATE_ARG_K(arg ,sizeof(GetRandomArg_64BIT));
    COPY_FROM_USER_ARG_K(arg, rArg , sizeof(GetRandomArg_64BIT));

#ifdef CONFIG_COMPAT
	if (is_compat_task())
	{
		presult = (OEMCryptoResult*)(compat_ptr(rArg.addr_r));
		prandomData = (uint8_t*)(compat_ptr(rArg.addr_rd));
	}
	else
#endif
	{
		presult = (OEMCryptoResult*)rArg.result;
		prandomData = (uint8_t*)rArg.randomData;
	}

    USR_SPACE_ACCESS_VALIDATE_ARG_K(presult, sizeof(OEMCryptoResult) );
    USR_SPACE_ACCESS_VALIDATE_ARG_K(prandomData , rArg.dataLength);

    CHECK_ALLOC(randomData ,rArg.dataLength, ret, final);

#ifdef CC_WIDEVINE_TZ_ENABLE
    CHECK_ALLOC(tzArg,sizeof(rArg),ret,final);
    x_memcpy(tzArg,&rArg,sizeof(rArg));
    tzArg->result     = (OEMCryptoResult* )PHYSICAL((UPTR)result);;
    tzArg->randomData = (uint8_t *)PHYSICAL((UPTR)randomData);

    TZ_CACHE_STR(result    , sizeof(OEMCryptoResult));
    TZ_CACHE_STR(randomData , rArg.dataLength);

    TZ_OEMCrypto_GetRandom(tzArg, sizeof(rArg));

    TZ_CACHE_END(result    , sizeof(OEMCryptoResult));
    TZ_CACHE_END(randomData , rArg.dataLength);
#else
    *result = OEMCrypto_GetRandom(randomData, rArg.dataLength);
#endif

    if(*result == OEMCrypto_SUCCESS)
    {
        COPY_TO_USER_ARG_K(prandomData,*randomData , rArg.dataLength);
    }

    COPY_TO_USER_ARG_K(presult, *result , sizeof(OEMCryptoResult));

final:
#ifdef CC_WIDEVINE_TZ_ENABLE
    CHECK_FREE(tzArg);
#endif
	if(result!=NULL)
		MTDMX_PRINT("MTAL: %s exit, *result=%d \n",__FUNCTION__,*result);

    CHECK_FREE(result);
    CHECK_FREE(randomData);

    x_sema_unlock(_hWidevineSema);

    return ret;

}

MT_RESULT_T _MTDRM_WV_OEMCrypto_WrapKeybox(unsigned long arg)
{
    MT_RESULT_T ret = MTR_OK;
    OEMCryptoResult *result=NULL, *presult = NULL;
    WrapKeyboxArg_64BIT rArg    = {{0},{0},0,{0},{0},{0},0};
	WrapKeyboxArg_64BIT *tzArg  = NULL;
    uint8_t *keybox=NULL, *pkeybox   = NULL;
    uint8_t *wrappedKeybox=NULL, *pwrappedKeybox     = NULL;
    uint8_t *transportKey=NULL, *ptransportKey       = NULL;
    UINT32 *wrappedKeyBoxLength=NULL, *pwrappedKeyBoxLength = NULL;
    UINT32 invDataLen;

	MTDMX_PRINT("MTAL: %s entry \n",__FUNCTION__);

    if (!u1Initialized)
    {
        x_sema_create(&_hWidevineSema, X_SEMA_TYPE_BINARY, X_SEMA_STATE_UNLOCK);
        u1Initialized = 1 ;
    }

    x_sema_lock(_hWidevineSema, X_SEMA_OPTION_WAIT) ;

    CHECK_ALLOC(result,sizeof(OEMCryptoResult),ret,final);
    *result = OEMCrypto_ERROR_UNKNOWN_FAILURE;

    USR_SPACE_ACCESS_VALIDATE_ARG_K(arg ,sizeof(WrapKeyboxArg_64BIT));
    COPY_FROM_USER_ARG_K(arg, rArg , sizeof(WrapKeyboxArg_64BIT));

#ifdef CONFIG_COMPAT
	if (is_compat_task())
	{
		presult = (OEMCryptoResult*)(compat_ptr(rArg.addr_r));
		pkeybox = (uint8_t*)(compat_ptr(rArg.addr_k));
		pwrappedKeybox = (uint8_t*)(compat_ptr(rArg.addr_w));
		ptransportKey = (uint8_t*)(compat_ptr(rArg.addr_tk));
		pwrappedKeyBoxLength = (UINT32*)(compat_ptr(rArg.addr_wl));
	}
	else
#endif
	{
		presult = (OEMCryptoResult*)rArg.result;
		pkeybox = (uint8_t*)rArg.keybox;
		pwrappedKeybox = (uint8_t*)rArg.wrappedKeybox;
		ptransportKey = (uint8_t*)rArg.transportKey;
		pwrappedKeyBoxLength = (UINT32*)rArg.wrappedKeyBoxLength;
	}

    USR_SPACE_ACCESS_VALIDATE_ARG_K(presult              , sizeof(int));

    USR_SPACE_ACCESS_VALIDATE_ARG_K(pwrappedKeyBoxLength , sizeof(UINT32));
    CHECK_ALLOC(wrappedKeyBoxLength,sizeof(UINT32),ret,final);
    COPY_FROM_USER_ARG_K(pwrappedKeyBoxLength,*wrappedKeyBoxLength, sizeof(UINT32));

    USR_SPACE_ACCESS_VALIDATE_ARG_K(pwrappedKeybox , *wrappedKeyBoxLength);
    CHECK_ALLOC(wrappedKeybox ,*wrappedKeyBoxLength, ret, final);

    USR_SPACE_ACCESS_VALIDATE_ARG_K(pkeybox        , rArg.keyBoxLength);
    CHECK_ALLOC(keybox ,rArg.keyBoxLength, ret, final);
    COPY_FROM_USER_ARG_K(pkeybox , *keybox , rArg.keyBoxLength);

    USR_SPACE_ACCESS_VALIDATE_ARG_K(ptransportKey  , rArg.transportKeyLength);
    CHECK_ALLOC(transportKey ,rArg.transportKeyLength, ret, final);
    COPY_FROM_USER_ARG_K(ptransportKey , *transportKey , rArg.transportKeyLength);

#ifdef CC_WIDEVINE_TZ_ENABLE
    CHECK_ALLOC(tzArg,sizeof(rArg),ret,final);
    x_memcpy(tzArg,&rArg,sizeof(rArg));
    tzArg->result              = (OEMCryptoResult* )PHYSICAL((UPTR)result );
    tzArg->keybox              = (uint8_t *)PHYSICAL((UPTR)keybox);
    tzArg->wrappedKeybox       = (uint8_t *)PHYSICAL((UPTR)wrappedKeybox);
    tzArg->wrappedKeyBoxLength = (UINT32 *)PHYSICAL((UPTR)wrappedKeyBoxLength);
    tzArg->transportKey        = (uint8_t *)PHYSICAL((UPTR)transportKey);

    invDataLen = *wrappedKeyBoxLength;

    TZ_CACHE_STR(transportKey        , rArg.transportKeyLength);
    TZ_CACHE_STR(keybox              , rArg.keyBoxLength);
    TZ_CACHE_STR(wrappedKeyBoxLength , sizeof(UINT32));
    TZ_CACHE_STR(result              , sizeof(OEMCryptoResult));
    TZ_CACHE_STR(wrappedKeybox       , *wrappedKeyBoxLength);

    TZ_OEMCrypto_WrapKeybox(tzArg, sizeof(rArg));

    TZ_CACHE_END(transportKey        , rArg.transportKeyLength);
    TZ_CACHE_END(keybox              , rArg.keyBoxLength);
    TZ_CACHE_END(wrappedKeyBoxLength , sizeof(UINT32));
    TZ_CACHE_END(result              , sizeof(OEMCryptoResult));
    TZ_CACHE_END(wrappedKeybox       , invDataLen);
#else
    *result =   OEMCrypto_WrapKeybox(keybox, rArg.keyBoxLength,
            wrappedKeybox,wrappedKeyBoxLength,
            transportKey,rArg.transportKeyLength);
#endif

    COPY_TO_USER_ARG_K(presult, *result, sizeof(OEMCryptoResult));
    COPY_TO_USER_ARG_K(pwrappedKeyBoxLength ,*wrappedKeyBoxLength , sizeof(UINT32));

    if(*result == OEMCrypto_SUCCESS)
    {
        COPY_TO_USER_ARG_K(pwrappedKeybox , *wrappedKeybox , *wrappedKeyBoxLength);
    }

final:

#ifdef CC_WIDEVINE_TZ_ENABLE
    CHECK_FREE(tzArg);
#endif
	if(result!=NULL)
		MTDMX_PRINT("MTAL: %s exit, *result=%d \n",__FUNCTION__,*result);

    CHECK_FREE(result);
    CHECK_FREE(wrappedKeyBoxLength);
    CHECK_FREE(keybox);
    CHECK_FREE(wrappedKeybox);
    CHECK_FREE(transportKey);

    x_sema_unlock(_hWidevineSema);

    return ret;
}

MT_RESULT_T _MTDRM_WV_OEMCrypto_RewrapDeviceRSAKey(unsigned long arg)
{
    MT_RESULT_T ret = MTR_OK;
	RewrapDeviceRSAKeyArg_64BIT rArg   = {{0},0,{0},0,{0},0,{0},{0},0,{0},{0},{0}};
    RewrapDeviceRSAKeyArg_64BIT *tzArg = NULL;
    OEMCryptoResult *result=NULL, *presult            = NULL;
    uint8_t *message=NULL, *pmessage                  = NULL;
    uint8_t *signature=NULL, *psignature              = NULL;
    uint32_t *nonce=NULL, *pnonce                     = NULL;
    uint8_t *enc_rsa_key=NULL, *penc_rsa_key          = NULL;
    uint8_t *enc_rsa_key_iv=NULL, *penc_rsa_key_iv    = NULL;
    uint8_t *wrapped_rsa_key=NULL, *pwrapped_rsa_key  = NULL;
    UINT32 *wrapped_rsa_key_length=NULL, *pwrapped_rsa_key_length = NULL;
    UINT32 buffer_size;
    UINT32 invDataLen;

	MTDMX_PRINT("MTAL: %s entry \n",__FUNCTION__);

    if (!u1Initialized)
    {
        x_sema_create(&_hWidevineSema, X_SEMA_TYPE_BINARY, X_SEMA_STATE_UNLOCK);
        u1Initialized = 1 ;
    }

    x_sema_lock(_hWidevineSema, X_SEMA_OPTION_WAIT) ;
    CHECK_ALLOC(result,sizeof(OEMCryptoResult),ret,final);
    *result = OEMCrypto_ERROR_UNKNOWN_FAILURE;

    CHECK_ALLOC(wrapped_rsa_key_length,sizeof(UINT32),ret,final);

    USR_SPACE_ACCESS_VALIDATE_ARG_K(arg ,sizeof(RewrapDeviceRSAKeyArg_64BIT));
    COPY_FROM_USER_ARG_K(arg, rArg , sizeof(RewrapDeviceRSAKeyArg_64BIT));

#ifdef CONFIG_COMPAT
	if (is_compat_task())
	{
		presult = (OEMCryptoResult*)(compat_ptr(rArg.addr_r));
		pmessage = (uint8_t*)(compat_ptr(rArg.addr_m));
		psignature = (uint8_t*)(compat_ptr(rArg.addr_s));
		pnonce = (uint32_t*)(compat_ptr(rArg.addr_n));
		penc_rsa_key = (uint8_t*)(compat_ptr(rArg.addr_ek));
		penc_rsa_key_iv = (uint8_t*)(compat_ptr(rArg.addr_eki));
		pwrapped_rsa_key = (uint8_t*)(compat_ptr(rArg.addr_w));
		pwrapped_rsa_key_length = (uint32_t*)(compat_ptr(rArg.addr_wl));
	}
	else
#endif
	{
		presult = (OEMCryptoResult*)rArg.result;
		pmessage = (uint8_t*)rArg.message;
		psignature = (uint8_t*)rArg.signature;
		pnonce = (uint32_t*)rArg.nonce;
		penc_rsa_key = (uint8_t*)rArg.enc_rsa_key;
		penc_rsa_key_iv = (uint8_t*)rArg.enc_rsa_key_iv;
		pwrapped_rsa_key = (uint8_t*)rArg.wrapped_rsa_key;
		pwrapped_rsa_key_length = (uint32_t*)rArg.wrapped_rsa_key_length;
	}

    USR_SPACE_ACCESS_VALIDATE_ARG_K(presult , sizeof(OEMCryptoResult));
    USR_SPACE_ACCESS_VALIDATE_ARG_K(pwrapped_rsa_key_length, sizeof(UINT32));
    COPY_FROM_USER_ARG_K(pwrapped_rsa_key_length , *wrapped_rsa_key_length , sizeof(UINT32));

    buffer_size = rArg.enc_rsa_key_length + sizeof(WrappedRSAKey);

    if (pwrapped_rsa_key == NULL || *wrapped_rsa_key_length < buffer_size) {
		MTDMX_PRINT("_MTDRM_WV_OEMCrypto_RewrapDeviceRSAKey  OEMCrypto_ERROR_SHORT_BUFFER \n");
        *wrapped_rsa_key_length = buffer_size;
        *result = OEMCrypto_ERROR_SHORT_BUFFER;
        goto result;
    }

    if (pmessage == NULL || rArg.message_length == 0 || psignature == NULL
            || rArg.signature_length == 0 || pnonce == NULL || penc_rsa_key == NULL) {
        MTDMX_PRINT("_MTDRM_WV_OEMCrypto_RewrapDeviceRSAKey  OEMCrypto_ERROR_INVALID_CONTEXT \n");
        *result = OEMCrypto_ERROR_INVALID_CONTEXT;
        goto result;
    }

    // Range check
    if (!RangeCheck(pmessage, rArg.message_length, (const uint8_t*)(pnonce),sizeof(uint32_t), true)
            || !RangeCheck(pmessage, rArg.message_length, penc_rsa_key, rArg.enc_rsa_key_length,true)
            || !RangeCheck(pmessage, rArg.message_length, penc_rsa_key_iv, 16 ,true)) {
        MTDMX_PRINT("_MTDRM_WV_OEMCrypto_RewrapDeviceRSAKey  RangeCheck fail \n");
        *result = OEMCrypto_ERROR_INVALID_CONTEXT;
        goto result;
    }

    USR_SPACE_ACCESS_VALIDATE_ARG_K(pmessage, rArg.message_length);
    USR_SPACE_ACCESS_VALIDATE_ARG_K(psignature, rArg.signature_length);
    USR_SPACE_ACCESS_VALIDATE_ARG_K(pwrapped_rsa_key, *wrapped_rsa_key_length);

    CHECK_ALLOC(message ,rArg.message_length, ret, final);
    COPY_FROM_USER_ARG_K(pmessage , *message , rArg.message_length);

    CHECK_ALLOC(signature ,rArg.signature_length, ret, final);
    COPY_FROM_USER_ARG_K(psignature , *signature , rArg.signature_length);

    CHECK_ALLOC(wrapped_rsa_key ,*wrapped_rsa_key_length, ret, final);

    nonce          = (uint32_t *)((const uint8_t *)pnonce - pmessage + message);
    enc_rsa_key    = (uint8_t *)(penc_rsa_key    - pmessage + message);
    enc_rsa_key_iv = (uint8_t *)(penc_rsa_key_iv - pmessage + message);

#ifdef CC_WIDEVINE_TZ_ENABLE
    CHECK_ALLOC(tzArg,sizeof(rArg),ret,final);
    x_memcpy(tzArg,&rArg,sizeof(rArg));
    tzArg->result                 = (OEMCryptoResult* )PHYSICAL((UPTR)result );
    tzArg->message                = (uint8_t *)PHYSICAL((UPTR)message);
    tzArg->signature              = (uint8_t *)PHYSICAL((UPTR)signature);
    tzArg->nonce                  = (uint32_t*)PHYSICAL((UPTR)nonce);
    tzArg->enc_rsa_key            = (uint8_t *)PHYSICAL((UPTR)enc_rsa_key);
    tzArg->enc_rsa_key_iv         = (uint8_t *)PHYSICAL((UPTR)enc_rsa_key_iv);
    tzArg->wrapped_rsa_key        = (uint8_t *)PHYSICAL((UPTR)wrapped_rsa_key);
    tzArg->wrapped_rsa_key_length = (UINT32 *)PHYSICAL((UPTR)wrapped_rsa_key_length);


    invDataLen = *wrapped_rsa_key_length;
    TZ_CACHE_STR(message   , rArg.message_length);
    TZ_CACHE_STR(signature , rArg.signature_length);
    TZ_CACHE_STR(result                , sizeof(OEMCryptoResult));
    TZ_CACHE_STR(wrapped_rsa_key_length , sizeof(UINT32));
    TZ_CACHE_STR(wrapped_rsa_key        , *wrapped_rsa_key_length);

    TZ_OEMCrypto_RewrapDeviceRSAKey(tzArg, sizeof(rArg));

    TZ_CACHE_END(message   , rArg.message_length);
    TZ_CACHE_END(signature , rArg.signature_length);
    TZ_CACHE_END(result                , sizeof(OEMCryptoResult));
    TZ_CACHE_END(wrapped_rsa_key_length , sizeof(UINT32));
    TZ_CACHE_END(wrapped_rsa_key        , invDataLen);
#else
    *result =   OEMCrypto_RewrapDeviceRSAKey(rArg.session, message, rArg.message_length,
            signature,rArg.signature_length,
            nonce, enc_rsa_key, rArg.enc_rsa_key_length,
            enc_rsa_key_iv, wrapped_rsa_key, wrapped_rsa_key_length);
#endif

    if(*result == OEMCrypto_SUCCESS)
    {
        COPY_TO_USER_ARG_K(pwrapped_rsa_key , *wrapped_rsa_key ,*wrapped_rsa_key_length);
    }
result:

    COPY_TO_USER_ARG_K(pwrapped_rsa_key_length , *wrapped_rsa_key_length, sizeof(UINT32));
    COPY_TO_USER_ARG_K(presult, *result, sizeof(OEMCryptoResult));

final:

#ifdef CC_WIDEVINE_TZ_ENABLE
    CHECK_FREE(tzArg);
#endif
	if(result!=NULL)
		MTDMX_PRINT("MTAL: %s exit, *result=%d \n",__FUNCTION__,*result);

    CHECK_FREE(result);
    CHECK_FREE(wrapped_rsa_key_length);
    CHECK_FREE(message);
    CHECK_FREE(signature);
    CHECK_FREE(wrapped_rsa_key);

    x_sema_unlock(_hWidevineSema);

    return ret;
}

MT_RESULT_T _MTDRM_WV_OEMCrypto_LoadDeviceRSAKey(unsigned long arg)
{
    MT_RESULT_T ret = MTR_OK;
    LoadDeviceRSAKeyArg_64BIT rArg   = {{0},0,{0},0};
	LoadDeviceRSAKeyArg_64BIT *tzArg = NULL;
    OEMCryptoResult *result=NULL, *presult = NULL;
    uint8_t *wrapped_rsa_key=NULL, *pwrapped_rsa_key = NULL;

	MTDMX_PRINT("MTAL: %s entry \n",__FUNCTION__);

    if (!u1Initialized)
    {
        x_sema_create(&_hWidevineSema, X_SEMA_TYPE_BINARY, X_SEMA_STATE_UNLOCK);
        u1Initialized = 1 ;
    }

    x_sema_lock(_hWidevineSema, X_SEMA_OPTION_WAIT) ;
    CHECK_ALLOC(result,sizeof(OEMCryptoResult),ret,final);
    *result = OEMCrypto_ERROR_UNKNOWN_FAILURE;
    USR_SPACE_ACCESS_VALIDATE_ARG_K(arg,sizeof(LoadDeviceRSAKeyArg_64BIT));
    COPY_FROM_USER_ARG_K(arg, rArg, sizeof(LoadDeviceRSAKeyArg_64BIT));

#ifdef CONFIG_COMPAT
	if (is_compat_task())
	{
		presult = (OEMCryptoResult*)(compat_ptr(rArg.addr_r));
		pwrapped_rsa_key = (uint8_t*)(compat_ptr(rArg.addr_w));
	}
	else
#endif
	{
		presult = (OEMCryptoResult*)rArg.result;
		pwrapped_rsa_key = (uint8_t*)rArg.wrapped_rsa_key;
	}

    USR_SPACE_ACCESS_VALIDATE_ARG_K(presult , sizeof(OEMCryptoResult));
    USR_SPACE_ACCESS_VALIDATE_ARG_K(pwrapped_rsa_key , rArg.wrapped_rsa_key_length);

    CHECK_ALLOC(wrapped_rsa_key ,rArg.wrapped_rsa_key_length, ret, final);
    COPY_FROM_USER_ARG_K(pwrapped_rsa_key, *wrapped_rsa_key , rArg.wrapped_rsa_key_length);

#ifdef CC_WIDEVINE_TZ_ENABLE
    CHECK_ALLOC(tzArg,sizeof(rArg),ret,final);
    x_memcpy(tzArg,&rArg,sizeof(rArg));
    tzArg->result           = (OEMCryptoResult* )PHYSICAL((UPTR)result );
    tzArg->wrapped_rsa_key = (uint8_t *)PHYSICAL((UPTR)wrapped_rsa_key);

    TZ_CACHE_STR(result , sizeof(OEMCryptoResult));
    TZ_CACHE_STR(wrapped_rsa_key , rArg.wrapped_rsa_key_length);

    TZ_OEMCrypto_LoadDeviceRSAKey(tzArg, sizeof(rArg));

    TZ_CACHE_END(result , sizeof(OEMCryptoResult));
    TZ_CACHE_END(wrapped_rsa_key , rArg.wrapped_rsa_key_length);
#else
    *result =  OEMCrypto_LoadDeviceRSAKey(rArg.session, wrapped_rsa_key,rArg.wrapped_rsa_key_length);
#endif
    COPY_TO_USER_ARG_K(presult, *result, sizeof(OEMCryptoResult));

final:
#ifdef CC_WIDEVINE_TZ_ENABLE
    CHECK_FREE(tzArg);
#endif
	if(result!=NULL)
		MTDMX_PRINT("MTAL: %s exit, *result=%d \n",__FUNCTION__,*result);

    CHECK_FREE(result);
    CHECK_FREE(wrapped_rsa_key);

    x_sema_unlock(_hWidevineSema);

    return ret;
}

MT_RESULT_T _MTDRM_WV_OEMCrypto_GenerateRSASignature(unsigned long arg)
{
    MT_RESULT_T ret = MTR_OK;
    OEMCryptoResult *result=NULL, *presult           = NULL;
    GenerateRSASignatureArg_64BIT rArg = {{0},0,{0},0,{0},{0},0};
	GenerateRSASignatureArg_64BIT *tzArg = NULL;
	uint8_t *pmessage = NULL;
	uint8_t *psignature = NULL;
    UINT32 *signature_length=NULL, *psignature_length = NULL;
    UINT32 invDataLen;

	MTDMX_PRINT("MTAL: %s entry \n",__FUNCTION__);

    if (!u1Initialized)
    {
        x_sema_create(&_hWidevineSema, X_SEMA_TYPE_BINARY, X_SEMA_STATE_UNLOCK);
        u1Initialized = 1 ;
    }

    x_sema_lock(_hWidevineSema, X_SEMA_OPTION_WAIT) ;

    CHECK_ALLOC(result,sizeof(OEMCryptoResult),ret,final);
    *result = OEMCrypto_ERROR_UNKNOWN_FAILURE;

    CHECK_ALLOC(signature_length,sizeof(UINT32),ret,final);

    USR_SPACE_ACCESS_VALIDATE_ARG_K(arg , sizeof(GenerateRSASignatureArg_64BIT));
    COPY_FROM_USER_ARG_K(arg, rArg, sizeof(GenerateRSASignatureArg_64BIT));

#ifdef CONFIG_COMPAT
	if (is_compat_task())
	{
		presult = (OEMCryptoResult*)(compat_ptr(rArg.addr_r));
		pmessage = (uint8_t*)(compat_ptr(rArg.addr_m));
		psignature = (uint8_t*)(compat_ptr(rArg.addr_s));
		psignature_length = (UINT32*)(compat_ptr(rArg.addr_sl));
	}
	else
#endif
	{
		presult = (OEMCryptoResult*)rArg.result;
		pmessage = (uint8_t*)rArg.message;
		psignature = (uint8_t*)rArg.signature;
		psignature_length = (UINT32*)rArg.signature_length;
	}

    USR_SPACE_ACCESS_VALIDATE_ARG_K(presult, sizeof(OEMCryptoResult));
    USR_SPACE_ACCESS_VALIDATE_ARG_K(psignature_length, sizeof(UINT32));
    COPY_FROM_USER_ARG_K(psignature_length , *signature_length , sizeof(UINT32));

    if (*signature_length < 2048/8) {
        *signature_length = 2048/8;
        *result = OEMCrypto_ERROR_SHORT_BUFFER;
        goto result;
    }

    if (pmessage == NULL || rArg.message_length == 0 || psignature == NULL ) {
        *result =  OEMCrypto_ERROR_INVALID_CONTEXT;
        goto result;
    }

    USR_SPACE_ACCESS_VALIDATE_ARG_K(pmessage, rArg.message_length);
    USR_SPACE_ACCESS_VALIDATE_ARG_K(psignature, *signature_length);

    if(*signature_length > MAX_BSP_ALLOC_SIZE)
        goto final;
    if(output_data_addr ==NULL)
        goto final;

    if(input_data_addr ==NULL)
        goto final;
    if(rArg.message_length > MAX_BSP_ALLOC_SIZE)
        goto final;
    COPY_FROM_USER_ARG_K(pmessage , *input_data_addr , rArg.message_length);

    CHECK_ALLOC(tzArg,sizeof(rArg),ret,final);
    x_memcpy(tzArg,&rArg,sizeof(rArg));
    tzArg->result           = (OEMCryptoResult* )PHYSICAL((UPTR)result );
    tzArg->message          = (uint8_t *)PHYSICAL((UPTR)input_data_addr);
    tzArg->signature        = (uint8_t *)PHYSICAL((UPTR)output_data_addr);
    tzArg->signature_length = (UINT32  *)PHYSICAL((UPTR)signature_length);

    invDataLen = *signature_length;

    TZ_CACHE_STR(result           , sizeof(OEMCryptoResult));
    TZ_CACHE_STR(input_data_addr          , rArg.message_length);
    TZ_CACHE_STR(signature_length , sizeof(UINT32));
    TZ_CACHE_STR(output_data_addr        , *signature_length);
    TZ_OEMCrypto_GenerateRSASignature(tzArg , sizeof(rArg));
    TZ_CACHE_END(result           , sizeof(OEMCryptoResult));
    TZ_CACHE_END(input_data_addr          , rArg.message_length);
    TZ_CACHE_END(signature_length , sizeof(UINT32));
    TZ_CACHE_END(output_data_addr        , invDataLen);

    if(*result == OEMCrypto_SUCCESS)
    {
        COPY_TO_USER_ARG_K(psignature , *output_data_addr , *signature_length);
    }
result:
    COPY_TO_USER_ARG_K(psignature_length , *signature_length , sizeof(UINT32));
    COPY_TO_USER_ARG_K(presult, *result, sizeof(OEMCryptoResult));

final:

#ifdef CC_WIDEVINE_TZ_ENABLE
    CHECK_FREE(tzArg);
#endif
	if(result!=NULL)
		MTDMX_PRINT("MTAL: %s exit, *result=%d \n",__FUNCTION__,*result);

    CHECK_FREE(result);
    CHECK_FREE(signature_length);
    x_sema_unlock(_hWidevineSema);

    return ret;
}

MT_RESULT_T _MTDRM_WV_OEMCrypto_DeriveKeysFromSessionKey(unsigned long arg)
{
    MT_RESULT_T ret = MTR_OK;
    OEMCryptoResult *result=NULL, *presult        = NULL;
    DeriveKeysFromSessionKeyArg_64BIT rArg   = {{0},0,{0},0,{0},0,{0},0};
	DeriveKeysFromSessionKeyArg_64BIT *tzArg = NULL;
    uint8_t *enc_session_key=NULL, *penc_session_key    = NULL;
    uint8_t *mac_key_context=NULL, *pmac_key_context    = NULL;
    uint8_t *enc_key_context=NULL, *penc_key_context    = NULL;

	MTDMX_PRINT("MTAL: %s entry \n",__FUNCTION__);

    if (!u1Initialized)
    {
        x_sema_create(&_hWidevineSema, X_SEMA_TYPE_BINARY, X_SEMA_STATE_UNLOCK);
        u1Initialized = 1 ;
    }

    x_sema_lock(_hWidevineSema, X_SEMA_OPTION_WAIT) ;

    CHECK_ALLOC(result,sizeof(OEMCryptoResult),ret,final);
    *result = OEMCrypto_ERROR_UNKNOWN_FAILURE;

    USR_SPACE_ACCESS_VALIDATE_ARG_K(arg,sizeof(DeriveKeysFromSessionKeyArg_64BIT));
    COPY_FROM_USER_ARG_K(arg,rArg, sizeof(DeriveKeysFromSessionKeyArg_64BIT));

#ifdef CONFIG_COMPAT
	if (is_compat_task())
	{
		presult = (OEMCryptoResult*)(compat_ptr(rArg.addr_r));
		penc_session_key = (uint8_t*)(compat_ptr(rArg.addr_esk));
		pmac_key_context = (uint8_t*)(compat_ptr(rArg.addr_mkc));
		penc_key_context = (uint8_t*)(compat_ptr(rArg.addr_ekc));
	}
	else
#endif
	{
		presult = (OEMCryptoResult*)rArg.result;
		penc_session_key = (uint8_t*)rArg.enc_session_key;
		pmac_key_context = (uint8_t*)rArg.mac_key_context;
		penc_key_context = (uint8_t*)rArg.enc_key_context;
	}

    USR_SPACE_ACCESS_VALIDATE_ARG_K(presult , sizeof(OEMCryptoResult));
    USR_SPACE_ACCESS_VALIDATE_ARG_K(penc_session_key , rArg.enc_session_key_length);
    USR_SPACE_ACCESS_VALIDATE_ARG_K(penc_key_context , rArg.enc_key_context_length);
    USR_SPACE_ACCESS_VALIDATE_ARG_K(pmac_key_context , rArg.mac_key_context_length);

    CHECK_ALLOC(enc_session_key ,rArg.enc_session_key_length, ret, final);
    COPY_FROM_USER_ARG_K(penc_session_key, *enc_session_key , rArg.enc_session_key_length);

    CHECK_ALLOC(enc_key_context ,rArg.enc_key_context_length, ret, final);
    COPY_FROM_USER_ARG_K(penc_key_context, *enc_key_context , rArg.enc_key_context_length);

    CHECK_ALLOC(mac_key_context ,rArg.mac_key_context_length ,ret, final);
    COPY_FROM_USER_ARG_K(pmac_key_context, *mac_key_context , rArg.mac_key_context_length);

#ifdef CC_WIDEVINE_TZ_ENABLE
    CHECK_ALLOC(tzArg,sizeof(rArg),ret,final);
    x_memcpy(tzArg,&rArg,sizeof(rArg));
    tzArg->result          = (OEMCryptoResult* )PHYSICAL((UPTR)result );
    tzArg->enc_session_key = (uint8_t *)PHYSICAL((UPTR)enc_session_key);
    tzArg->mac_key_context = (uint8_t *)PHYSICAL((UPTR)mac_key_context);
    tzArg->enc_key_context = (uint8_t *)PHYSICAL((UPTR)enc_key_context);

    TZ_CACHE_STR(enc_session_key , rArg.enc_session_key_length);
    TZ_CACHE_STR(mac_key_context , rArg.mac_key_context_length);
    TZ_CACHE_STR(enc_key_context , rArg.enc_key_context_length);
    TZ_CACHE_STR(result , sizeof(OEMCryptoResult));

    TZ_OEMCrypto_DeriveKeysFromSessionKey(tzArg, sizeof(rArg));

    TZ_CACHE_END(enc_session_key , rArg.enc_session_key_length);
    TZ_CACHE_END(mac_key_context , rArg.mac_key_context_length);
    TZ_CACHE_END(enc_key_context , rArg.enc_key_context_length);
    TZ_CACHE_END(result , sizeof(OEMCryptoResult));

#else
    *result =  OEMCrypto_DeriveKeysFromSessionKey(rArg.session,
            enc_session_key,
            rArg.enc_session_key_length,
            mac_key_context,
            rArg.mac_key_context_length,
            enc_key_context,
            rArg.enc_key_context_length);
#endif

    COPY_TO_USER_ARG_K(presult, *result, sizeof(OEMCryptoResult));

final:

#ifdef CC_WIDEVINE_TZ_ENABLE
    CHECK_FREE(tzArg);
#endif
	if(result!=NULL)
		MTDMX_PRINT("MTAL: %s exit, *result=%d \n",__FUNCTION__,*result);

    CHECK_FREE(result);
    CHECK_FREE(enc_session_key);
    CHECK_FREE(enc_key_context);
    CHECK_FREE(mac_key_context);

    x_sema_unlock(_hWidevineSema);
    return ret;
}

MT_RESULT_T _MTDRM_WV_OEMCrypto_Generic_Encrypt(unsigned long arg)
{
    MT_RESULT_T ret = MTR_OK;
	GenericEncryptArg_64BIT rArg   = {{0},0,{0},0,{0},0,{0}};
    GenericEncryptArg_64BIT *tzArg = NULL;
    OEMCryptoResult *result=NULL, *presult = NULL;
    uint8_t *iv=NULL, *piv                 = NULL;
	uint8_t *pin_buffer=NULL, *pout_buffer = NULL;
	size_t remain_length=0;
	const uint8_t *data_addr_cur;
	size_t cpy_length;
	size_t cpy_ofst=0;

	//MTDMX_PRINT("MTAL: %s entry \n",__FUNCTION__);

    if (!u1Initialized)
    {
        x_sema_create(&_hWidevineSema, X_SEMA_TYPE_BINARY, X_SEMA_STATE_UNLOCK);
        u1Initialized = 1 ;
    }

    x_sema_lock(_hWidevineSema, X_SEMA_OPTION_WAIT) ;

    CHECK_ALLOC(result,sizeof(OEMCryptoResult),ret,final);
    *result = OEMCrypto_ERROR_UNKNOWN_FAILURE;

    USR_SPACE_ACCESS_VALIDATE_ARG_K(arg, sizeof(GenericEncryptArg_64BIT));
    COPY_FROM_USER_ARG_K(arg , rArg,sizeof(GenericEncryptArg_64BIT));

#ifdef CONFIG_COMPAT
	if (is_compat_task())
	{
		presult = (OEMCryptoResult*)(compat_ptr(rArg.addr_r));
		pin_buffer = (uint8_t*)(compat_ptr(rArg.addr_i));
		piv = (uint8_t*)(compat_ptr(rArg.addr_iv));
		pout_buffer = (uint8_t*)(compat_ptr(rArg.addr_o));
	}
	else
#endif
	{
		presult = (OEMCryptoResult*)rArg.result;
		pin_buffer = (uint8_t*)rArg.in_buffer;
		piv = (uint8_t*)rArg.iv;
		pout_buffer = (uint8_t*)rArg.out_buffer;
	}

    if (pin_buffer == NULL || rArg.buffer_length == 0 ||
            piv == NULL || pout_buffer == NULL) {
        *result = OEMCrypto_ERROR_INVALID_CONTEXT;
        goto result;
    }

    USR_SPACE_ACCESS_VALIDATE_ARG_K(presult , sizeof(OEMCryptoResult));
    USR_SPACE_ACCESS_VALIDATE_ARG_K(pin_buffer , rArg.buffer_length);
    USR_SPACE_ACCESS_VALIDATE_ARG_K(piv , KEY_IV_SIZE);
    USR_SPACE_ACCESS_VALIDATE_ARG_K(pout_buffer , rArg.buffer_length);

	remain_length = rArg.buffer_length;
	data_addr_cur = pin_buffer;

    CHECK_ALLOC(iv,KEY_IV_SIZE, ret, final);
    COPY_FROM_USER_ARG_K(piv , *iv , KEY_IV_SIZE);

	if(input_data_addr==NULL || output_data_addr==NULL)
		goto result;

    CHECK_ALLOC(tzArg,sizeof(rArg),ret,final);
    x_memcpy(tzArg,&rArg,sizeof(rArg));
    tzArg->result     = (OEMCryptoResult* )PHYSICAL((UPTR)result );
    tzArg->in_buffer  = (uint8_t *)PHYSICAL((UPTR)input_data_addr);
    tzArg->iv         = (uint8_t *)PHYSICAL((UPTR)iv);
    tzArg->out_buffer = (uint8_t *)PHYSICAL((UPTR)output_data_addr);

	while(remain_length !=0)
	{
		if(remain_length > MAX_BSP_ALLOC_SIZE)  //MAX_BSP_ALLOC_SIZE_GEN //only for UT test Generic_Decrypt/Generic_Encrypt
		{
			cpy_length = MAX_BSP_ALLOC_SIZE;
		}else
		{
			cpy_length = remain_length ;
		}

		COPY_FROM_USER_ARG_K(data_addr_cur, *input_data_addr , cpy_length);

		remain_length -= cpy_length;
		data_addr_cur += cpy_length;

		tzArg->buffer_length	= cpy_length;

	    TZ_CACHE_STR(input_data_addr , cpy_length);
	    TZ_CACHE_STR(iv        , KEY_IV_SIZE);
	    TZ_CACHE_STR(result    , sizeof(OEMCryptoResult));
	    TZ_CACHE_STR(output_data_addr, cpy_length);

	    TZ_OEMCrypto_Generic_Encrypt(tzArg, sizeof(rArg));

	    TZ_CACHE_END(input_data_addr , cpy_length);
	    TZ_CACHE_END(iv        , KEY_IV_SIZE);
	    TZ_CACHE_END(result    , sizeof(OEMCryptoResult));
	    TZ_CACHE_END(output_data_addr, cpy_length);

	    if(*result == OEMCrypto_SUCCESS)
	    {
			COPY_TO_USER_ARG_K(pout_buffer+cpy_ofst , *output_data_addr , cpy_length);
			cpy_ofst += cpy_length;
	    }

            if (cpy_length >= KEY_IV_SIZE)
		x_memcpy(iv, output_data_addr+cpy_length-KEY_IV_SIZE, KEY_IV_SIZE);
	}

result:
    COPY_TO_USER_ARG_K(presult, *result, sizeof(OEMCryptoResult));

final:

#ifdef CC_WIDEVINE_TZ_ENABLE
    CHECK_FREE(tzArg);
#endif
	//if(result!=NULL)
	//	MTDMX_PRINT("MTAL: %s exit, *result=%d \n",__FUNCTION__,*result);

    CHECK_FREE(result);
    CHECK_FREE(iv);

    x_sema_unlock(_hWidevineSema);

    return ret;
}

MT_RESULT_T _MTDRM_WV_OEMCrypto_Generic_Decrypt(unsigned long arg)
{
    MT_RESULT_T ret = MTR_OK;
	GenericDecryptArg_64BIT rArg   = {{0},0,{0},0,{0},0,{0}};
    GenericDecryptArg_64BIT *tzArg = NULL;
    OEMCryptoResult *result=NULL, *presult        = NULL;
    uint8_t *iv=NULL, *piv                     = NULL;
	uint8_t *pin_buffer=NULL, *pout_buffer = NULL;
	size_t remain_length=0;
	const uint8_t *data_addr_cur;
	size_t cpy_length;
	size_t cpy_ofst=0;

	//MTDMX_PRINT("MTAL: %s entry \n",__FUNCTION__);

    if (!u1Initialized)
    {
        x_sema_create(&_hWidevineSema, X_SEMA_TYPE_BINARY, X_SEMA_STATE_UNLOCK);
        u1Initialized = 1 ;
    }

    x_sema_lock(_hWidevineSema, X_SEMA_OPTION_WAIT) ;

    CHECK_ALLOC(result,sizeof(OEMCryptoResult),ret,final);
    *result = OEMCrypto_ERROR_UNKNOWN_FAILURE;

    USR_SPACE_ACCESS_VALIDATE_ARG_K(arg, sizeof(GenericDecryptArg_64BIT));
    COPY_FROM_USER_ARG_K(arg , rArg,sizeof(GenericDecryptArg_64BIT));

#ifdef CONFIG_COMPAT
	if (is_compat_task())
	{
		presult = (OEMCryptoResult*)(compat_ptr(rArg.addr_r));
		pin_buffer = (uint8_t*)(compat_ptr(rArg.addr_i));
		piv = (uint8_t*)(compat_ptr(rArg.addr_iv));
		pout_buffer = (uint8_t*)(compat_ptr(rArg.addr_o));
	}
	else
#endif
	{
		presult = (OEMCryptoResult*)rArg.result;
		pin_buffer = (uint8_t*)rArg.in_buffer;
		piv = (uint8_t*)rArg.iv;
		pout_buffer = (uint8_t*)rArg.out_buffer;
	}

    if (pin_buffer == NULL || rArg.buffer_length == 0
            || piv == NULL || pout_buffer == NULL) {
        *result =  OEMCrypto_ERROR_INVALID_CONTEXT;
        goto result;
    }

    USR_SPACE_ACCESS_VALIDATE_ARG_K(presult , sizeof(OEMCryptoResult));
    USR_SPACE_ACCESS_VALIDATE_ARG_K(pin_buffer , rArg.buffer_length);
    USR_SPACE_ACCESS_VALIDATE_ARG_K(piv , KEY_IV_SIZE);
    USR_SPACE_ACCESS_VALIDATE_ARG_K(pout_buffer , rArg.buffer_length);

	remain_length = rArg.buffer_length;
	data_addr_cur = pin_buffer;


    CHECK_ALLOC(iv ,KEY_IV_SIZE, ret, final);
    COPY_FROM_USER_ARG_K(piv , *iv , KEY_IV_SIZE);

    if(input_data_addr==NULL || output_data_addr==NULL)
		goto result;

    CHECK_ALLOC(tzArg,sizeof(rArg),ret,final);
    x_memcpy(tzArg,&rArg,sizeof(rArg));
    tzArg->result     = (OEMCryptoResult* )PHYSICAL((UPTR)result );
    tzArg->in_buffer  = (uint8_t *)PHYSICAL((UPTR)input_data_addr);
    tzArg->iv         = (uint8_t *)PHYSICAL((UPTR)iv);
    tzArg->out_buffer = (uint8_t *)PHYSICAL((UPTR)output_data_addr);

	while(remain_length !=0)
	{
		if(remain_length > MAX_BSP_ALLOC_SIZE) //MAX_BSP_ALLOC_SIZE_GEN //only for UT test Generic_Decrypt/Generic_Encrypt
		{
			cpy_length = MAX_BSP_ALLOC_SIZE;
		}else
		{
			cpy_length = remain_length ;
		}

		COPY_FROM_USER_ARG_K(data_addr_cur, *input_data_addr , cpy_length);

		remain_length -= cpy_length;
		data_addr_cur += cpy_length;

		tzArg->buffer_length	= cpy_length;

	    TZ_CACHE_STR(input_data_addr , cpy_length);
	    TZ_CACHE_STR(iv        , KEY_IV_SIZE);
	    TZ_CACHE_STR(result    , sizeof(OEMCryptoResult));
	    TZ_CACHE_STR(output_data_addr , cpy_length);

	    TZ_OEMCrypto_Generic_Decrypt(tzArg, sizeof(rArg));

	    TZ_CACHE_END(input_data_addr , cpy_length);
	    TZ_CACHE_END(iv        , KEY_IV_SIZE);
	    TZ_CACHE_END(result    , sizeof(OEMCryptoResult));
	    TZ_CACHE_END(output_data_addr , cpy_length);

	    if(*result == OEMCrypto_SUCCESS)
	    {
			COPY_TO_USER_ARG_K(pout_buffer+cpy_ofst , *output_data_addr , cpy_length);
			cpy_ofst += cpy_length;
	    }

            if (cpy_length >= KEY_IV_SIZE)
		x_memcpy(iv, input_data_addr+cpy_length-KEY_IV_SIZE, KEY_IV_SIZE);
	}

result:
    COPY_TO_USER_ARG_K(presult, *result, sizeof(OEMCryptoResult));

final:

#ifdef CC_WIDEVINE_TZ_ENABLE
    CHECK_FREE(tzArg);
#endif
	//if(result!=NULL)
	//	MTDMX_PRINT("MTAL: %s exit, *result=%d \n",__FUNCTION__,*result);

    CHECK_FREE(result);
    CHECK_FREE(iv);

    x_sema_unlock(_hWidevineSema);
    return ret;
}

MT_RESULT_T _MTDRM_WV_OEMCrypto_Generic_Sign(unsigned long arg)
{
    MT_RESULT_T ret = MTR_OK;
    GenericSignArg_64BIT rArg   = {{0},0,{0},0,0,{0},{0},0};
    GenericSignArg_64BIT *tzArg = NULL;
    OEMCryptoResult *result=NULL, *presult     = NULL;
    UINT32 *signature_length=NULL, *psignature_length    = NULL;
	uint8_t *pin_buffer=NULL, *psignature = NULL;
    UINT32 invDataLen;
    size_t remain_length=0;
    const uint8_t *data_addr_cur;
    size_t cpy_length;
    uint32_t nums_packages = 0;
    uint32_t cur_package = 0;

	MTDMX_PRINT("MTAL: %s entry \n",__FUNCTION__);

    if (!u1Initialized)
    {
        x_sema_create(&_hWidevineSema, X_SEMA_TYPE_BINARY, X_SEMA_STATE_UNLOCK);
        u1Initialized = 1 ;
    }

    x_sema_lock(_hWidevineSema, X_SEMA_OPTION_WAIT) ;

    CHECK_ALLOC(result,sizeof(OEMCryptoResult),ret,final);
    *result = OEMCrypto_ERROR_UNKNOWN_FAILURE;

    CHECK_ALLOC(signature_length,sizeof(UINT32),ret,final);

    USR_SPACE_ACCESS_VALIDATE_ARG_K(arg, sizeof(GenericSignArg_64BIT));
    COPY_FROM_USER_ARG_K(arg , rArg,sizeof(GenericSignArg_64BIT));

#ifdef CONFIG_COMPAT
	if (is_compat_task())
	{
		presult = (OEMCryptoResult*)(compat_ptr(rArg.addr_r));
		pin_buffer = (uint8_t*)(compat_ptr(rArg.addr_i));
		psignature = (uint8_t*)(compat_ptr(rArg.addr_s));
		psignature_length = (UINT32*)(compat_ptr(rArg.addr_sl));
	}
	else
#endif
	{
		presult = (OEMCryptoResult*)rArg.result;
		pin_buffer = (uint8_t*)rArg.in_buffer;
		psignature = (uint8_t*)rArg.signature;
		psignature_length = (UINT32*)rArg.signature_length;
	}

	USR_SPACE_ACCESS_VALIDATE_ARG_K(presult, sizeof(OEMCryptoResult));
    USR_SPACE_ACCESS_VALIDATE_ARG_K(psignature_length , sizeof(UINT32));
    COPY_FROM_USER_ARG_K(psignature_length , *signature_length , sizeof(UINT32));

    if (*signature_length < SHA256_DIGEST_LENGTH) {
        *signature_length = SHA256_DIGEST_LENGTH;
        *result = OEMCrypto_ERROR_SHORT_BUFFER;
        goto result;
    }
    if (pin_buffer == NULL || rArg.buffer_length == 0 || psignature == NULL) {
        *result = OEMCrypto_ERROR_INVALID_CONTEXT;
        goto result;
    }

    USR_SPACE_ACCESS_VALIDATE_ARG_K(pin_buffer , rArg.buffer_length);
    USR_SPACE_ACCESS_VALIDATE_ARG_K(psignature , *signature_length);

    if(input_data_addr==NULL)
    {
        MTDMX_PRINT("MTAL: %s  input_data_addr==NULL \n",__FUNCTION__);
        goto final;
    }

    if(*signature_length >MAX_BSP_ALLOC_SIZE)
    {
        MTDMX_PRINT("MTAL: %s  signature_length > MAX_BSP_ALLOC_SIZE \n",__FUNCTION__);
        goto result;
    }
    if(output_data_addr==NULL)
    {
        MTDMX_PRINT("MTAL: %s  output_data_addr==NULL \n",__FUNCTION__);
        goto final;
    }

    CHECK_ALLOC(tzArg,sizeof(rArg),ret,final);
    x_memcpy(tzArg,&rArg,sizeof(rArg));
    tzArg->result           = (OEMCryptoResult* )PHYSICAL((UPTR)result );
    tzArg->in_buffer        = (uint8_t *)PHYSICAL((UPTR)input_data_addr);
    tzArg->signature        = (uint8_t *)PHYSICAL((UPTR)output_data_addr);
    tzArg->signature_length = (UINT32  *)PHYSICAL((UPTR)signature_length);

    remain_length = rArg.buffer_length;
    data_addr_cur = pin_buffer;
    invDataLen = *signature_length;

    if((rArg.buffer_length%MAX_BSP_ALLOC_SIZE) == 0)
        nums_packages = (rArg.buffer_length/MAX_BSP_ALLOC_SIZE);
    else
        nums_packages = (rArg.buffer_length/MAX_BSP_ALLOC_SIZE) + 1;

    while(remain_length !=0)
    {
        if(remain_length > MAX_BSP_ALLOC_SIZE)
        {
            cpy_length = MAX_BSP_ALLOC_SIZE;
        }else
        {
            cpy_length = remain_length ;
        }
        cur_package ++;

        if(nums_packages == 1)
        {
            tzArg->flag = ALL_PACKAGE;
        }
        else if(cur_package < nums_packages)
        {
            if(cur_package == 1)
                tzArg->flag = FIRST_PACKAGE;
            else
                tzArg->flag = MIDDLE_PACKAGE;
        }
        else if(cur_package == nums_packages)
        {
            tzArg->flag = LAST_PACKAGE;
        }

        COPY_FROM_USER_ARG_K(data_addr_cur, *input_data_addr, cpy_length);

        remain_length -= cpy_length;
        data_addr_cur += cpy_length;

        tzArg->buffer_length = cpy_length;

        TZ_CACHE_STR(input_data_addr , cpy_length);
        TZ_CACHE_STR(result    , sizeof(OEMCryptoResult));
        TZ_CACHE_STR(signature_length , sizeof(UINT32));
        TZ_CACHE_STR(output_data_addr , invDataLen);

        TZ_OEMCrypto_Generic_Sign(tzArg, sizeof(rArg));

        TZ_CACHE_END(input_data_addr , cpy_length);
        TZ_CACHE_END(result    , sizeof(OEMCryptoResult));
        TZ_CACHE_END(signature_length , sizeof(UINT32));
        TZ_CACHE_END(output_data_addr , invDataLen);
    }

    if(*result == OEMCrypto_SUCCESS)
    {
        COPY_TO_USER_ARG_K(psignature, *output_data_addr, *signature_length);
    }
    else
    {
        MTDMX_PRINT("MTAL: %s fail, *result=%d \n",__FUNCTION__,*result);
    }

    ret = MTR_OK;

result:
    COPY_TO_USER_ARG_K(psignature_length , *signature_length ,sizeof(UINT32));
    COPY_TO_USER_ARG_K(presult, *result, sizeof(OEMCryptoResult));

final:
#ifdef CC_WIDEVINE_TZ_ENABLE
    CHECK_FREE(tzArg);
#endif
	if(result!=NULL)
		MTDMX_PRINT("MTAL: %s exit, *result=%d \n",__FUNCTION__,*result);

    CHECK_FREE(result);
    CHECK_FREE(signature_length);
    x_sema_unlock(_hWidevineSema);

    return ret;
}

MT_RESULT_T _MTDRM_WV_OEMCrypto_Generic_Verify(unsigned long arg)
{
    MT_RESULT_T ret = MTR_OK;
	GenericVerifyArg_64BIT rArg   = {{0},0,{0},0,0,{0},0};
    GenericVerifyArg_64BIT *tzArg = NULL;
    OEMCryptoResult *result=NULL, *presult       = NULL;
    uint8_t *pin_buffer=NULL, *psignature = NULL;
    size_t remain_length=0;
    const uint8_t *data_addr_cur;
    size_t cpy_length;
    uint32_t nums_packages = 0;
    uint32_t cur_package = 0;

	MTDMX_PRINT("MTAL: %s entry \n",__FUNCTION__);

    if (!u1Initialized)
    {
        x_sema_create(&_hWidevineSema, X_SEMA_TYPE_BINARY, X_SEMA_STATE_UNLOCK);
        u1Initialized = 1 ;
    }

    x_sema_lock(_hWidevineSema, X_SEMA_OPTION_WAIT) ;

    CHECK_ALLOC(result,sizeof(OEMCryptoResult),ret,final);
    *result = OEMCrypto_ERROR_UNKNOWN_FAILURE;

    USR_SPACE_ACCESS_VALIDATE_ARG_K(arg, sizeof(GenericVerifyArg_64BIT));
    COPY_FROM_USER_ARG_K(arg , rArg,sizeof(GenericVerifyArg_64BIT));

#ifdef CONFIG_COMPAT
	if (is_compat_task())
	{
		presult = (OEMCryptoResult*)(compat_ptr(rArg.addr_r));
		pin_buffer = (uint8_t*)(compat_ptr(rArg.addr_i));
		psignature = (uint8_t*)(compat_ptr(rArg.addr_s));
	}
	else
#endif
	{
		presult = (OEMCryptoResult*)rArg.result;
		pin_buffer = (uint8_t*)rArg.in_buffer;
		psignature = (uint8_t*)rArg.signature;
	}

    if (rArg.signature_length != SHA256_DIGEST_LENGTH) {
        MTDMX_PRINT("MTAL: %s  signature_length != SHA256_DIGEST_LENGTH \n",__FUNCTION__);
        *result =  OEMCrypto_ERROR_UNKNOWN_FAILURE;
        goto result;
    }

    if (pin_buffer == NULL || rArg.buffer_length == 0 || psignature == NULL) {
        *result = OEMCrypto_ERROR_INVALID_CONTEXT;
        goto result;
    }

	USR_SPACE_ACCESS_VALIDATE_ARG_K(presult, sizeof(OEMCryptoResult));
    USR_SPACE_ACCESS_VALIDATE_ARG_K(pin_buffer , rArg.buffer_length);
    USR_SPACE_ACCESS_VALIDATE_ARG_K(psignature , rArg.signature_length);

    if(input_data_addr==NULL)
    {
        MTDMX_PRINT("MTAL: %s  input_data_addr==NULL \n",__FUNCTION__);
        goto final;
    }

    if(output_data_addr==NULL)
    {
        MTDMX_PRINT("MTAL: %s  output_data_addr==NULL \n",__FUNCTION__);
        goto final;
    }

    COPY_FROM_USER_ARG_K(psignature , *output_data_addr , rArg.signature_length);

    CHECK_ALLOC(tzArg,sizeof(rArg),ret,final);
    x_memcpy(tzArg,&rArg,sizeof(rArg));
    tzArg->result    = (OEMCryptoResult* )PHYSICAL((UPTR)result );
    tzArg->in_buffer = (uint8_t *)PHYSICAL((UPTR)input_data_addr);
    tzArg->signature = (uint8_t *)PHYSICAL((UPTR)output_data_addr);

    remain_length = rArg.buffer_length;
    data_addr_cur = pin_buffer;

    if((rArg.buffer_length%MAX_BSP_ALLOC_SIZE) == 0)
        nums_packages = (rArg.buffer_length/MAX_BSP_ALLOC_SIZE);
    else
        nums_packages = (rArg.buffer_length/MAX_BSP_ALLOC_SIZE) + 1;

    while(remain_length !=0)
    {
        if(remain_length > MAX_BSP_ALLOC_SIZE)
        {
            cpy_length = MAX_BSP_ALLOC_SIZE;
        }else
        {
            cpy_length = remain_length ;
         }
        cur_package ++;

        if(nums_packages == 1)
        {
            tzArg->flag = ALL_PACKAGE;
        }
        else if(cur_package < nums_packages)
        {
            if(cur_package == 1)
                tzArg->flag = FIRST_PACKAGE;
            else
                tzArg->flag = MIDDLE_PACKAGE;
        }
        else if(cur_package == nums_packages)
        {
            tzArg->flag = LAST_PACKAGE;
        }

        COPY_FROM_USER_ARG_K(data_addr_cur, *input_data_addr, cpy_length);

        remain_length -= cpy_length;
        data_addr_cur += cpy_length;

        tzArg->buffer_length = cpy_length;

        TZ_CACHE_STR(input_data_addr , cpy_length);
        TZ_CACHE_STR(result    , sizeof(OEMCryptoResult));
        TZ_CACHE_STR(output_data_addr , rArg.signature_length);

        TZ_OEMCrypto_Generic_Verify(tzArg, sizeof(rArg));

        TZ_CACHE_END(input_data_addr , cpy_length);
        TZ_CACHE_END(result    , sizeof(OEMCryptoResult));
        TZ_CACHE_END(output_data_addr , rArg.signature_length);
    }
result:
    COPY_TO_USER_ARG_K(presult, *result, sizeof(OEMCryptoResult));

final:

#ifdef CC_WIDEVINE_TZ_ENABLE
    CHECK_FREE(tzArg);
#endif
	if(result!=NULL)
		MTDMX_PRINT("MTAL: %s exit, *result=%d \n",__FUNCTION__,*result);

    CHECK_FREE(result);
    x_sema_unlock(_hWidevineSema);
    return ret;
}

MT_RESULT_T _MTDRM_WV_OEMCrypto_UpdateUsageTable(unsigned long arg)
{
    MT_RESULT_T ret         = MTR_OK;
    OEMCryptoResult *result = NULL;

	//MTDMX_PRINT("MTAL: %s entry \n",__FUNCTION__);

    if (!u1Initialized)
    {
        x_sema_create(&_hWidevineSema, X_SEMA_TYPE_BINARY, X_SEMA_STATE_UNLOCK);
        u1Initialized = 1 ;
    }

    x_sema_lock(_hWidevineSema, X_SEMA_OPTION_WAIT) ;
    RPMB_LOCK();

    CHECK_ALLOC(result,sizeof(OEMCryptoResult),ret,final);
    *result = OEMCrypto_ERROR_UNKNOWN_FAILURE;

    USR_SPACE_ACCESS_VALIDATE_ARG_K(arg , sizeof(OEMCryptoResult));

#ifdef CC_WIDEVINE_TZ_ENABLE
    TZ_OEMCrypto_UpdateUsageTable(result, sizeof(OEMCryptoResult));
#endif

    COPY_TO_USER_ARG_K(arg, *result, sizeof(OEMCryptoResult));
final:
	//if(result!=NULL)
	//	MTDMX_PRINT("MTAL: %s exit, *result=%d \n",__FUNCTION__,*result);

    CHECK_FREE(result);

    x_sema_unlock(_hWidevineSema);
    return ret;
}

MT_RESULT_T _MTDRM_WV_OEMCrypto_DeactivateUsageEntry(unsigned long arg)
{
    MT_RESULT_T ret = MTR_OK;
	DeactivateUsageEntryArg_64BIT rArg   = {{0},{0},0};
    DeactivateUsageEntryArg_64BIT *tzArg = NULL;
    OEMCryptoResult *result=NULL, *presult = NULL;
    uint8_t *pst=NULL, *ppst = NULL;

	MTDMX_PRINT("MTAL: %s entry \n",__FUNCTION__);

    if (!u1Initialized)
    {
        x_sema_create(&_hWidevineSema, X_SEMA_TYPE_BINARY, X_SEMA_STATE_UNLOCK);
        u1Initialized = 1 ;
    }

    x_sema_lock(_hWidevineSema, X_SEMA_OPTION_WAIT) ;
    RPMB_LOCK();

    CHECK_ALLOC(result,sizeof(OEMCryptoResult),ret,final);
    *result = OEMCrypto_ERROR_UNKNOWN_FAILURE;

    USR_SPACE_ACCESS_VALIDATE_ARG_K(arg, sizeof(DeactivateUsageEntryArg_64BIT));
    COPY_FROM_USER_ARG_K(arg , rArg,sizeof(DeactivateUsageEntryArg_64BIT));

#ifdef CONFIG_COMPAT
	if (is_compat_task())
	{
		presult = (OEMCryptoResult*)(compat_ptr(rArg.addr_r));
		ppst = (uint8_t*)(compat_ptr(rArg.addr_p));
	}
	else
#endif
	{
		presult = (OEMCryptoResult*)rArg.result;
		ppst = (uint8_t*)rArg.pst;
	}

	USR_SPACE_ACCESS_VALIDATE_ARG_K(presult, sizeof(OEMCryptoResult));
    CHECK_ALLOC(pst ,rArg.pst_length, ret, final);
    USR_SPACE_ACCESS_VALIDATE_ARG_K(ppst , rArg.pst_length);
    COPY_FROM_USER_ARG_K(ppst , *pst , rArg.pst_length);

#ifdef CC_WIDEVINE_TZ_ENABLE
    CHECK_ALLOC(tzArg,sizeof(rArg),ret,final);

    x_memcpy(tzArg,&rArg,sizeof(rArg));

    tzArg->result = (OEMCryptoResult* )PHYSICAL((UPTR)result );
    tzArg->pst    = (uint8_t *)PHYSICAL((UPTR)pst);

    TZ_CACHE_STR(result               , sizeof(OEMCryptoResult));
    TZ_CACHE_STR(pst                  , rArg.pst_length);

    TZ_OEMCrypto_DeactivateUsageEntry(tzArg , sizeof(rArg));

    TZ_CACHE_END(pst                  , rArg.pst_length);
    TZ_CACHE_END(result               , sizeof(OEMCryptoResult));

#endif

    COPY_TO_USER_ARG_K(presult, *result, sizeof(OEMCryptoResult));

final:
	if(result!=NULL)
		MTDMX_PRINT("MTAL: %s exit, *result=%d \n",__FUNCTION__,*result);

    CHECK_FREE(tzArg);
    CHECK_FREE(result);
    CHECK_FREE(pst);

    x_sema_unlock(_hWidevineSema);
    return ret;
}

MT_RESULT_T _MTDRM_WV_OEMCrypto_ReportUsage(unsigned long arg)
{
    MT_RESULT_T ret = MTR_OK;
	ReportUsageArg_64BIT rArg		   = {{0},0,{0},0,{0},{0}};
    ReportUsageArg_64BIT *tzArg        = NULL;
    OEMCryptoResult        *result=NULL, *presult               = NULL;
    uint8_t                *pst=NULL, *ppst                     = NULL;
    OEMCrypto_PST_Report   *buffer=NULL, *pbuffer               = NULL;
    UINT32                 *buffer_length=NULL, *pbuffer_length = NULL;
    UINT32                 dataLength;

	MTDMX_PRINT("MTAL: %s entry \n",__FUNCTION__);

    if (!u1Initialized)
    {
        x_sema_create(&_hWidevineSema, X_SEMA_TYPE_BINARY, X_SEMA_STATE_UNLOCK);
        u1Initialized = 1 ;
    }

    x_sema_lock(_hWidevineSema, X_SEMA_OPTION_WAIT) ;
    RPMB_LOCK();

    CHECK_ALLOC(result,sizeof(OEMCryptoResult),ret,final);
    *result = OEMCrypto_ERROR_UNKNOWN_FAILURE;

    USR_SPACE_ACCESS_VALIDATE_ARG_K(arg, sizeof(ReportUsageArg_64BIT));
    COPY_FROM_USER_ARG_K(arg , rArg,sizeof(ReportUsageArg_64BIT));

#ifdef CONFIG_COMPAT
	if (is_compat_task())
	{
		presult = (OEMCryptoResult*)(compat_ptr(rArg.addr_r));
		ppst = (uint8_t*)(compat_ptr(rArg.addr_p));
		pbuffer = (OEMCrypto_PST_Report*)(compat_ptr(rArg.addr_b));
		pbuffer_length = (UINT32*)(compat_ptr(rArg.addr_bl));
	}
	else
#endif
	{
		presult = (OEMCryptoResult*)rArg.result;
		ppst = (uint8_t*)rArg.pst;
		pbuffer = (OEMCrypto_PST_Report*)rArg.buffer;
		pbuffer_length = (UINT32*)rArg.buffer_length;
	}

	USR_SPACE_ACCESS_VALIDATE_ARG_K(presult, sizeof(OEMCryptoResult));
    CHECK_ALLOC(pst ,rArg.pst_length, ret, final);
    USR_SPACE_ACCESS_VALIDATE_ARG_K(ppst , rArg.pst_length);
    COPY_FROM_USER_ARG_K(ppst , *pst , rArg.pst_length);

    CHECK_ALLOC(buffer_length ,sizeof(UINT32), ret, final);
    USR_SPACE_ACCESS_VALIDATE_ARG_K(pbuffer_length , sizeof(UINT32));
    COPY_FROM_USER_ARG_K(pbuffer_length , *buffer_length ,sizeof(UINT32));

    CHECK_ALLOC(buffer                          , *buffer_length   , ret              , final);
    USR_SPACE_ACCESS_VALIDATE_ARG_K(pbuffer , *buffer_length);
    COPY_FROM_USER_ARG_K(pbuffer            , *buffer               , *buffer_length);

    CHECK_ALLOC(tzArg,sizeof(rArg),ret,final);

#ifdef CC_WIDEVINE_TZ_ENABLE
    x_memcpy(tzArg,&rArg,sizeof(rArg));

    tzArg->result        = (OEMCryptoResult* )PHYSICAL((UPTR)result );
    tzArg->pst           = (uint8_t *)PHYSICAL((UPTR)pst);
    tzArg->buffer        = (OEMCrypto_PST_Report *)PHYSICAL((UPTR)buffer);
    tzArg->buffer_length = (UINT32 *)PHYSICAL((UPTR)buffer_length);
    dataLength = *buffer_length;

    TZ_CACHE_STR(result        , sizeof(OEMCryptoResult));
    TZ_CACHE_STR(pst           , rArg.pst_length);
    TZ_CACHE_STR(buffer        , dataLength);
    TZ_CACHE_STR(buffer_length , sizeof(UINT32));

    TZ_OEMCrypto_ReportUsage(tzArg , sizeof(rArg));

    TZ_CACHE_END(result        , sizeof(OEMCryptoResult));
    TZ_CACHE_END(pst           , rArg.pst_length);
    TZ_CACHE_END(buffer_length , sizeof(UINT32));
    TZ_CACHE_END(buffer        , dataLength);

#endif

    COPY_TO_USER_ARG_K(presult, *result, sizeof(OEMCryptoResult));
    COPY_TO_USER_ARG_K(pbuffer_length , *buffer_length ,sizeof(UINT32));

    if(*result == OEMCrypto_SUCCESS)
    {
        COPY_TO_USER_ARG_K(pbuffer , *buffer ,*buffer_length);
    }

final:
	if(result!=NULL)
		MTDMX_PRINT("MTAL: %s exit, *result=%d \n",__FUNCTION__,*result);

    CHECK_FREE(result);
    CHECK_FREE(pst);
    CHECK_FREE(buffer_length);
    CHECK_FREE(buffer);
    CHECK_FREE(tzArg);

    x_sema_unlock(_hWidevineSema);

    return ret;
}

MT_RESULT_T _MTDRM_WV_OEMCrypto_DeleteUsageEntry(unsigned long arg)
{
    MT_RESULT_T ret = MTR_OK;
	DeleteUsageEntryArg_64BIT rArg = {{0},0,{0},0,{0},0,{0},0};
    DeleteUsageEntryArg_64BIT *tzArg = NULL;
    OEMCryptoResult      *result=NULL, *presult    = NULL;
    uint8_t              *pst=NULL, *ppst       = NULL;
    uint8_t              *message=NULL, *pmessage   = NULL;
    uint8_t              *signature=NULL, *psignature = NULL;

	MTDMX_PRINT("MTAL: %s entry \n",__FUNCTION__);

    if (!u1Initialized)
    {
        x_sema_create(&_hWidevineSema, X_SEMA_TYPE_BINARY, X_SEMA_STATE_UNLOCK);
        u1Initialized = 1 ;
    }

    x_sema_lock(_hWidevineSema, X_SEMA_OPTION_WAIT) ;
    RPMB_LOCK();

    CHECK_ALLOC(result,sizeof(OEMCryptoResult),ret,final);
    *result = OEMCrypto_ERROR_UNKNOWN_FAILURE;

    USR_SPACE_ACCESS_VALIDATE_ARG_K(arg, sizeof(DeleteUsageEntryArg_64BIT));
    COPY_FROM_USER_ARG_K(arg , rArg,sizeof(DeleteUsageEntryArg_64BIT));

#ifdef CONFIG_COMPAT
	if (is_compat_task())
	{
		presult = (OEMCryptoResult*)(compat_ptr(rArg.addr_r));
		ppst = (uint8_t*)(compat_ptr(rArg.addr_p));
		pmessage = (uint8_t*)(compat_ptr(rArg.addr_m));
		psignature = (uint8_t*)(compat_ptr(rArg.addr_s));
	}
	else
#endif
	{
		presult = (OEMCryptoResult*)rArg.result;
		ppst = (uint8_t*)rArg.pst;
		pmessage = (uint8_t*)rArg.message;
		psignature = (uint8_t*)rArg.signature;
	}

	USR_SPACE_ACCESS_VALIDATE_ARG_K(presult, sizeof(OEMCryptoResult));
    CHECK_ALLOC(message ,rArg.message_length, ret, final);
    USR_SPACE_ACCESS_VALIDATE_ARG_K(pmessage , rArg.message_length);
    COPY_FROM_USER_ARG_K(pmessage , *message , rArg.message_length);

    CHECK_ALLOC(signature ,rArg.signature_length, ret, final);
    USR_SPACE_ACCESS_VALIDATE_ARG_K(psignature , rArg.signature_length);
    COPY_FROM_USER_ARG_K(psignature , *signature , rArg.signature_length);

    if (!RangeCheck(pmessage, rArg.message_length, ppst, rArg.pst_length, false)) {
        *result =  OEMCrypto_ERROR_INVALID_CONTEXT;
        goto result;
    }

    pst = ppst - pmessage + message;

    CHECK_ALLOC(tzArg,sizeof(rArg),ret,final);

#ifdef CC_WIDEVINE_TZ_ENABLE
    x_memcpy(tzArg,&rArg,sizeof(rArg));

    tzArg->result    = (OEMCryptoResult* )PHYSICAL((UPTR)result);
    tzArg->pst       = (uint8_t *)PHYSICAL((UPTR)pst);
    tzArg->message   = (uint8_t *)PHYSICAL((UPTR)message);
    tzArg->signature = (uint8_t *)PHYSICAL((UPTR)signature);

    TZ_CACHE_STR(result    , sizeof(OEMCryptoResult));
    TZ_CACHE_STR(message   , rArg.message_length);
    TZ_CACHE_STR(signature , rArg.signature_length);

    TZ_OEMCrypto_DeleteUsageEntry(tzArg , sizeof(rArg));

    TZ_CACHE_END(result    , sizeof(OEMCryptoResult));
    TZ_CACHE_END(message   , rArg.message_length);
    TZ_CACHE_END(signature , rArg.signature_length);
#endif

result:
    COPY_TO_USER_ARG_K(presult, *result, sizeof(OEMCryptoResult));

final:
	if(result!=NULL)
		MTDMX_PRINT("MTAL: %s exit, *result=%d \n",__FUNCTION__,*result);

    CHECK_FREE(result);
    CHECK_FREE(message);
    CHECK_FREE(signature);
    CHECK_FREE(tzArg);

    x_sema_unlock(_hWidevineSema);

    return ret;
}
MT_RESULT_T _MTDRM_WV_OEMCrypto_DeleteUsageTable(unsigned long arg)
{
    MT_RESULT_T ret         = MTR_OK;
    OEMCryptoResult *result = NULL;

	MTDMX_PRINT("MTAL: %s entry \n",__FUNCTION__);

    if (!u1Initialized)
    {
        x_sema_create(&_hWidevineSema, X_SEMA_TYPE_BINARY, X_SEMA_STATE_UNLOCK);
        u1Initialized = 1 ;
    }

    x_sema_lock(_hWidevineSema, X_SEMA_OPTION_WAIT) ;
    RPMB_LOCK();

    CHECK_ALLOC(result,sizeof(OEMCryptoResult),ret,final);
    *result = OEMCrypto_ERROR_UNKNOWN_FAILURE;

    USR_SPACE_ACCESS_VALIDATE_ARG_K(arg , sizeof(OEMCryptoResult));

    TZ_OEMCrypto_DeleteUsageTable(result, sizeof(OEMCryptoResult));

    COPY_TO_USER_ARG_K(arg, *result, sizeof(OEMCryptoResult));
final:
	if(result!=NULL)
		MTDMX_PRINT("MTAL: %s exit, *result=%d \n",__FUNCTION__,*result);

    CHECK_FREE(result);

    x_sema_unlock(_hWidevineSema);
    return ret;
}

MT_RESULT_T _MTDRM_WV_OEMCrypto_GetUsageTableWriteRequest(unsigned long arg)
{
    GetUsageTableWriteRequestArg_64BIT rArg   = {{0},{0},{0},{0}};
	GetUsageTableWriteRequestArg_64BIT *tzArg = NULL;
    MT_RESULT_T ret         = MTR_OK;
    OEMCryptoResult *result=NULL, *presult = NULL;
    UINT32 *buffer_length=NULL, *pbuffer_length = NULL;
    uint8_t * buffer=NULL, *pbuffer        = NULL;
    RPMB_DATAFRAM *dFrame=NULL, *pdFrame   = NULL;

    UINT32 dataLength;

	MTDMX_PRINT("MTAL: %s entry \n",__FUNCTION__);

    if (!u1Initialized)
    {
        x_sema_create(&_hWidevineSema, X_SEMA_TYPE_BINARY, X_SEMA_STATE_UNLOCK);
        u1Initialized = 1 ;
    }

    x_sema_lock(_hWidevineSema, X_SEMA_OPTION_WAIT) ;

    CHECK_ALLOC(result,sizeof(OEMCryptoResult),ret,final);
    *result = OEMCrypto_ERROR_UNKNOWN_FAILURE;

    USR_SPACE_ACCESS_VALIDATE_ARG_K(arg, sizeof(GetUsageTableWriteRequestArg_64BIT));
    COPY_FROM_USER_ARG_K(arg , rArg,sizeof(GetUsageTableWriteRequestArg_64BIT));

#ifdef CONFIG_COMPAT
	if (is_compat_task())
	{
		presult = (OEMCryptoResult*)(compat_ptr(rArg.addr_r));
		pbuffer = (uint8_t*)(compat_ptr(rArg.addr_b));
		pbuffer_length = (UINT32*)(compat_ptr(rArg.addr_bl));
		pdFrame = (RPMB_DATAFRAM*)(compat_ptr(rArg.addr_d));
	}
	else
#endif
	{
		presult = (OEMCryptoResult*)rArg.result;
		pbuffer = (uint8_t*)rArg.buffer;
		pbuffer_length = (UINT32*)rArg.buffer_length;
		pdFrame = (RPMB_DATAFRAM*)rArg.dFrame;
	}

	USR_SPACE_ACCESS_VALIDATE_ARG_K(presult, sizeof(OEMCryptoResult));
    CHECK_ALLOC(buffer_length ,sizeof(UINT32), ret, final);
    USR_SPACE_ACCESS_VALIDATE_ARG_K(pbuffer_length , sizeof(UINT32));
    COPY_FROM_USER_ARG_K(pbuffer_length , *buffer_length ,sizeof(UINT32));

    CHECK_ALLOC(buffer                          , *buffer_length   , ret              , final);
    USR_SPACE_ACCESS_VALIDATE_ARG_K(pbuffer , *buffer_length);

    CHECK_ALLOC(dFrame                          , sizeof(RPMB_DATAFRAM), ret              , final);
    USR_SPACE_ACCESS_VALIDATE_ARG_K(pdFrame , sizeof(RPMB_DATAFRAM));

    CHECK_ALLOC(tzArg,sizeof(rArg),ret,final);

#ifdef CC_WIDEVINE_TZ_ENABLE
    x_memcpy(tzArg,&rArg,sizeof(rArg));

    tzArg->result        = (OEMCryptoResult* )PHYSICAL((UPTR)result );
    tzArg->buffer        = (uint8_t *)PHYSICAL((UPTR)buffer);
    tzArg->buffer_length = (UINT32 *)PHYSICAL((UPTR)buffer_length);
    tzArg->dFrame        = (RPMB_DATAFRAM *)PHYSICAL((UPTR)dFrame);

    dataLength = *buffer_length;

    TZ_CACHE_STR(result        , sizeof(OEMCryptoResult));
    TZ_CACHE_STR(buffer        , dataLength);
    TZ_CACHE_STR(buffer_length , sizeof(UINT32));
    TZ_CACHE_STR(dFrame        , sizeof(RPMB_DATAFRAM));

    TZ_OEMCrypto_GetUsageTableWriteRequest(tzArg, sizeof(GetUsageTableWriteRequestArg_64BIT));

    TZ_CACHE_END(result        , sizeof(OEMCryptoResult));
    TZ_CACHE_END(buffer        , dataLength);
    TZ_CACHE_END(buffer_length , sizeof(UINT32));
    TZ_CACHE_END(dFrame        , sizeof(RPMB_DATAFRAM));

#endif

    COPY_TO_USER_ARG_K(presult, *result, sizeof(OEMCryptoResult));
    COPY_TO_USER_ARG_K(pbuffer_length , *buffer_length ,sizeof(UINT32));

    if(*result == OEMCrypto_SUCCESS)
    {
        COPY_TO_USER_ARG_K(pbuffer , *buffer ,*buffer_length);
        COPY_TO_USER_ARG_K(pdFrame , *dFrame ,sizeof(RPMB_DATAFRAM));
    }
    else
    {
		//MTDMX_PRINT("_MTDRM_WV_OEMCrypto_GetUsageTableWriteRequest *result=%d \n",*result);
        RPMB_UNLOCK();
    }

final:
	if(result!=NULL)
		MTDMX_PRINT("MTAL: %s exit, *result=%d \n",__FUNCTION__,*result);

    CHECK_FREE(result);
    CHECK_FREE(buffer_length);
    CHECK_FREE(buffer);
    CHECK_FREE(dFrame);
    CHECK_FREE(tzArg);

    x_sema_unlock(_hWidevineSema);
    return ret;
}

MT_RESULT_T _MTDRM_WV_OEMCrypto_VerifyWriteResponse(unsigned long arg)
{
    VerifyWriteResponseArg_64BIT rArg = {{0},{0}};
	VerifyWriteResponseArg_64BIT *tzArg= NULL;
    MT_RESULT_T ret         = MTR_OK;
    OEMCryptoResult *result=NULL, *presult = NULL;
    RPMB_DATAFRAM *dFrame=NULL, *pdFrame   = NULL;

	MTDMX_PRINT("MTAL: %s entry \n",__FUNCTION__);

    if (!u1Initialized)
    {
        x_sema_create(&_hWidevineSema, X_SEMA_TYPE_BINARY, X_SEMA_STATE_UNLOCK);
        u1Initialized = 1 ;
    }

    x_sema_lock(_hWidevineSema, X_SEMA_OPTION_WAIT) ;

    CHECK_ALLOC(result,sizeof(OEMCryptoResult),ret,final);
    *result = OEMCrypto_ERROR_UNKNOWN_FAILURE;

    USR_SPACE_ACCESS_VALIDATE_ARG_K(arg, sizeof(VerifyWriteResponseArg_64BIT));
    COPY_FROM_USER_ARG_K(arg , rArg,sizeof(VerifyWriteResponseArg_64BIT));

#ifdef CONFIG_COMPAT
	if (is_compat_task())
	{
		presult = (OEMCryptoResult*)(compat_ptr(rArg.addr_r));
		pdFrame = (RPMB_DATAFRAM*)(compat_ptr(rArg.addr_d));
	}
	else
#endif
	{
		presult = (OEMCryptoResult*)rArg.result;
		pdFrame = (RPMB_DATAFRAM*)rArg.dFrame;
	}

	USR_SPACE_ACCESS_VALIDATE_ARG_K(presult, sizeof(OEMCryptoResult));
    CHECK_ALLOC(dFrame                          , sizeof(RPMB_DATAFRAM), ret              , final);
    USR_SPACE_ACCESS_VALIDATE_ARG_K(pdFrame , sizeof(RPMB_DATAFRAM));
    COPY_FROM_USER_ARG_K(pdFrame            , *dFrame, sizeof(RPMB_DATAFRAM));

    CHECK_ALLOC(tzArg,sizeof(rArg),ret,final);

#ifdef CC_WIDEVINE_TZ_ENABLE
    x_memcpy(tzArg,&rArg,sizeof(rArg));

    tzArg->result        = (OEMCryptoResult* )PHYSICAL((UPTR)result );
    tzArg->dFrame        = (RPMB_DATAFRAM *)PHYSICAL((UPTR)dFrame);

    TZ_CACHE_STR(result        , sizeof(OEMCryptoResult));
    TZ_CACHE_STR(dFrame        , sizeof(RPMB_DATAFRAM));

    TZ_OEMCrypto_VerifyWriteResponse(tzArg, sizeof(VerifyWriteResponseArg_64BIT));
    TZ_CACHE_END(result        , sizeof(OEMCryptoResult));
    TZ_CACHE_END(dFrame        , sizeof(RPMB_DATAFRAM));

#endif
    COPY_TO_USER_ARG_K(presult, *result, sizeof(OEMCryptoResult));
final:
	if(result!=NULL)
		MTDMX_PRINT("MTAL: %s exit, *result=%d \n",__FUNCTION__,*result);

    CHECK_FREE(result);
    CHECK_FREE(dFrame);
    CHECK_FREE(tzArg);

    RPMB_UNLOCK();

    x_sema_unlock(_hWidevineSema);
    return ret;
}

MT_RESULT_T _MTDRM_WV_OEMCrypto_GetUsageTableReadRequest(unsigned long arg)
{
    GetUsageTableReadRequesArg_64BIT rArg  = {{0},{0}};
    GetUsageTableReadRequesArg_64BIT *tzArg= NULL;
    MT_RESULT_T ret         = MTR_OK;
    OEMCryptoResult *result=NULL, *presult = NULL;
    RPMB_DATAFRAM *dFrame=NULL, *pdFrame   = NULL;

	MTDMX_PRINT("MTAL: %s entry \n",__FUNCTION__);

    if (!u1Initialized)
    {
        x_sema_create(&_hWidevineSema, X_SEMA_TYPE_BINARY, X_SEMA_STATE_UNLOCK);
        u1Initialized = 1 ;
    }

    x_sema_lock(_hWidevineSema, X_SEMA_OPTION_WAIT);

    CHECK_ALLOC(result,sizeof(OEMCryptoResult),ret,final);
    *result = OEMCrypto_ERROR_UNKNOWN_FAILURE;

    USR_SPACE_ACCESS_VALIDATE_ARG_K(arg, sizeof(GetUsageTableReadRequesArg_64BIT));
    COPY_FROM_USER_ARG_K(arg , rArg,sizeof(GetUsageTableReadRequesArg_64BIT));

#ifdef CONFIG_COMPAT
	if (is_compat_task())
	{
		presult = (OEMCryptoResult*)(compat_ptr(rArg.addr_r));
		pdFrame = (RPMB_DATAFRAM*)(compat_ptr(rArg.addr_d));
	}
	else
#endif
	{
		presult = (OEMCryptoResult*)rArg.result;
		pdFrame = (RPMB_DATAFRAM*)rArg.dFrame;
	}

	USR_SPACE_ACCESS_VALIDATE_ARG_K(presult, sizeof(OEMCryptoResult));
    CHECK_ALLOC(dFrame                          , sizeof(RPMB_DATAFRAM), ret              , final);
    USR_SPACE_ACCESS_VALIDATE_ARG_K(pdFrame , sizeof(RPMB_DATAFRAM));

    CHECK_ALLOC(tzArg,sizeof(rArg),ret,final);

#ifdef CC_WIDEVINE_TZ_ENABLE
    x_memcpy(tzArg,&rArg,sizeof(rArg));

    tzArg->result        = (OEMCryptoResult*)PHYSICAL((UPTR)result);
    tzArg->dFrame        = (RPMB_DATAFRAM *)PHYSICAL((UPTR)dFrame);

    TZ_CACHE_STR(result        , sizeof(OEMCryptoResult));
    TZ_CACHE_STR(dFrame        , sizeof(RPMB_DATAFRAM));

    TZ_OEMCrypto_GetUsageTableReadRequest(tzArg, sizeof(GetUsageTableReadRequesArg_64BIT));

    TZ_CACHE_END(result        , sizeof(OEMCryptoResult));
    TZ_CACHE_END(dFrame        , sizeof(RPMB_DATAFRAM));

#endif

    COPY_TO_USER_ARG_K(presult, *result, sizeof(OEMCryptoResult));

    if(*result == OEMCrypto_SUCCESS)
    {
        COPY_TO_USER_ARG_K(pdFrame , *dFrame ,sizeof(RPMB_DATAFRAM));
    }

final:
	if(result!=NULL)
		MTDMX_PRINT("MTAL: %s exit, *result=%d \n",__FUNCTION__,*result);

    CHECK_FREE(result);
    CHECK_FREE(dFrame);
    CHECK_FREE(tzArg);

    x_sema_unlock(_hWidevineSema);

    return ret;
}

MT_RESULT_T _MTDRM_WV_OEMCrypto_VerifyReadResponse(unsigned long arg)
{
    VerifyReadResponseArg_64BIT rArg = {{0},{0},0,{0}};
    VerifyReadResponseArg_64BIT *tzArg = NULL;
    MT_RESULT_T ret         = MTR_OK;
    OEMCryptoResult *result=NULL, *presult = NULL;
    uint8_t *buffer=NULL, *pbuffer         = NULL;
    RPMB_DATAFRAM *dFrame=NULL, *pdFrame   = NULL;

	MTDMX_PRINT("MTAL: %s entry \n",__FUNCTION__);

    if (!u1Initialized)
    {
        x_sema_create(&_hWidevineSema, X_SEMA_TYPE_BINARY, X_SEMA_STATE_UNLOCK);
        u1Initialized = 1 ;
    }

    x_sema_lock(_hWidevineSema, X_SEMA_OPTION_WAIT) ;

    CHECK_ALLOC(result,sizeof(OEMCryptoResult),ret,final);
    *result = OEMCrypto_ERROR_UNKNOWN_FAILURE;

    USR_SPACE_ACCESS_VALIDATE_ARG_K(arg, sizeof(VerifyReadResponseArg_64BIT));
    COPY_FROM_USER_ARG_K(arg , rArg,sizeof(VerifyReadResponseArg_64BIT));

#ifdef CONFIG_COMPAT
	if (is_compat_task())
	{
		presult = (OEMCryptoResult*)(compat_ptr(rArg.addr_r));
		pbuffer = (uint8_t*)(compat_ptr(rArg.addr_b));
		pdFrame = (RPMB_DATAFRAM*)(compat_ptr(rArg.addr_d));
	}
	else
#endif
	{
		presult = (OEMCryptoResult*)rArg.result;
		pbuffer = (uint8_t*)rArg.buffer;
		pdFrame = (RPMB_DATAFRAM*)rArg.dFrame;
	}

	USR_SPACE_ACCESS_VALIDATE_ARG_K(presult, sizeof(OEMCryptoResult));
    CHECK_ALLOC(buffer                          , rArg.buffer_length, ret              , final);
    USR_SPACE_ACCESS_VALIDATE_ARG_K(pbuffer , rArg.buffer_length);
    COPY_FROM_USER_ARG_K(pbuffer            , *buffer, rArg.buffer_length);

    CHECK_ALLOC(dFrame                          , sizeof(RPMB_DATAFRAM), ret              , final);
    USR_SPACE_ACCESS_VALIDATE_ARG_K(pdFrame , sizeof(RPMB_DATAFRAM));
    COPY_FROM_USER_ARG_K(pdFrame            , *dFrame, sizeof(RPMB_DATAFRAM));

    CHECK_ALLOC(tzArg,sizeof(rArg),ret,final);

#ifdef CC_WIDEVINE_TZ_ENABLE
    x_memcpy(tzArg,&rArg,sizeof(rArg));

    tzArg->result        = (OEMCryptoResult* )PHYSICAL((UPTR)result );
    tzArg->dFrame        = (RPMB_DATAFRAM *)PHYSICAL((UPTR)dFrame);
    tzArg->buffer        = (uint8_t *)PHYSICAL((UPTR)buffer);

    TZ_CACHE_STR(result        , sizeof(OEMCryptoResult));
    TZ_CACHE_STR(dFrame        , sizeof(RPMB_DATAFRAM));
    TZ_CACHE_STR(buffer        , rArg.buffer_length);

    TZ_OEMCrypto_VerifyReadResponse(tzArg, sizeof(VerifyReadResponseArg_64BIT));

    TZ_CACHE_END(result        , sizeof(OEMCryptoResult));
    TZ_CACHE_END(dFrame        , sizeof(RPMB_DATAFRAM));
    TZ_CACHE_END(buffer        , rArg.buffer_length);

#endif

    COPY_TO_USER_ARG_K(presult, *result, sizeof(OEMCryptoResult));

final:
	if(result!=NULL)
		MTDMX_PRINT("MTAL: %s exit, *result=%d \n",__FUNCTION__,*result);

    CHECK_FREE(result);
    CHECK_FREE(dFrame);
    CHECK_FREE(buffer);
    CHECK_FREE(tzArg);

    x_sema_unlock(_hWidevineSema);

    return ret;
}

MT_RESULT_T _MTDRM_WV_OEMCrypto_GetNumberOfOpenSessions(unsigned long arg)
{
	MT_RESULT_T ret = MTR_OK;
    GetNumberOfOpenSessionsArg_64BIT rArg = {{0},{0}};
	GetNumberOfOpenSessionsArg_64BIT *tzArg = NULL;
	OEMCryptoResult *result = NULL, *presult = NULL;
	UINT32 *count = NULL, *pcount= NULL;

	MTDMX_PRINT("MTAL: %s entry \n",__FUNCTION__);

	if (!u1Initialized)
	{
		x_sema_create(&_hWidevineSema, X_SEMA_TYPE_BINARY, X_SEMA_STATE_UNLOCK);
		u1Initialized = 1 ;
	}

	x_sema_lock(_hWidevineSema, X_SEMA_OPTION_WAIT) ;

	CHECK_ALLOC(result,sizeof(OEMCryptoResult),ret,final);
	*result = OEMCrypto_ERROR_UNKNOWN_FAILURE;
	CHECK_ALLOC(count,sizeof(UINT32),ret,final);

	USR_SPACE_ACCESS_VALIDATE_ARG_K(arg ,sizeof(GetNumberOfOpenSessionsArg_64BIT));
	COPY_FROM_USER_ARG_K(arg, rArg , sizeof(GetNumberOfOpenSessionsArg_64BIT));

	#ifdef CONFIG_COMPAT
	if (is_compat_task())
	{
		presult = (OEMCryptoResult*)(compat_ptr(rArg.addr_r));
		pcount = (UINT32*)(compat_ptr(rArg.addr_c));
	}
	else
#endif
	{
		presult = (OEMCryptoResult*)rArg.result;
		pcount = (UINT32*)rArg.count;
	}

	USR_SPACE_ACCESS_VALIDATE_ARG_K(presult, sizeof(OEMCryptoResult) );
	USR_SPACE_ACCESS_VALIDATE_ARG_K(pcount, sizeof(UINT32));

 	CHECK_ALLOC(tzArg,sizeof(rArg),ret,final);
	x_memcpy(tzArg,&rArg,sizeof(rArg));
	tzArg->result	  = (OEMCryptoResult* )PHYSICAL((UPTR)result);;
	tzArg->count 	 =(UINT32 *)PHYSICAL((UPTR)count);

	TZ_CACHE_STR(result    , sizeof(OEMCryptoResult));
	TZ_CACHE_STR(count, sizeof(UINT32));
	TZ_OEMCrypto_GetNumberOfOpenSessions(tzArg, sizeof(rArg));
	TZ_CACHE_END(result    , sizeof(OEMCryptoResult));
	TZ_CACHE_END(count , sizeof(UINT32));

	if(*result == OEMCrypto_SUCCESS)
	{
		COPY_TO_USER_ARG_K(pcount,*count , sizeof(UINT32));
	}
	COPY_TO_USER_ARG_K(presult, *result , sizeof(OEMCryptoResult));

final:
	if(result!=NULL)
		MTDMX_PRINT("MTAL: %s exit, *result=%d \n",__FUNCTION__,*result);
	CHECK_FREE(tzArg);
	CHECK_FREE(result);
	CHECK_FREE(count);

	x_sema_unlock(_hWidevineSema);

	return ret;
}

MT_RESULT_T _MTDRM_WV_OEMCrypto_CopyBuffer(unsigned long arg)
{
	MT_RESULT_T ret					  = MTR_OK;
    OEMCryptoResult *result=NULL, *presult = NULL;
	CopyBufferArg_64BIT rArg = {{0},{0},0,{0},0};
	CopyBufferArg_64BIT *tzArg = NULL;
    OEMCrypto_DestBufferDesc_64BIT *out_buffer=NULL, *pout_buffer = NULL;
	UINT32 max_length ;
	UINT32 remain_length=0;
    uint8_t *pdata_addr_cur=NULL;
    UINT32 cpy_length;
    uint8_t* destination = NULL;

	//MTDMX_PRINT("MTAL: %s entry \n",__FUNCTION__);

	if (!u1Initialized)
	{
		x_sema_create(&_hWidevineSema, X_SEMA_TYPE_BINARY, X_SEMA_STATE_UNLOCK);
		u1Initialized = 1 ;
	}

	x_sema_lock(_hWidevineSema, X_SEMA_OPTION_WAIT) ;

	CHECK_ALLOC(result,sizeof(OEMCryptoResult),ret,final);
	*result = OEMCrypto_ERROR_UNKNOWN_FAILURE;

	CHECK_ALLOC(out_buffer,sizeof(OEMCrypto_DestBufferDesc_64BIT),ret,final);

	USR_SPACE_ACCESS_VALIDATE_ARG_K(arg, sizeof(CopyBufferArg_64BIT));
	COPY_FROM_USER_ARG_K(arg , rArg, sizeof(CopyBufferArg_64BIT));

#ifdef CONFIG_COMPAT
	if (is_compat_task())
	{
		presult = (OEMCryptoResult*)(compat_ptr(rArg.addr_r));
		pdata_addr_cur = (uint8_t*)(compat_ptr(rArg.addr_d));
		pout_buffer = (OEMCrypto_DestBufferDesc_64BIT*)(compat_ptr(rArg.addr_o));

		if(pout_buffer->type ==OEMCrypto_BufferType_Secure)
		{
			pout_buffer->buffer.secure.handle =  (void*)( (UPTR)(pout_buffer->buffer.secure.handle) & (UPTR)0xFFFFFFFF );
		}
	}
	else
#endif
	{
		presult = (OEMCryptoResult*)rArg.result;
		pdata_addr_cur = (uint8_t*)rArg.data_addr;
		pout_buffer = (OEMCrypto_DestBufferDesc_64BIT*)rArg.out_buffer;
	}

	USR_SPACE_ACCESS_VALIDATE_ARG_K(presult 	, sizeof(OEMCryptoResult));
	USR_SPACE_ACCESS_VALIDATE_ARG_K(pdata_addr_cur	, rArg.data_length);

	if (pdata_addr_cur == NULL || pout_buffer == NULL) {
		MTDMX_PRINT("MTAL: %s : OEMCrypto_ERROR_INVALID_CONTEXT  pdata_addr_cur or pout_buffer == NULL \n",__FUNCTION__);
        *result = OEMCrypto_ERROR_INVALID_CONTEXT;
        goto result;
    }

	USR_SPACE_ACCESS_VALIDATE_ARG_K(pout_buffer , sizeof(OEMCrypto_DestBufferDesc_64BIT));
	COPY_FROM_USER_ARG_K(pout_buffer , *out_buffer , sizeof(OEMCrypto_DestBufferDesc_64BIT));

	switch (out_buffer->type) {
		case OEMCrypto_BufferType_Secure:
			destination = ((uint8_t*)out_buffer->buffer.secure.handle
						+ out_buffer->buffer.secure.offset);
			max_length = out_buffer->buffer.secure.max_length;
			break;
		case OEMCrypto_BufferType_Direct:
			*result = OEMCrypto_ERROR_UNKNOWN_FAILURE;
			goto result;
		default:
			max_length = 0xFFFFFFFF;
	}

	if (max_length < rArg.data_length) {
		*result =  OEMCrypto_ERROR_SHORT_BUFFER;
		goto result;
	}

	if ((out_buffer->type != OEMCrypto_BufferType_Direct)
      && (destination == NULL)) {
		MTDMX_PRINT("MTAL: %s : OEMCrypto_ERROR_INVALID_CONTEXT  destination == NULL \n",__FUNCTION__);
		*result = OEMCrypto_ERROR_INVALID_CONTEXT;
        goto result;
  	}

	if(input_data_addr == NULL){
        goto final;
    }

	remain_length = rArg.data_length;

	CHECK_ALLOC(tzArg,sizeof(rArg),ret,final);
	x_memcpy(tzArg,&rArg,sizeof(rArg));
	tzArg->result	  = (OEMCryptoResult* )PHYSICAL((UPTR)result );
	tzArg->data_addr  = (uint8_t *)PHYSICAL((UPTR)input_data_addr);
	tzArg->out_buffer = (OEMCrypto_DestBufferDesc_64BIT *)PHYSICAL((UPTR)out_buffer);


	while(remain_length !=0){
		if(remain_length > MAX_BSP_ALLOC_SIZE){
				cpy_length = MAX_BSP_ALLOC_SIZE;
		}else{
				cpy_length = remain_length ;
		}

		COPY_FROM_USER_ARG_K(pdata_addr_cur, *input_data_addr , cpy_length);

		remain_length -= cpy_length;
		pdata_addr_cur += cpy_length;

		tzArg->data_length	= cpy_length;

		 switch (out_buffer->type) {
            case OEMCrypto_BufferType_Secure:
                out_buffer->buffer.secure.max_length = cpy_length;
                break;
            default:
                break;
        }

		TZ_CACHE_STR(input_data_addr	 , cpy_length);
		TZ_CACHE_STR(out_buffer , sizeof(OEMCrypto_DestBufferDesc_64BIT));
		TZ_CACHE_STR(result , sizeof(OEMCryptoResult));

		TZ_OEMCrypto_CopyBuffer(tzArg, sizeof(rArg));

		TZ_CACHE_END(input_data_addr	 , cpy_length);
		TZ_CACHE_END(out_buffer , sizeof(OEMCrypto_DestBufferDesc_64BIT));
		TZ_CACHE_END(result , sizeof(OEMCryptoResult));


		switch (out_buffer->type) {
			case OEMCrypto_BufferType_Secure:
					out_buffer->buffer.secure.offset += cpy_length;
			default:
					break;
		}

		if(*result != OEMCrypto_SUCCESS)
        {
            MTDMX_PRINT("_MTDRM_WV_OEMCrypto_CopyBuffer fail \n");
            break;
        }

	}

result:
	COPY_TO_USER_ARG_K(presult, *result, sizeof(OEMCryptoResult));

final:
	//if(result!=NULL)
	//	MTDMX_PRINT("MTAL: %s exit, *result=%d \n",__FUNCTION__,*result);
	CHECK_FREE(tzArg);
	CHECK_FREE(result);
	CHECK_FREE(out_buffer);

	x_sema_unlock(_hWidevineSema);
	return ret;
}

MT_RESULT_T _MTDRM_WV_OEMCrypto_QueryKeyControl(unsigned long arg)
{
    OEMCryptoResult *result=NULL, *presult = NULL;
	QueryKeyControlArg_64BIT rArg  = {{0},0,{0},0,{0},{0}};
	QueryKeyControlArg_64BIT *tzArg = NULL;
	uint8_t *key_id = NULL, *pkey_id = NULL;
	uint8_t *key_control_block = NULL, *pkey_control_block  = NULL;
    UINT32 *key_control_block_length = NULL, *pkey_control_block_length = NULL;
	MT_RESULT_T ret 		  = MTR_OK;
	UINT32 invDataLen;

	MTDMX_PRINT("MTAL: %s entry \n",__FUNCTION__);

	if (!u1Initialized)
	{
		x_sema_create(&_hWidevineSema, X_SEMA_TYPE_BINARY, X_SEMA_STATE_UNLOCK);
		u1Initialized = 1 ;
	}

	x_sema_lock(_hWidevineSema, X_SEMA_OPTION_WAIT) ;

	CHECK_ALLOC(result,sizeof(OEMCryptoResult),ret,final);
	*result = OEMCrypto_ERROR_UNKNOWN_FAILURE;

	CHECK_ALLOC(key_control_block_length,sizeof(UINT32),ret,final);

	USR_SPACE_ACCESS_VALIDATE_ARG_K(arg, sizeof(QueryKeyControlArg_64BIT));
	COPY_FROM_USER_ARG_K(arg , rArg ,sizeof(QueryKeyControlArg_64BIT));

#ifdef CONFIG_COMPAT
	if (is_compat_task())
	{
		presult = (OEMCryptoResult*)(compat_ptr(rArg.addr_r));
		pkey_id = (uint8_t*)(compat_ptr(rArg.addr_ki));
		pkey_control_block = (uint8_t*)(compat_ptr(rArg.addr_kcb));
		pkey_control_block_length = (UINT32*)(compat_ptr(rArg.addr_kcbl));
	}
	else
#endif
	{
		presult = (OEMCryptoResult*)rArg.result;
		pkey_id = (uint8_t*)rArg.key_id;
		pkey_control_block = (uint8_t*)rArg.key_control_block;
		pkey_control_block_length = (UINT32*)rArg.key_control_block_length;
	}

	USR_SPACE_ACCESS_VALIDATE_ARG_K(presult, sizeof(OEMCryptoResult));
	USR_SPACE_ACCESS_VALIDATE_ARG_K(pkey_id, rArg.key_id_length);

	CHECK_ALLOC(key_id ,rArg.key_id_length, ret, final);
	COPY_FROM_USER_ARG_K(pkey_id , *key_id ,rArg.key_id_length);

 	USR_SPACE_ACCESS_VALIDATE_ARG_K(pkey_control_block_length, sizeof(UINT32));
    COPY_FROM_USER_ARG_K(pkey_control_block_length,*key_control_block_length , sizeof(UINT32));

	USR_SPACE_ACCESS_VALIDATE_ARG_K(pkey_control_block, *key_control_block_length );

    if(*key_control_block_length != 0 ){
        CHECK_ALLOC(key_control_block ,*key_control_block_length, ret, final);
    }

	CHECK_ALLOC(tzArg,sizeof(rArg),ret,final);
	x_memcpy(tzArg,&rArg,sizeof(rArg));
	tzArg->result = (OEMCryptoResult* )PHYSICAL((UPTR)result);;
	tzArg->key_id = (uint8_t *)PHYSICAL((UPTR)key_id);
	tzArg->key_control_block	   = (uint8_t * )PHYSICAL((UPTR)key_control_block );
	tzArg->key_control_block_length = (UINT32 *)PHYSICAL((UPTR)key_control_block_length);

	invDataLen = *key_control_block_length;

	TZ_CACHE_STR(key_id , rArg.key_id_length);
	TZ_CACHE_STR(result , sizeof(OEMCryptoResult));
    TZ_CACHE_STR(key_control_block , invDataLen);
    TZ_CACHE_STR(key_control_block_length , sizeof(UINT32));
	TZ_OEMCrypto_QueryKeyControl(tzArg, sizeof(rArg));
	TZ_CACHE_END(key_id , rArg.key_id_length);
	TZ_CACHE_END(result , sizeof(OEMCryptoResult));
    TZ_CACHE_END(key_control_block , invDataLen);
	TZ_CACHE_END(key_control_block_length	, sizeof(UINT32));

    if(*result == OEMCrypto_SUCCESS)
    {
        COPY_TO_USER_ARG_K(pkey_control_block , *key_control_block , *key_control_block_length);
    }
	COPY_TO_USER_ARG_K(pkey_control_block_length , *key_control_block_length , sizeof(UINT32));
	COPY_TO_USER_ARG_K(presult, *result, sizeof(OEMCryptoResult));

final:
	if(result!=NULL)
		MTDMX_PRINT("MTAL: %s exit, *result=%d \n",__FUNCTION__,*result);
	CHECK_FREE(key_id);
	CHECK_FREE(tzArg);
	CHECK_FREE(result);
	CHECK_FREE(key_control_block_length);
    CHECK_FREE(key_control_block);
	x_sema_unlock(_hWidevineSema);
	return ret;
}

MT_RESULT_T _MTDRM_WV_OEMCrypto_ForceDeleteUsageEntry(unsigned long arg)
{
	MT_RESULT_T ret = MTR_OK;
	ForceDeleteUsageEntryArg_64BIT rArg	 = {{0},{0},0};
	ForceDeleteUsageEntryArg_64BIT *tzArg = NULL;
    OEMCryptoResult *result=NULL, *presult = NULL;
	uint8_t *pst = NULL, *ppst = NULL;
	//int i;

	MTDMX_PRINT("MTAL: %s entry \n",__FUNCTION__);

	if (!u1Initialized)
	{
		x_sema_create(&_hWidevineSema, X_SEMA_TYPE_BINARY, X_SEMA_STATE_UNLOCK);
		u1Initialized = 1 ;
	}

	x_sema_lock(_hWidevineSema, X_SEMA_OPTION_WAIT) ;
    RPMB_LOCK();

	CHECK_ALLOC(result,sizeof(OEMCryptoResult),ret,final);
	*result = OEMCrypto_ERROR_UNKNOWN_FAILURE;

	USR_SPACE_ACCESS_VALIDATE_ARG_K(arg, sizeof(ForceDeleteUsageEntryArg_64BIT));
	COPY_FROM_USER_ARG_K(arg,rArg , sizeof(ForceDeleteUsageEntryArg_64BIT));

#ifdef CONFIG_COMPAT
		if (is_compat_task())
		{
			presult = (OEMCryptoResult*)(compat_ptr(rArg.addr_r));
			ppst = (uint8_t*)(compat_ptr(rArg.addr_p));
		}
		else
#endif
		{
			presult = (OEMCryptoResult*)rArg.result;
			ppst = (uint8_t*)rArg.pst;
		}

	USR_SPACE_ACCESS_VALIDATE_ARG_K(presult, sizeof(OEMCryptoResult));

	if (ppst == NULL)
        goto final;

	USR_SPACE_ACCESS_VALIDATE_ARG_K(ppst, rArg.pst_length);

	CHECK_ALLOC(pst ,rArg.pst_length, ret, final);
	COPY_FROM_USER_ARG_K(ppst , *pst ,rArg.pst_length);

	CHECK_ALLOC(tzArg,sizeof(rArg),ret,final);
	x_memcpy(tzArg,&rArg,sizeof(rArg));

	tzArg->result		   = (OEMCryptoResult* )PHYSICAL((UPTR)result);;
	tzArg->pst			   = (uint8_t *)PHYSICAL((UPTR)pst);

	TZ_CACHE_STR(pst	, rArg.pst_length);
	TZ_CACHE_STR(result , sizeof(OEMCryptoResult));
	TZ_OEMCrypto_ForceDeleteUsageEntry(tzArg, sizeof(rArg));
	TZ_CACHE_END(pst	, rArg.pst_length);
	TZ_CACHE_END(result , sizeof(OEMCryptoResult));

	COPY_TO_USER_ARG_K(presult, *result, sizeof(OEMCryptoResult));

final:
	if(result!=NULL)
		MTDMX_PRINT("MTAL: %s exit, *result=%d \n",__FUNCTION__,*result);

	CHECK_FREE(tzArg);
	CHECK_FREE(result);
	CHECK_FREE(pst);

	x_sema_unlock(_hWidevineSema);
	return ret;
}

MT_RESULT_T _MTDRM_WV_OEMCrypto_LoadTestKeybox(unsigned long arg)
{
	MT_RESULT_T ret = MTR_OK;
	OEMCryptoResult *result=NULL;

	MTDMX_PRINT("MTAL: %s entry \n",__FUNCTION__);

	if (!u1Initialized)
	{
		x_sema_create(&_hWidevineSema, X_SEMA_TYPE_BINARY, X_SEMA_STATE_UNLOCK);
		u1Initialized = 1 ;
	}

	x_sema_lock(_hWidevineSema, X_SEMA_OPTION_WAIT) ;

	CHECK_ALLOC(result,sizeof(OEMCryptoResult),ret,final);
	*result = OEMCrypto_ERROR_UNKNOWN_FAILURE;

 	TZ_OEMCrypto_LoadTestKeybox(result , sizeof(OEMCryptoResult));

	USR_SPACE_ACCESS_VALIDATE_ARG_K(arg , sizeof(OEMCryptoResult));
	COPY_TO_USER_ARG_K(arg , *result , sizeof(OEMCryptoResult));

final:
	if(result!=NULL)
		MTDMX_PRINT("MTAL: %s exit, *result=%d \n",__FUNCTION__,*result);

	CHECK_FREE(result);

	x_sema_unlock(_hWidevineSema);
	return ret;
}

MT_RESULT_T _MTDRM_WV_OEMCrypto_LoadTestRSAKey(unsigned long arg)
{
	MT_RESULT_T ret = MTR_OK;
	OEMCryptoResult *result=NULL;

	MTDMX_PRINT("MTAL: %s entry \n",__FUNCTION__);

	if (!u1Initialized)
	{
		x_sema_create(&_hWidevineSema, X_SEMA_TYPE_BINARY, X_SEMA_STATE_UNLOCK);
		u1Initialized = 1 ;
	}

	x_sema_lock(_hWidevineSema, X_SEMA_OPTION_WAIT) ;

	CHECK_ALLOC(result,sizeof(OEMCryptoResult),ret,final);
	*result = OEMCrypto_ERROR_UNKNOWN_FAILURE;

	TZ_OEMCrypto_LoadTestRSAKey(result , sizeof(OEMCryptoResult));

	USR_SPACE_ACCESS_VALIDATE_ARG_K(arg , sizeof(OEMCryptoResult));
	COPY_TO_USER_ARG_K(arg , *result , sizeof(OEMCryptoResult));

final:
	if(result!=NULL)
		MTDMX_PRINT("MTAL: %s exit, *result=%d \n",__FUNCTION__,*result);

	CHECK_FREE(result);

	x_sema_unlock(_hWidevineSema);
	return ret;
}

MT_RESULT_T  _MTDRM_WV_OEMCrypto_SetEntitlementKey(unsigned long arg)
{
#ifdef CC_WIDEVINE_TZ_ENABLE
    MT_RESULT_T ret = MTR_OK;
    SetEntitlementKeyArg_64BIT rArg    = {{0},{0},0};
    SetEntitlementKeyArg_64BIT *tzArg  = NULL;
    OEMCryptoResult            *result=NULL, *presult = NULL;
    uint8_t                    *emmKey=NULL, *pemmKey = NULL;

	MTDMX_PRINT("MTAL: %s entry \n",__FUNCTION__);

    if (!u1Initialized)
    {
        x_sema_create(&_hWidevineSema, X_SEMA_TYPE_BINARY, X_SEMA_STATE_UNLOCK);
        u1Initialized = 1 ;
    }

    x_sema_lock(_hWidevineSema, X_SEMA_OPTION_WAIT) ;

    CHECK_ALLOC(result,sizeof(OEMCryptoResult),ret,final);

    USR_SPACE_ACCESS_VALIDATE_ARG_K(arg, sizeof(SetEntitlementKeyArg_64BIT));
    COPY_FROM_USER_ARG_K(arg , rArg,sizeof(SetEntitlementKeyArg_64BIT));

#ifdef CONFIG_COMPAT
	if (is_compat_task())
	{
		presult = (OEMCryptoResult*)(compat_ptr(rArg.addr_r));
		pemmKey = (uint8_t*)(compat_ptr(rArg.addr_e));
	}
	else
#endif
	{
		presult = (OEMCryptoResult*)rArg.result;
		pemmKey = (uint8_t*)rArg.emmKey;
	}

    if (rArg.emmKeyLength != KEY_SIZE) {
        *result = OEMCrypto_ERROR_KEYBOX_INVALID;
        goto result;
    }

	USR_SPACE_ACCESS_VALIDATE_ARG_K(presult, sizeof(OEMCryptoResult));
    USR_SPACE_ACCESS_VALIDATE_ARG_K(pemmKey , rArg.emmKeyLength);
    CHECK_ALLOC(emmKey,rArg.emmKeyLength, ret, final);
    COPY_FROM_USER_ARG_K(pemmKey , *emmKey , rArg.emmKeyLength);

    CHECK_ALLOC(tzArg,sizeof(rArg),ret,final);
    x_memcpy(tzArg,&rArg,sizeof(rArg));
    tzArg->result    = (OEMCryptoResult* )PHYSICAL((UPTR)result );
    tzArg->emmKey = (uint8_t *)PHYSICAL((UPTR)emmKey);

    TZ_CACHE_STR(emmKey , rArg.emmKeyLength);
    TZ_CACHE_STR(result , sizeof(OEMCryptoResult));

    TZ_OEMCrypto_SetEntitlementKey(tzArg, sizeof(rArg));

    TZ_CACHE_END(emmKey , rArg.emmKeyLength);
    TZ_CACHE_END(result , sizeof(OEMCryptoResult));

result:
    COPY_TO_USER_ARG_K(presult, *result, sizeof(OEMCryptoResult));

final:
	if(result!=NULL)
		MTDMX_PRINT("MTAL: %s exit, *result=%d \n",__FUNCTION__,*result);

    CHECK_FREE(tzArg);
    CHECK_FREE(result);
    CHECK_FREE(emmKey);

    x_sema_unlock(_hWidevineSema);
    return ret;
#else
    return MTR_ERR_INV;
#endif
}

MT_RESULT_T  _MTDRM_WV_OEMCrypto_DeriveControlWord(unsigned long arg)
{
#ifdef CC_WIDEVINE_TZ_ENABLE
    MT_RESULT_T ret = MTR_OK;
    DeriveControlWordArg_64BIT rArg    = {{0},{0},0,{0}};
    DeriveControlWordArg_64BIT *tzArg  = NULL;
    OEMCryptoResult            *result=NULL, *presult = NULL;
    uint8_t                    *ecm=NULL, *pecm       = NULL;
    uint32_t                   *flags=NULL, *pflags   = NULL;

	MTDMX_PRINT("MTAL: %s entry \n",__FUNCTION__);

    if (!u1Initialized)
    {
        x_sema_create(&_hWidevineSema, X_SEMA_TYPE_BINARY, X_SEMA_STATE_UNLOCK);
        u1Initialized = 1 ;
    }

    x_sema_lock(_hWidevineSema, X_SEMA_OPTION_WAIT) ;

    CHECK_ALLOC(result,sizeof(OEMCryptoResult),ret,final);

    *result = OEMCrypto_ERROR_UNKNOWN_FAILURE;

    USR_SPACE_ACCESS_VALIDATE_ARG_K(arg, sizeof(DeriveControlWordArg_64BIT));
    COPY_FROM_USER_ARG_K(arg , rArg,sizeof(DeriveControlWordArg_64BIT));

#ifdef CONFIG_COMPAT
	if (is_compat_task())
	{
		presult = (OEMCryptoResult*)(compat_ptr(rArg.addr_r));
		pecm = (uint8_t*)(compat_ptr(rArg.addr_e));
		pflags = (uint32_t*)(compat_ptr(rArg.addr_f));
	}
	else
#endif
	{
		presult = (OEMCryptoResult*)rArg.result;
		pecm = (uint8_t*)rArg.ecm;
		pflags = (uint32_t*)rArg.flags;
	}

	if (rArg.length != CTRL_WORD_SIZE) {
	    *result = OEMCrypto_ERROR_NO_CW;
	    goto result;
    }

    USR_SPACE_ACCESS_VALIDATE_ARG_K(pecm , rArg.length);
    CHECK_ALLOC(ecm,rArg.length, ret, final);
    COPY_FROM_USER_ARG_K(pecm , *ecm , rArg.length);

    USR_SPACE_ACCESS_VALIDATE_ARG_K(pflags , FLAGS_SIZE);
    CHECK_ALLOC(flags,FLAGS_SIZE, ret, final);

    CHECK_ALLOC(tzArg,sizeof(rArg),ret,final);
    x_memcpy(tzArg,&rArg,sizeof(rArg));

    tzArg->result    = (OEMCryptoResult* )PHYSICAL((UPTR)result );
    tzArg->ecm       = (uint8_t *)PHYSICAL((UPTR)ecm);
    tzArg->flags     = (uint32_t *)PHYSICAL((UPTR)flags);

    TZ_CACHE_STR(result , sizeof(OEMCryptoResult));
    TZ_CACHE_STR(ecm    , rArg.length);
    TZ_CACHE_STR(flags  , FLAGS_SIZE);

    TZ_OEMCrypto_DeriveControlWord(tzArg, sizeof(rArg));

    TZ_CACHE_END(result , sizeof(OEMCryptoResult));
    TZ_CACHE_END(ecm    , rArg.length);
    TZ_CACHE_END(flags  , FLAGS_SIZE);

    if(*result == OEMCrypto_SUCCESS)
    {
        COPY_TO_USER_ARG_K(pflags , *flags , FLAGS_SIZE);
    }

result:
	USR_SPACE_ACCESS_VALIDATE_ARG_K(presult, sizeof(OEMCryptoResult));
    COPY_TO_USER_ARG_K(presult, *result, sizeof(OEMCryptoResult));

final:
	if(result!=NULL)
		MTDMX_PRINT("MTAL: %s exit, *result=%d \n",__FUNCTION__,*result);

    CHECK_FREE(tzArg);
    CHECK_FREE(result);
    CHECK_FREE(ecm);
    CHECK_FREE(flags);

    x_sema_unlock(_hWidevineSema);
    return ret;
#else
    return MTR_ERR_INV;
#endif
}

MT_RESULT_T  _MTDRM_WV_OEMCrypto_DecryptVideo(unsigned long arg)
{
#ifdef CC_WIDEVINE_TZ_ENABLE
    MT_RESULT_T ret = MTR_OK;
    DecryptVideoArg_64BIT rArg          = {{0},{0},{0},0,0,0,{0}};
    DecryptVideoArg_64BIT *tzArg        = NULL;
    OEMCryptoResult       *result=NULL, *presult   = NULL;
    uint8_t               *iv=NULL, *piv           = NULL;
	uint8_t               *pinput = NULL;
    uint32_t              *outputLength=NULL, *poutputLength = NULL;
    UINT32 cpyLen=0;
    UINT32 remainLen=0;
    UINT32 outLen=0;

	//MTDMX_PRINT("MTAL: %s entry \n",__FUNCTION__);

    if (!u1Initialized)
    {
        x_sema_create(&_hWidevineSema, X_SEMA_TYPE_BINARY, X_SEMA_STATE_UNLOCK);
        u1Initialized = 1 ;
    }

    x_sema_lock(_hWidevineSema, X_SEMA_OPTION_WAIT) ;

    CHECK_ALLOC(result,sizeof(OEMCryptoResult),ret,final);

    USR_SPACE_ACCESS_VALIDATE_ARG_K(arg, sizeof(DecryptVideoArg_64BIT));
    COPY_FROM_USER_ARG_K(arg , rArg,sizeof(DecryptVideoArg_64BIT));

#ifdef CONFIG_COMPAT
	if (is_compat_task())
	{
		presult = (OEMCryptoResult*)(compat_ptr(rArg.addr_r));
		piv = (uint8_t*)(compat_ptr(rArg.addr_iv));
		pinput = (uint8_t*)(compat_ptr(rArg.addr_i));
		poutputLength = (uint32_t*)(compat_ptr(rArg.addr_o));
	}
	else
#endif
	{
		presult = (OEMCryptoResult*)rArg.result;
		piv = (uint8_t*)rArg.iv;
		pinput = (uint8_t*)rArg.input;
		poutputLength = (uint32_t*)rArg.outputLength;
	}

	USR_SPACE_ACCESS_VALIDATE_ARG_K(presult, sizeof(OEMCryptoResult));
    if(NULL != piv)
    {
        USR_SPACE_ACCESS_VALIDATE_ARG_K(piv , KEY_IV_SIZE);
        CHECK_ALLOC(iv , KEY_IV_SIZE , ret , final);
        COPY_FROM_USER_ARG_K(piv , *iv , KEY_IV_SIZE );
    }

    USR_SPACE_ACCESS_VALIDATE_ARG_K(pinput , rArg.inputLength);

    if(input_data_addr==NULL){
        input_data_addr = x_mem_alloc(MAX_BSP_ALLOC_SIZE);
    }

    if(input_data_addr==NULL){
        goto final;
    }

    remainLen  = rArg.inputLength;

    USR_SPACE_ACCESS_VALIDATE_ARG_K(poutputLength , sizeof(uint32_t));
    CHECK_ALLOC(outputLength,sizeof(uint32_t), ret, final);
    COPY_FROM_USER_ARG_K(poutputLength , *outputLength , sizeof(uint32_t));

    CHECK_ALLOC(tzArg,sizeof(rArg),ret,final);
    x_memcpy(tzArg,&rArg,sizeof(rArg));

    tzArg->result       = (OEMCryptoResult* )PHYSICAL((UPTR)result );
    tzArg->iv           = (NULL==iv)? NULL : (uint8_t *)PHYSICAL((UPTR)iv);
    tzArg->input        = (uint8_t *)PHYSICAL((UPTR)input_data_addr);
    tzArg->outputLength = (uint32_t *)PHYSICAL((UPTR)outputLength);

    while(remainLen !=0){

        if(remainLen > MAX_BSP_ALLOC_SIZE){
            if((remainLen - MAX_BSP_ALLOC_SIZE) < 256){
                cpyLen = 16*1024;
            }else{
                cpyLen = MAX_BSP_ALLOC_SIZE;
            }
        }else{
            cpyLen = remainLen;
        }
        *outputLength = cpyLen;

        remainLen -= cpyLen;
        COPY_FROM_USER_ARG_K(pinput+outLen , *input_data_addr  , cpyLen);

        tzArg->inputLength  = cpyLen;

        TZ_CACHE_STR(result       , sizeof(OEMCryptoResult));
        TZ_CACHE_STR(iv           , KEY_IV_SIZE);
        TZ_CACHE_STR(input_data_addr    , cpyLen);
        TZ_CACHE_STR(outputLength , sizeof(uint32_t));

        TZ_OEMCrypto_DecryptVideo(tzArg, sizeof(rArg));

        TZ_CACHE_END(result       , sizeof(OEMCryptoResult));
        TZ_CACHE_END(iv           , KEY_IV_SIZE);
        TZ_CACHE_END(input_data_addr    , cpyLen);
        TZ_CACHE_END(outputLength , sizeof(uint32_t));

        outLen += cpyLen;
        tzArg->output_offset += cpyLen;

        if(*result != OEMCrypto_SUCCESS)
        {
            break;
        }
    }

    if(*result == OEMCrypto_SUCCESS)
    {
        if(iv !=NULL)
            COPY_TO_USER_ARG_K(piv           , *iv , KEY_IV_SIZE);
        COPY_TO_USER_ARG_K(poutputLength , outLen , sizeof(uint32_t));
    }

    COPY_TO_USER_ARG_K(presult , *result , sizeof(OEMCryptoResult));
final:
	//if(result!=NULL)
	//	MTDMX_PRINT("MTAL: %s exit, *result=%d \n",__FUNCTION__,*result);

    CHECK_FREE(tzArg);
    CHECK_FREE(result);
    CHECK_FREE(iv);
    CHECK_FREE(outputLength);

    x_sema_unlock(_hWidevineSema);
    return ret;
#else
    return MTR_ERR_INV;
#endif
}

MT_RESULT_T  _MTDRM_WV_OEMCrypto_DecryptAudio(unsigned long arg)
{
#ifdef CC_WIDEVINE_TZ_ENABLE
    MT_RESULT_T ret = MTR_OK;
    DecryptAudioArg_64BIT rArg          = {{0},{0},{0},0,{0},{0}};
    DecryptAudioArg_64BIT *tzArg        = NULL;
    OEMCryptoResult       *result=NULL, *presult   = NULL;
    uint8_t               *iv=NULL, *piv           = NULL;
	uint8_t               *pinput     = NULL;
	uint8_t               *poutput    = NULL;
    uint32_t              *outputLength=NULL, *poutputLength = NULL;
    UINT32 cpyLen=0;
    UINT32 remainLen=0;
    UINT32 outLen=0;

	//MTDMX_PRINT("MTAL: %s entry \n",__FUNCTION__);

    if (!u1Initialized)
    {
        x_sema_create(&_hWidevineSema, X_SEMA_TYPE_BINARY, X_SEMA_STATE_UNLOCK);
        u1Initialized = 1 ;
    }

    x_sema_lock(_hWidevineSema, X_SEMA_OPTION_WAIT) ;

    CHECK_ALLOC(result,sizeof(OEMCryptoResult),ret,final);

    USR_SPACE_ACCESS_VALIDATE_ARG_K(arg, sizeof(DecryptAudioArg_64BIT));
    COPY_FROM_USER_ARG_K(arg , rArg,sizeof(DecryptAudioArg_64BIT));

#ifdef CONFIG_COMPAT
	if (is_compat_task())
	{
		presult = (OEMCryptoResult*)(compat_ptr(rArg.addr_r));
		piv = (uint8_t*)(compat_ptr(rArg.addr_iv));
		pinput = (uint8_t*)(compat_ptr(rArg.addr_i));
		poutput = (uint8_t*)(compat_ptr(rArg.addr_o));
		poutputLength = (uint32_t*)(compat_ptr(rArg.addr_ol));
	}
	else
#endif
	{
		presult = (OEMCryptoResult*)rArg.result;
		piv = (uint8_t*)rArg.iv;
		pinput = (uint8_t*)rArg.input;
		poutput = (uint8_t*)rArg.output;
		poutputLength = (uint32_t*)rArg.outputLength;
	}

	USR_SPACE_ACCESS_VALIDATE_ARG_K(presult, sizeof(OEMCryptoResult));
    if(NULL != piv)
    {
        USR_SPACE_ACCESS_VALIDATE_ARG_K(piv , KEY_IV_SIZE);
        CHECK_ALLOC(iv , KEY_IV_SIZE , ret , final);
        COPY_FROM_USER_ARG_K(piv , *iv , KEY_IV_SIZE );
    }

    USR_SPACE_ACCESS_VALIDATE_ARG_K(pinput , rArg.inputLength);

    remainLen  = rArg.inputLength;

    if(input_data_addr==NULL){
        input_data_addr = x_mem_alloc(MAX_BSP_ALLOC_SIZE);
    }
    if(input_data_addr==NULL){
        goto final;
    }

    USR_SPACE_ACCESS_VALIDATE_ARG_K(poutputLength , sizeof(uint32_t));
    CHECK_ALLOC(outputLength,sizeof(uint32_t), ret, final);
    COPY_FROM_USER_ARG_K(poutputLength , *outputLength , sizeof(uint32_t));

    *outputLength = rArg.inputLength;

    USR_SPACE_ACCESS_VALIDATE_ARG_K(poutput , *outputLength);
    if(output_data_addr ==NULL){
        output_data_addr = x_mem_alloc(MAX_BSP_ALLOC_SIZE);
    }
    if(output_data_addr==NULL){
        goto final;
    }

    CHECK_ALLOC(tzArg,sizeof(rArg),ret,final);
    x_memcpy(tzArg,&rArg,sizeof(rArg));

    tzArg->result       = (OEMCryptoResult* )PHYSICAL((UPTR)result );
    tzArg->iv           = (NULL==iv)? NULL : (uint8_t *)PHYSICAL((UPTR)iv);
    tzArg->input        = (uint8_t *)PHYSICAL((UPTR)input_data_addr);
    tzArg->output       = (uint8_t *)PHYSICAL((UPTR)output_data_addr);
    tzArg->outputLength = (uint32_t *)PHYSICAL((UPTR)outputLength);

    while(remainLen !=0){

        if(remainLen > MAX_BSP_ALLOC_SIZE){
            if((remainLen - MAX_BSP_ALLOC_SIZE) < 16){
                cpyLen = 16*1024;
            }else{
                cpyLen = MAX_BSP_ALLOC_SIZE;
            }
        }else{
            cpyLen = remainLen;
        }

        remainLen -= cpyLen;
        COPY_FROM_USER_ARG_K(pinput+outLen , *input_data_addr  , cpyLen);

        *outputLength =cpyLen;
        tzArg->inputLength  = cpyLen;

        TZ_CACHE_STR(result       , sizeof(OEMCryptoResult));
        TZ_CACHE_STR(iv           , KEY_IV_SIZE);
        TZ_CACHE_STR(input_data_addr        , rArg.inputLength);
        TZ_CACHE_STR(output_data_addr       , cpyLen);
        TZ_CACHE_STR(outputLength , sizeof(uint32_t));

        TZ_OEMCrypto_DecryptAudio(tzArg, sizeof(rArg));

        TZ_CACHE_END(result       , sizeof(OEMCryptoResult));
        TZ_CACHE_END(iv           , KEY_IV_SIZE);
        TZ_CACHE_END(input_data_addr        , rArg.inputLength);
        TZ_CACHE_END(output_data_addr       , cpyLen);
        TZ_CACHE_END(outputLength , sizeof(uint32_t));

        if(*result == OEMCrypto_SUCCESS)
        {
            COPY_TO_USER_ARG_K(poutput+outLen , *output_data_addr  , cpyLen);
            outLen += cpyLen;
        }
        else
        {
            break;
        }
    }

    if(*result == OEMCrypto_SUCCESS)
    {
        COPY_TO_USER_ARG_K(poutputLength , rArg.inputLength, sizeof(uint32_t));
        if(iv !=NULL)
            COPY_TO_USER_ARG_K(piv           , *iv , KEY_IV_SIZE);
    }

    COPY_TO_USER_ARG_K(presult , *result , sizeof(OEMCryptoResult));
final:
	//if(result!=NULL)
	//	MTDMX_PRINT("MTAL: %s exit, *result=%d \n",__FUNCTION__,*result);

    CHECK_FREE(tzArg);
    CHECK_FREE(result);
    CHECK_FREE(iv);
    CHECK_FREE(outputLength);

    x_sema_unlock(_hWidevineSema);
    return ret;
#else
    return MTR_ERR_INV;
#endif
}
