diff options
Diffstat (limited to 'mobicore/MobiCoreDriverLib/Kernel/Platforms/Generic/CMcKMod.cpp')
-rw-r--r-- | mobicore/MobiCoreDriverLib/Kernel/Platforms/Generic/CMcKMod.cpp | 528 |
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, ¶ms); + 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; +} + |