blob: 036eed46f82fbbb6fcbfc9b5808958af7c63e7dd [file] [log] [blame]
/*
* TZ ICCC Support
*
*/
#include <asm/uaccess.h>
#include <linux/list.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/kobject.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/slab.h>
#include <linux/syscalls.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/proc_fs.h>
#include <linux/delay.h>
#include "tz_iccc.h"
/* ICCC implementation for kernel */
int is_iccc_ready;
#define DRIVER_DESC "A kernel module to read boot_completed status"
uint8_t *iccc_tci = NULL;
struct mc_session_handle iccc_mchandle;
uint32_t Iccc_SaveData_Kernel(uint32_t type, uint32_t value)
{
enum mc_result mc_ret;
struct mc_uuid_t uuid = TL_TZ_ICCC_UUID;
int ret = 0;
tciMessage_t *msg;
printk(KERN_ERR "ICCC : Iccc_SaveData_Kernel \n");
if (!is_iccc_ready) {
ret = RET_ICCC_FAIL;
pr_err("%s: Not ready! type:%#x, ret:%d\n", __func__, type, ret);
goto iccc_ret;
}
if(ICCC_SECTION_TYPE(type) != KERN_ICCC_TYPE_START) {
if (type != SELINUX_STATUS) {
ret = RET_ICCC_FAIL;
pr_err("iccc permission denied! ret = 0x%x", ret);
ret = RET_ICCC_FAIL;
goto iccc_ret;
}
}
/* open device for iccc trustlet */
mc_ret = mc_open_device(MC_DEVICE_ID_DEFAULT);
if (mc_ret != MC_DRV_OK) {
pr_err("ICCC --cannot get mobicore handle from kernel. %d\n",mc_ret);
ret = RET_ICCC_FAIL;
goto iccc_ret;
}
/* alloc world shared memory for iccc trustlet */
mc_ret = mc_malloc_wsm(MC_DEVICE_ID_DEFAULT, 0, sizeof(tciMessage_t),&iccc_tci, 0);
if (mc_ret != MC_DRV_OK) {
pr_err("ICCC --cannot alloc world shared memory.%d\n",mc_ret);
ret = RET_ICCC_FAIL;
goto iccc_close_device;
}
memset(&iccc_mchandle, 0, sizeof(struct mc_session_handle));
iccc_mchandle.device_id = MC_DEVICE_ID_DEFAULT;
/* open session for iccc trustlet */
mc_ret = mc_open_session(&iccc_mchandle, &uuid, iccc_tci,sizeof(tciMessage_t));
if (mc_ret != MC_DRV_OK) {
pr_err("ICCC : --cannot open mobicore session from kernel. %d\n",mc_ret);
ret = RET_ICCC_FAIL;
goto iccc_free_wsm;
}
msg = (tciMessage_t *)iccc_tci;
msg->header.id = CMD_ICCC_SAVEDATA;
msg->payload.generic.content.iccc_req.cmd_id = CMD_ICCC_SAVEDATA;
msg->payload.generic.content.iccc_req.type = type;
msg->payload.generic.content.iccc_req.value = value;
/* Send the command to the tl. */
mc_ret = mc_notify(&iccc_mchandle);
if (mc_ret != MC_DRV_OK) {
pr_err("ICCC--mc_notify failed.\n");
ret = RET_ICCC_FAIL;
goto iccc_close_session;
}
retry1:
mc_ret = mc_wait_notification(&iccc_mchandle, -1);
if (MC_DRV_ERR_INTERRUPTED_BY_SIGNAL == mc_ret) {
usleep_range(1000, 5000);
goto retry1;
}
if (mc_ret != MC_DRV_OK) {
pr_err("ICCC--wait_notify failed.\n");
ret = RET_ICCC_FAIL;
goto iccc_close_session;
}
pr_warn("ICCC--wait_notify completed.\n");
if (msg->payload.generic.content.iccc_rsp.ret == RET_ICCC_SUCCESS) {
pr_info("ICCC : Successfully write\n");
ret = RET_ICCC_SUCCESS;
}
else {
pr_err("ICCC : write failed with error (%d)\n",msg->payload.generic.content.iccc_rsp.ret);
ret = RET_ICCC_FAIL;
}
iccc_close_session:
if (mc_close_session(&iccc_mchandle) != MC_DRV_OK) {
pr_err("ICCC--failed to close mobicore session.\n");
}
iccc_free_wsm:
if (mc_free_wsm(MC_DEVICE_ID_DEFAULT, iccc_tci) != MC_DRV_OK) {
pr_err("ICCC--failed to free wsm.\n");
}
iccc_close_device:
if (mc_close_device(MC_DEVICE_ID_DEFAULT) != MC_DRV_OK) {
pr_err("ICCC--failed to shutdown mobicore instance.\n");
}
iccc_ret:
return ret;
}
uint32_t Iccc_ReadData_Kernel(uint32_t type, uint32_t *value)
{
enum mc_result mc_ret;
struct mc_uuid_t uuid = TL_TZ_ICCC_UUID;
int ret = 0;
tciMessage_t *msg;
printk(KERN_ERR "ICCC Iccc_ReadData_Kernel \n");
if (!is_iccc_ready) {
ret = RET_ICCC_FAIL;
pr_err("%s: Not ready! type:%#x, ret:%d\n", __func__, type, ret);
goto iccc_ret;
}
/* open device for iccc trustlet */
mc_ret = mc_open_device(MC_DEVICE_ID_DEFAULT);
if (mc_ret != MC_DRV_OK) {
pr_err("ICCC --cannot get mobicore handle from kernel. %d\n",mc_ret);
ret = RET_ICCC_FAIL;
goto iccc_ret;
}
/* alloc world shared memory for iccc trustlet */
mc_ret = mc_malloc_wsm(MC_DEVICE_ID_DEFAULT, 0, sizeof(tciMessage_t),&iccc_tci, 0);
if (mc_ret != MC_DRV_OK) {
pr_err("ICCC--cannot alloc world shared memory.%d\n",mc_ret);
ret = RET_ICCC_FAIL;
goto iccc_close_device;
}
memset(&iccc_mchandle, 0, sizeof(struct mc_session_handle));
iccc_mchandle.device_id = MC_DEVICE_ID_DEFAULT;
/* open session for iccc trustlet */
mc_ret = mc_open_session(&iccc_mchandle, &uuid, iccc_tci,sizeof(tciMessage_t));
if (mc_ret != MC_DRV_OK) {
pr_err("ICCC--cannot open mobicore session from kernel. %d\n",mc_ret);
ret = RET_ICCC_FAIL;
goto iccc_free_wsm;
}
/* Load message */
msg = (tciMessage_t *)iccc_tci;
msg->header.id = CMD_ICCC_READDATA;
msg->payload.generic.content.iccc_req.cmd_id = CMD_ICCC_READDATA;
msg->payload.generic.content.iccc_req.type = type;
/* Send the command to the tl. */
mc_ret = mc_notify(&iccc_mchandle);
if (mc_ret != MC_DRV_OK) {
pr_err("ICCC mc_notify failed.\n");
ret = RET_ICCC_FAIL;
goto iccc_close_session;
}
retry2:
mc_ret = mc_wait_notification(&iccc_mchandle, -1);
if (MC_DRV_ERR_INTERRUPTED_BY_SIGNAL == mc_ret) {
usleep_range(1000, 5000);
goto retry2;
}
if (mc_ret != MC_DRV_OK) {
pr_err("ICCC--wait_notify failed.\n");
ret = RET_ICCC_FAIL;
goto iccc_close_session;
}
pr_warn("ICCC--wait_notify completed.\n");
if (msg->payload.generic.content.iccc_rsp.ret == RET_ICCC_SUCCESS) {
pr_info("ICCC : Iccc_ReadData_Kernel successful\n");
ret = RET_ICCC_SUCCESS;
*value = msg->payload.generic.content.iccc_rsp.value;
}
else {
pr_err("ICCC : Iccc_ReadData_Kernel failed with error (%d)\n",msg->payload.generic.content.iccc_rsp.ret);
ret = RET_ICCC_FAIL;
}
iccc_close_session:
if (mc_close_session(&iccc_mchandle) != MC_DRV_OK) {
pr_err("ICCC--failed to close mobicore session.\n");
}
iccc_free_wsm:
if (mc_free_wsm(MC_DEVICE_ID_DEFAULT, iccc_tci) != MC_DRV_OK) {
pr_err("ICCC--failed to free wsm.\n");
}
iccc_close_device:
if (mc_close_device(MC_DEVICE_ID_DEFAULT) != MC_DRV_OK) {
pr_err("ICCC--failed to shutdown mobicore instance.\n");
}
iccc_ret:
return ret;
}
static ssize_t iccc_write(struct file *fp, const char __user *buf, size_t len, loff_t *off)
{
// uint32_t ret;
printk(KERN_ERR "%s:\n", __func__);
is_iccc_ready = 1;
#if 0//defined(CONFIG_SECURITY_SELINUX)
printk(KERN_INFO "%s: selinux_enabled:%d, selinux_enforcing:%d\n",__func__, selinux_is_enabled(), selinux_is_enforcing());
if (selinux_is_enabled() && selinux_is_enforcing()) {
if (0 != (ret = Iccc_SaveData_Kernel(SELINUX_STATUS,0x0))) {
printk(KERN_ERR "%s: Iccc_SaveData_Kernel failed, type = %x, value =%x\n", __func__,SELINUX_STATUS,0x0);
}
}
else {
if (0 != (ret = Iccc_SaveData_Kernel(SELINUX_STATUS,0x1))) {
printk(KERN_ERR "%s: Iccc_SaveData_Kernel failed, type = %x, value =%x\n", __func__,SELINUX_STATUS,0x1);
}
}
#endif
// len bytes successfully written
return len;
}
static const struct file_operations iccc_proc_fops = {
.write = iccc_write,
};
static int __init iccc_init(void)
{
printk(KERN_INFO"%s:\n", __func__);
if (proc_create("iccc_ready", 0644, NULL, &iccc_proc_fops) == NULL) {
printk(KERN_ERR "%s: proc_create() failed\n",__func__);
return -1;
}
printk(KERN_INFO"%s: registered /proc/iccc_boot_completed interface\n", __func__);
return 0;
}
static void __exit iccc_exit(void)
{
printk(KERN_INFO"deregistering /proc/iccc_boot_completed interface\n");
remove_proc_entry("iccc_ready", NULL);
}
module_init(iccc_init);
module_exit(iccc_exit);
MODULE_DESCRIPTION(DRIVER_DESC);
/* END ICCC implementation for kernel */