CMcKMod.cpp revision 4e9e8c9c0169b40318386436d762c3d73cf4c328
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_drv_module_api.h"
43#include "mcVersionHelper.h"
44
45#include "CMcKMod.h"
46
47#define LOG_TAG	"McDaemon"
48#include "log.h"
49
50//------------------------------------------------------------------------------
51MC_CHECK_VERSION(MCDRVMODULEAPI,0,1);
52
53// TODO: rename this to mapWsm
54//------------------------------------------------------------------------------
55int CMcKMod::mmap(
56	uint32_t	len,
57	uint32_t	*pHandle,
58	addr_t		*pVirtAddr,
59	addr_t		*pPhysAddr,
60	bool		*pMciReuse
61) {
62	int ret = 0;
63	do
64	{
65		LOG_I("mmap(): len=%d, mci_reuse=%x", len, *pMciReuse);
66
67		if (!isOpen())
68		{
69	        LOG_E("no connection to kmod");
70	        ret = ERROR_KMOD_NOT_OPEN;
71			break;
72		}
73
74		// TODO: add type parameter to distinguish between non-freeing TCI, MCI and others
75		addr_t virtAddr = ::mmap(0, len, PROT_READ | PROT_WRITE, MAP_SHARED,
76				fdKMod, *pMciReuse ? MC_DRV_KMOD_MMAP_MCI
77						: MC_DRV_KMOD_MMAP_WSM);
78		if (MAP_FAILED == virtAddr)
79		{
80			LOG_E("mmap() failed with errno: %d", errno);
81			ret = ERROR_MAPPING_FAILED;
82			break;
83		}
84
85		// mapping response data is in the buffer
86		struct mc_mmap_resp *pMmapResp = (struct mc_mmap_resp *) virtAddr;
87
88		*pMciReuse = pMmapResp->is_reused;
89
90		LOG_I("mmap(): virtAddr=%p, handle=%d, phys_addr=%p, is_reused=%s",
91				virtAddr, pMmapResp->handle, (addr_t) (pMmapResp->phys_addr),
92				pMmapResp->is_reused ? "true" : "false");
93
94		if (NULL != pVirtAddr)
95		{
96			*pVirtAddr = virtAddr;
97		}
98
99		if (NULL != pHandle)
100		{
101			*pHandle = pMmapResp->handle;
102		}
103
104		if (NULL != pPhysAddr)
105		{
106			*pPhysAddr = (addr_t) (pMmapResp->phys_addr);
107		}
108
109		// clean memory
110		memset(pMmapResp, 0, sizeof(*pMmapResp));
111
112	} while (0);
113
114	return ret;
115}
116
117
118//------------------------------------------------------------------------------
119int CMcKMod::mapPersistent(
120	uint32_t	len,
121	uint32_t	*pHandle,
122	addr_t		*pVirtAddr,
123	addr_t		*pPhysAddr
124) {
125	int ret = 0;
126	do
127	{
128		LOG_I("mapPersistent(): len=%d", len);
129
130		if (!isOpen())
131		{
132	        LOG_E("no connection to kmod");
133			ret = ERROR_KMOD_NOT_OPEN;
134			break;
135		}
136
137		addr_t virtAddr = ::mmap(0, len, PROT_READ | PROT_WRITE, MAP_SHARED,
138				fdKMod, MC_DRV_KMOD_MMAP_PERSISTENTWSM);
139
140		if (MAP_FAILED == virtAddr)
141		{
142			LOG_E("mmap() failed with errno: %d", errno);
143			ret = ERROR_MAPPING_FAILED;
144			break;
145		}
146
147		// mapping response data is in the buffer
148		struct mc_mmap_resp *pMmapResp = (struct mc_mmap_resp *) virtAddr;
149
150		LOG_I("mapPersistent(): virtAddr=%p, handle=%d, phys_addr=%p, is_reused=%s",
151				virtAddr, pMmapResp->handle,
152				(addr_t) (pMmapResp->phys_addr),
153				pMmapResp->is_reused ? "true" : "false");
154
155		if (NULL != pVirtAddr)
156		{
157			*pVirtAddr = virtAddr;
158		}
159
160		if (NULL != pHandle)
161		{
162			*pHandle = pMmapResp->handle;
163		}
164
165		if (NULL != pPhysAddr)
166		{
167			*pPhysAddr = (addr_t) (pMmapResp->phys_addr);
168		}
169
170		// clean memory
171		memset(pMmapResp, 0, sizeof(*pMmapResp));
172
173	} while (0);
174
175	return ret;
176}
177
178
179//------------------------------------------------------------------------------
180int CMcKMod::read(
181	addr_t		buffer,
182	uint32_t	len
183) {
184	int ret = 0;
185
186	do
187	{
188		if (!isOpen())
189		{
190	        LOG_E("no connection to kmod");
191			ret = ERROR_KMOD_NOT_OPEN;
192			break;
193		}
194
195		ret = ::read(fdKMod, buffer, len);
196		if(-1 == ret)
197		{
198			LOG_E("read() failed with errno: %d", errno);
199		}
200
201	} while (0);
202
203	return ret;
204}
205
206
207//------------------------------------------------------------------------------
208bool CMcKMod::waitSSIQ(
209	uint32_t *pCnt
210) {
211	int ret = true;
212
213	do
214	{
215		uint32_t cnt;
216		int ret = read(&cnt, sizeof(cnt));
217		if (sizeof(cnt) != ret)
218		{
219			ret = false;
220		}
221
222		if (NULL != pCnt)
223		{
224			*pCnt = cnt;
225		}
226
227	} while (0);
228
229	return ret;
230}
231
232
233//------------------------------------------------------------------------------
234int CMcKMod::fcInit(
235	addr_t		mciBuffer,
236	uint32_t	nqOffset,
237	uint32_t	nqLength,
238	uint32_t	mcpOffset,
239	uint32_t	mcpLength
240) {
241	int ret = 0;
242
243	do
244	{
245		if (!isOpen())
246		{
247			ret = ERROR_KMOD_NOT_OPEN;
248			break;
249		}
250
251		// Init MC with NQ and MCP buffer addresses
252		union mc_ioctl_init_params fcInitParams = {
253		// C++ does not support C99 designated initializers
254				/* .in = */{
255				/* .base = */(uint32_t) mciBuffer,
256				/* .nq_offset = */nqOffset,
257				/* .nq_length = */nqLength,
258				/* .mcp_offset = */mcpOffset,
259				/* .mcp_length = */mcpLength } };
260		ret = ioctl(fdKMod, MC_DRV_KMOD_IOCTL_FC_INIT, &fcInitParams);
261		if (ret != 0)
262		{
263			LOG_E("IOCTL_FC_INIT failed with ret = %d and errno = %d", ret, errno);
264			break;
265		}
266
267	} while (0);
268
269	return ret;
270}
271
272
273//------------------------------------------------------------------------------
274int CMcKMod::fcInfo(
275	uint32_t	extInfoId,
276	uint32_t	*pState,
277	uint32_t	*pExtInfo
278) {
279	int ret = 0;
280
281	do
282	{
283		if (!isOpen())
284		{
285	        LOG_E("no connection to kmod");
286			ret = ERROR_KMOD_NOT_OPEN;
287			break;
288		}
289
290		// Init MC with NQ and MCP buffer addresses
291		union mc_ioctl_info_params fcInfoParams = {
292		// C++ does not support C99 designated initializers
293				/* .in = */{
294				/* .ext_info_id = */extInfoId } };
295		ret = ioctl(fdKMod, MC_DRV_KMOD_IOCTL_FC_INFO, &fcInfoParams);
296		if (ret != 0)
297		{
298			LOG_E("IOCTL_FC_INFO failed with ret = %d and errno = %d", ret, errno);
299			break;
300		}
301
302		if (NULL != pState)
303		{
304			*pState = fcInfoParams.out.state;
305		}
306
307		if (NULL != pExtInfo)
308		{
309			*pExtInfo = fcInfoParams.out.ext_info;
310		}
311
312	} while (0);
313
314	return ret;
315}
316
317
318//------------------------------------------------------------------------------
319int CMcKMod::fcYield(
320	void
321) {
322	int ret = 0;
323
324	do
325	{
326		if (!isOpen())
327		{
328	        LOG_E("no connection to kmod");
329			ret = ERROR_KMOD_NOT_OPEN;
330			break;
331		}
332
333		ret = ioctl(fdKMod, MC_DRV_KMOD_IOCTL_FC_YIELD, NULL);
334		if (ret != 0)
335		{
336			LOG_E("IOCTL_FC_YIELD failed with ret = %d and errno = %d", ret, errno);
337			break;
338		}
339
340	} while (0);
341
342	return ret;
343}
344
345
346//------------------------------------------------------------------------------
347int CMcKMod::fcNSIQ(
348	void
349) {
350	int ret = 0;
351
352	do
353	{
354		if (!isOpen())
355		{
356	        LOG_E("no connection to kmod");
357			ret = ERROR_KMOD_NOT_OPEN;
358			break;
359		}
360
361		ret = ioctl(fdKMod, MC_DRV_KMOD_IOCTL_FC_NSIQ, NULL);
362		if (ret != 0)
363		{
364			LOG_E("IOCTL_FC_NSIQ failed with ret = %d and errno = %d", ret, errno);
365			break;
366		}
367
368	} while (0);
369
370	return ret;
371}
372
373
374//------------------------------------------------------------------------------
375int CMcKMod::free(
376	uint32_t handle
377) {
378	int ret = 0;
379
380	do
381	{
382		LOG_I("free(): handle=%d", handle);
383
384		if (!isOpen())
385		{
386	        LOG_E("no connection to kmod");
387			ret = ERROR_KMOD_NOT_OPEN;
388			break;
389		}
390
391		union mc_ioctl_free_params freeParams = {
392		// C++ does not support c99 designated initializers
393				/* .in = */{
394				/* .handle = */(uint32_t) handle } };
395
396		ret = ioctl(fdKMod, MC_DRV_KMOD_IOCTL_FREE, &freeParams);
397		if (0 != ret)
398		{
399			LOG_E("IOCTL_FREE failed with ret = %d and errno = %d", ret, errno);
400			break;
401		}
402
403	} while (0);
404
405	return ret;
406}
407
408
409//------------------------------------------------------------------------------
410int CMcKMod::registerWsmL2(
411	addr_t		buffer,
412	uint32_t	len,
413	uint32_t	pid,
414	uint32_t	*pHandle,
415	addr_t		*pPhysWsmL2
416) {
417	int ret = 0;
418
419	do
420	{
421		LOG_I("registerWsmL2(): buffer=%p, len=%d, pid=%d", buffer, len, pid);
422
423		if (!isOpen())
424		{
425	        LOG_E("no connection to kmod");
426			ret = ERROR_KMOD_NOT_OPEN;
427			break;
428		}
429
430		union mc_ioctl_app_reg_wsm_l2_params params = {
431		// C++ does not support C99 designated initializers
432				/* .in = */{
433				/* .buffer = */(uint32_t) buffer,
434				/* .len = */len,
435				/* .pid = */pid } };
436
437		ret = ioctl(fdKMod, MC_DRV_KMOD_IOCTL_APP_REGISTER_WSM_L2, &params);
438		if (0 != ret)
439		{
440			LOG_E("IOCTL_APP_REGISTER_WSM_L2 failed with ret = %d and errno = %d", ret, errno);
441			break;
442		}
443
444		LOG_I("WSM L2 phys=%x, handle=%d", params.out.phys_wsm_l2_table,
445				params.out.handle);
446
447		if (NULL != pHandle)
448		{
449			*pHandle = params.out.handle;
450		}
451
452		if (NULL != pPhysWsmL2)
453		{
454			*pPhysWsmL2 = (addr_t) params.out.phys_wsm_l2_table;
455		}
456
457	} while (0);
458
459	return ret;
460}
461
462
463//------------------------------------------------------------------------------
464int CMcKMod::unregisterWsmL2(
465	uint32_t handle
466) {
467	int ret = 0;
468
469	do
470	{
471		LOG_I("unregisterWsmL2(): handle=%d", handle);
472
473		if (!isOpen())
474		{
475	        LOG_E("no connection to kmod");
476			ret = ERROR_KMOD_NOT_OPEN;
477			break;
478		}
479
480		struct mc_ioctl_app_unreg_wsm_l2_params params = {
481		// C++ does not support c99 designated initializers
482				/* .in = */{
483				/* .handle = */handle } };
484
485		int ret = ioctl(fdKMod, MC_DRV_KMOD_IOCTL_APP_UNREGISTER_WSM_L2, &params);
486		if (0 != ret)
487		{
488			LOG_E("IOCTL_APP_UNREGISTER_WSM_L2 failed with ret = %d and errno = %d", ret, errno);
489			break;
490		}
491
492	} while (0);
493
494	return ret;
495}
496
497//------------------------------------------------------------------------------
498int CMcKMod::fcExecute(
499    addr_t    startAddr,
500    uint32_t  areaLength
501) {
502    int ret = 0;
503    union mc_ioctl_fc_execute_params params = {
504        /*.in =*/ {
505            /*.phys_start_addr = */ (uint32_t)startAddr,
506            /*.length = */ areaLength
507        }
508    };
509    do
510    {
511        if (!isOpen())
512        {
513            LOG_E("no connection to kmod");
514            break;
515        }
516
517        ret = ioctl(fdKMod, MC_DRV_KMOD_IOCTL_FC_EXECUTE, &params);
518        if (ret != 0)
519        {
520            LOG_E("IOCTL_FC_EXECUTE failed with ret = %d and errno = %d", ret, errno);
521            break;
522        }
523
524    } while(0);
525
526    return ret;
527}
528//------------------------------------------------------------------------------
529bool CMcKMod::checkKmodVersionOk(
530    void
531) {
532    bool ret = false;
533
534    do
535    {
536        if (!isOpen())
537        {
538            LOG_E("no connection to kmod");
539            break;
540        }
541
542        struct mc_ioctl_get_version_params params;
543
544        int ioret = ioctl(fdKMod, MC_DRV_KMOD_IOCTL_GET_VERSION, &params);
545        if (0 != ioret)
546        {
547            LOG_E("IOCTL_GET_VERSION failed with ret = %d and errno = %d", ret, errno);
548            break;
549        }
550
551        // Run-time check.
552        char* errmsg;
553        if (!checkVersionOkMCDRVMODULEAPI(params.out.kernel_module_version, &errmsg)) {
554            LOG_E("%s", errmsg);
555            break;
556        }
557        LOG_I("%s", errmsg);
558
559        ret = true;
560
561    } while (0);
562
563    return ret;
564}
565
566/** @} */
567