M7350v1_en_gpl

This commit is contained in:
T
2024-09-09 08:52:07 +00:00
commit f9cc65cfda
65988 changed files with 26357421 additions and 0 deletions
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,73 @@
/*
* Common data types for use by the MobiCore Kernel API Driver
*
* <-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _MC_KAPI_COMMON_H
#define _MC_KAPI_COMMON_H
#include "connection.h"
#include "mcinq.h"
void mcapi_insert_connection(struct connection *connection);
void mcapi_remove_connection(uint32_t seq);
unsigned int mcapi_unique_id(void);
#define MC_DAEMON_PID 0xFFFFFFFF
#define MC_DRV_MOD_DEVNODE_FULLPATH "/dev/mobicore"
/* dummy function helper macro */
#define DUMMY_FUNCTION() do {} while (0)
/* Found in main.c */
extern struct device *mc_kapi;
#define MCDRV_ERROR(dev, txt, ...) \
dev_err(dev, "%s() ### ERROR: " txt, __func__, ##__VA_ARGS__)
#if defined(DEBUG)
/* #define DEBUG_VERBOSE */
#if defined(DEBUG_VERBOSE)
#define MCDRV_DBG_VERBOSE MCDRV_DBG
#else
#define MCDRV_DBG_VERBOSE(...) DUMMY_FUNCTION()
#endif
#define MCDRV_DBG(dev, txt, ...) \
dev_info(dev, "%s(): " txt, __func__, ##__VA_ARGS__)
#define MCDRV_DBG_WARN(dev, txt, ...) \
dev_warn(dev, "%s() WARNING: " txt, __func__, ##__VA_ARGS__)
#define MCDRV_DBG_ERROR(dev, txt, ...) \
dev_err(dev, "%s() ### ERROR: " txt, __func__, ##__VA_ARGS__)
#define MCDRV_ASSERT(cond) \
do { \
if (unlikely(!(cond))) { \
panic("mc_kernelapi Assertion failed: %s:%d\n", \
__FILE__, __LINE__); \
} \
} while (0)
#elif defined(NDEBUG)
#define MCDRV_DBG_VERBOSE(...) DUMMY_FUNCTION()
#define MCDRV_DBG(...) DUMMY_FUNCTION()
#define MCDRV_DBG_WARN(...) DUMMY_FUNCTION()
#define MCDRV_DBG_ERROR(...) DUMMY_FUNCTION()
#define MCDRV_ASSERT(...) DUMMY_FUNCTION()
#else
#error "Define DEBUG or NDEBUG"
#endif /* [not] defined(DEBUG_MCMODULE) */
#define assert(expr) MCDRV_ASSERT(expr)
#endif /* _MC_KAPI_COMMON_H */
@@ -0,0 +1,204 @@
/*
* Connection data.
*
* <-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/netlink.h>
#include <linux/skbuff.h>
#include <linux/netlink.h>
#include <linux/semaphore.h>
#include <linux/time.h>
#include <net/sock.h>
#include <net/net_namespace.h>
#include "connection.h"
#include "common.h"
/* Define the initial state of the Data Available Semaphore */
#define SEM_NO_DATA_AVAILABLE 0
struct connection *connection_new(void)
{
struct connection *conn;
conn = kzalloc(sizeof(*conn), GFP_KERNEL);
conn->sequence_magic = mcapi_unique_id();
mutex_init(&conn->data_lock);
sema_init(&conn->data_available_sem, SEM_NO_DATA_AVAILABLE);
mcapi_insert_connection(conn);
return conn;
}
struct connection *connection_create(int socket_descriptor, pid_t dest)
{
struct connection *conn = connection_new();
conn->peer_pid = dest;
return conn;
}
void connection_cleanup(struct connection *conn)
{
if (!conn)
return;
kfree_skb(conn->skb);
mcapi_remove_connection(conn->sequence_magic);
kfree(conn);
}
bool connection_connect(struct connection *conn, pid_t dest)
{
/* Nothing to connect */
conn->peer_pid = dest;
return true;
}
size_t connection_read_data_msg(struct connection *conn, void *buffer,
uint32_t len)
{
size_t ret = -1;
MCDRV_DBG_VERBOSE(mc_kapi,
"reading connection data %u, connection data left %u",
len, conn->data_len);
/* trying to read more than the left data */
if (len > conn->data_len) {
ret = conn->data_len;
memcpy(buffer, conn->data_start, conn->data_len);
conn->data_len = 0;
} else {
ret = len;
memcpy(buffer, conn->data_start, len);
conn->data_len -= len;
conn->data_start += len;
}
if (conn->data_len == 0) {
conn->data_start = NULL;
kfree_skb(conn->skb);
conn->skb = NULL;
}
MCDRV_DBG_VERBOSE(mc_kapi, "read %u", ret);
return ret;
}
size_t connection_read_datablock(struct connection *conn, void *buffer,
uint32_t len)
{
return connection_read_data(conn, buffer, len, -1);
}
size_t connection_read_data(struct connection *conn, void *buffer, uint32_t len,
int32_t timeout)
{
size_t ret = 0;
MCDRV_ASSERT(buffer != NULL);
MCDRV_ASSERT(conn->socket_descriptor != NULL);
MCDRV_DBG_VERBOSE(mc_kapi, "read data len = %u for PID = %u",
len, conn->sequence_magic);
do {
/*
* Wait until data is available or timeout
* msecs_to_jiffies(-1) -> wait forever for the sem
*/
if (down_timeout(&(conn->data_available_sem),
msecs_to_jiffies(timeout))) {
MCDRV_DBG_VERBOSE(mc_kapi,
"Timeout reading the data sem");
ret = -2;
break;
}
if (mutex_lock_interruptible(&(conn->data_lock))) {
MCDRV_DBG_ERROR(mc_kapi,
"interrupted reading the data sem");
ret = -1;
break;
}
/* Have data, use it */
if (conn->data_len > 0)
ret = connection_read_data_msg(conn, buffer, len);
mutex_unlock(&(conn->data_lock));
/* There is still some data left */
if (conn->data_len > 0)
up(&conn->data_available_sem);
} while (0);
return ret;
}
size_t connection_write_data(struct connection *conn, void *buffer,
uint32_t len)
{
struct sk_buff *skb = NULL;
struct nlmsghdr *nlh;
int ret = 0;
MCDRV_DBG_VERBOSE(mc_kapi, "buffer length %u from pid %u\n",
len, conn->sequence_magic);
do {
skb = nlmsg_new(NLMSG_SPACE(len), GFP_KERNEL);
if (!skb) {
ret = -1;
break;
}
nlh = nlmsg_put(skb, 0, conn->sequence_magic, 2,
NLMSG_LENGTH(len), NLM_F_REQUEST);
if (!nlh) {
ret = -1;
break;
}
memcpy(NLMSG_DATA(nlh), buffer, len);
netlink_unicast(conn->socket_descriptor, skb,
conn->peer_pid, MSG_DONTWAIT);
ret = len;
} while (0);
if (!ret && skb != NULL)
kfree_skb(skb);
return ret;
}
int connection_process(struct connection *conn, struct sk_buff *skb)
{
int ret = 0;
do {
if (mutex_lock_interruptible(&(conn->data_lock))) {
MCDRV_DBG_ERROR(mc_kapi,
"Interrupted getting data semaphore!");
ret = -1;
break;
}
kfree_skb(conn->skb);
/* Get a reference to the incoming skb */
conn->skb = skb_get(skb);
if (conn->skb) {
conn->data_msg = nlmsg_hdr(conn->skb);
conn->data_len = NLMSG_PAYLOAD(conn->data_msg, 0);
conn->data_start = NLMSG_DATA(conn->data_msg);
up(&(conn->data_available_sem));
}
mutex_unlock(&(conn->data_lock));
ret = 0;
} while (0);
return ret;
}
@@ -0,0 +1,58 @@
/*
* Connection data.
*
* <-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _MC_KAPI_CONNECTION_H_
#define _MC_KAPI_CONNECTION_H_
#include <linux/semaphore.h>
#include <linux/mutex.h>
#include <stddef.h>
#include <stdbool.h>
struct connection {
/* Netlink socket */
struct sock *socket_descriptor;
/* Random? magic to match requests/answers */
uint32_t sequence_magic;
struct nlmsghdr *data_msg;
/* How much connection data is left */
uint32_t data_len;
/* Start pointer of remaining data */
void *data_start;
struct sk_buff *skb;
/* Data protection lock */
struct mutex data_lock;
/* Data protection semaphore */
struct semaphore data_available_sem;
/* PID address used for local connection */
pid_t self_pid;
/* Remote PID for connection */
pid_t peer_pid;
/* The list param for using the kernel lists */
struct list_head list;
};
struct connection *connection_new(void);
struct connection *connection_create(int socket_descriptor, pid_t dest);
void connection_cleanup(struct connection *conn);
bool connection_connect(struct connection *conn, pid_t dest);
size_t connection_read_datablock(struct connection *conn, void *buffer,
uint32_t len);
size_t connection_read_data(struct connection *conn, void *buffer,
uint32_t len, int32_t timeout);
size_t connection_write_data(struct connection *conn, void *buffer,
uint32_t len);
int connection_process(struct connection *conn, struct sk_buff *skb);
#endif /* _MC_KAPI_CONNECTION_H_ */
@@ -0,0 +1,215 @@
/*
* MobiCore client library device management.
*
* Device and Trustlet Session management Functions.
*
* <-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/list.h>
#include <linux/slab.h>
#include <linux/device.h>
#include "mc_kernel_api.h"
#include "public/mobicore_driver_api.h"
#include "device.h"
#include "common.h"
struct wsm *wsm_create(void *virt_addr, uint32_t len, uint32_t handle,
void *phys_addr)
{
struct wsm *wsm;
wsm = kzalloc(sizeof(*wsm), GFP_KERNEL);
wsm->virt_addr = virt_addr;
wsm->len = len;
wsm->handle = handle;
wsm->phys_addr = phys_addr;
return wsm;
}
struct mcore_device_t *mcore_device_create(uint32_t device_id,
struct connection *connection)
{
struct mcore_device_t *dev;
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
dev->device_id = device_id;
dev->connection = connection;
INIT_LIST_HEAD(&dev->session_vector);
INIT_LIST_HEAD(&dev->wsm_l2_vector);
return dev;
}
void mcore_device_cleanup(struct mcore_device_t *dev)
{
struct session *tmp;
struct wsm *wsm;
struct list_head *pos, *q;
/*
* Delete all session objects. Usually this should not be needed
* as close_device() requires that all sessions have been closed before.
*/
list_for_each_safe(pos, q, &dev->session_vector) {
tmp = list_entry(pos, struct session, list);
list_del(pos);
session_cleanup(tmp);
}
/* Free all allocated WSM descriptors */
list_for_each_safe(pos, q, &dev->wsm_l2_vector) {
wsm = list_entry(pos, struct wsm, list);
list_del(pos);
kfree(wsm);
}
connection_cleanup(dev->connection);
mcore_device_close(dev);
kfree(dev);
}
bool mcore_device_open(struct mcore_device_t *dev, const char *deviceName)
{
dev->instance = mobicore_open();
return (dev->instance != NULL);
}
void mcore_device_close(struct mcore_device_t *dev)
{
mobicore_release(dev->instance);
}
bool mcore_device_has_sessions(struct mcore_device_t *dev)
{
return !list_empty(&dev->session_vector);
}
bool mcore_device_create_new_session(struct mcore_device_t *dev,
uint32_t session_id,
struct connection *connection)
{
/* Check if session_id already exists */
if (mcore_device_resolve_session_id(dev, session_id)) {
MCDRV_DBG_ERROR(mc_kapi,
" session %u already exists", session_id);
return false;
}
struct session *session =
session_create(session_id, dev->instance, connection);
list_add_tail(&(session->list), &(dev->session_vector));
return true;
}
bool mcore_device_remove_session(struct mcore_device_t *dev,
uint32_t session_id)
{
bool ret = false;
struct session *tmp;
struct list_head *pos, *q;
list_for_each_safe(pos, q, &dev->session_vector) {
tmp = list_entry(pos, struct session, list);
if (tmp->session_id == session_id) {
list_del(pos);
session_cleanup(tmp);
ret = true;
break;
}
}
return ret;
}
struct session *mcore_device_resolve_session_id(struct mcore_device_t *dev,
uint32_t session_id)
{
struct session *ret = NULL;
struct session *tmp;
struct list_head *pos;
/* Get session for session_id */
list_for_each(pos, &dev->session_vector) {
tmp = list_entry(pos, struct session, list);
if (tmp->session_id == session_id) {
ret = tmp;
break;
}
}
return ret;
}
struct wsm *mcore_device_allocate_contiguous_wsm(struct mcore_device_t *dev,
uint32_t len)
{
struct wsm *wsm = NULL;
do {
if (len == 0)
break;
/* Allocate shared memory */
void *virt_addr;
uint32_t handle;
void *phys_addr;
int ret = mobicore_allocate_wsm(dev->instance, len, &handle,
&virt_addr, &phys_addr);
if (ret != 0)
break;
/* Register (vaddr,paddr) with device */
wsm = wsm_create(virt_addr, len, handle, phys_addr);
list_add_tail(&(wsm->list), &(dev->wsm_l2_vector));
} while (0);
return wsm;
}
bool mcore_device_free_contiguous_wsm(struct mcore_device_t *dev,
struct wsm *wsm)
{
bool ret = false;
struct wsm *tmp;
struct list_head *pos;
list_for_each(pos, &dev->wsm_l2_vector) {
tmp = list_entry(pos, struct wsm, list);
if (tmp == wsm) {
ret = true;
break;
}
}
if (ret) {
MCDRV_DBG_VERBOSE(mc_kapi,
"freeWsm virt_addr=0x%p, handle=%d",
wsm->virt_addr, wsm->handle);
/* ignore return code */
mobicore_free_wsm(dev->instance, wsm->handle);
list_del(pos);
kfree(wsm);
}
return ret;
}
struct wsm *mcore_device_find_contiguous_wsm(struct mcore_device_t *dev,
void *virt_addr)
{
struct wsm *wsm;
struct list_head *pos;
list_for_each(pos, &dev->wsm_l2_vector) {
wsm = list_entry(pos, struct wsm, list);
if (virt_addr == wsm->virt_addr)
return wsm;
}
return NULL;
}
@@ -0,0 +1,56 @@
/*
* MobiCore client library device management.
*
* Device and Trustlet Session management Functions.
*
* <-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _MC_KAPI_DEVICE_H_
#define _MC_KAPI_DEVICE_H_
#include <linux/list.h>
#include "connection.h"
#include "session.h"
#include "wsm.h"
struct mcore_device_t {
/* MobiCore Trustlet session associated with the device */
struct list_head session_vector;
struct list_head wsm_l2_vector; /* WSM L2 Table */
uint32_t device_id; /* Device identifier */
struct connection *connection; /* The device connection */
struct mc_instance *instance; /* MobiCore Driver instance */
/* The list param for using the kernel lists */
struct list_head list;
};
struct mcore_device_t *mcore_device_create(
uint32_t device_id, struct connection *connection);
void mcore_device_cleanup(struct mcore_device_t *dev);
bool mcore_device_open(struct mcore_device_t *dev, const char *deviceName);
void mcore_device_close(struct mcore_device_t *dev);
bool mcore_device_has_sessions(struct mcore_device_t *dev);
bool mcore_device_create_new_session(
struct mcore_device_t *dev, uint32_t session_id,
struct connection *connection);
bool mcore_device_remove_session(
struct mcore_device_t *dev, uint32_t session_id);
struct session *mcore_device_resolve_session_id(
struct mcore_device_t *dev, uint32_t session_id);
struct wsm *mcore_device_allocate_contiguous_wsm(
struct mcore_device_t *dev, uint32_t len);
bool mcore_device_free_contiguous_wsm(
struct mcore_device_t *dev, struct wsm *wsm);
struct wsm *mcore_device_find_contiguous_wsm(
struct mcore_device_t *dev, void *virt_addr);
#endif /* _MC_KAPI_DEVICE_H_ */
@@ -0,0 +1,117 @@
/*
* Notifications inform the MobiCore runtime environment that information is
* pending in a WSM buffer.
*
* The Trustlet Connector (TLC) and the corresponding Trustlet also utilize
* this buffer to notify each other about new data within the
* Trustlet Connector Interface (TCI).
*
* The buffer is set up as a queue, which means that more than one
* notification can be written to the buffer before the switch to the other
* world is performed. Each side therefore facilitates an incoming and an
* outgoing queue for communication with the other side.
*
* Notifications hold the session ID, which is used to reference the
* communication partner in the other world.
* So if, e.g., the TLC in the normal world wants to notify his Trustlet
* about new data in the TLC buffer
*
* Notification queue declarations.
*
* <-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _MCINQ_H_
#define _MCINQ_H_
/* Minimum and maximum count of elements in the notification queue */
#define MIN_NQ_ELEM 1 /* Minimum notification queue elements. */
#define MAX_NQ_ELEM 64 /* Maximum notification queue elements. */
/* Minimum notification length (in bytes). */
#define MIN_NQ_LEN (MIN_NQ_ELEM * sizeof(notification))
/* Maximum notification length (in bytes). */
#define MAX_NQ_LEN (MAX_NQ_ELEM * sizeof(notification))
/*
* MCP session ID is used when directly communicating with the MobiCore
* (e.g. for starting and stopping of Trustlets).
*/
#define SID_MCP 0
/* Invalid session id is returned in case of an error. */
#define SID_INVALID 0xffffffff
/* Notification data structure. */
struct notification {
uint32_t session_id; /* Session ID. */
int32_t payload; /* Additional notification info */
};
/*
* Notification payload codes.
* 0 indicated a plain simple notification,
* a positive value is a termination reason from the task,
* a negative value is a termination reason from MobiCore.
* Possible negative values are given below.
*/
enum notification_payload {
/* task terminated, but exit code is invalid */
ERR_INVALID_EXIT_CODE = -1,
/* task terminated due to session end, no exit code available */
ERR_SESSION_CLOSE = -2,
/* task terminated due to invalid operation */
ERR_INVALID_OPERATION = -3,
/* session ID is unknown */
ERR_INVALID_SID = -4,
/* session is not active */
ERR_SID_NOT_ACTIVE = -5
};
/*
* Declaration of the notification queue header.
* Layout as specified in the data structure specification.
*/
struct notification_queue_header {
uint32_t write_cnt; /* Write counter. */
uint32_t read_cnt; /* Read counter. */
uint32_t queue_size; /* Queue size. */
};
/*
* Queue struct which defines a queue object.
* The queue struct is accessed by the queue<operation> type of
* function. elementCnt must be a power of two and the power needs
* to be smaller than power of uint32_t (obviously 32).
*/
struct notification_queue {
/* Queue header. */
struct notification_queue_header hdr;
/* Notification elements. */
struct notification notification[MIN_NQ_ELEM];
};
#endif /* _MCINQ_H_ */
@@ -0,0 +1,67 @@
/*
* <-- Copyright Giesecke & Devrient GmbH 2011-2012 -->
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef _MCUUID_H_
#define _MCUUID_H_
#define UUID_TYPE
/* Universally Unique Identifier (UUID) according to ISO/IEC 11578. */
struct mc_uuid_t {
uint8_t value[16]; /* Value of the UUID. */
};
/* UUID value used as free marker in service provider containers. */
#define MC_UUID_FREE_DEFINE \
{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }
static const struct mc_uuid_t MC_UUID_FREE = {
MC_UUID_FREE_DEFINE
};
/* Reserved UUID. */
#define MC_UUID_RESERVED_DEFINE \
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
static const struct mc_uuid_t MC_UUID_RESERVED = {
MC_UUID_RESERVED_DEFINE
};
/* UUID for system applications. */
#define MC_UUID_SYSTEM_DEFINE \
{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE }
static const struct mc_uuid_t MC_UUID_SYSTEM = {
MC_UUID_SYSTEM_DEFINE
};
#endif /* _MCUUID_H_ */
@@ -0,0 +1,191 @@
/*
* MobiCore KernelApi module
*
* <-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/netlink.h>
#include <linux/kthread.h>
#include <linux/device.h>
#include <net/sock.h>
#include <linux/list.h>
#include "connection.h"
#include "common.h"
#define MC_DAEMON_NETLINK 17
struct mc_kernelapi_ctx {
struct sock *sk;
struct list_head peers;
atomic_t counter;
};
struct mc_kernelapi_ctx *mod_ctx;
/* Define a MobiCore Kernel API device structure for use with dev_debug() etc */
struct device_driver mc_kernel_api_name = {
.name = "mckernelapi"
};
struct device mc_kernel_api_subname = {
.init_name = "", /* Set to 'mcapi' at mcapi_init() time */
.driver = &mc_kernel_api_name
};
struct device *mc_kapi = &mc_kernel_api_subname;
/* get a unique ID */
unsigned int mcapi_unique_id(void)
{
return (unsigned int)atomic_inc_return(&(mod_ctx->counter));
}
static struct connection *mcapi_find_connection(uint32_t seq)
{
struct connection *tmp;
struct list_head *pos;
/* Get session for session_id */
list_for_each(pos, &mod_ctx->peers) {
tmp = list_entry(pos, struct connection, list);
if (tmp->sequence_magic == seq)
return tmp;
}
return NULL;
}
void mcapi_insert_connection(struct connection *connection)
{
list_add_tail(&(connection->list), &(mod_ctx->peers));
connection->socket_descriptor = mod_ctx->sk;
}
void mcapi_remove_connection(uint32_t seq)
{
struct connection *tmp;
struct list_head *pos, *q;
/*
* Delete all session objects. Usually this should not be needed as
* closeDevice() requires that all sessions have been closed before.
*/
list_for_each_safe(pos, q, &mod_ctx->peers) {
tmp = list_entry(pos, struct connection, list);
if (tmp->sequence_magic == seq) {
list_del(pos);
break;
}
}
}
static int mcapi_process(struct sk_buff *skb, struct nlmsghdr *nlh)
{
struct connection *c;
int length;
int seq;
pid_t pid;
int ret;
pid = nlh->nlmsg_pid;
length = nlh->nlmsg_len;
seq = nlh->nlmsg_seq;
MCDRV_DBG_VERBOSE(mc_kapi, "nlmsg len %d type %d pid 0x%X seq %d\n",
length, nlh->nlmsg_type, pid, seq);
do {
c = mcapi_find_connection(seq);
if (!c) {
MCDRV_ERROR(mc_kapi,
"Invalid incoming connection - seq=%u!",
seq);
ret = -1;
break;
}
/* Pass the buffer to the appropriate connection */
connection_process(c, skb);
ret = 0;
} while (false);
return ret;
}
static void mcapi_callback(struct sk_buff *skb)
{
struct nlmsghdr *nlh = nlmsg_hdr(skb);
int len = skb->len;
int err = 0;
while (NLMSG_OK(nlh, len)) {
err = mcapi_process(skb, nlh);
/* if err or if this message says it wants a response */
if (err || (nlh->nlmsg_flags & NLM_F_ACK))
netlink_ack(skb, nlh, err);
nlh = NLMSG_NEXT(nlh, len);
}
}
static int __init mcapi_init(void)
{
#if defined MC_NETLINK_COMPAT || defined MC_NETLINK_COMPAT_V37
struct netlink_kernel_cfg cfg = {
.input = mcapi_callback,
};
#endif
dev_set_name(mc_kapi, "mcapi");
dev_info(mc_kapi, "Mobicore API module initialized!\n");
mod_ctx = kzalloc(sizeof(struct mc_kernelapi_ctx), GFP_KERNEL);
#ifdef MC_NETLINK_COMPAT_V37
mod_ctx->sk = netlink_kernel_create(&init_net, MC_DAEMON_NETLINK,
&cfg);
#elif defined MC_NETLINK_COMPAT
mod_ctx->sk = netlink_kernel_create(&init_net, MC_DAEMON_NETLINK,
THIS_MODULE, &cfg);
#else
/* start kernel thread */
mod_ctx->sk = netlink_kernel_create(&init_net, MC_DAEMON_NETLINK, 0,
mcapi_callback, NULL, THIS_MODULE);
#endif
if (!mod_ctx->sk) {
MCDRV_ERROR(mc_kapi, "register of receive handler failed");
return -EFAULT;
}
INIT_LIST_HEAD(&mod_ctx->peers);
return 0;
}
static void __exit mcapi_exit(void)
{
dev_info(mc_kapi, "Unloading Mobicore API module.\n");
if (mod_ctx->sk != NULL) {
netlink_kernel_release(mod_ctx->sk);
mod_ctx->sk = NULL;
}
kfree(mod_ctx);
mod_ctx = NULL;
}
module_init(mcapi_init);
module_exit(mcapi_exit);
MODULE_AUTHOR("Giesecke & Devrient GmbH");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("MobiCore API driver");
@@ -0,0 +1,445 @@
/*
* MobiCore Driver API.
*
* The MobiCore (MC) Driver API provides access functions to the MobiCore
* runtime environment and the contained Trustlets.
*
* <-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _MOBICORE_DRIVER_API_H_
#define _MOBICORE_DRIVER_API_H_
#define __MC_CLIENT_LIB_API
#include "mcuuid.h"
/*
* Return values of MobiCore driver functions.
*/
enum mc_result {
/* Function call succeeded. */
MC_DRV_OK = 0,
/* No notification available. */
MC_DRV_NO_NOTIFICATION = 1,
/* Error during notification on communication level. */
MC_DRV_ERR_NOTIFICATION = 2,
/* Function not implemented. */
MC_DRV_ERR_NOT_IMPLEMENTED = 3,
/* No more resources available. */
MC_DRV_ERR_OUT_OF_RESOURCES = 4,
/* Driver initialization failed. */
MC_DRV_ERR_INIT = 5,
/* Unknown error. */
MC_DRV_ERR_UNKNOWN = 6,
/* The specified device is unknown. */
MC_DRV_ERR_UNKNOWN_DEVICE = 7,
/* The specified session is unknown.*/
MC_DRV_ERR_UNKNOWN_SESSION = 8,
/* The specified operation is not allowed. */
MC_DRV_ERR_INVALID_OPERATION = 9,
/* The response header from the MC is invalid. */
MC_DRV_ERR_INVALID_RESPONSE = 10,
/* Function call timed out. */
MC_DRV_ERR_TIMEOUT = 11,
/* Can not allocate additional memory. */
MC_DRV_ERR_NO_FREE_MEMORY = 12,
/* Free memory failed. */
MC_DRV_ERR_FREE_MEMORY_FAILED = 13,
/* Still some open sessions pending. */
MC_DRV_ERR_SESSION_PENDING = 14,
/* MC daemon not reachable */
MC_DRV_ERR_DAEMON_UNREACHABLE = 15,
/* The device file of the kernel module could not be opened. */
MC_DRV_ERR_INVALID_DEVICE_FILE = 16,
/* Invalid parameter. */
MC_DRV_ERR_INVALID_PARAMETER = 17,
/* Unspecified error from Kernel Module*/
MC_DRV_ERR_KERNEL_MODULE = 18,
/* Error during mapping of additional bulk memory to session. */
MC_DRV_ERR_BULK_MAPPING = 19,
/* Error during unmapping of additional bulk memory to session. */
MC_DRV_ERR_BULK_UNMAPPING = 20,
/* Notification received, exit code available. */
MC_DRV_INFO_NOTIFICATION = 21,
/* Set up of NWd connection failed. */
MC_DRV_ERR_NQ_FAILED = 22
};
/*
* Driver control command.
*/
enum mc_driver_ctrl {
/* Return the driver version */
MC_CTRL_GET_VERSION = 1
};
/*
* Structure of Session Handle, includes the Session ID and the Device ID the
* Session belongs to.
* The session handle will be used for session-based MobiCore communication.
* It will be passed to calls which address a communication end point in the
* MobiCore environment.
*/
struct mc_session_handle {
uint32_t session_id; /* MobiCore session ID */
uint32_t device_id; /* Device ID the session belongs to */
};
/*
* Information structure about additional mapped Bulk buffer between the
* Trustlet Connector (NWd) and the Trustlet (SWd). This structure is
* initialized from a Trustlet Connector by calling mc_map().
* In order to use the memory within a Trustlet the Trustlet Connector has to
* inform the Trustlet with the content of this structure via the TCI.
*/
struct mc_bulk_map {
/* The virtual address of the Bulk buffer regarding the address space
* of the Trustlet, already includes a possible offset! */
void *secure_virt_addr;
uint32_t secure_virt_len; /* Length of the mapped Bulk buffer */
};
/* The default device ID */
#define MC_DEVICE_ID_DEFAULT 0
/* Wait infinite for a response of the MC. */
#define MC_INFINITE_TIMEOUT ((int32_t)(-1))
/* Do not wait for a response of the MC. */
#define MC_NO_TIMEOUT 0
/* TCI/DCI must not exceed 1MiB */
#define MC_MAX_TCI_LEN 0x100000
/**
* mc_open_device() - Open a new connection to a MobiCore device.
* @device_id: Identifier for the MobiCore device to be used.
* MC_DEVICE_ID_DEFAULT refers to the default device.
*
* Initializes all device specific resources required to communicate with a
* MobiCore instance located on the specified device in the system. If the
* device does not exist the function will return MC_DRV_ERR_UNKNOWN_DEVICE.
*
* Return codes:
* MC_DRV_OK: operation completed successfully
* MC_DRV_ERR_INVALID_OPERATION: device already opened
* MC_DRV_ERR_DAEMON_UNREACHABLE: problems with daemon
* MC_DRV_ERR_UNKNOWN_DEVICE: device_id unknown
* MC_DRV_ERR_INVALID_DEVICE_FILE: kernel module under /dev/mobicore
* cannot be opened
*/
__MC_CLIENT_LIB_API enum mc_result mc_open_device(uint32_t device_id);
/**
* mc_close_device() - Close the connection to a MobiCore device.
* @device_id: Identifier for the MobiCore device.
*
* When closing a device, active sessions have to be closed beforehand.
* Resources associated with the device will be released.
* The device may be opened again after it has been closed.
*
* MC_DEVICE_ID_DEFAULT refers to the default device.
*
* Return codes:
* MC_DRV_OK: operation completed successfully
* MC_DRV_ERR_UNKNOWN_DEVICE: device id is invalid
* MC_DRV_ERR_SESSION_PENDING: a session is still open
* MC_DRV_ERR_DAEMON_UNREACHABLE: problems with daemon occur
*/
__MC_CLIENT_LIB_API enum mc_result mc_close_device(uint32_t device_id);
/**
* mc_open_session() - Open a new session to a Trustlet.
* @session: On success, the session data will be returned
* @uuid: UUID of the Trustlet to be opened
* @tci: TCI buffer for communicating with the Trustlet
* @tci_len: Length of the TCI buffer. Maximum allowed value
* is MC_MAX_TCI_LEN
*
* The Trustlet with the given UUID has to be available in the flash filesystem.
*
* Write MCP open message to buffer and notify MobiCore about the availability
* of a new command.
*
* Waits till the MobiCore responses with the new session ID (stored in the MCP
* buffer).
*
* Note that session.device_id has to be the device id of an opened device.
*
* Return codes:
* MC_DRV_OK: operation completed successfully
* MC_DRV_INVALID_PARAMETER: session parameter is invalid
* MC_DRV_ERR_UNKNOWN_DEVICE: device id is invalid
* MC_DRV_ERR_DAEMON_UNREACHABLE: problems with daemon socket occur
* MC_DRV_ERR_NQ_FAILED: daemon returns an error
*/
__MC_CLIENT_LIB_API enum mc_result mc_open_session(
struct mc_session_handle *session, const struct mc_uuid_t *uuid,
uint8_t *tci, uint32_t tci_len);
/**
* mc_close_session() - Close a Trustlet session.
* @session: Session to be closed.
*
* Closes the specified MobiCore session. The call will block until the
* session has been closed.
*
* Device device_id has to be opened in advance.
*
* Return codes:
* MC_DRV_OK: operation completed successfully
* MC_DRV_INVALID_PARAMETER: session parameter is invalid
* MC_DRV_ERR_UNKNOWN_SESSION: session id is invalid
* MC_DRV_ERR_UNKNOWN_DEVICE: device id of session is invalid
* MC_DRV_ERR_DAEMON_UNREACHABLE: problems with daemon occur
* MC_DRV_ERR_INVALID_DEVICE_FILE: daemon cannot open Trustlet file
*/
__MC_CLIENT_LIB_API enum mc_result mc_close_session(
struct mc_session_handle *session);
/**
* mc_notify() - Notify a session.
* @session: The session to be notified.
*
* Notifies the session end point about available message data.
* If the session parameter is correct, notify will always succeed.
* Corresponding errors can only be received by mc_wait_notification().
*
* A session has to be opened in advance.
*
* Return codes:
* MC_DRV_OK: operation completed successfully
* MC_DRV_INVALID_PARAMETER: session parameter is invalid
* MC_DRV_ERR_UNKNOWN_SESSION: session id is invalid
* MC_DRV_ERR_UNKNOWN_DEVICE: device id of session is invalid
*/
__MC_CLIENT_LIB_API enum mc_result mc_notify(struct mc_session_handle *session);
/**
* mc_wait_notification() - Wait for a notification.
* @session: The session the notification should correspond to.
* @timeout: Time in milliseconds to wait
* (MC_NO_TIMEOUT : direct return, > 0 : milliseconds,
* MC_INFINITE_TIMEOUT : wait infinitely)
*
* Wait for a notification issued by the MobiCore for a specific session.
* The timeout parameter specifies the number of milliseconds the call will wait
* for a notification.
*
* If the caller passes 0 as timeout value the call will immediately return.
* If timeout value is below 0 the call will block until a notification for the
* session has been received.
*
* If timeout is below 0, call will block.
*
* Caller has to trust the other side to send a notification to wake him up
* again.
*
* Return codes:
* MC_DRV_OK: operation completed successfully
* MC_DRV_ERR_TIMEOUT: no notification arrived in time
* MC_DRV_INFO_NOTIFICATION: a problem with the session was
* encountered. Get more details with
* mc_get_session_error_code()
* MC_DRV_ERR_NOTIFICATION: a problem with the socket occurred
* MC_DRV_INVALID_PARAMETER: a parameter is invalid
* MC_DRV_ERR_UNKNOWN_SESSION: session id is invalid
* MC_DRV_ERR_UNKNOWN_DEVICE: device id of session is invalid
*/
__MC_CLIENT_LIB_API enum mc_result mc_wait_notification(
struct mc_session_handle *session, int32_t timeout);
/**
* mc_malloc_wsm() - Allocate a block of world shared memory (WSM).
* @device_id: The ID of an opened device to retrieve the WSM from.
* @align: The alignment (number of pages) of the memory block
* (e.g. 0x00000001 for 4kb).
* @len: Length of the block in bytes.
* @wsm: Virtual address of the world shared memory block.
* @wsm_flags: Platform specific flags describing the memory to
* be allocated.
*
* The MC driver allocates a contiguous block of memory which can be used as
* WSM.
* This implicates that the allocated memory is aligned according to the
* alignment parameter.
*
* Always returns a buffer of size WSM_SIZE aligned to 4K.
*
* Align and wsm_flags are currently ignored
*
* Return codes:
* MC_DRV_OK: operation completed successfully
* MC_DRV_INVALID_PARAMETER: a parameter is invalid
* MC_DRV_ERR_UNKNOWN_DEVICE: device id is invalid
* MC_DRV_ERR_NO_FREE_MEMORY: no more contiguous memory is
* available in this size or for this
* process
*/
__MC_CLIENT_LIB_API enum mc_result mc_malloc_wsm(
uint32_t device_id,
uint32_t align,
uint32_t len,
uint8_t **wsm,
uint32_t wsm_flags
);
/**
* mc_free_wsm() - Free a block of world shared memory (WSM).
* @device_id: The ID to which the given address belongs
* @wsm: Address of WSM block to be freed
*
* The MC driver will free a block of world shared memory (WSM) previously
* allocated with mc_malloc_wsm(). The caller has to assure that the address
* handed over to the driver is a valid WSM address.
*
* Return codes:
* MC_DRV_OK: operation completed successfully
* MC_DRV_INVALID_PARAMETER: a parameter is invalid
* MC_DRV_ERR_UNKNOWN_DEVICE: when device id is invalid
* MC_DRV_ERR_FREE_MEMORY_FAILED: on failure
*/
__MC_CLIENT_LIB_API enum mc_result mc_free_wsm(uint32_t device_id,
uint8_t *wsm);
/**
*mc_map() - Map additional bulk buffer between a Trustlet Connector (TLC)
* and the Trustlet (TL) for a session
* @session: Session handle with information of the device_id and
* the session_id. The given buffer is mapped to the
* session specified in the sessionHandle
* @buf: Virtual address of a memory portion (relative to TLC)
* to be shared with the Trustlet, already includes a
* possible offset!
* @len: length of buffer block in bytes.
* @map_info: Information structure about the mapped Bulk buffer
* between the TLC (NWd) and the TL (SWd).
*
* Memory allocated in user space of the TLC can be mapped as additional
* communication channel (besides TCI) to the Trustlet. Limitation of the
* Trustlet memory structure apply: only 6 chunks can be mapped with a maximum
* chunk size of 1 MiB each.
*
* It is up to the application layer (TLC) to inform the Trustlet
* about the additional mapped bulk memory.
*
* Return codes:
* MC_DRV_OK: operation completed successfully
* MC_DRV_INVALID_PARAMETER: a parameter is invalid
* MC_DRV_ERR_UNKNOWN_SESSION: session id is invalid
* MC_DRV_ERR_UNKNOWN_DEVICE: device id of session is invalid
* MC_DRV_ERR_DAEMON_UNREACHABLE: problems with daemon occur
* MC_DRV_ERR_BULK_MAPPING: buf is already uses as bulk buffer or
* when registering the buffer failed
*/
__MC_CLIENT_LIB_API enum mc_result mc_map(
struct mc_session_handle *session, void *buf, uint32_t len,
struct mc_bulk_map *map_info);
/**
* mc_unmap() - Remove additional mapped bulk buffer between Trustlet Connector
* (TLC) and the Trustlet (TL) for a session
* @session: Session handle with information of the device_id and
* the session_id. The given buffer is unmapped from the
* session specified in the sessionHandle.
* @buf: Virtual address of a memory portion (relative to TLC)
* shared with the TL, already includes a possible offset!
* @map_info: Information structure about the mapped Bulk buffer
* between the TLC (NWd) and the TL (SWd)
*
* The bulk buffer will immediately be unmapped from the session context.
*
* The application layer (TLC) must inform the TL about unmapping of the
* additional bulk memory before calling mc_unmap!
*
* The clientlib currently ignores the len field in map_info.
*
* Return codes:
* MC_DRV_OK: operation completed successfully
* MC_DRV_INVALID_PARAMETER: a parameter is invalid
* MC_DRV_ERR_UNKNOWN_SESSION: session id is invalid
* MC_DRV_ERR_UNKNOWN_DEVICE: device id of session is invalid
* MC_DRV_ERR_DAEMON_UNREACHABLE: problems with daemon occur
* MC_DRV_ERR_BULK_UNMAPPING: buf was not registered earlier
* or when unregistering failed
*/
__MC_CLIENT_LIB_API enum mc_result mc_unmap(
struct mc_session_handle *session, void *buf,
struct mc_bulk_map *map_info);
/**
* mc_driver_ctrl() - Execute driver specific command.
* @param: Command ID of the command to be executed
* @data: Command data and response depending on command
* @len: Length of the data block
*
* Can be used to execute driver specific commands. Besides the control command
* MC_CTRL_GET_VERSION commands are implementation specific.
*
* Please refer to the corresponding specification of the driver manufacturer.
*
* Return codes:
* MC_DRV_ERR_NOT_IMPLEMENTED.
*/
__MC_CLIENT_LIB_API enum mc_result mc_driver_ctrl(
enum mc_driver_ctrl param, uint8_t *data, uint32_t len);
/**
* mc_manage() - Execute application management command.
* @device_id: Identifier for the MobiCore device to be used.
* NULL refers to the default device.
* @data: Command data/response data depending on command
* @len: Length of the data block
*
* Shall be used to exchange application management commands with the MobiCore.
* The MobiCore Application Management Protocol is described in [MCAMP].
*
* Return codes:
* MC_DRV_ERR_NOT_IMPLEMENTED.
*/
__MC_CLIENT_LIB_API enum mc_result mc_manage(
uint32_t device_id, uint8_t *data, uint32_t len);
/**
* mc_get_session_error_code() - Get additional error information of the last
* error that occurred on a session.
* @session: Session handle with information of the device_id and
* the session_id
* @last_error: >0 Trustlet has terminated itself with this value,
* <0 Trustlet is dead because of an error within the
* MobiCore (e.g. Kernel exception). See also MCI
* definition.
*
* After the request the stored error code will be deleted.
*
* Return codes:
* MC_DRV_OK: operation completed successfully
* MC_DRV_INVALID_PARAMETER: a parameter is invalid
* MC_DRV_ERR_UNKNOWN_SESSION: session id is invalid
* MC_DRV_ERR_UNKNOWN_DEVICE: device id of session is invalid
*/
__MC_CLIENT_LIB_API enum mc_result mc_get_session_error_code(
struct mc_session_handle *session, int32_t *last_error);
#endif /* _MOBICORE_DRIVER_API_H_ */
@@ -0,0 +1,267 @@
/*
* <-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _MOBICORE_DRIVER_CMD_H_
#define _MOBICORE_DRIVER_CMD_H_
#include "mcuuid.h"
enum mc_drv_cmd_t {
MC_DRV_CMD_PING = 0,
MC_DRV_CMD_GET_INFO = 1,
MC_DRV_CMD_OPEN_DEVICE = 2,
MC_DRV_CMD_CLOSE_DEVICE = 3,
MC_DRV_CMD_NQ_CONNECT = 4,
MC_DRV_CMD_OPEN_SESSION = 5,
MC_DRV_CMD_CLOSE_SESSION = 6,
MC_DRV_CMD_NOTIFY = 7,
MC_DRV_CMD_MAP_BULK_BUF = 8,
MC_DRV_CMD_UNMAP_BULK_BUF = 9
};
enum mc_drv_rsp_t {
MC_DRV_RSP_OK = 0,
MC_DRV_RSP_FAILED = 1,
MC_DRV_RSP_DEVICE_NOT_OPENED = 2,
MC_DRV_RSP_DEVICE_ALREADY_OPENED = 3,
MC_DRV_RSP_COMMAND_NOT_ALLOWED = 4,
MC_DRV_INVALID_DEVICE_NAME = 5,
MC_DRV_RSP_MAP_BULK_ERRO = 6,
MC_DRV_RSP_TRUSTLET_NOT_FOUND = 7,
MC_DRV_RSP_PAYLOAD_LENGTH_ERROR = 8,
};
struct mc_drv_command_header_t {
uint32_t command_id;
};
struct mc_drv_response_header_t {
uint32_t response_id;
};
#define MC_DEVICE_ID_DEFAULT 0 /* The default device ID */
struct mc_drv_cmd_open_device_payload_t {
uint32_t device_id;
};
struct mc_drv_cmd_open_device_t {
struct mc_drv_command_header_t header;
struct mc_drv_cmd_open_device_payload_t payload;
};
struct mc_drv_rsp_open_device_payload_t {
/* empty */
};
struct mc_drv_rsp_open_device_t {
struct mc_drv_response_header_t header;
struct mc_drv_rsp_open_device_payload_t payload;
};
struct mc_drv_cmd_close_device_t {
struct mc_drv_command_header_t header;
/*
* no payload here because close has none.
* If we use an empty struct, C++ will count it as 4 bytes.
* This will write too much into the socket at write(cmd,sizeof(cmd))
*/
};
struct mc_drv_rsp_close_device_payload_t {
/* empty */
};
struct mc_drv_rsp_close_device_t {
struct mc_drv_response_header_t header;
struct mc_drv_rsp_close_device_payload_t payload;
};
struct mc_drv_cmd_open_session_payload_t {
uint32_t device_id;
struct mc_uuid_t uuid;
uint32_t tci;
uint32_t len;
};
struct mc_drv_cmd_open_session_t {
struct mc_drv_command_header_t header;
struct mc_drv_cmd_open_session_payload_t payload;
};
struct mc_drv_rsp_open_session_payload_t {
uint32_t device_id;
uint32_t session_id;
uint32_t device_session_id;
uint32_t mc_result;
uint32_t session_magic;
};
struct mc_drv_rsp_open_session_t {
struct mc_drv_response_header_t header;
struct mc_drv_rsp_open_session_payload_t payload;
};
struct mc_drv_cmd_close_session_payload_t {
uint32_t session_id;
};
struct mc_drv_cmd_close_session_t {
struct mc_drv_command_header_t header;
struct mc_drv_cmd_close_session_payload_t payload;
};
struct mc_drv_rsp_close_session_payload_t {
/* empty */
};
struct mc_drv_rsp_close_session_t {
struct mc_drv_response_header_t header;
struct mc_drv_rsp_close_session_payload_t payload;
};
struct mc_drv_cmd_notify_payload_t {
uint32_t session_id;
};
struct mc_drv_cmd_notify_t {
struct mc_drv_command_header_t header;
struct mc_drv_cmd_notify_payload_t payload;
};
struct mc_drv_rsp_notify_payload_t {
/* empty */
};
struct mc_drv_rsp_notify_t {
struct mc_drv_response_header_t header;
struct mc_drv_rsp_notify_payload_t payload;
};
struct mc_drv_cmd_map_bulk_mem_payload_t {
uint32_t session_id;
uint32_t handle;
uint32_t phys_addr_l2;
uint32_t offset_payload;
uint32_t len_bulk_mem;
};
struct mc_drv_cmd_map_bulk_mem_t {
struct mc_drv_command_header_t header;
struct mc_drv_cmd_map_bulk_mem_payload_t payload;
};
struct mc_drv_rsp_map_bulk_mem_payload_t {
uint32_t session_id;
uint32_t secure_virtual_adr;
uint32_t mc_result;
};
struct mc_drv_rsp_map_bulk_mem_t {
struct mc_drv_response_header_t header;
struct mc_drv_rsp_map_bulk_mem_payload_t payload;
};
struct mc_drv_cmd_unmap_bulk_mem_payload_t {
uint32_t session_id;
uint32_t handle;
uint32_t secure_virtual_adr;
uint32_t len_bulk_mem;
};
struct mc_drv_cmd_unmap_bulk_mem_t {
struct mc_drv_command_header_t header;
struct mc_drv_cmd_unmap_bulk_mem_payload_t payload;
};
struct mc_drv_rsp_unmap_bulk_mem_payload_t {
uint32_t response_id;
uint32_t session_id;
uint32_t mc_result;
};
struct mc_drv_rsp_unmap_bulk_mem_t {
struct mc_drv_response_header_t header;
struct mc_drv_rsp_unmap_bulk_mem_payload_t payload;
};
struct mc_drv_cmd_nqconnect_payload_t {
uint32_t device_id;
uint32_t session_id;
uint32_t device_session_id;
uint32_t session_magic; /* Random data */
};
struct mc_drv_cmd_nqconnect_t {
struct mc_drv_command_header_t header;
struct mc_drv_cmd_nqconnect_payload_t payload;
};
struct mc_drv_rsp_nqconnect_payload_t {
/* empty; */
};
struct mc_drv_rsp_nqconnect_t {
struct mc_drv_response_header_t header;
struct mc_drv_rsp_nqconnect_payload_t payload;
};
union mc_drv_command_t {
struct mc_drv_command_header_t header;
struct mc_drv_cmd_open_device_t mc_drv_cmd_open_device;
struct mc_drv_cmd_close_device_t mc_drv_cmd_close_device;
struct mc_drv_cmd_open_session_t mc_drv_cmd_open_session;
struct mc_drv_cmd_close_session_t mc_drv_cmd_close_session;
struct mc_drv_cmd_nqconnect_t mc_drv_cmd_nqconnect;
struct mc_drv_cmd_notify_t mc_drv_cmd_notify;
struct mc_drv_cmd_map_bulk_mem_t mc_drv_cmd_map_bulk_mem;
struct mc_drv_cmd_unmap_bulk_mem_t mc_drv_cmd_unmap_bulk_mem;
};
union mc_drv_response_t {
struct mc_drv_response_header_t header;
struct mc_drv_rsp_open_device_t mc_drv_rsp_open_device;
struct mc_drv_rsp_close_device_t mc_drv_rsp_close_device;
struct mc_drv_rsp_open_session_t mc_drv_rsp_open_session;
struct mc_drv_rsp_close_session_t mc_drv_rsp_close_session;
struct mc_drv_rsp_nqconnect_t mc_drv_rsp_nqconnect;
struct mc_drv_rsp_notify_t mc_drv_rsp_notify;
struct mc_drv_rsp_map_bulk_mem_t mc_drv_rsp_map_bulk_mem;
struct mc_drv_rsp_unmap_bulk_mem_t mc_drv_rsp_unmap_bulk_mem;
};
#endif /* _MOBICORE_DRIVER_CMD_H_ */
@@ -0,0 +1,201 @@
/*
* <-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/device.h>
#include "mc_kernel_api.h"
#include "public/mobicore_driver_api.h"
#include "session.h"
struct bulk_buffer_descriptor *bulk_buffer_descriptor_create(
void *virt_addr, uint32_t len, uint32_t handle, void *phys_addr_wsm_l2)
{
struct bulk_buffer_descriptor *desc;
desc = kzalloc(sizeof(*desc), GFP_KERNEL);
desc->virt_addr = virt_addr;
desc->len = len;
desc->handle = handle;
desc->phys_addr_wsm_l2 = phys_addr_wsm_l2;
return desc;
}
struct session *session_create(
uint32_t session_id, void *instance, struct connection *connection)
{
struct session *session;
session = kzalloc(sizeof(*session), GFP_KERNEL);
session->session_id = session_id;
session->instance = instance;
session->notification_connection = connection;
session->session_info.last_error = SESSION_ERR_NO;
session->session_info.state = SESSION_STATE_INITIAL;
INIT_LIST_HEAD(&(session->bulk_buffer_descriptors));
return session;
}
void session_cleanup(struct session *session)
{
struct bulk_buffer_descriptor *bulk_buf_descr;
struct list_head *pos, *q;
unsigned int phys_addr_wsm_l2;
/* Unmap still mapped buffers */
list_for_each_safe(pos, q, &session->bulk_buffer_descriptors) {
bulk_buf_descr =
list_entry(pos, struct bulk_buffer_descriptor, list);
phys_addr_wsm_l2 =
(unsigned int)bulk_buf_descr->phys_addr_wsm_l2;
MCDRV_DBG_VERBOSE(mc_kapi,
"Phys Addr of L2 Table = 0x%X, handle= %d",
phys_addr_wsm_l2,
bulk_buf_descr->handle);
/* ignore any error, as we cannot do anything in this case. */
int ret = mobicore_unmap_vmem(session->instance,
bulk_buf_descr->handle);
if (ret != 0)
MCDRV_DBG_ERROR(mc_kapi,
"mobicore_unmap_vmem failed: %d", ret);
list_del(pos);
kfree(bulk_buf_descr);
}
/* Finally delete notification connection */
connection_cleanup(session->notification_connection);
kfree(session);
}
void session_set_error_info(struct session *session, int32_t err)
{
session->session_info.last_error = err;
}
int32_t session_get_last_err(struct session *session)
{
return session->session_info.last_error;
}
struct bulk_buffer_descriptor *session_add_bulk_buf(struct session *session,
void *buf, uint32_t len)
{
struct bulk_buffer_descriptor *bulk_buf_descr = NULL;
struct bulk_buffer_descriptor *tmp;
struct list_head *pos;
/*
* Search bulk buffer descriptors for existing vAddr
* At the moment a virtual address can only be added one time
*/
list_for_each(pos, &session->bulk_buffer_descriptors) {
tmp = list_entry(pos, struct bulk_buffer_descriptor, list);
if (tmp->virt_addr == buf)
return NULL;
}
do {
/*
* Prepare the interface structure for memory registration in
* Kernel Module
*/
uint32_t l2_table_phys;
uint32_t handle;
int ret = mobicore_map_vmem(session->instance, buf, len,
&handle, &l2_table_phys);
if (ret != 0) {
MCDRV_DBG_ERROR(mc_kapi,
"mobicore_map_vmem failed, ret=%d",
ret);
break;
}
MCDRV_DBG_VERBOSE(mc_kapi,
"Phys Addr of L2 Table = 0x%X, handle=%d",
(unsigned int)l2_table_phys, handle);
/* Create new descriptor */
bulk_buf_descr =
bulk_buffer_descriptor_create(buf, len,
handle,
(void *)l2_table_phys);
/* Add to vector of descriptors */
list_add_tail(&(bulk_buf_descr->list),
&(session->bulk_buffer_descriptors));
} while (0);
return bulk_buf_descr;
}
bool session_remove_bulk_buf(struct session *session, void *virt_addr)
{
bool ret = true;
struct bulk_buffer_descriptor *bulk_buf = NULL;
struct bulk_buffer_descriptor *tmp;
struct list_head *pos, *q;
MCDRV_DBG_VERBOSE(mc_kapi, "Virtual Address = 0x%X",
(unsigned int) virt_addr);
/* Search and remove bulk buffer descriptor */
list_for_each_safe(pos, q, &session->bulk_buffer_descriptors) {
tmp = list_entry(pos, struct bulk_buffer_descriptor, list);
if (tmp->virt_addr == virt_addr) {
bulk_buf = tmp;
list_del(pos);
break;
}
}
if (bulk_buf == NULL) {
MCDRV_DBG_ERROR(mc_kapi, "Virtual Address not found");
ret = false;
} else {
MCDRV_DBG_VERBOSE(mc_kapi, "WsmL2 phys=0x%X, handle=%d",
(unsigned int)bulk_buf->phys_addr_wsm_l2,
bulk_buf->handle);
/* ignore any error, as we cannot do anything */
int ret = mobicore_unmap_vmem(session->instance,
bulk_buf->handle);
if (ret != 0)
MCDRV_DBG_ERROR(mc_kapi,
"mobicore_unmap_vmem failed: %d", ret);
kfree(bulk_buf);
}
return ret;
}
uint32_t session_find_bulk_buf(struct session *session, void *virt_addr)
{
struct bulk_buffer_descriptor *tmp;
struct list_head *pos, *q;
MCDRV_DBG_VERBOSE(mc_kapi, "Virtual Address = 0x%X",
(unsigned int) virt_addr);
/* Search and return buffer descriptor handle */
list_for_each_safe(pos, q, &session->bulk_buffer_descriptors) {
tmp = list_entry(pos, struct bulk_buffer_descriptor, list);
if (tmp->virt_addr == virt_addr)
return tmp->handle;
}
return 0;
}
@@ -0,0 +1,144 @@
/*
* <-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _MC_KAPI_SESSION_H_
#define _MC_KAPI_SESSION_H_
#include "common.h"
#include <linux/list.h>
#include "connection.h"
struct bulk_buffer_descriptor {
void *virt_addr; /* The VA of the Bulk buffer */
uint32_t len; /* Length of the Bulk buffer */
uint32_t handle;
/* The physical address of the L2 table of the Bulk buffer*/
void *phys_addr_wsm_l2;
/* The list param for using the kernel lists*/
struct list_head list;
};
struct bulk_buffer_descriptor *bulk_buffer_descriptor_create(
void *virt_addr,
uint32_t len,
uint32_t handle,
void *phys_addr_wsm_l2
);
/*
* Session states.
* At the moment not used !!
*/
enum session_state {
SESSION_STATE_INITIAL,
SESSION_STATE_OPEN,
SESSION_STATE_TRUSTLET_DEAD
};
#define SESSION_ERR_NO 0 /* No session error */
/*
* Session information structure.
* The information structure is used to hold the state of the session, which
* will limit further actions for the session.
* Also the last error code will be stored till it's read.
*/
struct session_information {
enum session_state state; /* Session state */
int32_t last_error; /* Last error of session */
};
struct session {
struct mc_instance *instance;
/* Descriptors of additional bulk buffer of a session */
struct list_head bulk_buffer_descriptors;
/* Information about session */
struct session_information session_info;
uint32_t session_id;
struct connection *notification_connection;
/* The list param for using the kernel lists */
struct list_head list;
};
struct session *session_create(
uint32_t session_id,
void *instance,
struct connection *connection
);
void session_cleanup(struct session *session);
/*
* session_add_bulk_buf() - Add address information of additional bulk
* buffer memory to session and register virtual
* memory in kernel module
* @session: Session information structure
* @buf: The virtual address of bulk buffer.
* @len: Length of bulk buffer.
*
* The virtual address can only be added one time. If the virtual
* address already exist, NULL is returned.
*
* On success the actual Bulk buffer descriptor with all address information
* is returned, NULL if an error occurs.
*/
struct bulk_buffer_descriptor *session_add_bulk_buf(
struct session *session, void *buf, uint32_t len);
/*
* session_remove_bulk_buf() - Remove address information of additional bulk
* buffer memory from session and unregister
* virtual memory in kernel module
* @session: Session information structure
* @buf: The virtual address of the bulk buffer
*
* Returns true on success
*/
bool session_remove_bulk_buf(struct session *session, void *buf);
/*
* session_find_bulk_buf() - Find the handle of the bulk buffer for this
* session
*
* @session: Session information structure
* @buf: The virtual address of bulk buffer.
*
* On success the actual Bulk buffer handle is returned, 0
* if an error occurs.
*/
uint32_t session_find_bulk_buf(struct session *session, void *virt_addr);
/*
* session_set_error_info() - Set additional error information of the last
* error that occurred.
* @session: Session information structure
* @err: The actual error
*/
void session_set_error_info(struct session *session, int32_t err);
/*
* session_get_last_err() - Get additional error information of the last
* error that occurred.
* @session: Session information structure
*
* After request the information is set to SESSION_ERR_NO.
*
* Returns the last stored error code or SESSION_ERR_NO
*/
int32_t session_get_last_err(struct session *session);
#endif /* _MC_KAPI_SESSION_H_ */
@@ -0,0 +1,33 @@
/*
* World shared memory definitions.
*
* <-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _MC_KAPI_WSM_H_
#define _MC_KAPI_WSM_H_
#include "common.h"
#include <linux/list.h>
struct wsm {
void *virt_addr;
uint32_t len;
uint32_t handle;
void *phys_addr;
struct list_head list;
};
struct wsm *wsm_create(
void *virt_addr,
uint32_t len,
uint32_t handle,
/* NULL this may be unknown, so is can be omitted */
void *phys_addr
);
#endif /* _MC_KAPI_WSM_H_ */