M7350/kernel/drivers/gud/MobiCoreDriver/clientlib.c
2024-09-09 08:57:42 +00:00

434 lines
9.7 KiB
C

/*
* Copyright (c) 2013-2015 TRUSTONIC LIMITED
* All Rights Reserved.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/sched.h>
#include <linux/list.h>
#include "public/mc_linux.h"
#include "public/mc_admin.h"
#include "public/mobicore_driver_api.h"
#include "main.h"
#include "debug.h"
#include "client.h"
#include "session.h"
#include "api.h"
enum mc_result convert(int err)
{
switch (-err) {
case 0:
return MC_DRV_OK;
case ENOMSG:
return MC_DRV_NO_NOTIFICATION;
case EBADMSG:
return MC_DRV_ERR_NOTIFICATION;
case EAGAIN:
return MC_DRV_ERR_OUT_OF_RESOURCES;
case EHOSTDOWN:
return MC_DRV_ERR_INIT;
case ENODEV:
return MC_DRV_ERR_UNKNOWN_DEVICE;
case ENXIO:
return MC_DRV_ERR_UNKNOWN_SESSION;
case EPERM:
return MC_DRV_ERR_INVALID_OPERATION;
case EBADE:
return MC_DRV_ERR_INVALID_RESPONSE;
case ETIME:
return MC_DRV_ERR_TIMEOUT;
case ENOMEM:
return MC_DRV_ERR_NO_FREE_MEMORY;
case EUCLEAN:
return MC_DRV_ERR_FREE_MEMORY_FAILED;
case ENOTEMPTY:
return MC_DRV_ERR_SESSION_PENDING;
case EHOSTUNREACH:
return MC_DRV_ERR_DAEMON_UNREACHABLE;
case ENOENT:
return MC_DRV_ERR_INVALID_DEVICE_FILE;
case EINVAL:
return MC_DRV_ERR_INVALID_PARAMETER;
case EPROTO:
return MC_DRV_ERR_KERNEL_MODULE;
case EADDRINUSE:
return MC_DRV_ERR_BULK_MAPPING;
case EADDRNOTAVAIL:
return MC_DRV_ERR_BULK_UNMAPPING;
case ECOMM:
return MC_DRV_INFO_NOTIFICATION;
case EUNATCH:
return MC_DRV_ERR_NQ_FAILED;
default:
MCDRV_DBG("error is %d", err);
return MC_DRV_ERR_UNKNOWN;
}
}
static inline bool is_valid_device(uint32_t device_id)
{
return MC_DEVICE_ID_DEFAULT == device_id;
}
static struct tbase_client *client;
static int open_count;
static DEFINE_MUTEX(dev_mutex); /* Lock for the device */
static bool clientlib_client_get(void)
{
int ret = true;
mutex_lock(&dev_mutex);
if (!client)
ret = false;
else
client_get(client);
mutex_unlock(&dev_mutex);
return ret;
}
static void clientlib_client_put(void)
{
mutex_lock(&dev_mutex);
client_put(client);
mutex_unlock(&dev_mutex);
}
enum mc_result mc_open_device(uint32_t device_id)
{
enum mc_result mc_result = MC_DRV_OK;
/* Check parameters */
if (!is_valid_device(device_id))
return MC_DRV_ERR_UNKNOWN_DEVICE;
mutex_lock(&dev_mutex);
if (!open_count)
client = api_open_device(true);
if (client) {
open_count++;
MCDRV_DBG("Successfully opened the device.");
} else {
mc_result = MC_DRV_ERR_INVALID_DEVICE_FILE;
MCDRV_DBG("Could not open device");
}
mutex_unlock(&dev_mutex);
return mc_result;
}
EXPORT_SYMBOL(mc_open_device);
enum mc_result mc_close_device(uint32_t device_id)
{
enum mc_result mc_result = MC_DRV_OK;
/* Check parameters */
if (!is_valid_device(device_id))
return MC_DRV_ERR_UNKNOWN_DEVICE;
mutex_lock(&dev_mutex);
if (!client) {
mc_result = MC_DRV_ERR_DAEMON_DEVICE_NOT_OPEN;
goto end;
}
if (open_count > 1) {
open_count--;
goto end;
}
/* Check sessions and freeze client */
mc_result = convert(api_freeze_device(client));
if (MC_DRV_OK != mc_result)
goto end;
/* Close the device */
api_close_device(client);
client = NULL;
open_count = 0;
end:
mutex_unlock(&dev_mutex);
return mc_result;
}
EXPORT_SYMBOL(mc_close_device);
enum mc_result mc_open_session(struct mc_session_handle *session,
const struct mc_uuid_t *uuid,
uint8_t *tci, uint32_t len)
{
struct mc_identity identity = {
.login_type = TEEC_LOGIN_PUBLIC,
};
enum mc_result ret;
/* Check parameters */
if (!session)
return MC_DRV_ERR_INVALID_PARAMETER;
if (!is_valid_device(session->device_id))
return MC_DRV_ERR_UNKNOWN_DEVICE;
if (!clientlib_client_get())
return MC_DRV_ERR_DAEMON_DEVICE_NOT_OPEN;
/* Call core api */
ret = convert(api_open_session(client, &session->session_id, uuid,
(uintptr_t)tci, len, false, &identity));
clientlib_client_put();
return ret;
}
EXPORT_SYMBOL(mc_open_session);
enum mc_result mc_open_trustlet(struct mc_session_handle *session,
uint32_t spid,
uint8_t *trustlet, uint32_t trustlet_len,
uint8_t *tci, uint32_t len)
{
enum mc_result ret;
/* Check parameters */
if (!session)
return MC_DRV_ERR_INVALID_PARAMETER;
if (!is_valid_device(session->device_id))
return MC_DRV_ERR_UNKNOWN_DEVICE;
if (!clientlib_client_get())
return MC_DRV_ERR_DAEMON_DEVICE_NOT_OPEN;
/* Call core api */
ret = convert(api_open_trustlet(client, &session->session_id, spid,
(uintptr_t)trustlet, trustlet_len,
(uintptr_t)tci, len));
clientlib_client_put();
return ret;
}
EXPORT_SYMBOL(mc_open_trustlet);
enum mc_result mc_close_session(struct mc_session_handle *session)
{
enum mc_result ret;
/* Check parameters */
if (!session)
return MC_DRV_ERR_INVALID_PARAMETER;
if (!is_valid_device(session->device_id))
return MC_DRV_ERR_UNKNOWN_DEVICE;
if (!clientlib_client_get())
return MC_DRV_ERR_DAEMON_DEVICE_NOT_OPEN;
/* Call core api */
ret = convert(api_close_session(client, session->session_id));
clientlib_client_put();
return ret;
}
EXPORT_SYMBOL(mc_close_session);
enum mc_result mc_notify(struct mc_session_handle *session)
{
enum mc_result ret;
/* Check parameters */
if (!session)
return MC_DRV_ERR_INVALID_PARAMETER;
if (!is_valid_device(session->device_id))
return MC_DRV_ERR_UNKNOWN_DEVICE;
if (!clientlib_client_get())
return MC_DRV_ERR_DAEMON_DEVICE_NOT_OPEN;
/* Call core api */
ret = convert(api_notify(client, session->session_id));
clientlib_client_put();
return ret;
}
EXPORT_SYMBOL(mc_notify);
enum mc_result mc_wait_notification(struct mc_session_handle *session,
int32_t timeout)
{
enum mc_result ret;
/* Check parameters */
if (!session)
return MC_DRV_ERR_INVALID_PARAMETER;
if (!is_valid_device(session->device_id))
return MC_DRV_ERR_UNKNOWN_DEVICE;
if (!clientlib_client_get())
return MC_DRV_ERR_DAEMON_DEVICE_NOT_OPEN;
/* Call core api */
ret = convert(api_wait_notification(client, session->session_id,
timeout));
clientlib_client_put();
return ret;
}
EXPORT_SYMBOL(mc_wait_notification);
enum mc_result mc_malloc_wsm(uint32_t device_id, uint32_t align, uint32_t len,
uint8_t **wsm, uint32_t wsm_flags)
{
enum mc_result ret;
uintptr_t va;
/* Check parameters */
if (!is_valid_device(device_id))
return MC_DRV_ERR_UNKNOWN_DEVICE;
if (!len)
return MC_DRV_ERR_INVALID_PARAMETER;
if (!wsm)
return MC_DRV_ERR_INVALID_PARAMETER;
if (!clientlib_client_get())
return MC_DRV_ERR_DAEMON_DEVICE_NOT_OPEN;
/* Call core api */
ret = convert(api_malloc_cbuf(client, len, &va, NULL));
if (ret == MC_DRV_OK)
*wsm = (uint8_t *)va;
clientlib_client_put();
return ret;
}
EXPORT_SYMBOL(mc_malloc_wsm);
enum mc_result mc_free_wsm(uint32_t device_id, uint8_t *wsm)
{
enum mc_result ret;
uintptr_t va = (uintptr_t)wsm;
/* Check parameters */
if (!is_valid_device(device_id))
return MC_DRV_ERR_UNKNOWN_DEVICE;
if (!clientlib_client_get())
return MC_DRV_ERR_DAEMON_DEVICE_NOT_OPEN;
/* Call core api */
ret = convert(api_free_cbuf(client, va));
clientlib_client_put();
return ret;
}
EXPORT_SYMBOL(mc_free_wsm);
enum mc_result mc_map(struct mc_session_handle *session, void *address,
uint32_t length, struct mc_bulk_map *map_info)
{
enum mc_result ret;
struct mc_ioctl_buffer bufs[MC_MAP_MAX];
uint32_t i;
/* Check parameters */
if (!session)
return MC_DRV_ERR_INVALID_PARAMETER;
if (!is_valid_device(session->device_id))
return MC_DRV_ERR_UNKNOWN_DEVICE;
if (!map_info)
return MC_DRV_ERR_INVALID_PARAMETER;
if (!clientlib_client_get())
return MC_DRV_ERR_DAEMON_DEVICE_NOT_OPEN;
/* Call core api */
bufs[0].va = (uintptr_t)address;
bufs[0].len = length;
for (i = 1; i < MC_MAP_MAX; i++)
bufs[i].va = 0;
ret = convert(api_map_wsms(client, session->session_id, bufs));
if (ret == MC_DRV_OK) {
map_info->secure_virt_addr = bufs[0].sva;
map_info->secure_virt_len = bufs[0].len;
}
clientlib_client_put();
return ret;
}
EXPORT_SYMBOL(mc_map);
enum mc_result mc_unmap(struct mc_session_handle *session, void *address,
struct mc_bulk_map *map_info)
{
enum mc_result ret;
struct mc_ioctl_buffer bufs[MC_MAP_MAX];
uint32_t i;
/* Check parameters */
if (!session)
return MC_DRV_ERR_INVALID_PARAMETER;
if (!is_valid_device(session->device_id))
return MC_DRV_ERR_UNKNOWN_DEVICE;
if (!map_info)
return MC_DRV_ERR_INVALID_PARAMETER;
if (!clientlib_client_get())
return MC_DRV_ERR_DAEMON_DEVICE_NOT_OPEN;
/* Call core api */
bufs[0].va = (uintptr_t)address;
bufs[0].len = map_info->secure_virt_len;
bufs[0].sva = map_info->secure_virt_addr;
for (i = 1; i < MC_MAP_MAX; i++)
bufs[i].va = 0;
ret = convert(api_unmap_wsms(client, session->session_id, bufs));
clientlib_client_put();
return ret;
}
EXPORT_SYMBOL(mc_unmap);
enum mc_result mc_get_session_error_code(struct mc_session_handle *session,
int32_t *exit_code)
{
enum mc_result ret;
/* Check parameters */
if (!session)
return MC_DRV_ERR_INVALID_PARAMETER;
if (!is_valid_device(session->device_id))
return MC_DRV_ERR_UNKNOWN_DEVICE;
if (!exit_code)
return MC_DRV_ERR_INVALID_PARAMETER;
if (!clientlib_client_get())
return MC_DRV_ERR_DAEMON_DEVICE_NOT_OPEN;
/* Call core api */
ret = convert(api_get_session_exitcode(client, session->session_id,
exit_code));
clientlib_client_put();
return ret;
}
EXPORT_SYMBOL(mc_get_session_error_code);