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//------------------------------------------------------------------------------
50MC_CHECK_VERSION(MCDRVMODULEAPI, 1, 1);
51
52//------------------------------------------------------------------------------
53mcResult_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
68struct 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//------------------------------------------------------------------------------
105mcResult_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
114struct 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//------------------------------------------------------------------------------
161mcResult_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//------------------------------------------------------------------------------
174int 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//------------------------------------------------------------------------------
192bool 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//------------------------------------------------------------------------------
208int 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 = {
219nq_offset :
220        nqOffset,
221nq_length :
222        nqLength,
223mcp_offset :
224        mcpOffset,
225mcp_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//------------------------------------------------------------------------------
237int 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
247struct 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//------------------------------------------------------------------------------
269int 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//------------------------------------------------------------------------------
289int 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//------------------------------------------------------------------------------
309mcResult_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//------------------------------------------------------------------------------
335mcResult_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 = {
350buffer :
351        (uint32_t) buffer,
352len :
353        len,
354pid :
355        pid
356    };
357
358    int ret = ioctl(fdKMod, MC_IO_REG_WSM, &params);
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//------------------------------------------------------------------------------
379mcResult_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//------------------------------------------------------------------------------
398mcResult_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//------------------------------------------------------------------------------
419mcResult_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//------------------------------------------------------------------------------
441addr_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, &param);
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//------------------------------------------------------------------------------
463mcResult_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//------------------------------------------------------------------------------
489mcResult_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//------------------------------------------------------------------------------
510int CMcKMod::fcExecute(addr_t startAddr, uint32_t areaLength)
511{
512    int ret = 0;
513    struct mc_ioctl_execute params = {
514phys_start_addr :
515        (uint32_t)startAddr,
516length :
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, &params);
526    if (ret != 0) {
527        LOG_ERRNO("ioctl MC_IO_EXECUTE");
528    }
529
530    return ret;
531}
532//------------------------------------------------------------------------------
533bool 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