tzcom: Trustzone communicator driver

- The Trustzone Communicator driver provides interface for userspace
  to communicate with TrustZone.

Change-Id: Id0dadacb9997d4a50e88f48ceb03540e1897df93
Signed-off-by: Sachin Shah <sachins@codeaurora.org>
This commit is contained in:
Sachin Shah 2011-05-19 19:11:45 -07:00 committed by Stephen Boyd
parent 4490e07b47
commit 67026061d7
7 changed files with 1687 additions and 0 deletions

181
Documentation/tzcom.txt Normal file
View file

@ -0,0 +1,181 @@
Introduction
============
The tzcom (TrustZone Communicator) device driver provides IOCTLs for userspace
to communicate with TrustZone Operating Environment (TZBSP) using Secure
Channel Manager (SCM) interface. It also provides a way for TZBSP to utilize
services in HLOS.
Hardware description
====================
The hardware interaction is specified in Secure Channel Manager for TZBSP design
document. This driver exercises the SCM interface (scm_call).
Software description
====================
This driver is a character device driver and following operations are registered:
- tzcom_open()
- tzcom_release()
- tzcom_ioctl()
This driver provides following IOCTL methods:
TZCOM_IOCTL_REGISTER_SERVICE_REQ - to register HLOS service
TZCOM_IOCTL_UNREGISTER_SERVICE_REQ - to unregister HLOS service
TZCOM_IOCTL_SEND_CMD_REQ - send a command to a service
TZCOM_IOCTL_READ_NEXT_CMD_REQ - wait for a cmd from TZBSP to use HLOS service
TZCOM_IOCTL_CONTINUE_CMD_REQ - continue the last incomplete cmd on TZBSP
TZCOM_IOCTL_REGISTER_SERVICE_REQ sequence diagram:
+--------------+ +---------------+
| USERSPACE | | TZCOM |
+------+-------+ +-------+-------+
| REGISTER_SERVICE |
|----------------->| ___
| |,-' ``.
| + verify &`.
| | add |
| | service |
| | to a list|
| registered |<-.._,,,,/
|<-----------------|
| |
TZCOM_IOCTL_READ_NEXT_CMD_REQ, TZCOM_IOCTL_SEND_CMD_REQ and
TZCOM_IOCTL_CONTINUE_CMD_REQ sequence:
+--------------+ +---------------+ +-------------+ +----------------+
| USERSPACE | | TZCOM | | SCM | | TZBSP |
+---+--+-------+ +-------+-------+ +------+------+ +-------+--------+
| | READ_NEXT_CMD | | |
+--|----------------->| | |
| | |.--------. | |
| | || BLOCKED| | |
| | |`--------' | |
| | | | |
| | | | |
| | SEND_CMD | | |
| +----------------->| | |
| | | scm_call | |
| | +---------------->| SEND_CMD |
| | | +---------------->|
| | | | cmd incomplete |
| | | scm_call returns|<----------------+
| | |<----------------+ |
| | | | |
| | |,-'''-. | |
| | + READ `. | |
| | | NEXT | | |
| | | CMD / | |
| | READ_NEXT_CMD ret|<.____,' | |
|<-|------------------+ | |
,---. | | | | |
/ \ | | | | |
/perform\| | | | |
received) | | | |
\command/| | | | |
\ / | | | | |
`---' | | | | |
| | | | |
| | CONTINUE_CMD | | |
+--|----------------->| | |
| | returns | _,... | |
| | immediately |' `. | |
| | | fill in`. | |
| | | incomplete | |
| | | cmd ; | |
| |<-...---' | |
| | scm_call | |
| +---------------->| SEND_CMD |
| | +---------------->|
| | | cmd complete |
| | scm_call returns|<----------------+
|SEND_CMD return |<----------------+ |
|<-----------------+ | |
| | | |
There are three shared buffers between TZCOM driver and TZBSP.
1) For command and response buffers for SEND_CMD requests
2) For commands originated from TZBSP and their corresponding responses
3) For debug service
When calling IOCTL_SEND_CMD_REQ from userspace, command request and response
buffers are initialized and provided in the IOCTL arguments. Where request and
response buffers will be passed as an arguments to the smc_call method.
The requests are synchronous. The driver will put the process to sleep,
waiting for the completion of the requests using wait_for_completion().
This driver uses kmalloc for shared buffer pools which get initialized at driver
initialization. There are three buffers each 20 KB. If any of the buffers fail
to initialize then driver will fail to load. Assumption is the allocated
memory for buffers is contiguous.
Design
======
The goal of this driver is to provide a communication API for the userspace
application to execute services in TrustZone as well as TrustZone operating
environment to access services in HLOS.
Currently TZ->HLOS communication happens from a blocking call to READ_NEXT_CMD
that is initiated from the userspace and on receiving a command request from TZ
service, command is placed on a queue to unblock READ_NEXT_CMD call. This could
have been solved by using a callback, but the practice of invoking callbacks in
userspace from kernel is discouraged.
Power Management
================
n/a
SMP/multi-core
==============
TZCOM allows multiple services being registered from HLOS and multiple processes
or threads can call IOCTL_READ_NEXT_MSG. These services will block until new
data arrives on the shared buffer (buffer #2 as mentioned in Software
Description). This is achieved using wait queues.
Security
========
Please refer to Security Channel Manager design document.
Performance
===========
Every scm_call is a context switch between non-trusted and trusted operating
environment. There are no performance related matrix for scm_call available as
of now.
Interface
=========
This driver will have a /dev/tzcom node and following IOCTL calls can be made.
Userspace API (ioctl calls):
TZCOM_IOCTL_REGISTER_SERVICE_REQ - to register HLOS service
TZCOM_IOCTL_UNREGISTER_SERVICE_REQ - to unregister HLOS service
TZCOM_IOCTL_SEND_CMD_REQ - send a command to a service
TZCOM_IOCTL_READ_NEXT_CMD_REQ - wait for a cmd from TZBSP to use HLOS service
TZCOM_IOCTL_CONTINUE_CMD_REQ - continue the last incomplete cmd on TZBSP
Dependencies
============
This driver interacts with Trustzone operating environment, thus depends on
the TZBSP supported architecture.
To do
=====
TBD

View file

@ -609,6 +609,14 @@ config PMIC8058_XOADC
PMIC8058. Driver interface to program registers of the ADC over
AMUX channels, devices on programmable MPP's and xotherm.
config TZCOM
tristate "Trustzone Communicator driver"
default n
help
Provides a communication interface between userspace and
TrustZone Operating Environment (TZBSP) using Secure Channel
Manager (SCM) interface.
source "drivers/misc/c2port/Kconfig"
source "drivers/misc/eeprom/Kconfig"
source "drivers/misc/cb710/Kconfig"

View file

@ -62,3 +62,4 @@ obj-$(CONFIG_PMIC8XXX_VIBRATOR) += pm8xxx-vibrator.o
obj-$(CONFIG_PMIC8XXX_NFC) += pm8xxx-nfc.o
obj-$(CONFIG_PMIC8XXX_UPL) += pm8xxx-upl.o
obj-$(CONFIG_PMIC8058_XOADC) += pmic8058-xoadc.o
obj-$(CONFIG_TZCOM) += tzcom.o

1248
drivers/misc/tzcom.c Normal file

File diff suppressed because it is too large Load diff

112
drivers/misc/tzcomi.h Normal file
View file

@ -0,0 +1,112 @@
/* Qualcomm TrustZone communicator driver
*
* Copyright (c) 2011, Code Aurora Forum. 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 and
* only 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.
*/
#ifndef __TZCOMI_H_
#define __TZCOMI_H_
#include <linux/types.h>
enum tz_sched_cmd_id {
TZ_SCHED_CMD_ID_INVALID = 0,
TZ_SCHED_CMD_ID_INIT_SB_OUT, /**< Initialize the shared buffer */
TZ_SCHED_CMD_ID_INIT_SB_LOG, /**< Initialize the logging shared buf */
TZ_SCHED_CMD_ID_UNKNOWN = 0x7FFFFFFE,
TZ_SCHED_CMD_ID_MAX = 0x7FFFFFFF
};
enum tz_sched_cmd_type {
TZ_SCHED_CMD_INVALID = 0,
TZ_SCHED_CMD_NEW, /** New TZ Scheduler Command */
TZ_SCHED_CMD_PENDING, /** Pending cmd...sched will restore stack */
TZ_SCHED_CMD_COMPLETE, /** TZ sched command is complete */
TZ_SCHED_CMD_MAX = 0x7FFFFFFF
};
enum tz_sched_cmd_status {
TZ_SCHED_STATUS_INCOMPLETE = 0,
TZ_SCHED_STATUS_COMPLETE,
TZ_SCHED_STATUS_MAX = 0x7FFFFFFF
};
/** Command structure for initializing shared buffers (SB_OUT
and SB_LOG)
*/
__packed struct tz_pr_init_sb_req_s {
/** First 4 bytes should always be command id
* from enum tz_sched_cmd_id */
uint32_t pr_cmd;
/** Pointer to the physical location of sb_out buffer */
uint32_t sb_ptr;
/** length of shared buffer */
uint32_t sb_len;
};
__packed struct tz_pr_init_sb_rsp_s {
/** First 4 bytes should always be command id
* from enum tz_sched_cmd_id */
uint32_t pr_cmd;
/** Return code, 0 for success, Approp error code otherwise */
int32_t ret;
};
/**
* struct tzcom_command - tzcom command buffer
* @cmd_type: value from enum tz_sched_cmd_type
* @sb_in_cmd_addr: points to physical location of command
* buffer
* @sb_in_cmd_len: length of command buffer
*/
__packed struct tzcom_command {
uint32_t cmd_type;
uint8_t *sb_in_cmd_addr;
uint32_t sb_in_cmd_len;
};
/**
* struct tzcom_response - tzcom response buffer
* @cmd_status: value from enum tz_sched_cmd_status
* @sb_in_rsp_addr: points to physical location of response
* buffer
* @sb_in_rsp_len: length of command response
*/
__packed struct tzcom_response {
uint32_t cmd_status;
uint8_t *sb_in_rsp_addr;
uint32_t sb_in_rsp_len;
};
/**
* struct tzcom_callback - tzcom callback buffer
* @cmd_id: command to run in registered service
* @sb_out_rsp_addr: points to physical location of response
* buffer
* @sb_in_cmd_len: length of command response
*
* A callback buffer would be laid out in sb_out as follows:
*
* --------------------- <--- struct tzcom_callback
* | callback header |
* --------------------- <--- tzcom_callback.sb_out_cb_data_off
* | callback data |
* ---------------------
*/
__packed struct tzcom_callback {
uint32_t cmd_id;
uint32_t sb_out_cb_data_len;
uint32_t sb_out_cb_data_off;
};
#endif /* __TZCOMI_H_ */

View file

@ -416,5 +416,6 @@ header-y += xattr.h
header-y += xfrm.h
header-y += msm_mdp.h
header-y += msm_rotator.h
header-y += tzcom.h
header-y += qcedev.h
header-y += genlock.h

136
include/linux/tzcom.h Normal file
View file

@ -0,0 +1,136 @@
/* Qualcomm TrustZone communicator API */
#ifndef __TZCOM_H_
#define __TZCOM_H_
#include <linux/types.h>
#include <linux/ioctl.h>
#define MAX_ION_FD 4
/**
* struct tzcom_register_svc_op_req - for register service ioctl request
* @svc_id - service id (shared between userspace and TZ)
* @cmd_id_low - low number in cmd_id range (shared between userspace and TZ)
* @cmd_id_high - high number in cmd_id range (shared between userspace and TZ)
* @instance_id - unique id for the given service generated by tzcom driver
*/
struct tzcom_register_svc_op_req {
uint32_t svc_id; /* in */
uint32_t cmd_id_low; /* in */
uint32_t cmd_id_high; /* in */
uint32_t instance_id; /* out */
};
/**
* struct tzcom_unregister_svc_op_req - for unregister service ioctl request
* @svc_id - service id to unregister (provided in register_service request)
* @instance_id - instance id generated in register service request
*/
struct tzcom_unregister_svc_op_req {
uint32_t svc_id; /* in */
uint32_t instance_id; /* in */
};
/**
* struct tzcom_next_cmd_op_req - for read next command ioctl request
* @svc_id - has to be a registered svc_id (see @tzcom_register_svc_op_req)
* @instance_id - unique id for the given service (see @tzcom_register_svc_op_req)
* @cmd_id - command to execute on the given service, received from TZ
* @req_len - request buffer length, received from TZ
* @req - request buffer, received from TZ
*/
struct tzcom_next_cmd_op_req {
uint32_t svc_id; /* in */
uint32_t instance_id; /* in */
uint32_t cmd_id; /* out */
unsigned int req_len; /* in/out */
void *req_buf; /* in/out */
};
/**
* struct tzcom_send_cmd_op_req - for send command ioctl request
* @cmd_id - command to execute on TZBSP side
* @ifd_data_fd - ion handle to some memory allocated in user space
* @cmd_buf_offset - command buffer offset
* @cmd_len - command buffer length
* @cmd_buf - command buffer
* @resp_len - response buffer length
* @resp_buf - response buffer
*/
struct tzcom_send_cmd_op_req {
uint32_t cmd_id; /* in */
unsigned int cmd_len; /* in */
void *cmd_buf; /* in */
unsigned int resp_len; /* in/out */
void *resp_buf; /* in/out */
};
/**
* struct tzcom_ion_fd_info - ion fd handle data information
* @fd - ion handle to some memory allocated in user space
* @cmd_buf_offset - command buffer offset
*/
struct tzcom_ion_fd_info {
int32_t fd;
uint32_t cmd_buf_offset;
};
/**
* struct tzcom_send_cmd_op_req - for send command ioctl request
* @cmd_id - command to execute on TZBSP side
* @ifd_data_fd - ion handle to some memory allocated in user space
* @cmd_buf_offset - command buffer offset
* @cmd_len - command buffer length
* @cmd_buf - command buffer
* @resp_len - response buffer length
* @resp_buf - response buffer
*/
struct tzcom_send_cmd_fd_op_req {
uint32_t cmd_id; /* in */
struct tzcom_ion_fd_info ifd_data[MAX_ION_FD];
unsigned int cmd_len; /* in */
void *cmd_buf; /* in */
unsigned int resp_len; /* in/out */
void *resp_buf; /* in/out */
};
/**
* struct tzcom_cont_cmd_op_req - for continue command ioctl request. used
* as a trigger from HLOS service to notify TZCOM that it's done with its
* operation and provide the response for TZCOM can continue the incomplete
* command execution
* @cmd_id - Command to continue filled in by tzcom as tzcom knows about the
* last incomplete command.
* @instance_id - Instance id of the svc
* @resp_len - Length of the response
* @resp_buf - Response buffer where the response of the cmd should go.
*/
struct tzcom_cont_cmd_op_req {
uint32_t cmd_id; /* out */
uint32_t instance_id; /* in */
unsigned int resp_len; /* in */
void *resp_buf; /* in */
};
#define TZCOM_IOC_MAGIC 0x97
/* For HLOS service */
#define TZCOM_IOCTL_REGISTER_SERVICE_REQ \
_IOWR(TZCOM_IOC_MAGIC, 1, struct tzcom_register_svc_op_req)
/* For HLOS service */
#define TZCOM_IOCTL_UNREGISTER_SERVICE_REQ \
_IOWR(TZCOM_IOC_MAGIC, 2, struct tzcom_unregister_svc_op_req)
/* For TZ service */
#define TZCOM_IOCTL_SEND_CMD_REQ \
_IOWR(TZCOM_IOC_MAGIC, 3, struct tzcom_send_cmd_op_req)
/* For HLOS service */
#define TZCOM_IOCTL_READ_NEXT_CMD_REQ \
_IOWR(TZCOM_IOC_MAGIC, 4, struct tzcom_next_cmd_op_req)
/* For TZ service */
#define TZCOM_IOCTL_CONTINUE_CMD_REQ \
_IOWR(TZCOM_IOC_MAGIC, 5, struct tzcom_cont_cmd_op_req)
#define TZCOM_IOCTL_ABORT_REQ _IO(TZCOM_IOC_MAGIC, 6)
/* For TZ service */
#define TZCOM_IOCTL_SEND_CMD_FD_REQ \
_IOWR(TZCOM_IOC_MAGIC, 7, struct tzcom_send_cmd_fd_op_req)
#endif /* __TZCOM_H_ */