blob: bda89b66b40561d29b5eab22955909afdc024eee [file] [log] [blame]
/** @addtogroup MCD_MCDIMPL_DAEMON_KERNEL
* @{
* @file
*
* MobiCore Driver Kernel Module Interface.
*
* <!-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. The name of the author may not be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
*/
#include <cstdlib>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <inttypes.h>
#include <cstring>
#include "McTypes.h"
#include "mcDrvModuleApi.h"
#include "mcVersionHelper.h"
#include "CMcKMod.h"
#define LOG_TAG "McDaemon"
#include "log.h"
//------------------------------------------------------------------------------
MC_CHECK_VERSION(MCDRVMODULEAPI,0,1);
// TODO: rename this to mapWsm
//------------------------------------------------------------------------------
int CMcKMod::mmap(
uint32_t len,
uint32_t *pHandle,
addr_t *pVirtAddr,
addr_t *pPhysAddr,
bool *pMciReuse
) {
int ret = 0;
do
{
LOG_I("mmap(): len=%d, mci_reuse=%x", len, *pMciReuse);
if (!isOpen())
{
LOG_E("no connection to kmod");
ret = ERROR_KMOD_NOT_OPEN;
break;
}
// TODO: add type parameter to distinguish between non-freeing TCI, MCI and others
addr_t virtAddr = ::mmap(0, len, PROT_READ | PROT_WRITE, MAP_SHARED,
fdKMod, *pMciReuse ? MC_DRV_KMOD_MMAP_MCI
: MC_DRV_KMOD_MMAP_WSM);
if (MAP_FAILED == virtAddr)
{
LOG_E("mmap() failed with errno: %d", errno);
ret = ERROR_MAPPING_FAILED;
break;
}
// mapping response data is in the buffer
struct mcMmapResp *pMmapResp = (struct mcMmapResp *) virtAddr;
*pMciReuse = pMmapResp->isReused;
LOG_I("mmap(): virtAddr=%p, handle=%d, physAddr=%p, isReused=%s",
virtAddr, pMmapResp->handle, (addr_t) (pMmapResp->physAddr),
pMmapResp->isReused ? "true" : "false");
if (NULL != pVirtAddr)
{
*pVirtAddr = virtAddr;
}
if (NULL != pHandle)
{
*pHandle = pMmapResp->handle;
}
if (NULL != pPhysAddr)
{
*pPhysAddr = (addr_t) (pMmapResp->physAddr);
}
// clean memory
memset(pMmapResp, 0, sizeof(*pMmapResp));
} while (0);
return ret;
}
//------------------------------------------------------------------------------
int CMcKMod::mapPersistent(
uint32_t len,
uint32_t *pHandle,
addr_t *pVirtAddr,
addr_t *pPhysAddr
) {
int ret = 0;
do
{
LOG_I("mapPersistent(): len=%d", len);
if (!isOpen())
{
LOG_E("no connection to kmod");
ret = ERROR_KMOD_NOT_OPEN;
break;
}
addr_t virtAddr = ::mmap(0, len, PROT_READ | PROT_WRITE, MAP_SHARED,
fdKMod, MC_DRV_KMOD_MMAP_PERSISTENTWSM);
if (MAP_FAILED == virtAddr)
{
LOG_E("mmap() failed with errno: %d", errno);
ret = ERROR_MAPPING_FAILED;
break;
}
// mapping response data is in the buffer
struct mcMmapResp *pMmapResp = (struct mcMmapResp *) virtAddr;
LOG_I("mapPersistent(): virtAddr=%p, handle=%d, physAddr=%p, isReused=%s",
virtAddr, pMmapResp->handle,
(addr_t) (pMmapResp->physAddr),
pMmapResp->isReused ? "true" : "false");
if (NULL != pVirtAddr)
{
*pVirtAddr = virtAddr;
}
if (NULL != pHandle)
{
*pHandle = pMmapResp->handle;
}
if (NULL != pPhysAddr)
{
*pPhysAddr = (addr_t) (pMmapResp->physAddr);
}
// clean memory
memset(pMmapResp, 0, sizeof(*pMmapResp));
} while (0);
return ret;
}
//------------------------------------------------------------------------------
int CMcKMod::read(
addr_t buffer,
uint32_t len
) {
int ret = 0;
do
{
if (!isOpen())
{
LOG_E("no connection to kmod");
ret = ERROR_KMOD_NOT_OPEN;
break;
}
ret = ::read(fdKMod, buffer, len);
if(-1 == ret)
{
LOG_E("read() failed with errno: %d", errno);
}
} while (0);
return ret;
}
//------------------------------------------------------------------------------
bool CMcKMod::waitSSIQ(
uint32_t *pCnt
) {
int ret = true;
do
{
uint32_t cnt;
int ret = read(&cnt, sizeof(cnt));
if (sizeof(cnt) != ret)
{
ret = false;
}
if (NULL != pCnt)
{
*pCnt = cnt;
}
} while (0);
return ret;
}
//------------------------------------------------------------------------------
int CMcKMod::fcInit(
addr_t mciBuffer,
uint32_t nqOffset,
uint32_t nqLength,
uint32_t mcpOffset,
uint32_t mcpLength
) {
int ret = 0;
do
{
if (!isOpen())
{
ret = ERROR_KMOD_NOT_OPEN;
break;
}
// Init MC with NQ and MCP buffer addresses
union mcIoCtlInitParams fcInitParams = {
// C++ does not support C99 designated initializers
/* .in = */{
/* .base = */(uint32_t) mciBuffer,
/* .nqOffset = */nqOffset,
/* .nqLength = */nqLength,
/* .mcpOffset = */mcpOffset,
/* .mcpLength = */mcpLength } };
ret = ioctl(fdKMod, MC_DRV_KMOD_IOCTL_FC_INIT, &fcInitParams);
if (ret != 0)
{
LOG_E("IOCTL_FC_INIT failed with ret = %d and errno = %d", ret, errno);
break;
}
} while (0);
return ret;
}
//------------------------------------------------------------------------------
int CMcKMod::fcInfo(
uint32_t extInfoId,
uint32_t *pState,
uint32_t *pExtInfo
) {
int ret = 0;
do
{
if (!isOpen())
{
LOG_E("no connection to kmod");
ret = ERROR_KMOD_NOT_OPEN;
break;
}
// Init MC with NQ and MCP buffer addresses
union mcIoCtlInfoParams fcInfoParams = {
// C++ does not support C99 designated initializers
/* .in = */{
/* .extInfoId = */extInfoId } };
ret = ioctl(fdKMod, MC_DRV_KMOD_IOCTL_FC_INFO, &fcInfoParams);
if (ret != 0)
{
LOG_E("IOCTL_FC_INFO failed with ret = %d and errno = %d", ret, errno);
break;
}
if (NULL != pState)
{
*pState = fcInfoParams.out.state;
}
if (NULL != pExtInfo)
{
*pExtInfo = fcInfoParams.out.extInfo;
}
} while (0);
return ret;
}
//------------------------------------------------------------------------------
int CMcKMod::fcYield(
void
) {
int ret = 0;
do
{
if (!isOpen())
{
LOG_E("no connection to kmod");
ret = ERROR_KMOD_NOT_OPEN;
break;
}
ret = ioctl(fdKMod, MC_DRV_KMOD_IOCTL_FC_YIELD, NULL);
if (ret != 0)
{
LOG_E("IOCTL_FC_YIELD failed with ret = %d and errno = %d", ret, errno);
break;
}
} while (0);
return ret;
}
//------------------------------------------------------------------------------
int CMcKMod::fcNSIQ(
void
) {
int ret = 0;
do
{
if (!isOpen())
{
LOG_E("no connection to kmod");
ret = ERROR_KMOD_NOT_OPEN;
break;
}
ret = ioctl(fdKMod, MC_DRV_KMOD_IOCTL_FC_NSIQ, NULL);
if (ret != 0)
{
LOG_E("IOCTL_FC_NSIQ failed with ret = %d and errno = %d", ret, errno);
break;
}
} while (0);
return ret;
}
//------------------------------------------------------------------------------
int CMcKMod::free(
uint32_t handle
) {
int ret = 0;
do
{
LOG_I("free(): handle=%d", handle);
if (!isOpen())
{
LOG_E("no connection to kmod");
ret = ERROR_KMOD_NOT_OPEN;
break;
}
union mcIoCtltoFreeParams freeParams = {
// C++ does not support c99 designated initializers
/* .in = */{
/* .handle = */(uint32_t) handle } };
ret = ioctl(fdKMod, MC_DRV_KMOD_IOCTL_FREE, &freeParams);
if (0 != ret)
{
LOG_E("IOCTL_FREE failed with ret = %d and errno = %d", ret, errno);
break;
}
} while (0);
return ret;
}
//------------------------------------------------------------------------------
int CMcKMod::registerWsmL2(
addr_t buffer,
uint32_t len,
uint32_t pid,
uint32_t *pHandle,
addr_t *pPhysWsmL2
) {
int ret = 0;
do
{
LOG_I("registerWsmL2(): buffer=%p, len=%d, pid=%d", buffer, len, pid);
if (!isOpen())
{
LOG_E("no connection to kmod");
ret = ERROR_KMOD_NOT_OPEN;
break;
}
union mcIoCtlAppRegWsmL2Params params = {
// C++ does not support C99 designated initializers
/* .in = */{
/* .buffer = */(uint32_t) buffer,
/* .len = */len,
/* .pid = */pid } };
ret = ioctl(fdKMod, MC_DRV_KMOD_IOCTL_APP_REGISTER_WSM_L2, &params);
if (0 != ret)
{
LOG_E("IOCTL_APP_REGISTER_WSM_L2 failed with ret = %d and errno = %d", ret, errno);
break;
}
LOG_I("WSM L2 phys=%x, handle=%d", params.out.physWsmL2Table,
params.out.handle);
if (NULL != pHandle)
{
*pHandle = params.out.handle;
}
if (NULL != pPhysWsmL2)
{
*pPhysWsmL2 = (addr_t) params.out.physWsmL2Table;
}
} while (0);
return ret;
}
//------------------------------------------------------------------------------
int CMcKMod::unregisterWsmL2(
uint32_t handle
) {
int ret = 0;
do
{
LOG_I("unregisterWsmL2(): handle=%d", handle);
if (!isOpen())
{
LOG_E("no connection to kmod");
ret = ERROR_KMOD_NOT_OPEN;
break;
}
struct mcIoCtlAppUnregWsmL2Params params = {
// C++ does not support c99 designated initializers
/* .in = */{
/* .handle = */handle } };
int ret = ioctl(fdKMod, MC_DRV_KMOD_IOCTL_APP_UNREGISTER_WSM_L2, &params);
if (0 != ret)
{
LOG_E("IOCTL_APP_UNREGISTER_WSM_L2 failed with ret = %d and errno = %d", ret, errno);
break;
}
} while (0);
return ret;
}
//------------------------------------------------------------------------------
int CMcKMod::fcExecute(
addr_t startAddr,
uint32_t areaLength
) {
int ret = 0;
union mcIoCtlFcExecuteParams params = {
/*.in =*/ {
/*.physStartAddr = */ (uint32_t)startAddr,
/*.length = */ areaLength
}
};
do
{
if (!isOpen())
{
LOG_E("no connection to kmod");
break;
}
ret = ioctl(fdKMod, MC_DRV_KMOD_IOCTL_FC_EXECUTE, &params);
if (ret != 0)
{
LOG_E("IOCTL_FC_EXECUTE failed with ret = %d and errno = %d", ret, errno);
break;
}
} while(0);
return ret;
}
//------------------------------------------------------------------------------
bool CMcKMod::checkKmodVersionOk(
void
) {
bool ret = false;
do
{
if (!isOpen())
{
LOG_E("no connection to kmod");
break;
}
struct mcIoCtlGetVersionParams params;
int ioret = ioctl(fdKMod, MC_DRV_KMOD_IOCTL_GET_VERSION, &params);
if (0 != ioret)
{
LOG_E("IOCTL_GET_VERSION failed with ret = %d and errno = %d", ret, errno);
break;
}
// Run-time check.
char* errmsg;
if (!checkVersionOkMCDRVMODULEAPI(params.out.kernelModuleVersion, &errmsg)) {
LOG_E("%s", errmsg);
break;
}
LOG_I("%s", errmsg);
ret = true;
} while (0);
return ret;
}
/** @} */