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 = {
69 .len = 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 = {
115 .len = 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 = nqOffset,
220 .nq_length = nqLength,
221 .mcp_offset = mcpOffset,
222 .mcp_length = mcpLength
223 };
224
225 ret = ioctl(fdKMod, MC_IO_INIT, &fcInitParams);
226 if (ret != 0) {
227 LOG_ERRNO("ioctl MC_IO_INIT");
228 }
229
230 return ret;
231 }
232
233 //------------------------------------------------------------------------------
fcInfo(uint32_t extInfoId,uint32_t * pState,uint32_t * pExtInfo)234 int CMcKMod::fcInfo(uint32_t extInfoId, uint32_t *pState, uint32_t *pExtInfo)
235 {
236 int ret = 0;
237
238 if (!isOpen()) {
239 LOG_E("no connection to kmod");
240 return MC_DRV_ERR_KMOD_NOT_OPEN;
241 }
242
243 // Init MC with NQ and MCP buffer addresses
244 struct mc_ioctl_info fcInfoParams = {
245 .ext_info_id = extInfoId
246 };
247 ret = ioctl(fdKMod, MC_IO_INFO, &fcInfoParams);
248 if (ret != 0) {
249 LOG_ERRNO("ioctl MC_IO_INFO");
250 return ret;
251 }
252
253 if (pState != NULL) {
254 *pState = fcInfoParams.state;
255 }
256
257 if (pExtInfo != NULL) {
258 *pExtInfo = fcInfoParams.ext_info;
259 }
260
261 return ret;
262 }
263
264
265 //------------------------------------------------------------------------------
fcYield(void)266 int CMcKMod::fcYield(void)
267 {
268 int ret = 0;
269
270 if (!isOpen()) {
271 LOG_E("no connection to kmod");
272 return MC_DRV_ERR_KMOD_NOT_OPEN;
273 }
274
275 ret = ioctl(fdKMod, MC_IO_YIELD, NULL);
276 if (ret != 0) {
277 LOG_ERRNO("ioctl MC_IO_YIELD");
278 LOG_E("ret = %d", ret);
279 }
280
281 return ret;
282 }
283
284
285 //------------------------------------------------------------------------------
fcNSIQ(void)286 int CMcKMod::fcNSIQ(void)
287 {
288 int ret = 0;
289
290 if (!isOpen()) {
291 LOG_E("no connection to kmod");
292 return MC_DRV_ERR_KMOD_NOT_OPEN;
293 }
294
295 ret = ioctl(fdKMod, MC_IO_NSIQ, NULL);
296 if (ret != 0) {
297 LOG_ERRNO("ioctl MC_IO_NSIQ");
298 LOG_E("ret = %d", ret);
299 }
300
301 return ret;
302 }
303
304
305 //------------------------------------------------------------------------------
free(uint32_t handle,addr_t buffer,uint32_t len)306 mcResult_t CMcKMod::free(uint32_t handle, addr_t buffer, uint32_t len)
307 {
308 LOG_V("free(): handle=%d", handle);
309
310 if (!isOpen()) {
311 LOG_E("no connection to kmod");
312 return MC_DRV_ERR_KMOD_NOT_OPEN;
313 }
314
315 // Even if unmap fails we still go on with our request
316 if (::munmap(buffer, len)) {
317 LOG_I("buffer = %p, len = %d", buffer, len);
318 LOG_ERRNO("mmap failed");
319 }
320
321 int ret = ioctl(fdKMod, MC_IO_FREE, handle);
322 if (ret != 0) {
323 LOG_ERRNO("ioctl MC_IO_FREE");
324 return MAKE_MC_DRV_KMOD_WITH_ERRNO(errno);
325 }
326
327 return MC_DRV_OK;
328 }
329
330
331 //------------------------------------------------------------------------------
registerWsmL2(addr_t buffer,uint32_t len,uint32_t pid,uint32_t * pHandle,addr_t * pPhysWsmL2)332 mcResult_t CMcKMod::registerWsmL2(
333 addr_t buffer,
334 uint32_t len,
335 uint32_t pid,
336 uint32_t *pHandle,
337 addr_t *pPhysWsmL2)
338 {
339 LOG_I(" Registering virtual buffer at %p, len=%d as World Shared Memory", buffer, len);
340
341 if (!isOpen()) {
342 LOG_E("no connection to kmod");
343 return MC_DRV_ERR_KMOD_NOT_OPEN;
344 }
345
346 struct mc_ioctl_reg_wsm params = {
347 .buffer = (uint32_t) buffer,
348 .len = len,
349 .pid = pid
350 };
351
352 int ret = ioctl(fdKMod, MC_IO_REG_WSM, ¶ms);
353 if (ret != 0) {
354 LOG_ERRNO("ioctl MC_IO_UNREG_WSM");
355 return MAKE_MC_DRV_KMOD_WITH_ERRNO(errno);
356 }
357
358 LOG_I(" Registered, handle=%d, L2 phys=0x%x ", params.handle, params.table_phys);
359
360 if (pHandle != NULL) {
361 *pHandle = params.handle;
362 }
363
364 if (pPhysWsmL2 != NULL) {
365 *pPhysWsmL2 = (addr_t) params.table_phys;
366 }
367
368 return MC_DRV_OK;
369 }
370
371
372 //------------------------------------------------------------------------------
unregisterWsmL2(uint32_t handle)373 mcResult_t CMcKMod::unregisterWsmL2(uint32_t handle)
374 {
375 LOG_I(" Unregistering World Shared Memory with handle %d", handle);
376
377 if (!isOpen()) {
378 LOG_E("no connection to kmod");
379 return MC_DRV_ERR_KMOD_NOT_OPEN;
380 }
381
382 int ret = ioctl(fdKMod, MC_IO_UNREG_WSM, handle);
383 if (ret != 0) {
384 LOG_ERRNO("ioctl MC_IO_UNREG_WSM");
385 return MAKE_MC_DRV_KMOD_WITH_ERRNO(errno);
386 }
387
388 return MC_DRV_OK;
389 }
390
391 //------------------------------------------------------------------------------
lockWsmL2(uint32_t handle)392 mcResult_t CMcKMod::lockWsmL2(uint32_t handle)
393 {
394 int ret = 0;
395
396 LOG_I(" Locking World Shared Memory with handle %d", handle);
397
398 if (!isOpen()) {
399 LOG_E("no connection to kmod");
400 return MC_DRV_ERR_KMOD_NOT_OPEN;
401 }
402
403 ret = ioctl(fdKMod, MC_IO_LOCK_WSM, handle);
404 if (ret != 0) {
405 LOG_ERRNO("ioctl MC_IO_UNREG_WSM");
406 LOG_E("ret = %d", ret);
407 }
408
409 return ret;
410 }
411
412 //------------------------------------------------------------------------------
unlockWsmL2(uint32_t handle)413 mcResult_t CMcKMod::unlockWsmL2(uint32_t handle)
414 {
415 int ret = 0;
416
417 LOG_I(" Unlocking World Shared Memory with handle %d", handle);
418
419 if (!isOpen()) {
420 LOG_E("no connection to kmod");
421 return MC_DRV_ERR_KMOD_NOT_OPEN;
422 }
423
424 ret = ioctl(fdKMod, MC_IO_UNLOCK_WSM, handle);
425 // Failure here is not really important
426 if (ret != 0) {
427 LOG_I("ret = %d", ret);
428 }
429
430 return ret;
431 }
432
433
434 //------------------------------------------------------------------------------
findWsmL2(uint32_t handle)435 addr_t CMcKMod::findWsmL2(uint32_t handle)
436 {
437 int ret = 0;
438 uint32_t param = handle;
439
440 LOG_I(" Resolving the WSM l2 for handle=%u", handle);
441
442 if (!isOpen()) {
443 LOG_E("no connection to kmod");
444 return NULL;
445 }
446
447 ret = ioctl(fdKMod, MC_IO_RESOLVE_WSM, ¶m);
448 if (ret != 0 || param == 0) {
449 LOG_ERRNO("ioctl MC_IO_RESOLVE_WSM");
450 LOG_E("param %u, ret = %d", param, ret);
451 }
452
453 return (addr_t)param;
454 }
455
456 //------------------------------------------------------------------------------
findContiguousWsm(uint32_t handle,addr_t * phys,uint32_t * len)457 mcResult_t CMcKMod::findContiguousWsm(uint32_t handle, addr_t *phys, uint32_t *len)
458 {
459 mcResult_t ret = MC_DRV_OK;
460 struct mc_ioctl_resolv_cont_wsm wsm;
461
462 wsm.handle = handle;
463
464 LOG_I(" Resolving the contiguous WSM l2 for handle=%u", handle);
465
466 if (!isOpen()) {
467 LOG_E("no connection to kmod");
468 return NULL;
469 }
470
471 ret = ioctl(fdKMod, MC_IO_RESOLVE_CONT_WSM, &wsm);
472 if (ret != 0) {
473 LOG_ERRNO("ioctl MC_IO_RESOLVE_CONT_WSM");
474 } else {
475 *phys = (addr_t)wsm.phys;
476 *len = wsm.length;
477 }
478
479 return ret;
480 }
481
482 //------------------------------------------------------------------------------
cleanupWsmL2(void)483 mcResult_t CMcKMod::cleanupWsmL2(void)
484 {
485 int ret = 0;
486
487 LOG_I(" Cleaning up the orphaned bulk buffers");
488
489 if (!isOpen()) {
490 LOG_E("no connection to kmod");
491 return MC_DRV_ERR_KMOD_NOT_OPEN;
492 }
493
494 ret = ioctl(fdKMod, MC_IO_CLEAN_WSM, 0);
495 if (ret != 0) {
496 LOG_ERRNO("ioctl MC_IO_UNREG_WSM");
497 LOG_E("ret = %d", ret);
498 }
499
500 return ret;
501 }
502
503 //------------------------------------------------------------------------------
fcExecute(addr_t startAddr,uint32_t areaLength)504 int CMcKMod::fcExecute(addr_t startAddr, uint32_t areaLength)
505 {
506 int ret = 0;
507 struct mc_ioctl_execute params = {
508 .phys_start_addr = (uint32_t)startAddr,
509 .length = areaLength
510 };
511
512 if (!isOpen()) {
513 LOG_E("no connection to kmod");
514 return MC_DRV_ERR_KMOD_NOT_OPEN;
515 }
516
517 ret = ioctl(fdKMod, MC_IO_EXECUTE, ¶ms);
518 if (ret != 0) {
519 LOG_ERRNO("ioctl MC_IO_EXECUTE");
520 }
521
522 return ret;
523 }
524 //------------------------------------------------------------------------------
checkVersion(void)525 bool CMcKMod::checkVersion(void)
526 {
527 uint32_t version;
528 if (!isOpen()) {
529 LOG_E("no connection to kmod");
530 return false;
531 }
532
533 int ret = ioctl(fdKMod, MC_IO_VERSION, &version);
534 if (ret != 0) {
535 LOG_ERRNO("ioctl MC_IO_VERSION");
536 LOG_E("ret = %d", ret);
537 return false;
538 }
539
540 // Run-time check.
541 char *errmsg;
542 if (!checkVersionOkMCDRVMODULEAPI(version, &errmsg)) {
543 LOG_E("%s", errmsg);
544 return false;
545 }
546 LOG_I("%s", errmsg);
547
548 return true;
549 }
550
551 /** @} */
552