summaryrefslogtreecommitdiff
path: root/mobicore/MobiCoreDriverLib/Kernel/Platforms/Generic/CMcKMod.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'mobicore/MobiCoreDriverLib/Kernel/Platforms/Generic/CMcKMod.cpp')
-rw-r--r--mobicore/MobiCoreDriverLib/Kernel/Platforms/Generic/CMcKMod.cpp528
1 files changed, 528 insertions, 0 deletions
diff --git a/mobicore/MobiCoreDriverLib/Kernel/Platforms/Generic/CMcKMod.cpp b/mobicore/MobiCoreDriverLib/Kernel/Platforms/Generic/CMcKMod.cpp
new file mode 100644
index 0000000..0e57874
--- /dev/null
+++ b/mobicore/MobiCoreDriverLib/Kernel/Platforms/Generic/CMcKMod.cpp
@@ -0,0 +1,528 @@
+/*
+ * Copyright (c) 2013-2014 TRUSTONIC LIMITED
+ * All rights reserved.
+ *
+ * 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. Neither the name of the TRUSTONIC LIMITED 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.
+ */
+/**
+ * <t-base Driver Kernel Module Interface.
+ */
+#include <cstdlib>
+
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <cstring>
+
+#include "McTypes.h"
+#include "mc_linux.h"
+#include "mcVersionHelper.h"
+
+#include "CMcKMod.h"
+
+#include "log.h"
+
+//------------------------------------------------------------------------------
+MC_CHECK_VERSION(MCDRVMODULEAPI, 1, 1);
+
+//------------------------------------------------------------------------------
+mcResult_t CMcKMod::mapWsm(
+ uint32_t len,
+ uint32_t *pHandle,
+ addr_t *pVirtAddr)
+{
+ int ret = 0;
+ LOG_V(" mapWsm(): len=%d", len);
+
+ if (!isOpen()) {
+ LOG_E("no connection to kmod");
+ return MC_DRV_ERR_KMOD_NOT_OPEN;
+ }
+
+ // mapping response data is in the buffer
+ struct mc_ioctl_map mapParams = { len : len };
+
+ ret = ioctl(fdKMod, MC_IO_MAP_WSM, &mapParams);
+ if (ret != 0) {
+ LOG_ERRNO("ioctl MC_IO_MAP_WSM");
+ return MAKE_MC_DRV_KMOD_WITH_ERRNO(errno);
+ }
+
+ addr_t virtAddr = ::mmap(0, len, PROT_READ | PROT_WRITE, MAP_SHARED,
+ fdKMod, mapParams.phys_addr);
+ if (virtAddr == MAP_FAILED) {
+ LOG_ERRNO("mmap");
+ (void)ioctl(fdKMod, MC_IO_FREE, mapParams.handle);
+ return MAKE_MC_DRV_KMOD_WITH_ERRNO(errno);
+ }
+
+
+ LOG_V(" mapped to %p, handle=%d", virtAddr,
+ mapParams.handle);
+
+ if (pVirtAddr != NULL) {
+ *pVirtAddr = virtAddr;
+ }
+
+ if (pHandle != NULL) {
+ *pHandle = mapParams.handle;
+ }
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+mcResult_t CMcKMod::mapMCI(
+ uint32_t len,
+ addr_t *pVirtAddr,
+ bool *pReuse)
+{
+ LOG_I("Mapping MCI: len=%d", len);
+ // mapping response data is in the buffer
+ struct mc_ioctl_map mapParams = { len : len };
+
+ if (!isOpen()) {
+ LOG_E("no connection to kmod");
+ return MC_DRV_ERR_KMOD_NOT_OPEN;
+ }
+
+ int ret = ioctl(fdKMod, MC_IO_MAP_MCI, &mapParams);
+ if (ret != 0) {
+ LOG_ERRNO("ioctl MC_IO_MAP_MCI");
+ return MAKE_MC_DRV_KMOD_WITH_ERRNO(errno);
+ }
+
+ // MCI is defined as offset 0, so we do not pass the mapParams.phys_addr to mmap.
+ addr_t virtAddr = ::mmap(0, len, PROT_READ | PROT_WRITE, MAP_SHARED,
+ fdKMod, 0);
+ if (virtAddr == MAP_FAILED) {
+ LOG_ERRNO("mmap");
+ return MAKE_MC_DRV_KMOD_WITH_ERRNO(errno);
+ }
+
+ *pReuse = mapParams.reused;
+
+ LOG_V(" MCI mapped to %p, handle=%d, reused=%s",
+ (void *)virtAddr, mapParams.handle,
+ mapParams.reused ? "true" : "false");
+
+ if (pVirtAddr != NULL) {
+ *pVirtAddr = (void *)virtAddr;
+ }
+
+ return MC_DRV_OK;
+}
+
+//------------------------------------------------------------------------------
+int CMcKMod::read(addr_t buffer, uint32_t len)
+{
+ int ret = 0;
+
+ if (!isOpen()) {
+ LOG_E("no connection to kmod");
+ return MC_DRV_ERR_KMOD_NOT_OPEN;
+ }
+
+ ret = ::read(fdKMod, buffer, len);
+ if (ret == -1) {
+ LOG_ERRNO("read");
+ }
+ return ret;
+}
+
+
+//------------------------------------------------------------------------------
+bool CMcKMod::waitSSIQ(uint32_t *pCnt)
+{
+ uint32_t cnt;
+ if (read(&cnt, sizeof(cnt)) != sizeof(cnt)) {
+ return false;
+ }
+
+ if (pCnt != NULL) {
+ *pCnt = cnt;
+ }
+
+ return true;
+}
+
+
+//------------------------------------------------------------------------------
+int CMcKMod::fcInit(uint32_t nqLength, uint32_t mcpOffset, uint32_t mcpLength)
+{
+ int ret = 0;
+
+ if (!isOpen()) {
+ return MC_DRV_ERR_KMOD_NOT_OPEN;
+ }
+
+ // Init MC with NQ and MCP buffer addresses
+ struct mc_ioctl_init fcInitParams = {
+nq_length :
+ nqLength,
+mcp_offset :
+ mcpOffset,
+mcp_length :
+ mcpLength
+ };
+ ret = ioctl(fdKMod, MC_IO_INIT, &fcInitParams);
+ if (ret != 0) {
+ LOG_ERRNO("ioctl MC_IO_INIT");
+ }
+
+ return ret;
+}
+
+//------------------------------------------------------------------------------
+int CMcKMod::fcInfo(uint32_t extInfoId, uint32_t *pState, uint32_t *pExtInfo)
+{
+ int ret = 0;
+
+ if (!isOpen()) {
+ LOG_E("no connection to kmod");
+ return MC_DRV_ERR_KMOD_NOT_OPEN;
+ }
+
+ // Init MC with NQ and MCP buffer addresses
+ struct mc_ioctl_info fcInfoParams = { ext_info_id : extInfoId };
+ ret = ioctl(fdKMod, MC_IO_INFO, &fcInfoParams);
+ if (ret != 0) {
+ LOG_ERRNO("ioctl MC_IO_INFO");
+ return ret;
+ }
+
+ if (pState != NULL) {
+ *pState = fcInfoParams.state;
+ }
+
+ if (pExtInfo != NULL) {
+ *pExtInfo = fcInfoParams.ext_info;
+ }
+
+ return ret;
+}
+
+
+//------------------------------------------------------------------------------
+int CMcKMod::fcYield(void)
+{
+ int ret = 0;
+
+ if (!isOpen()) {
+ LOG_E("no connection to kmod");
+ return MC_DRV_ERR_KMOD_NOT_OPEN;
+ }
+
+ ret = ioctl(fdKMod, MC_IO_YIELD, NULL);
+ if (ret != 0) {
+ LOG_ERRNO("ioctl MC_IO_YIELD");
+ LOG_E("ret = %d", ret);
+ }
+
+ return ret;
+}
+
+
+//------------------------------------------------------------------------------
+
+int CMcKMod::fcNSIQ(void)
+{
+ int ret = 0;
+
+ if (!isOpen()) {
+ LOG_E("no connection to kmod");
+ return MC_DRV_ERR_KMOD_NOT_OPEN;
+ }
+
+ ret = ioctl(fdKMod, MC_IO_NSIQ, NULL);
+ if (ret != 0) {
+ LOG_ERRNO("ioctl MC_IO_NSIQ");
+ LOG_E("ret = %d", ret);
+ }
+
+ return ret;
+}
+
+
+//------------------------------------------------------------------------------
+mcResult_t CMcKMod::free(uint32_t handle, addr_t buffer, uint32_t len)
+{
+ LOG_V("free(): handle=%d", handle);
+
+ if (!isOpen()) {
+ LOG_E("no connection to kmod");
+ return MC_DRV_ERR_KMOD_NOT_OPEN;
+ }
+
+ // Even if unmap fails we still go on with our request
+ if (::munmap(buffer, len)) {
+ LOG_I("buffer = %p, len = %d", buffer, len);
+ LOG_ERRNO("munmap failed");
+ }
+
+ int ret = ioctl(fdKMod, MC_IO_FREE, handle);
+ if (ret != 0) {
+ LOG_ERRNO("ioctl MC_IO_FREE");
+ return MAKE_MC_DRV_KMOD_WITH_ERRNO(errno);
+ }
+
+ return MC_DRV_OK;
+}
+
+
+//------------------------------------------------------------------------------
+mcResult_t CMcKMod::registerWsmL2(
+ addr_t buffer,
+ uint32_t len,
+ uint32_t pid,
+ uint32_t *pHandle,
+ uint64_t *pPhysWsmL2)
+{
+ LOG_I(" Registering virtual buffer at %p, len=%d as World Shared Memory", buffer, len);
+
+ if (!isOpen()) {
+ LOG_E("no connection to kmod");
+ return MC_DRV_ERR_KMOD_NOT_OPEN;
+ }
+
+ struct mc_ioctl_reg_wsm params = {
+buffer :
+ (uintptr_t) buffer,
+len :
+ len,
+pid :
+ pid
+ };
+
+ int ret = ioctl(fdKMod, MC_IO_REG_WSM, &params);
+ if (ret != 0) {
+ LOG_ERRNO("ioctl MC_IO_REG_WSM");
+ return MAKE_MC_DRV_KMOD_WITH_ERRNO(errno);
+ }
+
+ LOG_I(" Registered, handle=%d, L2 phys=0x%llx ", params.handle, params.table_phys);
+
+ if (pHandle != NULL) {
+ *pHandle = params.handle;
+ }
+
+ if (pPhysWsmL2 != NULL) {
+ *pPhysWsmL2 = params.table_phys;
+ }
+
+ return MC_DRV_OK;
+}
+
+
+//------------------------------------------------------------------------------
+mcResult_t CMcKMod::unregisterWsmL2(uint32_t handle)
+{
+ LOG_I(" Unregistering World Shared Memory with handle %d", handle);
+
+ if (!isOpen()) {
+ LOG_E("no connection to kmod");
+ return MC_DRV_ERR_KMOD_NOT_OPEN;
+ }
+
+ int ret = ioctl(fdKMod, MC_IO_UNREG_WSM, handle);
+ if (ret != 0) {
+ LOG_ERRNO("ioctl MC_IO_UNREG_WSM");
+ return MAKE_MC_DRV_KMOD_WITH_ERRNO(errno);
+ }
+
+ return MC_DRV_OK;
+}
+
+//------------------------------------------------------------------------------
+mcResult_t CMcKMod::lockWsmL2(uint32_t handle)
+{
+ int ret = 0;
+
+ LOG_I(" Locking World Shared Memory with handle %d", handle);
+
+ if (!isOpen()) {
+ LOG_E("no connection to kmod");
+ return MC_DRV_ERR_KMOD_NOT_OPEN;
+ }
+
+ ret = ioctl(fdKMod, MC_IO_LOCK_WSM, handle);
+ if (ret != 0) {
+ LOG_ERRNO("ioctl MC_IO_LOCK_WSM");
+ LOG_E("ret = %d", ret);
+ }
+
+ return ret;
+}
+
+//------------------------------------------------------------------------------
+mcResult_t CMcKMod::unlockWsmL2(uint32_t handle)
+{
+ int ret = 0;
+
+ LOG_I(" Unlocking World Shared Memory with handle %d", handle);
+
+ if (!isOpen()) {
+ LOG_E("no connection to kmod");
+ return MC_DRV_ERR_KMOD_NOT_OPEN;
+ }
+
+ ret = ioctl(fdKMod, MC_IO_UNLOCK_WSM, handle);
+ // Failure here is not really important
+ if (ret != 0) {
+ LOG_I("ret = %d", ret);
+ }
+
+ return ret;
+}
+
+
+//------------------------------------------------------------------------------
+uint64_t CMcKMod::findWsmL2(uint32_t handle, int fd)
+{
+ int ret = 0;
+
+ struct mc_ioctl_resolv_wsm wsm;
+
+ wsm.handle = handle;
+ wsm.fd = fd;
+ wsm.phys = 0;
+
+ LOG_I(" Resolving the WSM l2 for handle=%u", handle);
+
+ if (!isOpen()) {
+ LOG_E("no connection to kmod");
+ return 0;
+ }
+
+ ret = ioctl(fdKMod, MC_IO_RESOLVE_WSM, &wsm);
+ if (ret != 0) {
+ LOG_ERRNO("ioctl MC_IO_RESOLVE_WSM");
+ LOG_E("ret = %d", ret);
+ return 0;
+ }
+
+ return wsm.phys;
+}
+
+//------------------------------------------------------------------------------
+mcResult_t CMcKMod::findContiguousWsm(uint32_t handle, int fd, uint64_t *phys, uint32_t *len)
+{
+ mcResult_t ret = MC_DRV_OK;
+ struct mc_ioctl_resolv_cont_wsm wsm;
+
+ wsm.handle = handle;
+ wsm.phys = 0;
+ wsm.length = 0;
+ wsm.fd = fd;
+
+ LOG_I(" Resolving the contiguous WSM l2 for handle=%u", handle);
+
+ if (!isOpen()) {
+ LOG_E("no connection to kmod");
+ return MC_DRV_ERR_KMOD_NOT_OPEN;
+ }
+
+ ret = ioctl(fdKMod, MC_IO_RESOLVE_CONT_WSM, &wsm);
+ if (ret != 0) {
+ LOG_W("ioctl MC_IO_RESOLVE_CONT_WSM failed with \"%s\"(errno %i)", strerror(errno), errno);
+ } else {
+ *phys = wsm.phys;
+ *len = wsm.length;
+ }
+
+ return ret;
+}
+
+//------------------------------------------------------------------------------
+mcResult_t CMcKMod::cleanupWsmL2(void)
+{
+ int ret = 0;
+
+ LOG_I(" Cleaning up the orphaned bulk buffers");
+
+ if (!isOpen()) {
+ LOG_E("no connection to kmod");
+ return MC_DRV_ERR_KMOD_NOT_OPEN;
+ }
+
+ ret = ioctl(fdKMod, MC_IO_CLEAN_WSM, 0);
+ if (ret != 0) {
+ LOG_ERRNO("ioctl MC_IO_CLEAN_WSM");
+ LOG_E("ret = %d", ret);
+ }
+
+ return ret;
+}
+
+//------------------------------------------------------------------------------
+mcResult_t CMcKMod::setupLog(void)
+{
+ int ret = 0;
+
+ LOG_I(" Setting up the memory logging system");
+
+ if (!isOpen()) {
+ LOG_E("no connection to kmod");
+ return MC_DRV_ERR_KMOD_NOT_OPEN;
+ }
+
+ ret = ioctl(fdKMod, MC_IO_LOG_SETUP, 0);
+ if (ret != 0) {
+ LOG_W("ioctl MC_IO_LOG_SETUP failed with \"%s\"(errno %i)", strerror(errno), errno);
+ }
+
+ return ret;
+}
+
+//------------------------------------------------------------------------------
+bool CMcKMod::checkVersion(void)
+{
+ uint32_t version;
+ if (!isOpen()) {
+ LOG_E("no connection to kmod");
+ return false;
+ }
+
+ int ret = ioctl(fdKMod, MC_IO_VERSION, &version);
+ if (ret != 0) {
+ LOG_ERRNO("ioctl MC_IO_VERSION");
+ LOG_E("ret = %d", ret);
+ return false;
+ }
+
+ // Run-time check.
+ char *errmsg;
+ if (!checkVersionOkMCDRVMODULEAPI(version, &errmsg)) {
+ LOG_E("%s", errmsg);
+ return false;
+ }
+ LOG_I("%s", errmsg);
+
+ return true;
+}
+