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 //------------------------------------------------------------------------------
mapWsm(uint32_t len,uint32_t * pHandle,addr_t * pVirtAddr,addr_t * pPhysAddr)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 //------------------------------------------------------------------------------
mapMCI(uint32_t len,uint32_t * pHandle,addr_t * pVirtAddr,addr_t * pPhysAddr,bool * pReuse)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 //------------------------------------------------------------------------------
mapPersistent(uint32_t len,uint32_t * pHandle,addr_t * pVirtAddr,addr_t * pPhysAddr)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 //------------------------------------------------------------------------------
read(addr_t buffer,uint32_t len)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 //------------------------------------------------------------------------------
waitSSIQ(uint32_t * pCnt)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 //------------------------------------------------------------------------------
fcInit(uint32_t nqOffset,uint32_t nqLength,uint32_t mcpOffset,uint32_t mcpLength)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 //------------------------------------------------------------------------------
fcInfo(uint32_t extInfoId,uint32_t * pState,uint32_t * pExtInfo)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 //------------------------------------------------------------------------------
fcYield(void)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 //------------------------------------------------------------------------------
fcNSIQ(void)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 //------------------------------------------------------------------------------
free(uint32_t handle,addr_t buffer,uint32_t len)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 //------------------------------------------------------------------------------
registerWsmL2(addr_t buffer,uint32_t len,uint32_t pid,uint32_t * pHandle,addr_t * pPhysWsmL2)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 //------------------------------------------------------------------------------
unregisterWsmL2(uint32_t handle)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 //------------------------------------------------------------------------------
lockWsmL2(uint32_t handle)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 //------------------------------------------------------------------------------
unlockWsmL2(uint32_t handle)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 //------------------------------------------------------------------------------
findWsmL2(uint32_t handle)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 //------------------------------------------------------------------------------
findContiguousWsm(uint32_t handle,addr_t * phys,uint32_t * len)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 //------------------------------------------------------------------------------
cleanupWsmL2(void)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 //------------------------------------------------------------------------------
fcExecute(addr_t startAddr,uint32_t areaLength)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 //------------------------------------------------------------------------------
checkVersion(void)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