mirror of
https://github.com/hardkernel/linux.git
synced 2026-04-01 18:53:02 +09:00
PD#148390: add nandkey and secure storage the reserve mem used by secure monitor comes form secure os. we should not redefine it in DTS Change-Id: If42f2410474e090ed5b2bca143d5a9d16260f49c Signed-off-by: Jiamin Ma <jiamin.ma@amlogic.com>
260 lines
6.5 KiB
C
260 lines
6.5 KiB
C
/*
|
|
* drivers/amlogic/secure_monitor/flash_secure.c
|
|
*
|
|
* Copyright (C) 2017 Amlogic, Inc. 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 as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* 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/cdev.h>
|
|
#include <linux/module.h>
|
|
#include <linux/device.h>
|
|
#include <linux/types.h>
|
|
#include <linux/init.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/string.h>
|
|
#include <linux/ioport.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/err.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/bitops.h>
|
|
#include <linux/crc32.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/uaccess.h>
|
|
#include <linux/kthread.h>
|
|
#include <asm/irqflags.h>
|
|
#include <linux/errno.h>
|
|
#include <linux/of.h>
|
|
#include <linux/of_fdt.h>
|
|
#include <linux/libfdt_env.h>
|
|
#include <linux/of_reserved_mem.h>
|
|
#include <linux/io.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/dma-contiguous.h>
|
|
#include <linux/amlogic/meson-secure.h>
|
|
#include <asm/compiler.h>
|
|
#include "flash_secure.h"
|
|
|
|
|
|
#define SECURE_MONITOR_MODULE_NAME "secure_monitor"
|
|
#define SECURE_MONITOR_DRIVER_NAME "secure_monitor"
|
|
#define SECURE_MONITOR_DEVICE_NAME "secure_monitor"
|
|
#define SECURE_MONITOR_CLASS_NAME "secure_monitor"
|
|
|
|
|
|
static uint32_t sm_share_mem_addr;
|
|
static uint32_t sm_share_mem_size;
|
|
|
|
/*
|
|
* SHARE MEM:
|
|
* Communicate Head: 1KB
|
|
* communicate Head lock mutex location: the last 4B of HEAD; inited by secureOS
|
|
* Data: 128KB
|
|
*/
|
|
#define SHARE_MEM_HEAD_OFFSET 0x0
|
|
#define SHARE_MEM_DATA_OFFSET 0x400
|
|
#define SHARE_MEM_PHY_SIZE 0x20400
|
|
#define FLASH_BUF_SIZE 0x20000
|
|
|
|
#define SHARE_MEM_CMD_FREE 0x00000000
|
|
#define SHARE_MEM_CMD_WRITE 0x00000001
|
|
|
|
struct __NS_SHARE_MEM_HEAD {
|
|
unsigned int cmdlock;
|
|
unsigned int cmd;
|
|
unsigned int state;
|
|
/* can store input data position in NS_SHARE_MEM_CONTENT */
|
|
unsigned int input;
|
|
unsigned int inlen;
|
|
unsigned int output;
|
|
unsigned int outlen;
|
|
};
|
|
|
|
struct secure_monitor_arg {
|
|
unsigned char *pfbuf;
|
|
unsigned char *psbuf;
|
|
};
|
|
static struct secure_monitor_arg secure_monitor_buf;
|
|
static struct task_struct *secure_task;
|
|
|
|
static int secure_writer_monitor(void *arg);
|
|
|
|
static int secure_monitor_start(void)
|
|
{
|
|
int ret = 0;
|
|
|
|
sm_share_mem_addr = meson_secure_mem_flash_start();
|
|
sm_share_mem_size = meson_secure_mem_flash_size();
|
|
|
|
pr_info("%s:%d\n", __func__, __LINE__);
|
|
pr_info("sm share mem start: 0x%x, size: 0x%x\r\n",
|
|
sm_share_mem_addr, sm_share_mem_size);
|
|
secure_monitor_buf.pfbuf = kmalloc(FLASH_BUF_SIZE, GFP_KERNEL);
|
|
if (!secure_monitor_buf.pfbuf) {
|
|
pr_err("nandbuf create fail!\n");
|
|
ret = -ENOMEM;
|
|
goto flash_monitor_probe_exit;
|
|
}
|
|
secure_monitor_buf.psbuf = ioremap_cached(
|
|
sm_share_mem_addr,
|
|
sm_share_mem_size);
|
|
if (!secure_monitor_buf.psbuf) {
|
|
pr_err("ioremap share memory fail\n");
|
|
ret = -ENOMEM;
|
|
goto flash_monitor_probe_exit1;
|
|
}
|
|
|
|
secure_task = kthread_run(secure_writer_monitor,
|
|
(void *)(&secure_monitor_buf), "secure_flash");
|
|
if (IS_ERR_OR_NULL(secure_task)) {
|
|
pr_err("create secure task failed\n");
|
|
ret = -ENODEV;
|
|
goto flash_monitor_probe_exit2;
|
|
}
|
|
goto flash_monitor_probe_exit;
|
|
|
|
flash_monitor_probe_exit2:
|
|
if (secure_monitor_buf.psbuf)
|
|
iounmap(secure_monitor_buf.psbuf);
|
|
secure_monitor_buf.psbuf = NULL;
|
|
|
|
flash_monitor_probe_exit1:
|
|
kfree(secure_monitor_buf.pfbuf);
|
|
secure_monitor_buf.pfbuf = NULL;
|
|
|
|
flash_monitor_probe_exit:
|
|
return ret;
|
|
}
|
|
|
|
|
|
void write_to_flash(unsigned char *psrc, unsigned int size)
|
|
{
|
|
#ifdef CONFIG_AMLOGIC_M8B_NAND
|
|
int error = 0;
|
|
|
|
pr_info("%s %d save secure here\n", __func__, __LINE__);
|
|
error = secure_storage_nand_write(psrc, size);
|
|
if (error)
|
|
pr_err("save secure failed\n");
|
|
pr_info("///////////////////////////////////////save secure success//////////////////////////////////\n");
|
|
return;
|
|
#endif
|
|
|
|
#ifdef CONFIG_SPI_NOR_SECURE_STORAGE
|
|
unsigned char *secure_ptr = psrc;
|
|
int error = 0;
|
|
|
|
pr_info("%s %d save secure here\n", __func__, __LINE__);
|
|
error = secure_storage_spi_write(secure_ptr, size);
|
|
if (error)
|
|
pr_err("save secure failed\n");
|
|
pr_info("///////////////////////////////////////save secure success//////////////////////////////////\n");
|
|
return;
|
|
#endif
|
|
|
|
#ifdef CONFIG_EMMC_SECURE_STORAGE
|
|
unsigned char *secure_ptr = psrc;
|
|
int error = 0;
|
|
|
|
pr_info("%s %d save secure here\n", __func__, __LINE__);
|
|
error = mmc_secure_storage_ops(secure_ptr, size, 1);
|
|
if (error)
|
|
pr_err("save secure failed\n");
|
|
pr_info("///////////////////////////////////////save secure success//////////////////////////////////\n");
|
|
return;
|
|
#endif
|
|
}
|
|
|
|
|
|
static int secure_writer_monitor(void *arg)
|
|
{
|
|
struct secure_monitor_arg *parg = (struct secure_monitor_arg *)arg;
|
|
unsigned char *pfbuf = parg->pfbuf;
|
|
unsigned long flags;
|
|
|
|
struct __NS_SHARE_MEM_HEAD *pshead = (struct __NS_SHARE_MEM_HEAD *)
|
|
(parg->psbuf+SHARE_MEM_HEAD_OFFSET);
|
|
unsigned char *psdata = parg->psbuf + SHARE_MEM_DATA_OFFSET;
|
|
bool w_busy = false;
|
|
|
|
while (1) {
|
|
if (w_busy) {
|
|
write_to_flash(pfbuf, FLASH_BUF_SIZE);
|
|
w_busy = false;
|
|
}
|
|
|
|
flags = arch_local_irq_save();
|
|
if (lock_mutex_try(&(pshead->cmdlock))) {
|
|
if (pshead->cmd == SHARE_MEM_CMD_WRITE) {
|
|
memcpy(pfbuf, psdata, FLASH_BUF_SIZE);
|
|
pshead->cmd = SHARE_MEM_CMD_FREE;
|
|
w_busy = true;
|
|
pr_info("************kernel detect write flag*****\n");
|
|
}
|
|
unlock_mutex(&(pshead->cmdlock));
|
|
}
|
|
arch_local_irq_restore(flags);
|
|
|
|
if (!w_busy) {
|
|
if (kthread_should_stop())
|
|
break;
|
|
msleep(200);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int __init secure_monitor_init(void)
|
|
{
|
|
int ret = -1;
|
|
|
|
pr_info("%s:%d\n", __func__, __LINE__);
|
|
if (meson_secure_enabled()) {
|
|
ret = secure_monitor_start();
|
|
if (ret != 0) {
|
|
pr_err("fail to register sm drv err:%d\n", ret);
|
|
return -ENODEV;
|
|
}
|
|
return ret;
|
|
} else
|
|
return 0;
|
|
}
|
|
|
|
static void __exit secure_monitor_exit(void)
|
|
{
|
|
pr_info("**************flash_secure_remove start!\n");
|
|
if (secure_task) {
|
|
kthread_stop(secure_task);
|
|
secure_task = NULL;
|
|
}
|
|
|
|
if (secure_monitor_buf.psbuf)
|
|
iounmap(secure_monitor_buf.psbuf);
|
|
secure_monitor_buf.psbuf = NULL;
|
|
|
|
kfree(secure_monitor_buf.pfbuf);
|
|
secure_monitor_buf.pfbuf = NULL;
|
|
|
|
pr_info("**************flash_secure_remove end!\n");
|
|
}
|
|
|
|
|
|
module_init(secure_monitor_init);
|
|
module_exit(secure_monitor_exit);
|
|
|
|
|
|
MODULE_DESCRIPTION("AMLOGIC secure monitor driver");
|
|
MODULE_LICENSE("GPL");
|
|
MODULE_AUTHOR("Yan Wang <yan.wang@amlogic.com>");
|