1 /** @addtogroup MCD_MCDIMPL_DAEMON_KERNEL 2 * @{ 3 * @file 4 * 5 * MobiCore Driver Kernel Module Interface. 6 * 7 * <!-- Copyright Giesecke & Devrient GmbH 2009 - 2012 --> 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. The name of the author may not be used to endorse or promote 18 * products derived from this software without specific prior 19 * written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 22 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 23 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 25 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 27 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 #include <cstdlib> 34 35 #include <sys/mman.h> 36 #include <sys/ioctl.h> 37 #include <errno.h> 38 #include <inttypes.h> 39 #include <cstring> 40 41 #include "McTypes.h" 42 #include "mc_linux.h" 43 #include "mcVersionHelper.h" 44 45 #include "CMcKMod.h" 46 47 #include "log.h" 48 49 //------------------------------------------------------------------------------ 50 MC_CHECK_VERSION(MCDRVMODULEAPI, 1, 1); 51 52 //------------------------------------------------------------------------------ 53 mcResult_t CMcKMod::mapWsm( 54 uint32_t len, 55 uint32_t *pHandle, 56 addr_t *pVirtAddr, 57 addr_t *pPhysAddr) 58 { 59 int ret = 0; 60 LOG_V(" mapWsm(): len=%d", len); 61 62 if (!isOpen()) { 63 LOG_E("no connection to kmod"); 64 return MC_DRV_ERR_KMOD_NOT_OPEN; 65 } 66 67 // mapping response data is in the buffer 68 struct mc_ioctl_map mapParams = { len: 69 len 70 }; 71 72 ret = ioctl(fdKMod, MC_IO_MAP_WSM, &mapParams); 73 if (ret != 0) { 74 LOG_ERRNO("ioctl MC_IO_MAP_WSM"); 75 return MAKE_MC_DRV_KMOD_WITH_ERRNO(errno); 76 } 77 78 addr_t virtAddr = ::mmap(0, len, PROT_READ | PROT_WRITE, MAP_SHARED, 79 fdKMod, mapParams.phys_addr); 80 if (virtAddr == MAP_FAILED) { 81 LOG_ERRNO("mmap"); 82 return MAKE_MC_DRV_KMOD_WITH_ERRNO(errno); 83 } 84 85 86 LOG_V(" mapped to %p, handle=%d, phys=%p ", virtAddr, 87 mapParams.handle, (addr_t) (mapParams.phys_addr)); 88 89 if (pVirtAddr != NULL) { 90 *pVirtAddr = virtAddr; 91 } 92 93 if (pHandle != NULL) { 94 *pHandle = mapParams.handle; 95 } 96 97 if (pPhysAddr != NULL) { 98 *pPhysAddr = (addr_t) (mapParams.phys_addr); 99 } 100 101 return 0; 102 } 103 104 //------------------------------------------------------------------------------ 105 mcResult_t CMcKMod::mapMCI( 106 uint32_t len, 107 uint32_t *pHandle, 108 addr_t *pVirtAddr, 109 addr_t *pPhysAddr, 110 bool *pReuse) 111 { 112 LOG_I("Mapping MCI: len=%d", len); 113 // mapping response data is in the buffer 114 struct mc_ioctl_map mapParams = { len: 115 len 116 }; 117 118 if (!isOpen()) { 119 LOG_E("no connection to kmod"); 120 return MC_DRV_ERR_KMOD_NOT_OPEN; 121 } 122 123 int ret = ioctl(fdKMod, MC_IO_MAP_MCI, &mapParams); 124 if (ret != 0) { 125 LOG_ERRNO("ioctl MC_IO_MAP_MCI"); 126 return MAKE_MC_DRV_KMOD_WITH_ERRNO(errno); 127 } 128 129 addr_t virtAddr = ::mmap(0, len, PROT_READ | PROT_WRITE, MAP_SHARED, 130 fdKMod, 0); 131 if (virtAddr == MAP_FAILED) { 132 LOG_ERRNO("mmap"); 133 return MAKE_MC_DRV_KMOD_WITH_ERRNO(errno); 134 } 135 mapParams.addr = (unsigned long)virtAddr; 136 *pReuse = mapParams.reused; 137 138 LOG_V(" MCI mapped to %p, handle=%d, phys=%p, reused=%s", 139 (void *)mapParams.addr, mapParams.handle, (addr_t) (mapParams.phys_addr), 140 mapParams.reused ? "true" : "false"); 141 142 if (pVirtAddr != NULL) { 143 *pVirtAddr = (void *)mapParams.addr; 144 } 145 146 if (pHandle != NULL) { 147 *pHandle = mapParams.handle; 148 } 149 150 if (pPhysAddr != NULL) { 151 *pPhysAddr = (addr_t) (mapParams.phys_addr); 152 } 153 154 // clean memory 155 //memset(pMmapResp, 0, sizeof(*pMmapResp)); 156 157 return MC_DRV_OK; 158 } 159 160 //------------------------------------------------------------------------------ 161 mcResult_t CMcKMod::mapPersistent( 162 uint32_t len, 163 uint32_t *pHandle, 164 addr_t *pVirtAddr, 165 addr_t *pPhysAddr) 166 { 167 // Not currently supported by the driver 168 LOG_E("MobiCore Driver does't support persistent buffers"); 169 return MC_DRV_ERR_NOT_IMPLEMENTED; 170 } 171 172 173 //------------------------------------------------------------------------------ 174 int CMcKMod::read(addr_t buffer, uint32_t len) 175 { 176 int ret = 0; 177 178 if (!isOpen()) { 179 LOG_E("no connection to kmod"); 180 return MC_DRV_ERR_KMOD_NOT_OPEN; 181 } 182 183 ret = ::read(fdKMod, buffer, len); 184 if (ret == -1) { 185 LOG_ERRNO("read"); 186 } 187 return ret; 188 } 189 190 191 //------------------------------------------------------------------------------ 192 bool CMcKMod::waitSSIQ(uint32_t *pCnt) 193 { 194 uint32_t cnt; 195 if (read(&cnt, sizeof(cnt)) != sizeof(cnt)) { 196 return false; 197 } 198 199 if (pCnt != NULL) { 200 *pCnt = cnt; 201 } 202 203 return true; 204 } 205 206 207 //------------------------------------------------------------------------------ 208 int CMcKMod::fcInit(uint32_t nqOffset, uint32_t nqLength, uint32_t mcpOffset, 209 uint32_t mcpLength) 210 { 211 int ret = 0; 212 213 if (!isOpen()) { 214 return MC_DRV_ERR_KMOD_NOT_OPEN; 215 } 216 217 // Init MC with NQ and MCP buffer addresses 218 struct mc_ioctl_init fcInitParams = { 219 nq_offset : 220 nqOffset, 221 nq_length : 222 nqLength, 223 mcp_offset : 224 mcpOffset, 225 mcp_length : 226 mcpLength 227 }; 228 ret = ioctl(fdKMod, MC_IO_INIT, &fcInitParams); 229 if (ret != 0) { 230 LOG_ERRNO("ioctl MC_IO_INIT"); 231 } 232 233 return ret; 234 } 235 236 //------------------------------------------------------------------------------ 237 int CMcKMod::fcInfo(uint32_t extInfoId, uint32_t *pState, uint32_t *pExtInfo) 238 { 239 int ret = 0; 240 241 if (!isOpen()) { 242 LOG_E("no connection to kmod"); 243 return MC_DRV_ERR_KMOD_NOT_OPEN; 244 } 245 246 // Init MC with NQ and MCP buffer addresses 247 struct mc_ioctl_info fcInfoParams = {ext_info_id : 248 extInfoId 249 }; 250 ret = ioctl(fdKMod, MC_IO_INFO, &fcInfoParams); 251 if (ret != 0) { 252 LOG_ERRNO("ioctl MC_IO_INFO"); 253 return ret; 254 } 255 256 if (pState != NULL) { 257 *pState = fcInfoParams.state; 258 } 259 260 if (pExtInfo != NULL) { 261 *pExtInfo = fcInfoParams.ext_info; 262 } 263 264 return ret; 265 } 266 267 268 //------------------------------------------------------------------------------ 269 int CMcKMod::fcYield(void) 270 { 271 int ret = 0; 272 273 if (!isOpen()) { 274 LOG_E("no connection to kmod"); 275 return MC_DRV_ERR_KMOD_NOT_OPEN; 276 } 277 278 ret = ioctl(fdKMod, MC_IO_YIELD, NULL); 279 if (ret != 0) { 280 LOG_ERRNO("ioctl MC_IO_YIELD"); 281 LOG_E("ret = %d", ret); 282 } 283 284 return ret; 285 } 286 287 288 //------------------------------------------------------------------------------ 289 int CMcKMod::fcNSIQ(void) 290 { 291 int ret = 0; 292 293 if (!isOpen()) { 294 LOG_E("no connection to kmod"); 295 return MC_DRV_ERR_KMOD_NOT_OPEN; 296 } 297 298 ret = ioctl(fdKMod, MC_IO_NSIQ, NULL); 299 if (ret != 0) { 300 LOG_ERRNO("ioctl MC_IO_NSIQ"); 301 LOG_E("ret = %d", ret); 302 } 303 304 return ret; 305 } 306 307 308 //------------------------------------------------------------------------------ 309 mcResult_t CMcKMod::free(uint32_t handle, addr_t buffer, uint32_t len) 310 { 311 LOG_V("free(): handle=%d", handle); 312 313 if (!isOpen()) { 314 LOG_E("no connection to kmod"); 315 return MC_DRV_ERR_KMOD_NOT_OPEN; 316 } 317 318 // Even if unmap fails we still go on with our request 319 if (::munmap(buffer, len)) { 320 LOG_I("buffer = %p, len = %d", buffer, len); 321 LOG_ERRNO("mmap failed"); 322 } 323 324 int ret = ioctl(fdKMod, MC_IO_FREE, handle); 325 if (ret != 0) { 326 LOG_ERRNO("ioctl MC_IO_FREE"); 327 return MAKE_MC_DRV_KMOD_WITH_ERRNO(errno); 328 } 329 330 return MC_DRV_OK; 331 } 332 333 334 //------------------------------------------------------------------------------ 335 mcResult_t CMcKMod::registerWsmL2( 336 addr_t buffer, 337 uint32_t len, 338 uint32_t pid, 339 uint32_t *pHandle, 340 addr_t *pPhysWsmL2) 341 { 342 LOG_I(" Registering virtual buffer at %p, len=%d as World Shared Memory", buffer, len); 343 344 if (!isOpen()) { 345 LOG_E("no connection to kmod"); 346 return MC_DRV_ERR_KMOD_NOT_OPEN; 347 } 348 349 struct mc_ioctl_reg_wsm params = { 350 buffer : 351 (uint32_t) buffer, 352 len : 353 len, 354 pid : 355 pid 356 }; 357 358 int ret = ioctl(fdKMod, MC_IO_REG_WSM, ¶ms); 359 if (ret != 0) { 360 LOG_ERRNO("ioctl MC_IO_UNREG_WSM"); 361 return MAKE_MC_DRV_KMOD_WITH_ERRNO(errno); 362 } 363 364 LOG_I(" Registered, handle=%d, L2 phys=0x%x ", params.handle, params.table_phys); 365 366 if (pHandle != NULL) { 367 *pHandle = params.handle; 368 } 369 370 if (pPhysWsmL2 != NULL) { 371 *pPhysWsmL2 = (addr_t) params.table_phys; 372 } 373 374 return MC_DRV_OK; 375 } 376 377 378 //------------------------------------------------------------------------------ 379 mcResult_t CMcKMod::unregisterWsmL2(uint32_t handle) 380 { 381 LOG_I(" Unregistering World Shared Memory with handle %d", handle); 382 383 if (!isOpen()) { 384 LOG_E("no connection to kmod"); 385 return MC_DRV_ERR_KMOD_NOT_OPEN; 386 } 387 388 int ret = ioctl(fdKMod, MC_IO_UNREG_WSM, handle); 389 if (ret != 0) { 390 LOG_ERRNO("ioctl MC_IO_UNREG_WSM"); 391 return MAKE_MC_DRV_KMOD_WITH_ERRNO(errno); 392 } 393 394 return MC_DRV_OK; 395 } 396 397 //------------------------------------------------------------------------------ 398 mcResult_t CMcKMod::lockWsmL2(uint32_t handle) 399 { 400 int ret = 0; 401 402 LOG_I(" Locking World Shared Memory with handle %d", handle); 403 404 if (!isOpen()) { 405 LOG_E("no connection to kmod"); 406 return MC_DRV_ERR_KMOD_NOT_OPEN; 407 } 408 409 ret = ioctl(fdKMod, MC_IO_LOCK_WSM, handle); 410 if (ret != 0) { 411 LOG_ERRNO("ioctl MC_IO_UNREG_WSM"); 412 LOG_E("ret = %d", ret); 413 } 414 415 return ret; 416 } 417 418 //------------------------------------------------------------------------------ 419 mcResult_t CMcKMod::unlockWsmL2(uint32_t handle) 420 { 421 int ret = 0; 422 423 LOG_I(" Unlocking World Shared Memory with handle %d", handle); 424 425 if (!isOpen()) { 426 LOG_E("no connection to kmod"); 427 return MC_DRV_ERR_KMOD_NOT_OPEN; 428 } 429 430 ret = ioctl(fdKMod, MC_IO_UNLOCK_WSM, handle); 431 // Failure here is not really important 432 if (ret != 0) { 433 LOG_I("ret = %d", ret); 434 } 435 436 return ret; 437 } 438 439 440 //------------------------------------------------------------------------------ 441 addr_t CMcKMod::findWsmL2(uint32_t handle) 442 { 443 int ret = 0; 444 uint32_t param = handle; 445 446 LOG_I(" Resolving the WSM l2 for handle=%u", handle); 447 448 if (!isOpen()) { 449 LOG_E("no connection to kmod"); 450 return NULL; 451 } 452 453 ret = ioctl(fdKMod, MC_IO_RESOLVE_WSM, ¶m); 454 if (ret != 0 || param == 0) { 455 LOG_ERRNO("ioctl MC_IO_RESOLVE_WSM"); 456 LOG_E("param %u, ret = %d", param, ret); 457 } 458 459 return (addr_t)param; 460 } 461 462 //------------------------------------------------------------------------------ 463 mcResult_t CMcKMod::findContiguousWsm(uint32_t handle, addr_t *phys, uint32_t *len) 464 { 465 mcResult_t ret = MC_DRV_OK; 466 struct mc_ioctl_resolv_cont_wsm wsm; 467 468 wsm.handle = handle; 469 470 LOG_I(" Resolving the contiguous WSM l2 for handle=%u", handle); 471 472 if (!isOpen()) { 473 LOG_E("no connection to kmod"); 474 return NULL; 475 } 476 477 ret = ioctl(fdKMod, MC_IO_RESOLVE_CONT_WSM, &wsm); 478 if (ret != 0) { 479 LOG_ERRNO("ioctl MC_IO_RESOLVE_CONT_WSM"); 480 } else { 481 *phys = (addr_t)wsm.phys; 482 *len = wsm.length; 483 } 484 485 return ret; 486 } 487 488 //------------------------------------------------------------------------------ 489 mcResult_t CMcKMod::cleanupWsmL2(void) 490 { 491 int ret = 0; 492 493 LOG_I(" Cleaning up the orphaned bulk buffers"); 494 495 if (!isOpen()) { 496 LOG_E("no connection to kmod"); 497 return MC_DRV_ERR_KMOD_NOT_OPEN; 498 } 499 500 ret = ioctl(fdKMod, MC_IO_CLEAN_WSM, 0); 501 if (ret != 0) { 502 LOG_ERRNO("ioctl MC_IO_UNREG_WSM"); 503 LOG_E("ret = %d", ret); 504 } 505 506 return ret; 507 } 508 509 //------------------------------------------------------------------------------ 510 int CMcKMod::fcExecute(addr_t startAddr, uint32_t areaLength) 511 { 512 int ret = 0; 513 struct mc_ioctl_execute params = { 514 phys_start_addr : 515 (uint32_t)startAddr, 516 length : 517 areaLength 518 }; 519 520 if (!isOpen()) { 521 LOG_E("no connection to kmod"); 522 return MC_DRV_ERR_KMOD_NOT_OPEN; 523 } 524 525 ret = ioctl(fdKMod, MC_IO_EXECUTE, ¶ms); 526 if (ret != 0) { 527 LOG_ERRNO("ioctl MC_IO_EXECUTE"); 528 } 529 530 return ret; 531 } 532 //------------------------------------------------------------------------------ 533 bool CMcKMod::checkVersion(void) 534 { 535 uint32_t version; 536 if (!isOpen()) { 537 LOG_E("no connection to kmod"); 538 return false; 539 } 540 541 int ret = ioctl(fdKMod, MC_IO_VERSION, &version); 542 if (ret != 0) { 543 LOG_ERRNO("ioctl MC_IO_VERSION"); 544 LOG_E("ret = %d", ret); 545 return false; 546 } 547 548 // Run-time check. 549 char *errmsg; 550 if (!checkVersionOkMCDRVMODULEAPI(version, &errmsg)) { 551 LOG_E("%s", errmsg); 552 return false; 553 } 554 LOG_I("%s", errmsg); 555 556 return true; 557 } 558 559 /** @} */ 560