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, &params);
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, &param);
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, &params);
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